©2000-2017 Roedy Green of Canadian Mind Products
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)
- 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.
: 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.
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:
Bubblegum b = new Bubblegom();
Unfortunately the popularity of the ++ operator makes it harder to get away with
pseudo-redundant code like this:
swimmer = swimner + 1;
: 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.
Be polite, Never Assert
: Avoid the assert() mechanism because it could turn
a three-day debug fest into a ten minute one.
: 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.
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
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
: 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
: 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.
Too Much of A Good Thing™
myPanel.add( getMyButton() );
private JButton getMyButton()
That one probably did not even seem funny. Don’t worry. It will some day.
: 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
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.
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.
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
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.
: 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.
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
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
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.
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.
: 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.
: 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
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.
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.
: 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.
: 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!
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.
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.
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
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.
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
: In C, functions are supposed to be idempotent, (without side effects). I hope that hint is
: 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.
: 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.
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.
: 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
: 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.
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.