views:

199

answers:

4

What are some best practices to keep in mind when developing a script program that could be integrated with a GUI, probably by somebody else, in the future?

Possible scenario:

  1. i develop a fancy python CLI program that scrapes every unicorn images from the web
  2. i decide to publish it on github
  3. a unicorn fan programmer decides to take the sources and build a GUI on them.
  4. he\she gives up because my code is not reusable

How do i avoid step four and let unicorn fan programmer build his\her GUI without hassle?

+4  A: 

This sounds like a question about how to write usable code.

When considering reusablility of code, generally speaking, one should try to:

  • separate functionality into modules
  • have a well-defined interface

Separating functionality into modules

One should try to separate code into parts that have a simple responsibility. For example, a program that goes out to the internet to scrape pictures of unicorns may be separated into sections that a) scrapes the web for images, b) determines if an image is a unicorn and c) stores the said unicorn images into some specified location.

Have a well-defined interface

Having a well-designed interface, an API (application programming interface), is going to be crucial to providing a way to reuse or extend an application.

Providing entry points into each functionality will allow other programmers to actually write a new user interface for the provided functionality.

coobird
+1 That's a pretty good explanation, thanks. Don't you think that GUI would require an interface more specific than the CLI counterpart?
systempuntoout
In developing a GUI on top of a CLI (which is a very common design pattern -- separating the functionality from the presentation) one frequently finds a couple of options that are useful or necessary for the GUI but not much use for interactive or scripting. So, those options get added to the CLI. But most of a well designed and executed CLI will work just fine as a GUI back end.
mpez0
+10  A: 

You do it by applying a good portion of layering (maybe implementing the MVP pattern) and treating your CLI as a UI in it's own right.

UPDATE

This text from the wikipedia article about the Model-View-Presenter pattern explains it quite well.

Model-view-presenter (MVP) is a user interface design pattern engineered to facilitate automated unit testing and improve the separation of concerns in presentation logic.

* The model is an interface defining the data to be displayed or

otherwise acted upon in the user interface.

* The view is an interface that displays data (the model) and routes

user commands (events) to the presenter to act upon that data.

* The presenter acts upon the model and the view. It retrieves data

from repositories (the model), persists it, and formats it for display in the view.

The main point being that you need to work on separation of concern in your application. Your CLI would be one implementation of a view, whereas the unicorn fan would implement another view for a rich client. The unicorn fan, would base his view on the same presenters as your CLI. If those presenters are not sufficient for his rich client he could easily add more, because each presenter is based on data from the model. The model, in turn, is where all the core logic of your application is based. Designing a good model is an entire subject in itself. You may be interested in reading, for example, about Domain-Driven Design, even though I don't know how well it applies to your current application. But it's interesting reading anyway. As you can see, the wikipedia article on MVP also talks about testability, which is also crucial if you want to provide a robust framework for others to build on. To reach a high level of testability in your code-base, it is often a good idea to use some kind of Dependency Injection framework.

I hope this gives you a general idea of the techniques you need to employ, although I understand that it may be a little overwhelming. Don't hesitate to ask if you have any further doubts.

/Klaus

klausbyskov
+1 Could you elaborate a little?
systempuntoout
@systempuntoout I have elaborated a litte :-)
klausbyskov
Thanks a lot Klaus
systempuntoout
+1  A: 

You'll be taking input, executing an action, and presenting output. It might be a good idea to use a callback mechanism (such as event handlers, passing a method as a parameter, or passing this/self to the called class) to decouple the input and output methods from the execution of the action.

Aside from this, program to an interface, not to an implementation - the essence of MVC/MVP, as klausbyskov mentioned. e.g., Don't directly call file.write(); make myModel.saveMyData() which calls file.write, so someone else can make a somebodysModel.saveMyData() that writes to a database.

T.R.
+2  A: 

The solution to this kind of problem is very simple, but in practice, a lot of junior programmers have trouble with this pattern. Here's the solution:

  • You design a unicorn-scraping API. This is the hard step; good API design is insanely hard, and there aren't many examples to study. One API that I think is worth studying is the one in Dave Hanson's book C Interfaces and Implementations.

  • Then you design your command-line interface. If the functionality you are exposing is not to complicated, this is not too hard. But if it's complicated, you may want to think seriously about managing your API using an embedded scripting language like Lua or Tcl and designing an interface for scripting rather than for the command line.

  • Finally you write your command-line processing code and glue everything together.

Your hypothetical successor builds his or her GUI in one of two ways: using the embedded scripting languages, or directly on top of your API.

As noted in other answers, model/view/controller may be a good pattern to use in designing your API.

Norman Ramsey