- Computer Humour Archive -
There is more computer humour in the general humour archives, but I've singled these ones
out for "special treatment" as they are very unlikely to be understood
by anyone who is not into computer programming - I'm aware that some of the funnies
in the general humour archive maybe ought to be moved into here, but right now I have to
admit that I just can't be bothered to work out which ones to move!
Right now this archive is pretty small as I've only just set it up - in time
I'm sure I'll remember more of my experiences and post them here, or if anybody E-mails
me with something it may well end up here as well - watch this space!
- Obfuscated no-ops and other stupidities
- Hexadecimal words
- Undocumented Instruction Opcodes
- Everyday SQL
- How to write illegible programs
- Information: Use of the MotherInLaw object
- Types of Bug
- Information: Possible Solution to MotherInLaw problems
- Technical Support: a bug in the system
- Murphy's Computer Laws (9th September 2005)
- Obfuscating your Error Messages (18h October 2005)
OBFUSCATED NO-OPS AND OTHER STUPIDITIES
The following is a great way to include a no-op in your Unix shell scripting:-
- ENVAR=`env | grep "^ENVAR=" | sed "s/[^=]*=//g"`
export ENVAR
For ENVAR substitute any environment variable of your choice, whether or not it exists.
As you can see, the env will pull out every environment variable, the grep will
find the line that starts with ENVAR followed by an equals
sign, and the sed will get rid of it leaving only the value of the variable.
The value returned will therefore be the existing value of ENVAR, which will then be
plugged back into ENVAR and exported. Pretty impressive no-op, huh?
==================
How about this to test for execution timings in C?
- for (i = 0; i < 10; i ++);
followed by
- for (i = 0; i < 100000; i ++);
A decent compiler will pick up the fact that the loop does absolutely nothing
and will replace the first statement with i=10; and the latter with i=100000;
Even better, if the loop variable is not used anymore or re-initialised without
first being used, the compiler (if it's worth it's salt) will get rid of the whole
loop altogether!
What is really fun is when someone asks you to debug their C code because after the
for (...) statement they have mistakenly placed a semicolon before the opening curly.
It can take ages to spot mistakes like that!
==================
At one stage, I was required to debug a program which had the following lines of code -
in those days I was working in 6800 Assembler Language, and the CLR instruction is
used to clear a single byte of memory:-
I presume the second clear was needed in case the first one should fail, and the third
one in case the second one failed....(!) Or maybe it was the bug I was looking for?
HEXADECIMAL WORDS
You're probably aware that machine-code programmers (and others!) use hexadecimal a lot.
This is a numbering system that uses the digits 0 to 9 and the letters A to F as it
required to represent 0 through 15 each using a single digit. Using 0 as an "O,"
1 as an "I" and 5 as an "S" it is possible to make the following words
(ignoring plurals formed by adding an S or ES):-
| A1D |
A1DED |
AB1DE |
AB0DE |
ACE |
ACCE55 |
| ADD |
ADDED |
A5 |
A5CE515 |
A51A |
A51DE |
| A55 |
BAB1E5 |
BAD |
BADE |
BADD1E |
BA5E |
| BA5ED |
BA5E5 |
BA51C |
BA515 |
BA55 |
BE |
| BEAD |
BEE |
BEEF |
BEEFED |
BED |
BED51DE |
| BED51DE5 |
BE5IDE |
B1A5 |
B1A5ED |
B105 |
B1D |
| B1DE |
B1D5 |
B0D |
B0DE |
B055 |
B055ED |
| CAB |
CABB1E |
CADD15 |
CACA0 |
CAD |
CAD1 |
| CADD1E |
CAFE |
CA1550N |
CA5E |
CA5ED |
CEA5E |
| CEA5ED |
CEA5E5 |
C1A0 |
C0D |
C0DA |
C0DE |
| C0DED |
C0DE5 |
C0FFEE |
C00 |
C00ED |
DA15 |
| DAD |
DADD1E5 |
DEAD |
DEAF |
DEBB1E |
DECADE |
| DECAF |
DECEA5E |
DECEA5ED |
DECEA5E5 |
DEC1DE |
DEC1DED |
| DEC1DE5 |
DEBA5ED |
DEC0DE |
DEC0DED |
DEED |
DEFACE |
| DEFACED |
DEFACE5 |
DEED |
DEF1ED |
DEF1E5 |
DE1F1ED |
| DE1F1E5 |
D1CE |
D1CED |
D1E |
D1ED |
D1E5 |
| D10DE |
D15C |
D15C0 |
D15C5 |
D15EA5E |
D15EA5ED |
| D0 |
D0E5 |
D05E |
D05ED |
EA5E |
EA5ED |
| FACADE |
FACE |
FACED |
FADE |
FADED |
FAECE5 |
| FA5C1A |
FED |
FEE |
FEED |
FEED5 |
F1A5C0 |
| F0B |
F0E |
F00D |
1CE |
1CED |
1DEA |
| 15 |
0A515 |
0DE |
0F |
0FF |
51DE |
| 51DED |
51DE5 |
5AD |
5AFE |
5A1D |
50D |
| 50DA |
5EA5 |
5EA51DE |
5EE |
5EED |
5EEDED |
| 5EE5 |
50 |
|
|
|
|
I hope the phrase, "Get a Life" doesn't spring to mind!
There are almost certainly plenty more, and I'll add them as I come across them!
I think what really takes the biscuit was the day I was running the C debugger
at work, and gave the X command by mistake, which displays the internal registers.
Most of the registers contained DEADBEEF.
UNDOCUMENTED INSTRUCTION OPCODES
I've finally discovered that the reason why computers don't always behave as expected
is because it is executing one of the following instructions.
- SAD: Spontaneously Adjust Document
Ever been typing a document
and the word processor insists that you are writing a letter, creating a list, or doing
something else that is not only unexpected but positively irritating? Well, now you know
the instruction that does it!
- RCC: Read Card and Crumple
Included for historical reasons - this would be executed on card readers to ensure the
cards were Read Once Only.
- XRI: eXecute Random Instruction
A useful instruction to make the computer do something completely unpredictable
such as insisting that you want to re-connect to the Internet when you are in the middle of
typing a Word document, for example.
- FWR: Format Winch and Reboot
This is one for the virus writers
- CTS: Cripple The System
Kicks off a processor-hungry task that makes everything else grind to a halt.
Usually hacks the disk big time and leaves you wondering, "What the hell is
going on?"
- FAR: Force Abnormal Reboot
This instruction locks the system up solid so you can't do anything at all - including
moving the mouse pointer. You have to switch off and back on again and run ScanDisk
before you can continue working.
- HCF: Halt and Catch Fire
Believe it or not, this one really does exist! HCF halts the system
and waits for an interrupt.
If you don't believe me see the Motorola M6800 instruction set!
- TIC: Terminate Internet Connection
Throws you off the Internet for no apparent or good reason. There is one good use for
this instruction, namely for people downloading naughty pictures!
- CNR: Crash for No Reason
Causes programs to crash with that "The program has performed an illegal operation
and will be shut down" error message.
It takes a parameter, namely the number of times you have to click
that "Close" button to be able to continue working.
Some of these can be modified with the BT (Big Time) modifier, and others with the WAV
(With A Vengeance) suffix. Sometimes the two can be combined, hence it is possible
to have the following instruction:-
- CTSBTWAV: Cripple The System Big Time With A Vengeance
Perfect for use in multi-user environments when you want to hog the system
for your own use.
EVERYDAY SQL
Here are some SQL instructions you may find useful from time to time:
-
To find sucky websites:
SELECT WEBSITE_URL FROM KNOWN_WEBSITES WHERE SITE_SUCKS LIKE 'TORNADO';
-
To put JOHN into your bad books:
INSERT INTO BAD_BOOKS
(SELECT * FROM GOOD_BOOKS WHERE NAME = 'JOHN');
DELETE FROM GOOD_BOOKS WHERE NAME = 'JOHN';
-
One for the ladies when trying to find a cheap dress:-
SELECT DRESS FROM CHARITY_SHOP WHERE PRICE < 10 AND DRESS LIKE 'NEW';
-
This one is useful at breaktimes:-
SELECT SNACK FROM VENDING_MACHINE WHERE SNACK_TASTES LIKE 'CHOCOLATE';
HOW TO WRITE ILLEGIBLE PROGRAMS
- Use non-obvious abbreviations for your variable, function and subroutine
names. For example, why use a variable name such as "return_code" when
"rc" will do? When you need to have a variable such as "run_condition"
in the same program then call it something like "rc1."
- Make sure that you use such variable names as "retncd," "retcode,"
"returncd," "return_code", "returncode", etc.
all in the same program.
- If you don't like short variable names, then try using long names instead.
We love having to plough through programs which use variable names
such as "property_status_after_the_first_iteration_of_the_outer_loop."
If that really is too long then just use "psatfiotol" instead.
- If variable names are case-sensitive, use all possible combinations
available. So "rc," "Rc," "rC" and "RC"
are all game on. This technique is good for when you don't want other people to
understand your code - a sort of software protection if you like.
- If you must use variable names such as "return_code," ensure also
that you use a variable such as "code_returned" as well. It gets
really confusing when you have to continually use similar-sounding
variable names, and one common mistake is to use one when you should
be using the other.
- Sorry - another one on variable names. I recently discovered the following
variable names in use at work. They were both of type BLOB (Binary Large OBject):
- BlobberyRubberyThing
- MrBlobby
- Use GOTO whenever possible. There's nothing that support guys like more
than having to wade through tons of spaghetti coding that is nigh on
impossible to understand. It gives them a kick to know that they can
understand something that the rest of us wouldn't have a clue about, or
would have given up on ages ago.
- Do not indent your code at conditional statements, functions, subroutines
and loops. You will probably need to save the space that indenting tabs
or spaces would have used up. Plus lines of code that spead over 2 lines
due to indentation look really, really ugly.
Alternatively, use a non-standard indentation technique to make readers
think that code at one level should be at a different level.
- Do not, whatever you do, dare to use comments. They take up valuable
space and clutter your program up so you can't see the code for the
remarks. It's sooooooo much fun trying to figure out what your code
does that you wrote 5 years ago and are now required to modify.
- If you do like comments and can't bear the thought of having a program
without any, then make sure you comment every line of code in such a way
as to be absolutely no help to others whatsoever.
They're only there for your own benefit anyway.
Alternatively, write a dissertation at the top of every 5-line function
explaining what it does, the way it does it, and why it does it.
- Do not remove dead code, or even comment it out. Just leave it hanging
around in there so that others will come across it and try to understand
what it does. When someone does do this, gently point out to him/her
that the code is dead so it doesn't matter, but leave it a day or so
first so you can have a good laugh.
- When you change the functionality of a section of code, do not alter the
comments (if any) to reflect what it now does. Support people like having
to clairvoyantly detect whether any particular comment is accurate or not.
- When you need to write some code that does 75% of what an existing function
does, do not lift the code from the function and write a customised version.
Rather, call the function and follow this with lots more code to unpick the
work the function did that you didn't require.
It's sure to contain a bug somewhere along the line as well.
- Have umpteen copies of the same section of code hanging
around and refuse to package it up in a function.
You'll have loads of fun in 5 years time when you have to make a change -
now you've got to change it in 20 different places instead of just one,
and (as an added bonus) have to work out what each occurrence of the code
does to make sure there are no subtle differences between each one.
- Adopt the attitude, "Why make it simple when I can make it complicated?"
Write code in as obfuscated a manner as possible, and cram as much as you
can into each line of code. This is particularly effective in such
languages as C, Perl, and shell-scripting. People who can't understand
your code shouldn't come anywhere near your programs anyway.
- Tips for assembler programmers:
- Use hexadecimal numbers instead of names or sensible constants.
Why use 'A' for example when #&41 or 65 will suffice?
Also, represent bit patterns as decimal numbers, so a series of 8 flags
that can be set or clear for example could be represented by a number like
172 instead of #&AC.
- Refer to bits within a flags byte by its bit value instead of giving each
one a name. Thus you will refer to each bit as 1, 2, 4, 8 etc. instead of
using sensible flag names such as read_only, write_only, locked, in_core, etc.
- Don't use named constants. Hardcode the values instead. Making simple
changes to easy-to-read code is for wimps, and no programmer wants to be
accused of writing code for wimps.
- Make your error messages as incomprehensible or meaningless as possible,
and use the same message to mean entirely different things.
If a routine can display an error message at several different points,
use the same message each time with no indication as to which error exit
is being taken. A good message might run along the lines of,
"Function <name> has detected a memory violation." Let support sort
it out - they're good at that sort of thing.
- Make sure that messages written to log files are of absolutely no use
whatsoever. God forbid that anybody should be able to trace your code
should it appear to work but does absolutely nothing without letting
you know about it. The same applies for messages written to error
log files.
INFORMATION: USE OF THE MOTHERINLAW OBJECT
The YoungLady object inherits from its Mother object.
When you use the Marry() method of the YoungLady object,
because it inherits from its Mother object, you end up instantiating
this same object by default. To you, this object may be referenced
using MotherInLaw, although TheOldBattleaxe is usually an accepted synonym.
Very few methods of the MotherInLaw are useful, but some are, and others
may be exploited to good use:
-
SendToTaxidermist()
This method will make the MotherInLaw object get stuffed.
Usage: li_RetVal = MotherInLaw.SendToTaxidermist();
An exit value of 0 indicates that your MotherInLaw has successfuly got
stuffed, while any other value indicates abject failure.
It is suggested you use this function in a loop such as the following:
li_RetVal = -1;
while (li_RetVal != 0) li_RetVal = MotherInLaw.SendToTaxidermist();
This will continue executing until the function is successful.
-
PopUp()
This method causes the MotherInLaw object to pop up.
Usage: li_RetVal = MotherInLaw.PopUp();
This method may not appear useful at first sight, since very few,
if any, applications require the MotherInLaw object to pop up at all.
Unfortunately, this method has the undesired side-effect in that it
often executes without warning and for no known or good reason,
and sometimes seems to execute explicitly when required not to do so.
However, if you can control when the MotherInLaw pops up, you may use
the Punch() method (see below).
The exit status of the PopUp() method is usually 0 (popped up successfully)
or 1 (already popped up). A value of -1 (failure to pop up) is
theoretically possible but in practice never occurs,
unless the Marry() method of some YoungLady object has not been used.
-
Punch(arg)
This method will punch the MotherInLaw object wherever specified by
the argument passed as a parameter. The accepted values for arg are
"eyes," "nose," "mouth," "stomach."
A null or invalid value will default to "mouth".
It usually works fine, but the PopUp() method must have been executed first,
or your Punch() will return an error code of -1 (meaning "missed").
It has been discovered that using this method often triggers the Offend()
event of the YoungLady object.
This is unfortunate, but as it takes very little indeed to
trigger this event, this is hardly surprising.
The Offend() method of the YoungLady object has the effect of setting the
Offended property which can only be cleared by the use of other
YoungLady methods such as GiveChocolates(), GiveLotsOfTLC(),
DealWithYouDontLoveMeRemarks(), and
ApologiseProfuselyButExplainWhyItHadToBeDone().
-
Interfere()
You NEVER need to call this method. It will always execute spontaneously,
and for no known or good reason. Anyone who writes an application that
uses this method needs his/her head seen to, or (much better) the men in
white coats to come and take them away.
Interference can only be caused by a popped-up MotherInLaw,
so the first thing the Interfere() method does is to call the PopUp() method.
This is why the PopUp() method sometimes seems to execute spontaneously.
A sufficiently quick use of Punch() after the implicit PopUp() may
stop interference, but MotherInLaw objects usually have built-in
regeneration methods that enable them to bounce back,
usually with quite a vengeance.
Code (function) example:
void DealWithMotherInLaw()
{
// Ensure the MotherInLaw is popped up
li_RetVal = MotherInLaw.PopUp();
// Ensure MotherInLaw has popped up
// Crash the system if not because
// something has gone seriously wrong
if (li_RetVal < 0)
This.Crash();
else
{
// Deal with popped up object
MotherInLaw.Punch(mouth);
MotherInLaw.Punch(eyes);
MotherInLaw.Punch(nose);
MotherInLaw.Punch(stomach);
// Now let her get stuffed
li_RetVal = -1;
while (li_RetVal < 0)
li_RetVal = MotherInLaw.SendToTaxidermist();
}
// Now deal with the unwanted side-effects
// many of which could be very serious.
// Use the 'with YoungLady' construct to
// specify which object the methods are in.
with YoungLady
{
while (Offended)
{
GiveChocolates(expensive);
GiveLotsOfTLC();
DealWithYouDontLoveMeRemarks();
ApologiseProfuselyButExplainWhyItHadToBeDone();
}
}
}
Note that this code is packaged into a function. It is worth placing it into
a global object, so it can be referenced from anywhere within the system.
Additional Complications:
The fact that you used a Marry() method of some YoungLady object means that
she, by default, has used your Marry() method. As you inherit from your
Mother object, this means that the YoungLady will also instantiate a
MotherInLaw object too. This has been known to cause system conflicts,
especially should the two MotherInLaw objects come close together in memory,
and can often result in a deadly embrace. Whatever you do, DO NOT let the
two MotherInLaw objects use the Interfere() method simultaneously as
the results can be quite fatal.
Please Click here to see a possible solution
to the Mother-In-Law problem.
TYPES OF BUG
-
Bohr bug:
/bohr buhg/ n. [from quantum physics] A repeatable bug; one that manifests
reliably under a possibly unknown but well-defined set of conditions.
-
Heisenbug:
/hi:'zen-buhg/ n. [from Heisenberg's Uncertainty Principle in quantum
physics] A bug that disappears or alters its behavior when one attempts
to probe or isolate it (this usage is not even particularly fanciful;
the use of a debugger sometimes alters a program's operating environment
significantly enough that buggy code, such as that which relies on the
values of uninitialized memory, behaves quite differently).
-
Mandelbug:
/man'del-buhg/ n. [from the Mandelbrot set] A bug whose underlying causes
are so complex and obscure as to make its behavior appear chaotic or even
non-deterministic.
-
Schroedinbug:
/shroh'din-buhg/ n. [MIT: from the Schroedinger's Cat thought-experiment in
quantum physics] A design or implementation bug in a program that doesn't
manifest until someone reading source or using the program in an unusual way
notices that it never should have worked, at which point the program
promptly stops working for everybody until fixed. Though this sounds
impossible, it happens; some programs have harbored latent schroedinbugs
for years.
-
Fandango on core
[Unix/C, from the Mexican dance] In C, a wild pointer that runs out of
bounds, causing a core dump, or corrupts the malloc arena in such a way
as to cause mysterious failures later on, is sometimes said to have
"done a fandango on core". On low-end personal machines without
an MMU, this can corrupt the operating system itself, causing massive
lossage. Other frenetic dances such as the rhumba, cha-cha, or watusi,
may be substituted.
-
Overrun screw
A variety of fandango on core produced by a C program scribbling past
the end of an array (C implementations typically have no checks for
this error). This is relatively benign and easy to spot if the array
is static; if it is auto, the result may be to smash the stack -
often resulting in heisenbugs of the most diabolical subtlety. The term
"overrun screw" is used especially of scribbles beyond the
end of arrays allocated with malloc; this typically overwrites the
allocation header for the next block in the arena, producing massive
lossage within malloc and often a core dump on the next operation to
use stdio or malloc itself.
INFORMATION: POSSIBLE SOLUTION TO MOTHERINLAW PROBLEMS
You may, at some stage, find it desirable to use some YoungLady's
Marry() method (assuming you haven't already done so),
but at the same time not want the problems caused by
inheriting MotherInLaw objects in the process.
This is perfectly understandable, and nobody will blame you if you
find such a desire arising within yourself.
Please Click here for a description of the methods of
a MotherInLaw object, and how some of them can be exploited to good use.
What if the YoungLady object is instantiated halfway across the world?
What do you think the effects of that could be? Especially if her
default Language property is not set to the same as yours?
Firstly, it could result in communication problems between the Self
object and the YoungLady.
She would need to use her Language.Learn(English) method
and you would need to use your Language.Learn(x) method, where x is
the default value of the YoungLady's Language property.
Alternatively, you could both use your Language.Learn(y) methods, where
y is any other language of choice for both of you.
Unfortunately this appears to be the only way to get a common language
that both objects can communicate in.
However, there would be no need for the respective MotherInLaw objects to
use any Language.Learn() methods, thus they will be unable to communicate
due to the lack of a common language as well as the vast distance
separating the two objects.
Another conflict that would never arise with this scenario is that of
problems occurring due to the two MotherInLaw objects coming too close
in memory: either they will remain a safe distance from each other, or,
should they come too close, the fact that their Language properties
are set differently will ensure that no Interfere() method can
be called.
Thus, chances are, you'll be safe from many problems caused by
these objects being around.
TECHNICAL SUPPORT: A BUG IN THE SYSTEM
This woman went out to a local computer store to buy a computer that her family wanted
her to get so she can e-mail them. The sales person told her that they would deliver
the computer, set it up and give her some pointers on using it, if she had any problems
later all she had to do was call their "Technical Support" they would talk her
through it over the phone or come back to her house to find the problem.
The sales person asked her if she wanted to purchase 2 years in house warranty, the woman
said yes. A few months went by, she was getting good sending and receiving mail and
checking the other web sites with only one call to tech support until one day.
She called tech support.
SUPPORT: Hello, technical support how can I help you?
LADY: Last night my computer started making a lot of hissing noise at me so I shut it down.
This morning, when I turned it on, the computer started hissing and cracking then started
smoking and a bad smell, then nothing.
SUPPORT: I will have a technician come over first thing this morning. Just leave the
computer just like it is so they can find the problem and fix it or change it with another
computer. Give me your address and phone number and the technician will be there just as
soon as they can in the morning.
When the technician got there, the lady showed the technician where the computer was, and
said what had happened to it. This is what the technician found wrong...




MURPHY'S COMPUTER LAWS
- Any given program, when running, is obsolete.
- Any given program costs more and takes longer each time it is run.
- If a program is useful, it will have to be changed.
- If a program is useless, it will have to be documented.
- Any given program will expand to fill all the available memory.
- The value of a program is inversely proportional to the weight of its output.
- Program complexity grows until it exceeds the capability of the programmer who must maintain it.
- Every non- trivial program has at least one bug
- Corollary 1 - A sufficient condition for program triviality is that it have no bugs.
- Corollary 2 - At least one bug will be observed after the author leaves the organization.
- Bugs will appear in one part of a working program when another 'unrelated' part is modified.
- The subtlest bugs cause the greatest damage and problems.
- Corollary - A subtle bug will modify storage thereby masquerading as some other problem.
- A 'debugged' program that crashes will wipe out source files on storage devices when there is the least available backup.
- A hardware failure will cause system software to crash, and the customer engineer will blame the programmer.
- A system software crash will cause hardware to act strangely and the programmers will blame the customer engineer.
- Undetectable errors are infinite in variety, in contrast to detectable errors, which by definition are limited.
- Adding manpower to a late software project makes it later.
- Make it possible for programmers to write programs in English, and you will find that programmers can not write in English.
- The documented interfaces between standard software modules will have undocumented quirks.
- The probability of a hardware failure disappearing is inversely proportional to the distance between the computer and the customer engineer.
- A working program is one that has only unobserved bugs.
- No matter how many resources you have, it is never enough.
- Any cool program always requires more memory than you have.
- When you finally buy enough memory, you will not have enough disk space.
- Disks are always full. It is futile to try to get more disk space. Data expands to fill any void.
- If a program actually fits in memory and has enough disk space, it is guaranteed to crash.
- If such a program has not crashed yet, it is waiting for a critical moment before it crashes.
- No matter how good of a deal you get on computer components, the price will always drop immediately after the purchase.
- All components become obsolete.
- The speed with which components become obsolete is directly proportional to the price of the component.
- Software bugs are impossible to detect by anybody except the end user.
- The maintenance engineer will never have seen a model quite like yours before.
- It is axiomatic that any spares required will have just been discontinued and will be no longer in stock.
- Any VDU, from the cheapest to the most expensive, will protect a twenty cent fuse by blowing first.
- Any manufacturer making his warranties dependent upon the device being earthed will only supply power cabling with two wires.
- If a circuit requires n components, then there will be only n - 1 components in locally-held stocks.
- A failure in a device will never appear until it has passed final inspection.
- Adding manpower to a late software project makes it later.
- A program generator creates programs that are more buggy than the program generator.
- All Constants are Variables.
- Constants aren't
- Variables won't
OBFUSCATING YOUR ERROR MESSAGES
One thing that Support people really detest is being able to
find error messages in any given program quickly and easily.
They like those messages to be hidden behind lots of
confusing code;
it gives them a kick to know they can suss out how the most
cleverly-obfuscated error messages are being generated,
especially when they have customers breathing down their
necks for a quick resolution to their fault calls.
Given that these days most job descriptions state that you
"must be able to work well under pressure", there
is no excuse for not obscuring these errors; anyone who cannot
hack the pressure is in the wrong job and probably ought to
find a supermarket somewhere that needs a shelf-stacker.
Note that any code provided in this tutorial is not intended
to be in any given computer language; it is designed to
give an outline only rather than a specific implementation.
This tutorial explains one method for burying your error
messages so deeply in the code that your support personnel
will really have to know what they're doing to be in with
a fighting chance of ever understanding how you did it.
An example could be used at the interview for new support
personnel: if they can't find where the error message
is coming from, you simply don't hire them!
Consider an application error message such as the
following:
"No accounts for that property exist"
This could be generated using a simple Message Box
function, thus:
MessageBox("Application Title",
"No accounts for that property exist");
|
But that would be far too simple, wouldn't it? I mean,
Support could easily carry out a search for the text
of the error message and find it within seconds.
It's an insult to his intelligence!
Stage 1 is to remove the error message itself, and hide it
away securely into a database table. Have a database table
defined something like this:
CODE NUMBER(6)
TEXT VARCHAR2(255)
|
with a unique index on CODE. Note that the column names are
words that are likely to crop up all over the program
during a word search, thereby making it hard to track down where
this table is being used. Call the table something like ECODES
(for 'Error CODES') as this also potentially introduces some
bonus obfuscation.
So ... for each error message you have an error number. Let's
call this one error number 1. Your database table entry will
look like this:
CODE = 1
TEXT = 'No accounts for that property exist'
Now instead of your simple MessageBox, you can do the following:
SELECT text
INTO :ls_error
FROM ecodes
WHERE code = 1
<check for database errors>
MessageBox("Application Title", ls_error);
|
Stage 2 is to make certain that the error message is not raised
in an obvious place. This is an attempt to make using a debugger
difficult (at worst) or nigh on impossible (best possible case).
If you're using an object-oriented language, then this is
very easy as you can bury your errors behind lots of levels
of inheritance, thus necessitating the need for Support to plough
through (or debug their way through) dozens of scripts to get
to it.
DO NOT, UNDER ANY CIRCUMSTANCES, give your error numbers
meaningful names as this makes it easy to track the messages
down, thereby defeating the object of the whole exercise!
In any large application, there should be a good few thousand
references to the table ECODES, thus this is quite safe. It
is even safe to wrap that up in a function along the following
lines:
function generate_error(errno)
{
string ls_error;
SELECT text
INTO :ls_error
FROM ecodes
WHERE code = :errno
<check for database errors>
MessageBox("Application Title", ls_error);
}
|
and call it like this:
as there will still be thousands of calls to this function,
so it will still be hard enough to find which invocation
is the relevant one.
Next, we can parameterise the error messages. This is where
the real fun begins (the fun we just had was fake fun).
The first step here is to identify a common grammatical structure
for each error message. For instance, we've already seen
"No accounts for that property exist"
but let's suppose we also have the following errors:
"No details for that account exist"
"No occupants for that property exist"
"No parties for that account exist"
Note how they all take the following form:
"No %1 for that %2 exist"
where %1 and %2 would be "accounts" and "property"
respectively for our original error message. But it is easy to see that
other error messages follow exactly the same form. Therefore,
error 1 now becomes:
"No %1 for that %2 exist"
The function can now be rewritten thus:
function generate_error(errno, s1, s2, s3, s4)
{
string ls_error;
SELECT text
INTO :ls_error
FROM ecodes
WHERE code = :errno
<check for database errors>
if (s1 != "")
{
ls_error = Replace(ls_error, "%1", s1);
}
if (s2 != "")
{
ls_error = Replace(ls_error, "%2", s2);
}
if (s3 != "")
{
ls_error = Replace(ls_error, "%3", s3);
}
if (s4 != "")
{
ls_error = Replace(ls_error, "%4", s4);
}
MessageBox("Application Title", ls_error);
}
|
We're allowing for upto 4 parameters for each error message;
if any require fewer parameters, just pass blanks in.
For our original error, we can now call it thus:
generate_error(1, "accounts", "property", "", "");
|
You've now got a very obfuscated error reporting system
that should make your programs as unsupportable as possible,
and should provide endless hours of 'fun' for your support
personnel when they need to track down any given error message
and where it's coming from.
Alternatively, it will leave them thoroughly
discombobulated by the obfuscation...