image provider

Program Design


The cardinal rule of writing unmaintainable code is to specify each fact in as many places as possible and in as many ways as possible.
~ Roedy (1948-02-04 age:70)
  1. The key to writing maintainable code is to specify each fact about the application in only one place. To change your mind, you need change it in only one place and you are guaranteed the entire program will still work. Therefore, the key to writing unmaintainable code is to specify a fact over and over, in as many places as possible, in as many variant ways as possible. Happily, languages like Java go out of their way to make writing this sort of unmaintainable code easy. For example, it is almost impossible to change the type of a widely used variable because all the casts and conversion functions will no longer work and the types of the associated temporary variables will no longer be appropriate. Further, if the variable is displayed on the screen, all the associated display and data entry code has to be tracked down and manually modified. The Algol family of languages which include C and Java treat storing data in an array, Hashtable, flat file and database with totally different syntax. In languages like Abundance and to some extent Smalltalk, the syntax is identical; just the declaration changes. Take advantage of Java’s ineptitude. Put data you know will grow too large for RAM (Random Access Memory), for now into an array. That way the maintenance programmer will have a horrendous task converting from array to file access later. Similarly place tiny files in databases so the maintenance programmer can have the fun of converting them to array access when it comes time to performance tune.
  2. Java Casts

    : Java’s casting scheme is a gift from the Gods. You can use it without guilt since the language requires it. Every time you retrieve an object from a Collection you must cast it back to its original type. Thus the type of the variable may be specified in dozens of places. If the type later changes, all the casts must be changed to match. The compiler may or may not detect if the hapless maintenance programmer fails to catch them all (or changes one too many). In a similar way, all matching casts to (short) need to be changed to (int) if the type of a variable changes from short to int. There is a movement afoot in invent a generic cast operator (cast) and a generic conversion operator (convert) that would require no maintenance when the type of variable changes. Make sure this heresy never makes it into the language specification. Vote no on RFE 114691 and on genericity which would eliminate the need for many casts.
  3. Exploit Java’s Redundancy

    : Java insists you specify the type of every variable twice. Java programmers are so used to this redundancy they won’t notice if you make the two types slightly different, as in this example:
    // note subtle spelling change
    Bubblegum b = new Bubblegom();
    Unfortunately the popularity of the ++ operator makes it harder to get away with pseudo-redundant code like this:
    // note subtle spelling change
    swimmer = swimner + 1;
  4. Never Validate

    : Never check input data for any kind of correctness or discrepancies. It will demonstrate that you absolutely trust the company’s equipment as well as that you are a perfect team player who trusts all project partners and system operators. Always return reasonable values even when data inputs are questionable or erroneous.
  5. Be polite, Never Assert

    : Avoid the assert() mechanism because it could turn a three-day debug fest into a ten minute one.
  6. Avoid Encapsulation

    : In the interests of efficiency, avoid encapsulation. Callers of a method need all the external clues they can get to remind them how the method works inside.
  7. Clone & Modify

    : In the name of efficiency, use cut/paste/clone/modify. This works much faster than using many small reusable modules. This is especially useful in shops that measure your progress by the number of lines of code you’ve written.
  8. Use Static Arrays

    : If a module in a library needs an array to hold an image, just define a static array. Nobody will ever have an image bigger than 512 × 512, so a fixed-size array is OK. For best precision, make it an array of doubles. Bonus effect for hiding a 2 Meg static array which causes the program to exceed the memory of the client’s machine and thrash like crazy even if they never use your routine.
  9. Dummy Interfaces

    : Write an empty interface called something like WrittenByMe and make all of your classes implement it. Then, write wrapper classes for any of Java’s built-in classes that you use. The idea is to make sure that every single object in your program implements this interface. Finally, write all methods so that both their arguments and return types are WrittenByMe. This makes it nearly impossible to figure out what some methods do, and introduces all sorts of entertaining casting requirements. For a further extension, have each team member have his/her own personal interface (e.g., WrittenByJoe); any class worked on by a programmer gets to implement his/her interface. You can then arbitrarily refer to objects by any one of a large number of meaningless interfaces!
  10. Giant Listeners

    : Never create separate Listeners for each Component. Always have one listener for every button in your project and simply use massive if…else statements to test for which button was pressed.
  11. Too Much of A Good Thing™

    : Go
    myPanel.add( getMyButton() );
    
    private JButton getMyButton()
       {
       return myButton;
       }
    That one probably did not even seem funny. Don’t worry. It will some day.
  12. Friendly Friend

    : Use as often as possible the friend-declaration in C++. Combine this with handing the pointer of the creating class to a created class. Now you don’t need to fritter away your time in thinking about interfaces. Additionally you should use the keywords private and protected to prove that your classes are well encapsulated.
  13. Use Three Dimensional Arrays

    : Lots of them. Move data between the arrays in convoluted ways, say, filling the columns in arrayB with the rows from arrayA. Doing it with an offset of 1, for no apparent reason, is a nice touch. Makes the maintenance programmer nervous.
  14. Mix and Match

    : Use both accessor methods and public variables. That way, you can change an object’s variable without the overhead of calling the accessor, but still claim that the class is a Java Bean. This has the additional advantage of frustrating the maintenence programmer who adds a logging function to try to figure out who is changing the value.
  15. Wrap, wrap, wrap

    : Whenever you have to use methods in code you did not write, insulate your code from that other dirty code by at least one layer of wrapper. After all, the other author might some time in the future recklessly rename every method. Then where would you be? You could of course, if he did such a thing, insulate your code from the changes by writing a wrapper or you could let VAJ (Visual Age for Java) handle the global rename. However, this is the perfect excuse to preemptively cut him off at the pass with a wrapper layer of indirection, before he does anything idiotic. One of Java’s main faults is that there is no way to solve many simple problems without dummy wrapper methods that do nothing but call another method of the same name, or a closely related name. This means it is possible to write wrappers four-levels deep that do absolutely nothing, and almost no one will notice. To maximise the obscuration, at each level, rename the methods, selecting random synonyms from a thesaurus. This gives the illusion something of note is happening. Further, the renaming helps ensure the lack of consistent project terminology. To ensure no one attempts to prune your levels back to a reasonable number, invoke some of your code bypassing the wrappers at each of the levels.
  16. Wrap Wrap Wrap Some More

    : Make sure all API (Application Programming Interface) functions are wrapped at least 6 to 8 times, with function definitions in separate source files. Using #defines to make handy shortcuts to these functions also helps.
  17. No Secrets!

    : Declare every method and variable public. After all, somebody, sometime might want to use it. Once a method has been declared public, it can’t very well be retracted, now can it? This makes it very difficult to later change the way anything works under the covers. It also has the delightful side effect of obscuring what a class is for. If the boss asks if you are out of your mind, tell him you are following the classic principles of transparent interfaces.
  18. The Kama Sutra

    : This technique has the added advantage of driving any users or documenters of the package to distraction as well as the maintenance programmers. Create a dozen overloaded variants of the same method that differ in only the most minute detail. I think it was Oscar Wilde who observed that positions 47 and 115 of the Kama Sutra were the same except in 115 the woman had her fingers crossed. Users of the package then have to carefully peruse the long list of methods to figure out just which variant to use. The technique also balloons the documentation and thus ensures it will more likely be out of date. If the boss asks why you are doing this, explain it is solely for the convenience of the users. Again for the full effect, clone any common logic and sit back and wait for it the copies to gradually get out of sync.
  19. Permute and Baffle

    : Reverse the parameters on a method called drawRectangle(height, width) to drawRectangle(width, height) without making any change whatsoever to the name of the method. Then a few releases later, reverse it back again. The maintenance programmers can’t tell by quickly looking at any call if it has been adjusted yet. Generalisations are left as an exercise for the reader.
  20. Theme and Variations

    : Instead of using a parameter to a single method, create as many separate methods as you can. For example instead of setAlignment(int alignment) where alignment is an enumerated constant, for left, right, center, create three methods: setLeftAlignment, setRightAlignment and setCenterAlignment. Of course, for the full effect, you must clone the common logic to make it hard to keep in sync.
  21. Static Is Good

    : Make as many of your variables as possible static. If you don’t need more than one instance of the class in this program, no one else ever will either. Again, if other coders in the project complain, tell them about the execution speed improvement you’re getting.
  22. Cargill’s Quandry

    : Take advantage of Cargill’s quandary (I think this was his): "any design problem can be solved by adding an additional level of indirection, except for too many levels of indirection." Decompose OO (Object Oriented) programs until it becomes nearly impossible to find a method which actually updates program state. Better yet, arrange all such occurrences to be activated as callbacks from by traversing pointer forests which are known to contain every function pointer used within the entire system. Arrange for the forest traversals to be activated as side-effects from releasing reference counted objects previously created via deep copies which aren’t really all that deep.
  23. Packratting

    : Keep all of your unused and outdated methods and variables around in your code. After all — if you needed to use it once in 1976, who knows if you will want to use it again sometime? Sure the program’s changed since then, but it might just as easily change back, you "don’t want to have to reinvent the wheel" (supervisors love talk like that). If you have left the comments on those methods and variables untouched, and sufficiently cryptic, anyone maintaining the code will be too scared to touch them.
  24. And That’s Final

    : Make all of your leaf classes final. After all, you’re done with the project — certainly no one else could possibly improve on your work by extending your classes. And it might even be a security flaw — after all, isn’t java.lang.String final for just this reason? If other coders in your project complain, tell them about the execution speed improvement you’re getting.
  25. Eschew The Interface

    : In Java, disdain the interface. If your supervisors complain, tell them that Java interfaces force you to cut-and-paste code between different classes that implement the same interface the same way and they know how hard that would be to maintain. Instead, do as the Java AWT (Advanced Windowing Toolkit) designers did — put lots of functionality in your classes that can only be used by classes that inherit from them and use lots of instanceof checks in your methods. This way, if someone wants to reuse your code, they have to extend your classes. If they want to reuse your code from two different classes — tough luck, they can’t extend both of them at once! If an interface is unavoidable, make an all-purpose one and name it something like ImplementableIface. Another gem from academia is to append Impl to the names of classes that implement interfaces. This can be used to great advantage, e.g. with classes that implement Runnable.
  26. Avoid Layouts

    : Never use layouts. That way when the maintenance programmer adds one more field he will have to manually adjust the absolute coordinates of every other thing displayed on the screen. If your boss forces you to use a layout, use a single giant GridBagLayout and hard code in absolute grid coordinates.
  27. Environment variables

    : If you have to write classes for some other programmer to use, put environment-checking code (getenv() in C++ / System.getProperty() in Java ) in your classes’ nameless static initializers, and pass all your arguments to the classes this way, rather than in the constructor methods. The advantage is that the initializer methods get called as soon as the class program binaries get loaded, even before any of the classes get instantiated, so they will usually get executed before the program main(). In other words, there will be no way for the rest of the program to modify these parameters before they get read into your classes — the users better have set up all their environment variables just the way you had them!
  28. Table Driven Logic

    : Eschew any form of table-driven logic. It starts out innocently enough, but soon leads to end users proofreading and then shudder, even modifying the tables for themselves.
  29. Modify Mom’s Fields

    : In Java, all primitives passed as parameters are effectively read-only because they are passed by value. The callee can modify the parameters, but that has no effect on the caller’s variables. In contrast all objects passed are read-write. The reference is passed by value, which means the object itself is effectively passed by reference. The callee can do whatever it wants to the fields in your object. Never document whether a method actually modifies the fields in each of the passed parameters. Name your methods to suggest they only look at the fields when they actually change them.
  30. The Magic of Global Variables

    : Instead of using exceptions to handle error processing, have your error message routine set a global variable. Then make sure that every long-running loop in the system checks this global flag and terminates if an error occurs. Add another global variable to signal when a user presses the 'reset' button. Of course, all the major loops in the system also have to check this second flag. Hide a few loops that don’t terminate on demand.
  31. Globals, We Can’t Stress These Enough!

    : If God didn’t want us to use global variables, he wouldn’t have invented them. Rather than disappoint God, use and set as many global variables as possible. Each function should use and set at least two of them, even if there’s no reason to do this. After all, any good maintenance programmer will soon figure out this is an exercise in detective work and she’ll be happy for the exercise that separates real maintenance programmers from the dabblers.
  32. Globals, One More Time, Boys

    : Global variables save you from having to specify arguments in functions. Take full advantage of this. Elect one or more of these global variables to specify what kinds of processes to do on the others. Maintenance programmers foolishly assume that C functions will not have side effects. Make sure they squirrel results and internal state information away in global variables.
  33. Side Effects

    : In C, functions are supposed to be idempotent, (without side effects). I hope that hint is sufficient.
  34. Backing Out

    : Within the body of a loop, assume that the loop action is successful and immediately update all pointer variables. If an exception is later detected on that loop action, back out the pointer advancements as side effects of a conditional expression following the loop body.
  35. Local Variables

    : Never use local variables. Whenever you feel the temptation to use one, make it into an instance or static variable instead to unselfishly share it with all the other methods of the class. This will save you work later when other methods need similar declarations. C++ programmers can go a step further by making all variables global.
  36. Reduce, Reuse, Recycle

    : If you have to define a structure to hold data for callbacks, always call the structure PRIVDATA. Every module can define it’s own PRIVDATA. In VC++, this has the advantage of confusing the debugger so that if you have a PRIVDATA variable and try to expand it in the watch window, it doesn’t know which PRIVDATA you mean, so it just picks one.
  37. Configuration Files

    : These usually have the form keyword=value. The values are loaded into Java variables at load time. The most obvious obfuscation technique is to use slightly different names for the keywords and the Java variables. Use configuration files even for constants that never change at run time. Parameter file variables require at least five times as much code to maintain as a simple variable would.
  38. Bloated classes

    : To ensure your classes are bounded in the most obtuse way possible, make sure you include peripheral, obscure methods and attributes in every class. For example, a class that defines astrophysical orbit geometry really should have a method that computes ocean tide schedules and attributes that comprise a Crane weather model. Not only does this over-define the class, it makes finding these methods in the general system code like looking for a guitar pick in a landfill.
  39. Subclass With Abandon

    : Object oriented programming is a godsend for writing unmaintainable code. If you have a class with 10 properties (member/method) in it, consider a base class with only one property and subclassing it 9 levels deep so that each descendant adds one property. By the time you get to the last descendant class, you’ll have all 10 properties. If possible, put each class declaration in a separate file. This has the added effect of bloating your INCLUDE or USES statements, and forces the maintainer to open that many more files in his or her editor. Make sure you create at least one instance of each subclass.

This page is posted
on the web at:

http://mindprod.com/jgloss/unmaindesign.html

Optional Replicator mirror
of mindprod.com
on local hard disk J:

J:\mindprod\jgloss\unmaindesign.html
Canadian Mind Products
Please the feedback from other visitors, or your own feedback about the site.
Contact Roedy. Please feel free to link to this page without explicit permission.

IP:[65.110.21.43]
Your face IP:[44.221.83.121]
You are visitor number