PHPnews.io

Fat vs. Skinny Design

Written by Yegor Bugayenko / Original link on Feb. 19, 2020

It seems that type/class hierarchies in OOP may be designed in two extreme ways: either with full encapsulation of data in mind; or with just a few interfaces making raw data visible, and letting classes deal with it, parse it, and turn it into smaller data elements. You may be surprised, but I’m suggesting the second option is more elegant. It seems to me that we don’t lose object orientation, but rather gain a lot of flexibility, reusability, testability, and so on.

owning-mahowny.jpgOwning Mahowny (2003) by Richard Kwietniowski

Take a look at this (let’s call it fat and I will explain why later):

interface Article {
  Head head();
}
interface Head {
  Author author();
  String title();
}
interface Author {
  String name();
  String email();
}

To obtain the name of the author we do:

// It is stored in PostgreSQL (that's why the Pg
// prefix) and retrieves everything using SQL
Article a = new PgArticle();
String name = a.head().author().name();

Visually, this design may look like this (in UML):

b9cc42a8e5ed92f94f4362cfd328fb0d.svg

Now, let’s compare it with an alternative design (which is much less fat than the previous one, I would even call it skinny):

interface Article {
  String head();
}
class TxtHead {
  private final Article article;
  String author();
  String title();
}
class TxtAuthor {
  private final Head head;
  String name();
  String email();
}

Here, in order to obtain the name of the author we have to extract the head as a String, extract the author as a String, and then extract the name as a String:

Article a = new PgArticle();
String head = a.head();
String author = new TxtHead(head).author();
String name = new TxtAuthor(author).name();

Visually in UML, it looks like this:

930f06f36724929287c1ee82fd95c77b.svg

There were three interfaces in the first design, while the second one has only one interface and two classes. I call the first one “fat” because it returns interfaces, which already implement the functionality we are looking for, and we don’t need to cover them with additional decorators or adapters. Its hierarchy of three interfaces is rich enough to give us everything we need. That’s why it’s fat. The second one, on other hand is pretty skinny, there is only one interface, which returns us plain text data, which we have to parse on our own. We need to dress it up.

It seems that the skinny design is better, for a number of reasons:

Everything said above is true for both 1) from-PostgreSQL data retrievals and 2) to-PostgreSQL data manipulations. Of course, manipulations may require many methods to exist in SqlArticle, which will make the skinny design look ugly, and it will become obvious that some of these methods have to be moved to lower-level classes/interfaces. This only demonstrates that it’s not always possible to make skinny design with a single interface, like in the example above. Sometimes we simply have to make it more fat.

However, there is one serious concern related to the skinny design: it lets the raw naked data jump out of SqlArticle, which is against the very idea of object-oriented programming, as we know. Indeed, if we let TxtHead do the parsing, we may lose some interesting PostgreSQL-related context, which is available only inside SqlArticle. We don’t want complex data parsing to happen far away from the place where the data is born. We want everything data-related to happen where the data lives: inside SqlArticle.

This is a valid concern, but letting PostgreSQL-related information (like connection settings) move from PgArticle to PgHead and then to PgAuthor is an even larger violation of the data encapsulation principle.

In real-life situations, of course, it’s not possible to imagine pure one-interface skinny designs. They will all be fat to some extent. My suggestion, though, is to try to make designs less fat, letting interface users dress them up however they like. This suggestion is very close to what I said earlier about smart classes, but this time the principle is broader.

yegor256 oop calevans

« Auto-configuration of Doctrine repositories as services - My female perspective at madewithlove »