1

I'll describe the anti-pattern I see occasionally as this.

Rather than using encapsulation or inheritance, a utility library grows with feature specializations directly added to it. Subsequent usage by another component requires a dependency (header, linker, runtime) to that feature code. Thereby increasing developer time to incorporate, build time, and/or runtime bloat.

Extreme example in C++:

Start with an innocent looking json parser library:

class JsonSaxParser
{
private:
   <json parser internals>
public:
    JsonSaxParser(const string& s);
    JsonToken* ReadNextToken();
};

It gets used a couple of times by the author and everyone agrees its goodness. Months later, another developer needs to read a json file out of a database. Rather than writing a new class based on inheritance or encapsulation of the class above, he directly modifies it and adds feature specific code. Suddenly, the class above starts to look like this:

#include "DatabaseDetails.h"
#include "FooBarThing.h"
#include "DBSchema.h"

class JsonSaxParser
{
private:
    <json parser internals>
    Database _db;
    bool _isUsingDatabaseForIO;
    bool DoSelectCall(string& query);
public:
    JsonSaxParser(const string& s);

    JsonSaxParser(DatabaseDetails& database, string& username, string& password, int formatVersion);
    JsonToken* ReadNextToken();

    FooBarThing ReadFooBarThingFromDatabase(DBSchema schema, const string& queryString);
};

The above would be ok if we were building a single program and never needed to share code with the teams down the hall. But in practice, we have different teams building different dynamic libraries, executables, and components out of the same code base. And now when the next component comes along that needs a json parser, it finds that it can't use the one above without taking a dependency on the FooBarThing and correpdoning DB library. The solution is to just suck it up and bloat the build, fork it, or spend unplanned time to refactor it. Or even worse - just continue to add more feature dependencies to the original class library.

Is there a name for this?

3

I am sure some creative people have invented some fancy names for different kind of such issues. Maybe someone tells you one of those "inventions", but don't be astonished when you notice such a term is not widely adopted and does not really help to improve communication.

Instead, I would recommend to name the principles which got violated here, (which is, first and foremost the single responsibility principle). That's a term most software engineers understand immediately.

However, a more constructive approach here would be to ask how to prevent such maldesign from happening. Especially when someone in the team starts to modify reusable components, there should always be code reviews. The need to add extra dependencies to an existing component should always be a red flag for any experienced reviewer. But even if there are no extra dependencies introduced, every extra method added should fit to the responsiblity and level of abstraction of that component. These are things which cannot be detected automatically, only a human can.

  • The “pioneers, settlers, town planners” model can be useful to understand these expectations on a software. As a software starts being depended on it must settle down and can't continue changing things every week. In C++ this means starting to commit to ABI stability and to pimpl those classes. – amon Mar 3 at 14:23
  • Thanks. I think the best way to sum up this answer for my team is this: Evangelize the value of the (single responsibility) pattern, amend it to the existing coding standards doc, and let the code review process in place enforce it. – selbie Mar 3 at 20:43
6

The major issue here is that this class has many responsibilities. And so I would call this a bloated class, defined by Prof. Jon Pearce at SJSU, as

bloated class is a class with too many responsibilities. Every system change seems to require a change to this class. A bloated class often has many special cases: attributes or behavior valid for some instances but not others. Often programmers attempt to deal with special cases by introducing type tags. Another way to deal with special cases is by introducing multi-way conditionals. Bloated classes often contain bloated methods.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.