Saturday, September 15, 2018

Bugslayer

His name was William and he worked on a troubled team. Their product was very successful and had been around for a long time.

The longer the product persisted, the worse its quality problems seemed to become.

Sever bugs in production were a regular occurrence and one developer always seemed ready to leap into the fray. They called him “Bill the Bugslayer”.

The worse things got, the more he seemed to thrive. He reveled in his reputation and in the nickname that went with it.

If there was a bug, he didn’t wait for prioritization. He didn’t wait for permission. He didn’t wait for repro steps. He just attacked.

His vigor for bugslaying was understood and respected by all. The bigger the effect of the bug, the more business lauded his victory. The more difficult the fix, the more impressed his peers were by his success.

Of course, he never missed a chance to let people know about his conquests.

The team had a “no time to get it done right” attitude. Instead, their culture was “close it right now”. The hyper-focus on immediate results and the glory showered upon William blinded everyone to the fact that their bugfixes tended to create more problems than they solved.

The product went into maintenance mode and no new features were to be added. Yet the workload continued to increase. Quality problems caused growth to stall, more or less calcifying the current user base. Still, the pressure climbed.

Eventually, someone noticed that the problem wasn’t how many bugs they were fixing. It’s how many bugs they were writing. They agreed to do things a new way, where they finished their work completely before they moved on and took measures to ensure that fixing one issue didn’t create multiple new ones.

Bill was unconvinced. Some think it’s because he couldn’t see his place in the new world. Some think it’s because he genuinely didn’t understand. Whatever the case, he refused to take a disciplined approach and continued to thrash head-on against every problem until he was convinced he could claim it was fixed.

The team could not fix problems as fast as Bill the Bugslayer could create them and they decided to build a new product. The new product was not a solution to all their old problems. It was a place where they could work free of William’s influence. Yet it was a smashing success.

Still. The same way Bill the Bugslayer wouldn’t give up his old ways, there were customers who wouldn’t migrate to the new product. They continued to pay higher support fees for a legacy system that was dwindling in its user base.

Eventually, it was just a handful of stalwart customers, Bill the Bugslayer, and all the bugs he could write.

Friday, September 14, 2018

How Do You Know People Are Smart?

How do you know that someone is really that intelligent?

I mean, maybe you know that they are smarter than you or you are smarter than they are. That's a relative assessment.

How do you know how smart someone is in the absolute sense?

Thursday, September 13, 2018

Fantastic Inheritance

I love it when people tell me that they like to eliminate redundancy by turning this...


...into this...




There may or may not be benefits but eliminating redundancy is not one of them. Don't believe me? Let's re-examine those diagrams with a little splash of color.



 ...and...



The former design has two associations that point to an object of type A. The alternative design subclasses two classes from a class that points to an object of type A. Both kinds of relationships must be declared, maintained, and attended to whatever extent is required and supported by the language of choice.

Adding a layer of inheritance didn't eliminate a redundancy, it transmuted one.

Again, maybe that's good but let's be honest about what it is. It could be encapsulation. It could improve coupling. It could make things more expressive. It could improve a lot of code qualities. What it can't be is an elimination of a redundancy.

Yet, despite years of experience and reams of evidence, people seem to think that inheritance has some magical property that makes it more suited to reuse of, for instance, a method. It's a shared fantasy for which I have no explanation.

There is only one thing that inheritance allows a class to reuse that they couldn't reuse via composition: clients. Everything else can be shared by composition with zero additional cost over inheritance, and far more maintainability options.

If you find yourself wanting to move some behavior to a base class in order to prevent it from being repeated, do a quick reality check: Is inheritance really the only way to reuse this? Does it really buy me anything over composition? Then act appropriately for the answers it yields.

Wednesday, September 12, 2018

Objective and Subjective Code Qualities

Some code qualities are objective and others are subjective.

I don't mean this in the colloquial sense of the words. I mean it in the actual sense of those words. Objective qualities are qualities which are properties of  the code itself. Subjective qualities are qualities which only exist as part of a developer experience.

Tuesday, September 11, 2018

Inheritance Allows a Base Class to Share its Clients with Inheritors

Superclassing and subclassing are always there, no matter what language you use.

A lot of people think that superclassing is a good way to share code and avoid redundancy and it might be...but what's the most valuable thing a superclass can share with its subclass?

Many would answer "put a protected method in there so all the child classes can use that!"

That's a way of sharing an algorithm, sure. Yet, is it the most important thing a superclass grants its subclasses?

No. It is not.

The most important thing a superclass can share with its subclasses (and thus all subclasses can share via a common superclass) is its pool of potential clients.

Consider the following two designs...

Two alternative designs, one that promotes reuse of a method through inheritance and one through composition.
Alternative Methods of Reuse

In design (A), we create (or maybe have) a base class and put a protected method in it, which Child1 and Child2 are both able to access. In design (B), we create (or have) a component class, which has an internal (package-private) method on it that is used by two classes (Child1, and Child2).

Both these options facilitate the reuse of the Reused() method. Maybe one of them is better than another for some reason or other but they both solve the reuse problem for the classes that are drawn on the diagram.

Yet, I think there is a kind of sharing that is unique to subclassing. In order to dig into it, I want to examine a different kind of relationship: usage.

Consider the following design...

A class, Client, depends on another class, Server
A Classic UML Depiction of Usage
Almost everyone considers Client to have a relationship with Server. Do you ever think of this as a Server having a relationship with Client? The arrow at the end of the dashed line in UML betrays how we tend to think of this kind of relationship as unidirectional.

Yet, the relationship definitely works both ways.

A depiction of a relationship from a client class to a server class with the client-end emphasized
Even a Usage-Type Dependency is a Two-Way Relationship

Each class has a relationship with all the other classes that couple to it. This relationship is the one thing that can only be shared with some form of subclassing.

Avoiding redundancy in coupling to a class is an enormously powerful property of inheritance and there doesn't appear to be another way to get it. At least, there's not another equivalently-convenient way.

A depiction of several relationships and many potential targets with the question "How many copies would you like?" scrawled in red

Monday, September 10, 2018

Superclasses and Subclasses Are Concepts, Not Just Language Features

In some languages, the concept of a class and a superclass are explicit and the relationships between them are explicit. In other languages, superclasses can be declared but the relationship between subclass and superclass is implied. In some languages, even the abstraction itself is implied.

Yet the superclasses and relationships are always present, when relevant; even if only in our minds.