Architecture and Design for Clash of Civilizations


Architecture and design guidelines for the Clash of Civilizations code

Prepared by Gary Thomas, June 2002


Intent

The intent of these notes is to provide some general guidelines on the principles used in coding the Clash of Civilizations project, together with a high level design, and low level design specifics where useful.

You will have to excuse me if it is a hybrid of a description of the way the Clash coding works now (for new recuits), on the one hand, and a plan for how it should ideally work (for everybody, particularly me), on the other hand.

The document is divided into the following sections:

  1. Intent — this section.
  2. Introduction — a general statement on the aims of the Clash code.
  3. Associated reading — some important and less important references..
  4. Style and coding guidelines — some guidelines on Java coding style and practices.
  5. SDLC, a buzzword — some information on the Software Development Life Cycle.
  6. Architectural standards — notes on the principles which lead to better code.
  7. Clash philosophy — the general principles behind the development of Clash of Civilizations, from the Clash web site.
  8. Clash design — a high level design structure for Clash.
  9. Detailed design — notes on the detailed design, particularly where the classes concerned have a general application.
  10. Refactoring — what you do to imporve your code.
  11. Unit testing — a method of ensuring that your code works before anyone else has to cope with it.
  12. Libraries — a user guide for the library classes.
  13. Implementations — this is intended as a reference back to forum discussions leading to implementation decisions. Where relevant, the original text will be quoted (rather than referenced in the forum).
  14. Notes — a series of notes giving greater explanation, in the form "see [1]" for example.
  15. Index — an alphabetical index.


Introduction

The Clash of Civilizations program has not previously had any real documentation. I am speaking here of the code, not the project as a whole. There have been occasional forum posts aimed at improving the standard of the code, but these have been scattered, and have tended to get swamped with more detailed discussion, tending to obscure the underlying message.

It is important to understand the nature of the Clash program. It differs in significant ways from the normal run of software development.

The most significant difference arises from the fact that the code is written by physically separated individuals who have volunteered their time, communicating through the Clash Forum, and through email. This has led to particular constraints on what is possible, and in fact has in many cases significantly delayed progress. This happens, in particular, when new coders offer their services but, for whatever reason, never produce any code.

One of the aims of this document is to provide some guidance and assistance for these volunteers, based on my perception that being plunged into such a large project with no background or documentation will be, to say the least, daunting. Hopefully this will increase the number who stick with the project.

There are other differences — the program is intended to run as an application on a single machine (see [1]). This is a very considerable simplification, since all of the complexities associated with enterprise architecture do not apply.

So far running the program does not need any extra software, beyond a Java Virtual Machine. It is my strong preference to maintain this independence from the vagaries of other, sometimes "flavour of the month" and supposedly time-saving software. As will become evident during this document, it is my convinced opinion that dependencies are the the greatest single cause of software problems, and the only cause of that horror for all coders, software rot. It is bad enough having dependencies within the program, having them outside it can only lead to a general feeling of unease. If the program was written under the kind of tight control available in a normal software development environment this would be much less of a problem. However, there is a possibility, in the Clash coding environment, of a coder introducing some wonderful new tool, then departing the scene, with no-one else able to understand the resulting code. This has to be assessed as a high degree of risk.

Again, because of the environment, a higher than usual insistence on such development tools as JavaDocs is warranted. I will enlarge on this later.

There are some general principles which quite a few years of exposure to the problems of software development have convinced me are of general impact and importance. So here is a brief statement of the Precepts of Gary. I will return to these frequently.

I would have liked to include a hyperlink to the Clash web site and forum, but those addresses seem a little unstable. Presumably anyone reading this document already knows how to access them.


Associated reading

Naturally every book list is going to reflect the selector's personal preferences to some extent. However I have tried to restrict this list to books that are widely accepted as the best available. The categories I have used are learning Java, Java style, specialist Java, and Non-Java books.

Learning Java

The two volume Core Java series is an excellent introduction to Java, giving details of nearly everything required for normal Java coding. The books are:

Core Jave 2, Volume 1 — Fundamentals (1999)
Core Jave 2, Volume 2 — Advance Features (2000)
both by Cay S. Horstman, Gary Cornell, published by Sun Microsystems, the 5th edition is available as at 2002/06/13 (for date formats, see [2]).

Java style

The style book "Elements of Java Style" is a very small and very well done synopsis of the important elements of style in Java coding. It has 108 "rules". Each of these is clearly stated and, more to the point, is justified — they include no rule unless they can say why the rule is there.

