Big corporations are bureaucratic enough to make you say: "wtf?!"

Governments are bureaucratic enough to make you shout: "WTF!!!"

Government-run corporations, however, raise WTF to an art form.

M. C.. wrote to tell of the trials and tribulations of working at one such government-run institution.

Secure Access

To get from the front entrance of the building to the Windows Desktop, you must perform the following:

  1. Use an electronic key card at the turnstile
  2. Fingerprint scan at the elevator
  3. Different electronic key card at the office outer door on your floor
  4. Different electronic key card at the guard desk inside the office door
  5. A dedicated USB drive must be put into a particular USB port on the PC to get past disk encryption so it will boot
  6. Enter a password to match up against the USB drive's encrypted stuff
  7. Enter Windows login
  8. Enter Windows password
  9. Enter a rotating numeric code from one of those code-generating key fobs

All of this to get to a desktop where nothing secure is stored, or even accessible!

Bad Sign

Once you're at your desktop, you know you're in trouble when you are reading a developer-setup guide, and see a link:

https://intranet.██████.gov/corpname/portal/developerguidelines/majorVersionNum/minorVersionNum/doc_page_19034

Unit Tests

We can all agree that unit tests, implemented properly and kept up to date, can provide a safety net against mistakes. Most folks will agree that one-line functions such as get/set methods don't need unit tests as you'd only be testing the language's ability to set/retrieve the value of a variable.

From the Developer Guidelines:

All code shall have unit tests. Unit tests must cover the full range of values for affected variables/methods. You may not check in any code unless code coverage by unit tests is 100%. No exceptions!

And so, in the entire system, over hundreds of modules, thousands of classes and for countless member variables, we have this pattern:

  class SomeObject {
    private int x;
    public void setX(int x) { this.x = x; }
    public int getX()       { return x;   }
  }

  @Test	// for: member: int x
  public void memberXtest() {
    SomeObject o = new SomeObject();

    // Max int
    o.setX(Integer.MAX_VALUE);
    assertEquals(Integer.MAX_VALUE, o.getX());

    // 1
    o.setX(1);
    assertEquals(1, o.getX());

    // 0
    o.setX(0);
    assertEquals(0, o.getX());

    // -1
    o.setX(-1);
    assertEquals(-1, o.getX());

    // Min int
    o.setX(Integer.MIN_VALUE);
    assertEquals(Integer.MIN_VALUE, o.getX());
  }

QA

The QA people were assured by the pre-QA testers that everyone could rest easy because 100% code coverage had been achieved by the unit tests. M. C. explained to them the concept of 100% context coverage. You know, where input can change the way something operates? She gave an example: if you have a list of 1000 items and one set of data causes you to scan from 100 to 500, you have covered 100% of the code in the loop. However, another set of inputs might cause you to scan items 600 to 1001, causing an out of bounds exception. Until the unit tests cover not only the normal case, but the limiting cases and the one-step-out-of-bounds cases, the fact that you have 100% code coverage can not only be misleading; it can hide potentially destructive bugs.

Form vs Function

From the Developer Guidelines:

Do not create database lookup methods keyed upon individual attributes. Instead, always pass the entire entity object to the lookup routine in the DAO. This applies even if you need to make an additional call to the database to retrieve the entire entity object!

So, instead of:

  // Assume we have attrX already set in the code
  RelatedObject ro = dao.getRelatedObjectByAttrX(attrX);

...we need to code:

  // Even though we have attrX already set in the code, we're going to ignore it
  int pkToFind = ...;
  MyObject mo = dao.getMyObject(pkToFind);
  RelatedObject ro = dao.getRelatedObject(mo);

...and in: dao.getRelatedObject(...):

  public RelatedObject getRelatedObject(MyObject mo) {
     int attrX = mo.getAttrX();
     // do select, read results, construct an instance of RelatedObject and return it
  }

Rules Run Amok

From the Developer Guidelines:

Do NOT use enums in your code; even for static data. For example: January...December, Sunday...Saturday, Male-Female, etc. Instead, read the values from the database into a disk-backed ehCache object, and expose a service so the UI can look up what it needs, rather than hard coding such things.

The coding standard then descended into an 18 page tirade extolling the virtues of designing flexible code.

It continued:

