Writing Flexible Code @(http://www.cs.usfca.edu/~parrt, Terence Parr) #### Introduction Writing flexible code requires you to learn a collection to tricks (patterns). If you follow this advice, your programs will live much longer lives. These patterns are not always the best approach at first. Sometimes you need to code quickly and then, if the code lives a few "generations", then you can refactor it to make it more flexible. #### Making an app run for multiple users on multiple machines Very often your program must be run on multiple machines by multiple people. This may include running on multiple OS types. Certain values may need to change in order for your application to work. For example, often where you store data on the disk is different or who should receive email when the software causes errors (you don't want errors going to all developers, just the one testing the software). The simplest thing to do is to create a property file full of values like this: << error.mail = parrt@jguru.com data.dir = /var/data/webmail developer = parrt >> Each developer would have a different file. Then, you can write software to ask for these values. Your application should be sensitive to these values. << // Looks for this file in CLASSPATH public static final String WEBMAIL_PROPS = "webmail.properties"; public String getClientProperty(String name) { InputStream in = ClassLoader.getSystemResourceAsStream(WEBMAIL_PROPS); EnhancedProperties props = new EnhancedProperties(); props.load(inStream); String prop = props.getProperty(name); return prop; } >> You can even make your application load a property file based upon the host name. << String hostname = InetAddress.getLocalHost().getHostName(); File f = new File( PROPERTY_FILE_REPOSITORY, hostname+".webmail.properties" ); ... >> In this case, a file called _hostname_{.webmail.properties} is loaded, automatically taking into account what machine the app will run on. #### Abstracting common functionality Checking for logged in state is common to most or all pages. Pull it up to a common superclass of all pages called Page. Change this: << class ForumViewPage { public void body() { if ( !loggedIn ) { // redirect to login page response.sendRedirect("/login"); return; } // logged in if they reach here! UserContext ux = session.getValue("usercontext"); int UID = ux.getPersonID(); Person person = PersonManager.getPerson(UID); String name = person.getName(); out.println("Hi "+name); } } >> to this: << public abstract class Page { public void generate() { if ( !loggedIn ) { // redirect to login page response.sendRedirect("/login"); return; } body(); } public abstract void body(); } class ForumViewPage extends Page { public void body() { ... // you know you are logged in UserContext ux = session.getValue("usercontext"); } } >> Now you have a single place to change common functionality for all pages such as this "logged in state" test. #### How To Design A Service To Be Swappable What is the problem with using a bunch of static methods grouped into a class like the following? << Person p = DatabaseManager.getPerson(376); >> The problem is that you have to change every one of these references if you need to swap out the {DatabaseManager}. Instead, create an interface that lets you refer to multiple implementations (polymorphism at its finest!): << ... DBInterface db = ServiceManager.getSomeDBInterfaceImplementation(); Person p = db.getPerson(376); ... class DatabaseManager implements DBInterface { public Person getPerson(int id) {x} } class RemotedatabaseManager implements DBInterface { public Person getPerson(int id) {do x on another machine} } class ServiceManager { public static DBInterface getSomeDBInterfaceImplementation() { if ( local ) { return new DatabaseManager(); } else if ( remote ) { return new RemoteDatabaseManager(); } } } >> As another example, consider building a visualization tool where you want both Swing and PostScript output. Define the generic concept of a graphics output engine: << public interface GraphicsEngine { public void drawLine(int x1, int y1, int x2, int y2); public void drawText(String txt, int x1, int y1); ... } >> and then make specific implementations: << public class SwingEngine implements GraphicsEngine { public void drawLine(int x1, int y1, int x2, int y2) { System.out.println("swing: drawLine"); // Graphics2D.... } public void drawText(String txt, int x1, int y1) { } } >> and << public class PSEngine implements GraphicsEngine { public void drawLine(int x1, int y1, int x2, int y2) { System.out.println("PS: drawLine"); } public void drawText(String txt, int x1, int y1) { } } >> Your program can generate output using a generic engine object << drawSomething(GraphicsEngine engine) { engine.drawLine(...); engine.drawText(...); } >> but the main program can indicate which actual implementation: << SwingEngine swing = new SwingEngine(); PSEngine ps = new PSEngine(); drawSomething(swing); drawSomething(ps); >> The important thing to note is the {drawSomething} does not know what actual implementation is being used. Late binding determines which {drawLine} etc... to actually call at runtime. #### Use accessor functions getXXX, setXXX _Note that I've since changed my mind so that I don't always use accessors. Intellij and other IDEs know how to refactor obj.var into obj.getVar() when necessary. My new rules are essentially that booleans and arrays and any data structure are used via accessors, but simple pointers to other objects or variables are used directly. This all assumes you are using Intellij or similar that knows how to change direct field access to accessor methods via a refactoring function in case the situation changes._ Imagine you have a {List} like this: << class List { public int n=0; public Object get(int i) {...} public Object add(Object value) {...} } >> You are tempted to access field {n} directly like this: << public static void main(String[] args) { List users = new List(); users.add("Ter"); ... int size = users.n; } >> This is easy to type and very fast. The problem is that you may change the implementation of the list and then {n} must be computed. Ooops...now you have to go change all of your {List.n} references to {getSize()} references. It is better to always use the accessor method for flexibility. << class List { int n=0; public int getSize() {...} ... } >> The on-the-fly compiler is usually smart enough to "inline" these method calls so you don't lose anything in speed, but gain all the flexibility. #### Avoid use of literals, use constants I see programs that use literals directly in code such as: << int[] a = new int[100]; >> There are two problems with this: 1 It's not as meaningful as {NUMBER_USERS} or whatever. 1 To change it, you have to find all places that use 100. Worse there may be multiple values of 100 with multiple meanings. A constant separates the various uses of 100. Another place where I see literals where you can do better: String lengths. Instead of doing this: << // get file name from "GET file" HTTP line String file = line.substring(4, line.length()); >> Consider the following: << String file = line.substring("GET ".length(), line.length()); >> This way it's clear (particularly if somebody doesn't include the comment above). Even better, is when you factor out your String literals. Here, "GET" is unlikely to change as billions of browsers around the world use that command. In other cases though you may want to factor out strings in case things change and you have multiple refs to the string. << public static final String SERVER_SIDE_JAVA_SIGNAL = "/java"; ... if ( file.startsWith(SERVER_SIDE_JAVA_SIGNAL) ) { ... } >> #### Separate Data and Code Originally jGuru code for menus was specific to our implementation rather than a table (or config property). E.g., << public void displayMenu() { // draw Home // draw FAQ ... } >> rather than a table and a loop for {displayMenu()}. The following is must more flexible and easy to change: << public static final String[] menuItems = { "Home", "FAQ", ...} ... public void displayMenu(String[] menuItems) { // for each item in menuItems, display item } >> Or you can use a property or config file to specify the data. Properties are good for fontsize and erroremail etc... as well. When building your web pages with StringTemplate, you'll see that keeping that HTML safely squirreled away in the templates and out of your code is great! Those templates can be changed without touching code and can even be updated on a live running server. Consider the following code that prints a list of files like your HTTP server project: << String[] filelist = dir.list(); p.println("