The book is:

The Elements of Java Style (2000)
by Allan Vermeulen, Scott W. Ambler, Greg Bumgardner, Eldon Metz, Trevor Misfeldt, Jim Shur, Patrick Thomson, published by Cambridge Press for Roque Wave Software, part of the SIGS Books Series.

The only part of this book that I find myself in disagreement with are the rules relating to programming by contract.

Getting more to the coding level, Joshua Bloch's book on Effective Java has invaluable tips on many aspect of good Java coding. The book is:

Effective Java; Programming Language Guide (2001)
by Joshua Bloch, published by Sun Microsystems.

Finally, a book an Java design, more project oriented, has many useful tips and approaches. The book is:

Java Design; Building Better Apps & Applets (1999)
by Peter Coad, Mark Mayfield, Jon Kern, published by Yourden Press.

The second edition is available as at 2002/06/13.

Specialist Java

The O'Reilly series of books on specialist Java topics is a good range, with a uniformly high standard. The Java I/O book is likely to be of particular interest to beginning Java programmers.

Non-Java books

There are two very significant books, not specifically aimed at Java (in fact they are C++ oriented) which I cannot recommend strongly enough.

The best known is:

Design Patterns; Elements of Reusable Object-Oriented Software (1995)
by "the Gang of Four", Erich Gamma, Richard Helm, Ralph Johnson, John Vlissides, published by Addison Wesley.

This book has set a standard for communication between coders about code. Expressions like "I coded it as a singleton" or "I used a broker to hide the details" have become common. There have been attempts to extend the original concept to specialist areas and to other languages, such as Java, however these do not appear to have greatly added to the field.

Every coder should read this book.

The other book is:

Refactoring; Improving the Design of Existing Code (1999)
by Martin Fowler (with contributions by others), published by Addison Wesley.

This is quite possibly the best book on computing that I have ever read (out of a total of over a thousand). It emphasizes that a program, or program section is never "finished". It then describes the many ways in which a program can be seen to be begging for refactoring. This refactoring is the process of improving the code by re-writing or re-organizing parts of it. The book explains it better than I can. I have more to say on this subject under refactoring.

Don't be fooled by the reference to "existing code". The moment that you have written a line of code it becomes existing code and is a candidate for refactoring.


Style and coding guidelines

Some style rules are more important than others. Bear in mind that other people will have to read your code, and, hopefully, understand it. So, try and write it in such a way that their task is made easier. As a by-product, when you come back to your own code in a year's time, you will find it easier yourself. These rules are all aimed at making the code more readable. Many of them are just common politeness.

The concept of indenting nested code is so ingrained in most coders that it is easy to overlook the fact that many beginners do not even realize that it should be done. Of all the rules of style this is the most important. Badly indented (or unindented) code is atrocious to read. The rules are simple, always use indents and always use the same size indents. A subsidiary rule is always indent on continuation lines. There are lines of code in the current codebase where line continuations are aligned on the left with the first line. Ugly.

As a minor, related, rule that can be rather infuriating if disregarded, don't use hard tabs, use spaces to indent. Tabs on another person's machine may not work the way they do on yours.

It doesn't really matter what the size of the indent is. Common practice has two or four spaces. I personally prefer two (as recommended in Elements of Java Style), on the grounds that you run out of space more slowly, but if you have religious reasons for using four, by all means do so. However each java file should use one or the other, not mix them.

Always limit the line length to 80 columns. Not 81 or 82. Although this is to some extent a hangover from the very bad old days of punched cards and text screens it is nevertheless a convenient width for reading code. To have to scroll horizontally to see the rest of the line is intensely annoying.

As I have said before, always complete the JavaDocs comments. This is simple courtesy.

In many cases code is produced by a kind of code generator (Rational Rose, Together, or the drag and drop gui facilities of, for example, JBuilder). These programs often name their variables with names derived from the class of the variable, for example jPanel1, jPanel2, and so forth. Again it is a matter of courtesy (often to yourself) if you take the time to rename these to something more explanatory, such as topPanel, detailPanel, or whatever.

Don't use abbreviations — you may know what some strange combination of letters means, but even you may not remember exactly which particular version you chose. For example, which of "number", "num", "nr", "no", "nbr", "nmbr" or even "#" is the flavour of the month?

