While there are a number of frameworks for web development (JEE, Spring etc.) that provide Off-The-Shelf design guidelines to help developers structuring their code, standalone (desktop) applications lack one. It is unfortunate to see even very good developers having difficulties in designing their code and creating spaghetti code.
Software design should be simple. In this blog entry we present some simple guidelines to good design. The Model-View-Controller (MVC) software architecture will be used. Even though the examples are in Java, these guidelines can be easily applied to other Object-oriented programming languages.
- Software officially starts from the requirements (most of the time). You should seek for a formal document that describes what you have to do, or put them down to paper (or in electronic form). Start by identifying the domain objects; these represent entities of the real world most of the time. E.g. if you have to develop an electronic library system, then your domain objects would be: Book, Librarian, User, etc. Try to identify the attributes (fields) of each domain object, e.g. for the Book(ISBN, title, authors, pages) etc. Assuming Java as your programming language, you should create 3 packages: model, view, controller. Inside model, create a domainobjects sub-package and inside there create the domain objects as Plain Old Java Objects (POJOs) or Value Objects (VOs). These should only contain the attributes and getters/setters. They are the base of your application, the objects that hold and transfer your data. They should contain no processing logic, like e.g. extractMessageFromNetworkObject() or parseWsdl(). Think that you should be able to directly persist them to a database. This way you can populate them from different sources (database, network, web services) without any change to them.
- Then you should be able to populate the domain objects with data. This is the job of a controller. It could be a controller that parses a text file, or retrieves data from a database or a SOAP message etc. Ideally, it should be a utility class with static methods and no state. It should return a VO (domain object), e.g. public static Book getBookBy(String isbn); retrieves a Book record from the database and creates and returns a Book VO out of it.
- To display the book data to the UI (an HTML form, a JavaFX client etc.), the view class should call the above controller to retrieve the Book object or another controller which will prepare the data according to the wishes of the view. This controller should ideally return the required data; the view should only deal with the presentation of the data, not their processing.
- Some more guidelines that enforce encapsulation and low coupling.
- Avoid dependencies to attributes as much as possible; e.g. assume a method that calculates the key of Book to be used by the e-Library application as the id (could be ISBN too but too slow). This could be a private method of the Book class (since it is private it doesn't matter much and doesn't violate the POJO discipline). This method calculates the key based on information from ISBN, the title, the authors and the category (e.g. science, history etc.). Instead of creating a method calculateKey() that depends on the attributes isbn, title, category, authors, the method signature should be calculateKey(String isbn, String title, Category category, List
authors) and you should pass the attributes as parameters to the method, where it is being called inside the Book class. If you need to refactor this method to another class, you only need to modify the callers to the method and you are done! - Try to reduce dependencies among classes. Think twice before you create a new dependency to another class and take a minute to think of the consequences. Think what could be changed in the future and what the impact will be. You should be able to easily refactor your code. Keep it simple.
- Try to use design patterns but don't overdo it. Design patterns provide a clean design that most of the time can be proved a good choice for future changes of requirements. You choose which design pattern might be appropriate for your problem by its intent.
- Comment your code; use javadoc and ideally a Software Architecture/Design Document. Unecessary documented code is much better than no comments at all. There you describe your intent, things for other developers to pay attention to, source (e.g. URL) of your algorithm, TODOs, the design pattern you use (or use annotations) etc. Your code is self-explanatory only to you. Not everybody thinks your way.