Monday, 6 June 2011

Introducing synoptic - a console application framework for .net

If you want to go directly to the app, you can find us on github or you can view the wiki.

There needs to be more love for console applications. As a standard, our company produces a console application for every web site we develop. It doesn't contain all the functionality of the website, but does serve the following purpose:

  • Allows us to automate various parts of the site by giving us something that can be easily invoked via the build process (e.g. running a nightly map-reduce to update our data aggregates).
  • Allows us to debug the installation without firing up a web browser (e.g. showing the audit trail of a particular transaction if the client has any queries).
  • It proves to us that the front-end is sufficiently decoupled from the rest of the application to allow us to build a different user-interface for it later if necessary (e.g. mobile etc).
In our minds, the console application is not just a throw-away application - it is a first-class citizen of our solution and should be treated as such. I am going to presume that most (if not all) readers have implemented a console application at some point in their lives. These are some of the issues you probably had to deal with (or chose to ignore):

  • How do I parse the parameters input from the command line and what format do I support (--param, -param, param, /param?) 
  • How do I show the command line usage?
  • How do I map these parameters to methods that I want to call? How do I make sure that the parameters are valid for this particular method?
  • What about stderr and stdout? How do I prevent exception messages from being piped to other commands?
  • How do I output text neatly on the command line? Given that the console is 80 characters by default (but can be resized by the user), how do I make sure that the text wraps and indents correctly? For example, I often see this:
    This is my long text. I wanted it to be indented. What happens when it wraps to the next line?

or (note how the right edge of the first and second cells are not aligned correctly):

    This is the first cell.    This is text for the first cell.
    This is a much longer cell.    This is text for the second cell. 

Wouldn't it be better if it looked like this?

    This is the first cell.        This is text for the first cell
                                   and it wraps with the correct indentation.
    This is a much longer cell.    This is text for the second cell. 

Maybe this doesn't seem like a big deal, but it's not terribly difficult to fix (hint: the answer is not to manually insert line-breaks in your text because you don't know before-hand how wide the console is going to be).

These problems are already solved for web applications. The url and form parameters represent the input (which, using whatever web framework you decide to use, designates what method to run and how these parameters are parsed). The layout is obviously taken care of with html.

So what can synoptic do for you?

If you have used any reasonable web mvc framework, you have defined classes and methods which maps to user input (the url). Synoptic does a similar thing, but for command line applications. It's best explained by using an example:

Suppose you were using solr for search in your website and you were attempting to tune or maintain your search index. You might want to be able to do this from the command line so you can measure the performance or relevance regularly and maintain some kind of log. In synoptic, you would define this using the following syntax:
[Command(Name="search", Description="Allows you to perform various operations on the site search engine.")]
public class SearchCommand
{
    [CommandAction]
    public void Query(string term)
    {
        // Search logic goes here.
    }

    [CommandAction]
    public void RebuildIndex()
    {
        // Logic to rebuild you index goes here.
    }

}
Then in your application entry point, you feed the arguments to synoptic:
public class MyProgram
{
    public static void Main(string[] args)
    {
        new CommandRunner().Run(args);
    }
}
You could now invoke the query method from the command line using the following:
myapp.exe search query --term=mysearchterm

... or you could rebuild the search index with the following command:

myapp.exe search rebuild-index

If you run your application without specifying a command, you will see the usage pattern that is automatically generated (this is largely modeled on the git command line client behavior if it looks familiar).

That's all you need to get your first synoptic application up-and-running. There is much more information on the wiki that covers more advanced features such as:

  • Using dependency injection with your commands
  • Supporting "global" options (e.g. allowing the user to specify logging verbosity)
  • Customizing and validating parameters
  • Using the ConsoleFormatter to format text (including ConsoleTable, ConsoleRow, ConsoleCell and ConsoleStyle which can be used to create perfectly formatted, wrapped and indented content on the command line).
There are many new features we have in mind that we will hopefully be adding shortly (feel free to contribute with ideas or code):

  • Model-binding so that methods support more than just primitive types
  • More console-widgets (e.g. download progress etc.)
  • Additional customizations around global options
  • Internationalization

A big thank you to Mono.Options for providing such a versatile command parsing library (which synoptic uses internally).

6 comments:

  1. Good concept. This is helpful to me. Thanks for sharing.

    seo training in chennai

    ReplyDelete
  2. I want to thank for sharing this blog, really great and informative. Share more stuff like this.thanks for your information really good and very nice web design company in velachery

    ReplyDelete
  3. There are many new features we have in mind that we will hopefully be adding shortly (feel free to contribute with ideas or code):

    ReplyDelete