Do not code in JDBC as it (the driver) ties us to the database vendor. Do not code in Hibernate as it might not be around forever; use JPA instead. Do not use HashMaps; instead use Spring Caching and configure the implementation to use disk-backed ehCaches.

Hmmm, forgetting multi-lingual support for a moment, for the UI to get a list of the names of the days of the week, we would normally do:

public String []dayNames = { "Sunday", ..., "Saturday" };

Instead, we need to have:

  1. Web Service: WSDL, SOAP, XML libraries to call...
  2. DAO: Java code to wrap calling...
  3. JPA: to insulate us from the details of...
  4. Hibernate: to insulate us from the details of...
  5. JDBC: to call...
  6. The database: to read in a few static variables, in case they change things (Helluary? Wtfday? Octember?)
  7. Then read it all the way back and let Spring store it...
  8. ...in a disk-backed ehCache, so the UI can then get a list of said static data values in a flexible way

Leverage Spring

From the Developer Guidelines:

Spring can be used to cache the results of each function call, along with the arguments provided to that function call, so identical calls with identical arguments can be short circuited, and the result returned directly.

Ok, sounds nice.

For a moment, forget that people write functions with side affects. Forget that caching DB query function call- and result-set arguments won't yield correct results if some other task updates the data in the database.

M. C. found an instance where a particular query was being (legitimately) called millions of times, each time with a different set of values. The result? The Spring-maintained function-call-plus-argument-plus-results list grew. And grew. And grew. To the point that searching it (to see if that function had been called with those particular arguments) was taking longer than just doing each query.

Production Code

There is a report that has a fixed column layout:

  AABBBDDDDEE...

The code to print it out is:

  VAR-A PIC X(2),
  VAR-B PIC X(3),
  VAR-C PIC X(1),
  VAR-D PIC X(4),
  VAR-E PIC X(2),
  ...

M. C. went to the developers and asked if field C could contain bytes with a value of zero (e.g.: non-printing). The following conversation ensued.

  M: The code listings don't match up with the report.
  D: But that can't be: this is production code!
  M: Then this report wasn't produced by production code.
  D: We have several test environments, all tightly controlled; there's no way that could happen!

After much research and finger pointing, it was discovered that different versions of the code were running in production and production-test, and nobody realized it.

Did they recall the other releases that had been blessed against this environment? Nope, because it would take too long!

The Architect

Architects generally know pretty much everything there is to know about how a given system works, what makes it tick, it's capabilities, limits, and the data and messages that it passes around. M. C. asked the Master Architect for some details about certain messages that were passed around by the system (header and message layouts, embedded binary data, envelope info, data size, frequency and such). The Master Architect replied that he didn't know anything about any of the messages the system used. M. C. reflexively inquired: "Then how do you know whether you under- or over-designed things?" The Master Architect replied that his job was to design it and IT would build it; once it's built and can be tested, if there are performance problems, we'll address them at that time. M. C. continued: "How could you have designed it and not know the details of the messages?" He replied: I just draw lines between the boxes in the architecture tool; it's up to the developers to fill in the details!

The Architect - Redux

M. C. had written a detailed design document, specifying specific field-by-field data layouts, algorithms to be used, pseudo-code, etc. Although the information contained therein was correct, the Architect refused to bless it until the order in which the details were presented was changed to reflect a business case. Pseudo-code and algorithms were to be deleted from the document! When all was said and done, the bean-counters blessed the document, but there wasn't enough technical information left in it for the developers to code from, so they had to wing it.

Your Tax Dollars at Work!

M. C. received an email blast that went out to all 13K+ employees:

________________________________________________________
From: security-complaince@██████.gov
To: dl-allIT@██████.gov
Subject: IMPORTANT NOTICE!!

We need to inventory all the RSA key fobs that have been issued to all employees. 
Use mandatory procedure XYZZ-2011 to determine the serial number of your fob. Then open
the spreadsheet at _URL_ to check out the spreadsheet and update the row with 
your name. Then save the spreadsheet and check it back in. You have one week to 
complete this task else your access will be affected.

Let's see, if the average person has to wait only 10 minutes before they are able to grab and unlock the spreadsheet, that's 130,000+ minutes, or 2,167+ hours, or about 1.1 man years of wasted effort.