Arty works on a team maintaining a legacy application that can best be described as a birds nest of code. It is a massive collection of global variables and a few tens of thousands of routines that would independently modify the data. Decapsulation was the overriding design pattern of choice. Of course, changing the value of some variable invariably has all sorts of unpredictable side affects. Naturally, this lead management to be fearful of making any changes, no matter how urgent, for fear of what would inevitably happen.
Fortunately, management recognized the need to replace it. The directive was given. A new application would be built. The replacement would be designed in such a way as to keep data and the routines that needed to access it somehow tied together. The state of a variable would only be changed as an end-result of some business action.
The senior members of the team started designing. Encapsulation was the order of the day. Each business function would wrap methods and state variables in a class, and nothing outside that class could change the state, except by telling the class to perform some action, the end-result of which would be to adjust the state accordingly.
The architects worked hard to keep the classes down to a reasonable size and level of complexity. The also tried to balance the depth of the class hierarchy with the breadth of the source tree. The idea being not to let class-proliferation create such a confusing source tree that it became unwieldy.
Finally, it came time to build this new beast.
To this end, management hired the cheapest youngest offshore development team they could find. After all, a code-monkey is a code-monkey is a code-monkey. As long as they could read the specifications and write code, they could do the job!
Given the tender years of the new development team, the architects insisted not only on after-the-fact code reviews, but on design walk-throughs at the beginning of each unit of work. This was to make sure that the developer understood what he was trying to accomplish, and the context in which it had to work. Management decided that this would take too much time away from coding and issued the mandate that units of work would be delegated to the offshore team, and it would be reviewed afterwards.
While the architects held their breath, the offshore team began to churn out code.
When the code was finally submitted for review, the architects immediately noticed a pattern in widespread use across all of the data objects:
class SomeImmutableData { private int v1; private int v2; public SomeImmutableData(int v1, int v2) { this.v1 = v1; this.v2 = v2; } public int getV1() { return v1; } public int getV2() { return v2; } public void setV2(int v2) { this.v2 = v2; } }
When they asked the offshore team why there were setters on some of the internal variables of an immutable object, they were told that after they loaded the object into the application, they discovered that downstream modules needed to change it, and this was the easiest way to let that happen.
After a few face-palms, the architects tried to explain to the junior developers how to design and implement stateful verses immutable objects. The junior developers said that it would take too much time to go back and change everything, so they were just going to keep doing this wherever it was needed.
When the architects tried to put their collective foot down, the offshore team complained to management that their progress was being impeded by the architects.
The architects explained the situation to management, but were rebuked because it would take time to fix it.
Thus, the junior developers wound up maiming the architecture, decapsulating all of the encapsulated classes, and leaving the new application susceptible to unintended state changes that would cause all sorts of instability.... because a code-monkey is a code-monkey is a code-monkey.
Photo credit: lorda / Foter / CC BY-SA