The Language: Naming
Naming classes, methods, and variables is an important activity that you need to devote time to, because names convey meaninga lot of meaning. Yet a name that conveys a lot of meaning to you may not convey that same meaning to another person. In particular, abbreviated names can really hamper how well the intended meaning is received. You should refrain from using any acronyms, abbreviations, and "initialisms" in your code unless the abbreviated form is so common that most people do not know the extended form (XML, for example). If you have any doubt about the meaning one of your names will convey, run it by a few members of your team. There is no substitute for peer review here.
For this example, you need to come up with good names for classes that perform the following functions:
- Run a background thread that wakes up periodically to look for XML files to validate
- Query the file system for files in the input directory; execute XSD schema validations on them
- Execute an XSD schema validation as a runnable task on a background thread pool
- Manage a thread pool that runs each validation task
Compare the names you would use with those on the following list:
What improvements could you make to convey the most meaning in each name? Here's a hint: good software designs maximize cohesion and minimize coupling. Cohesive classes contain code that centers around one central concept. That central concept should be, you guessed it, the name of the class. Code that does not relate to the central concept of that class should not be part of the class, or it will decrease cohesion. You introduce that code through coupling instead.
If you wrote only cohesive code, your software system would not be able to accomplish anything. You would have a collection of highly cohesive classes that would not cooperate to do anything useful. Coupling is an interaction of cohesive concepts to accomplish a particular purpose. You typically establish coupling by introducing variables of other classes into your class. Coupling is necessary, but needs to be minimized or your software system becomes unmanageable over time. Tightly coupled systems break easily when you enhance the code because the classes are overly interrelated.
Transfer Knowledge Through Pictures
The concept of coupling is best communicated with UML class diagrams of the various classes in this example. The class diagram in Figure 1 shows the classes governing the entry point into the system.
|Figure 1. Startup Overview:|
This class diagram shows the classes governing the entry point into the system.
The StartupValidator is the simple start-up servlet discussed previously. That class is coupled to the ValidatorPoller class (see Listing 8), so that the start-up servlet can start and stop a background thread that will poll the file system for files to validate. The FileProcessor class (see Listing 9) is coupled to the ValidatorPoller class so the poller (when it wakes up every 30 seconds or so) can simply tell the FileProcessor to collect and process any files it finds.
The UML class diagram in Figure 2 shows the coupling between the major classes that execute XSD schema validations.
|Figure 2. Coupling Between Validator Classes:|
This class diagram shows the coupling between the major classes that execute XSD schema validations.
The XSD schema validations start with the FileProcessor, which is coupled to the MultiThreadValidator class (see Listing 10). When the FileProcessor is told to execute validations, it sends any files it finds to the MultiThreadValidator. The MultiThreadValidator is coupled to the ValidatorProperties class (see Listing 11), which contains all the validation configuration information, such as where to find input files, where to send them when validated, how many background threads to run, and so on.
When the MultiThreadValidator is given a file to validate, it creates a ValidatorRunnable (see Listing 6) object and schedules it for execution on the thread pool it maintains. ValidatorRunnable cannot do its job alone, so it is coupled to a ValidationErrorHandler object (see Listing 7).
A picture is worth a thousand words. If you are not creating pictures, you are missing out on one of the most valuable mechanisms for transferring your knowledge to others. If you do create these valuable diagrams, make sure they are available to your team. You can easily convert them to images and include them in Javadoc as image references (see Figure 3). Of course, you can place them in design documentation as well.
|Figure 3. Javadoc Screen Capture:|
You can include UML class diagrams in Javadoc as image references.
Some of the most difficult decisions you will make when creating UML class diagrams are which details to leave in and which to leave out. For instance, the diagrams for this example could have included the utility classes FileUtil and PropertiesUtil, as well as many classes that come with the JDK (the ExecutorService, references to the Runnable interface, and so on). UML class diagrams may also document the variables and methods in your class, but too much detail will confuse your audience. Yet if you provide too little detail you may miss out on a valuable opportunity to convey knowledge.