Don't use really long names. They are hard to read, and likely incomprehensible anyway. If you find you need such long names, it is likely that refactoring is called for.

Also, don't use Hungarian notation. This was designed for a more primitive language and is not appropriate for Java. It seriously impairs clarity with little or no added value. If you require bizarre mnemonics to understand what is going on in your code, you should be looking to repair the design faults.

Don't put comments at the end of the line — they interfere with the flow of the code. Comments should be on a single line, and refer to the next and subsequent lines of code. An exception to this is an explanation for local variables.

I personally am fond of ruling lines across code (using //---------) to break the code into more digestible sections. I often insert a brief heading into the middle of these lines. In particular I separate all the static data and methods into a single section of code, separated from the normal class definition by a line.

In case there are any who don't realize, Java class names, by convention, start with a capital letter. Constant names are all upper case. All other variables start with a lower case letter. Always.

And finally, keep everything small. A method longer than 30 lines should be looked at askance, as should a class file longer than 500 lines. These are guidelines, not rules, sometimes longer ones are needed. But make sure that they really are needed.

I should mention the "curly bracket on the same line" versus the "curly bracket on the next line" difference of opinion. So, I have now mentioned it.

Java deficiencies and traps

Java was designed by a committee. Actually by many committees. It would be a miracle under those circumstances if all parts of Java were consistent or up to the same standard of excellence. Sure enough, some parts of the Java language are defective and should be avoided. These are listed briefly below, with reasons and, where available, a reference to a more extended treatment. There are also some parts of Java in which it is easy, and tempting, to misuse the facilities that Java provides. These are discussedin this section.

Exceptions

There are some conceptual problems with the use of unchecked exceptions. Unchecked exceptions can be dangerous. They should only be used for what amount to unexpected and fatal errors in the program, and they should not be caught, they should cause the program to fail. They should not be thrown by your code. Since they should only occur in catastrophic disasters,if you are able to throw such an exception, then, as a preferred course of action, instead of crashing the program, shut it down gracefully.

Anything that can happen in the normal course of program execution should be caught and handled gracefully. In particular, it is bad form to throw an exception, to be caught and handled by the person using your classes, simply because you can't be bothered working out what to do about the exception condition. You are just ducking the problem.

Don't convert exceptions to reduce the amount of information available. This subverts the reason for having exceptions.

And, above all, never use a construction like:


  try {
    ...
  }
  catch (Exception e) {}

Java 1 Containers

The Vector and Hashtable classes have a number of deficiences, rectified by the the introduction of the container framework of Java 2. There are minor oddities (the methods of Vector and all declared final, those of Hashtable are not), but the most important reason for avoiding these classes is that their methods are synchronized, adding a significant and unnecessary overhead to their use. They should be replaced by ArrayList and HashMap.

Clone

This is discussed at length in Effective Java. Esssentially the clonable interface is defective because it fails to provide a clone method, and because the clone method of Object is protected, which means it cannot be called from outside the class or its descendants.

If you implement the Cloneable interface for a class, "it and all of its superclasses must obey a fairly complex, unenforceable, and largely undocumented protocol. The resulting mechanism is extralinguistic: It creates an object without calling a constructor" (from Effective Java).

So avoid the use of Cloneable.

The same effect can be achieved, without the extralinguistic "feature", by the use of copy constructors.

Observer and observable

These classes, dating from Java 1.0, have severe defects. The idea was to have a generic way of passing messages between classes, using a publisher/subscriber mechanism. The system is implemented by an observable class extending Observable, and the observer implementing an Observer interface. This immediately violates the "is-a" requirement for extension. Although the observable class is, indeed, observable, it is probably many other things as well, and the observability is not likely to be its most important characteristic. In effect, extension is being used to fill a role of the class, not its essence. This is bad coding practice.

There is another defect in the design of the Observer interface, in that the observable parameter in the update method is declared as Observable, rather than Object, which would make the interface much more useful (and modifiable).

This is discussed, with an alternative version, if you really must have an observer/observable option, in Java Design, section 5.3.1.3.

Don't put static data into interfaces

In an ill-judged attempt to provide something like the enum construct of C++, the Java language has the ability to include static data in an interface. This is sometimes used as a repository for constants. The only apparent advantage of doing this is to avoid having to prefix the name of the constant, when invoking it, with a class name. This saving of a few characters in typing is at the cost of possible naming confusion. Java name spaces are there for a reason, and are one of the significant advantages of the language.

In any case, constants should be typed and included in the class that defines them. An example of the preferred usage is the game.military.Category class in Clash.

The use of string constants (the usual use for static interface constants) should be approached with care, especially in an environment, such as Clash, where multi-language support is an ultimate aim.

Serialization

I will not dwell here on the problems of serialization, since, as a principle, it has been decided that Clash will not use serialization. The problems are very many, relating to the difficulty of debugging, and the possibility of software rot as new versions of Java become available. These matters are discussed in Effective Java, Chapter 10.

Clash has its own XML based equivalent, human readable and rot-free.

Strings

The string class provided by Java is a very convenient class for its purpose. However it should not be used in contexts outside that purpose. They should be used for output to a gui, and for name lists on input from an xml file. That is the extent of their use. Effective Java, item 32 has a detailed description of the deficiences of using strings as other kinds of data.


SDLC, a buzzword

The Software Development Life Cycle is a badly named (it doesn't usually include death or reproduction) area of knowledge much admired by many managers. It represents all the process from the initial inspiration which begins the project, through to release. It does not (usually) cover such things as fix-up releases. A great deal of nonsense has been written and spoken in the name of SDLC.

It is not the purpose of this section to provide a textbook on SDLC, just enough will be presented to make the points I want relating to the Clash project and the way it works.

Waterfalls

The most common model for development is what is known as the "waterfall model", which looks something like (there are many variants on the actual entries in the list):

Requirements
   |
   Scoping
      |
      Use cases
         |
         Use case realizations
            |
            High level design
               |
               Detailed design
                  |
                  Code
                     |
                     Unit testing
                        |
                        System testing
                           |
                           Acceptance testing
                              |
                              Release
This an excellent method for producing code that:

The problem with the straight waterfall model is that it has the underlying assumption that people can foretell the future accurately, and predict, before trying it out, exactly how the code will work. There is a simple improvement available for this model — iteration.

Iteration

In a word, the waterfall model lacks iteration. It attempts to write the whole program before testing begins. That system is much improved if part of the waterfall model is repeated as many times as necessary. This is the "iteration model". At each iteration more functionality is added (typically by implementing one or more extra use cases), and a fully tested version produced. It may have limited functionality, but it is tested code.

In the iteration model, the following section of the waterfall model is repeated (possibly without the Detailed design part) many times:

Detailed design
   |
   Code
      |
      Unit testing
         |
         System testing

This is probably the standard way for software houses to produce code, and is quite efficient. If, to this is added the possibility of going back to any previous point and re-working from that point, then good code will be the result.

Extreme programming

The next step in improving the software production cycle to to use what is termed "extreme programming" (or XP for short) techniniques. These techniques are described in the extreme programming web site at http://www.extremeprogramming.org and in the book:

Extreme Programming Explained; Embrace Change (2000)
by Kent Beck, published by Addison Wesley.

There are several important principles of extreme programming. However, many of them do not fit well with the distributed development environment that is the norm for Clash development.

Two that do apply are refactoring and unit testing.

Application to the Clash of Civilizations project

Inspection of the waterfall model reveals that most of the entries do not exist for Clash. There are some very high level specifications for various models, and some discussion on the forum. The description of models makes no attempt to link them together or put them in a framework of a program. There is no description or specification for program infrastructure of any kind. One of the purposes of this document is to provide some of the missing items, though not, mercifully, in the terms used in the waterfall model.

The Clash development environment does not permit many of the useful, or at least traditional, steps in the normal software development process.

Here are some of the salient features which make the Clash environment stand out:

What is lacking in this system is any kind of overall plan, to ensure that the separate coding efforts fit smoothly together. It is the main aim of these notes to provide that missing area.

Covering the items mentioned in the waterfall model:


Architectural standards


Clash philosophy


Clash design


Detailed design


Refactoring


Unit testing


Libraries


Implementations


Notes

[1] Earlier talk of runnig the program as an applet did not take into account the fact that program will inevitably become rather large (perhaps many megabytes) and impractical to download every time. Later plans for multi-player games can be incorporated in the design when they get closer to reality.

[2] In the coding team we have people who express dates as "July 24 2002", "7/24/2002", "24/7/2002", "24 juillet 2002" and perhaps others I have overlooked. The convention I have used here (and elsewhere) is the Asian format: 2002/07/24, or, in file names 20020724. This has two advantages:

For reasons that escape me I have been unable to convince others of the virtue of this approach.


Index