Mathias Quintero Jan 31, 2019 · 9 min read

Kintsugi: The Art of the Anti-Pattern

So! I’ve been thinking! I know; big surprise there… But most blog posts I read around software tend to revolve around two things:

  • Management: What are we doing wrong and what can we do right?
  • Engineering: Here’s this cool concept using new tools you could apply!

And I deeply admire those who write about these topics. However, I rarely see people talk about how we can turn around software that has gone wrong. We often talk about what made them go in a bad direction, what patterns turned out to be anti-patterns, and what we should avoid in the future. But when it comes to what to do with these running systems, the answer appears to be a unanimous:

Re-write and slowly phase the old system out

Or what I will be calling: the Take-Out-The-Trash-Method.

Let’s talk about Kintsugi

So there’s this thing called Kintsugi. It’s a Japanese art style where instead of throwing out broken pottery, it is put back together and carefully repaired. Joint by lacquer mixed with gold to make them beautiful.

Out of a defective plate, we can now make art.

And we can interpret and discuss a lot about their philosophy:

  • Have we made something beautiful by not only embracing its flaws, but also by putting them in the foreground and platting them with gold? Attracting more looks than before?
  • Or are we simply admiring the craftmansship of taking something broken and putting it back to use? More elegant than before.
  • Or perhaps we just want stories? The one of how it got broken. The one of how we repaired it. The one where we wrote a blog post about it. So Meta

Ok, I’m getting off track here. My point is that these are all aspects that make Kintsugi not only special and beautiful, but an appropriate way of treating broken software as well. Boom! Stuck the landing!

The Art of the Anti-Pattern

Or maybe I should call them “Arti-Patterns”.

No. I shouldn’t. I really really shouldn't.

Anyways, an Anti-Pattern is basically a design pattern turned bad. Like its evil twin in a soap opera. It’s when a reoccurring solution to a reoccurring problem ends up creating more problems, adding tech-debt and ultimately being very, and I mean very counterproductive. Engineers, Professors and even Students love Anti-Patterns. They love talking badly about them. Almost as if they’re above them. Even me (especially me):

But they mostly just love coming up with them, later noticing what they’ve done and re-writing everything to avoid their previous mistake. And this often works. Usually our mistakes are relatively small and a refactor here and there can fix everything. Until the next refactor, that is.

However, what happens when you’re in too deep and trying to keep, up above in your head, instead of going under? Sorry, I’ve lapsed into song lyrics, there. What I mean is that sometimes a big refactor is not an option anymore. There’s way too many moving parts and no escape from tech-debt. What can we do?

Let’s Kintsugi the Sh*t out of it!

Start embracing what makes your system yours and fix it up, not by removing all its flaws but by working around them and bathing them in gold!

I know it sounds weird; I’m basically suggesting what we call a Lava Flow, but hear me out!

Let our solution around the anti-pattern be a thing of beauty. Everyone will look at your elegant solution, and never even consider the anti-pattern it’s working around. Let’s hit it with some examples:

The God Class

The God Class is a self explanatory problem. You created a class that appears to be responsible for everything. We can no longer navigate it. It is simply too much at once.

And most people who encounter this solve this by:

  • Split responsibilities into multiple new classes. Tend towards single responsability per class.
  • Rewrite API to accomodate changes

However, the larger your code base or other limitations on the side, this is rendered impossible. So here’s the Kintsugi solution; Modularize, but keep the God Class:

  • Find out what the responsibilities are
  • For each responsability create an Interface and match the signature of the God Class
  • Write Component X that implements that Interface with the code from the God Class
  • Inject Component to God Class
  • Let God Class delegate it’s job to the Component

This may sound complicated, but it’s much simpler in code. Given this ugly implementation of a God Class in Kotlin:

data class GodClass(val foo: String) {

  fun bar(baz: Int): Boolean {
    // complicated logic using foo
  }
  
  // more complicated functions that don't really have anything to do with each other
  
}

We can start by splitting it. We recognize the Bar method and the foo variable belong to the same responsibility. So we create a Bar interface for it.

interface Bar {
  val foo: String
  fun bar(baz: Int): Boolean
}

And the component encapsulating the implementation that was previously in the God Class:

data class BarComponent(val foo: String) : Bar {

  fun bar(baz: Int): Boolean {
    // complicated logic using foo
  }

}

And finally make the God Class delegate all its Bar responsabilities to the Component:

data class GodClass(val bar: Bar) : Bar by bar {
  
  // Rest of the code that should also be refactored this way
  
}

And voila! We have turned a god class into a modular component based solution that is easier to navigate, and all without changing the API or the rest of the system. Or basically we’ve turned our God Class anti-pattern into a Facade Pattern.

Constant interface

Most people will think this isn’t quite an Anti-Pattern. But it’s one of the most common ones. The idea is that you put all your constants in an Interface’s definition to be able to namespace them, and have more context about what you’re accessing without injecting.

The problem is that this Interface is now part of the implementation. And most would argue that constants belong in configuration objects and exported as part of the API.

But instead of dealing with injecting configurations and making sure you pass the correct one’s: we can embrace the constant interface, and just decouple the definition from the values.

Let’s see what I’m talking about. Here’s an example of us using the Constant Interface Anti-Pattern in Swift (with enums instead of protocols)

enum Constants {
  static let padding = 20
  static let height = 100
}

class Builder {

  func element() -> Element {
    return Element(padding: Constants.padding, height: Constants.height)
  }
  
}

This builder is accessing the constants through the name space. If we want to remove these implementation details we can introduce a generic type that contains our Constants. And we can continue with the exact same code as before. Let’s begin by defining a protocol:

protocol BuilderConstants {
  static var padding: Int { get }
  static var height: Int { get }
}

And we introduce a generic type with the same name to our builder:

class Builder<Constants: BuilderConstants> {

  func element() -> Element {
    return Element(padding: Constants.padding, height: Constants.height)
  }
  
}

And now you can define your actual Constants:

enum StandardConstants: BuilderConstants {
  static let padding = 20
  static let height = 100
}

But now, you might say: you’re still including which constants you’re using right into the Builders signature. This isn’t much better. Well that’s where type erasure comes to the rescue. With type erasure we can refer to our builder without extra generic information getting in our way.

We start by encapsulating the builder’s api into a protocol:

protocol BuilderProtocol {
  func element() -> Element
}

And we create a wrapper class that erases the generic constraints:

class AnyBuilder: BuilderProtocol { 

  let _element: () -> Element
  
  init<Builder: Builder>(_ builder:  Builder) {
    _element = builder.element
  }
  
  func element() -> Element {
    return _element()
  }
  
}

And we can now always refer to AnyBuilder as the new builder:

let builder = AnyBuilder(Builder<StandardConstants>())

TADA! We have successfully removed what makes this Anti-Pattern an Anti-Pattern.

Object orgy

Granted. I’ve only included this particular one because I find the name so amusing. Yeah. I’m a child. But Object Orgies are a frustrating and problematic issue in many code bases. They’re called this way because everything has access to everything. Anything can be changed from anywhere. Systems like this tend to be very chaotic. Not only because it can be very unclear where what is going on, but our types give no guide or indications about how to approach problems.

Consider the following class modeling a Book:

class Book {
  var title: String?
  var author: String?
  var isbn: String?
}

In this code anything can read and write any properties of the Book. Refactoring this can be problematic since the flow of the application heavily depends on being able to change these properties at any time. But how could we introduce some extra safety without completely rewriting the flow of the system?

An answer might be adding extra safety by writing a wrapper with a Phantom-Type.

But what’s a Phantom-Type, anyways? A Phantom-Type is a generic parameter that is not directly used, but instead serves as an type safe indicator of how we can deal with the object. And we can even regulate how we read and write properties of an object using these types.

So let’s start by a creating a simple wrapper. We’ll call it Safe.

class Safe<Value, Rights> {
  private let value: Value
  
  init(value: Value) {
    self.value = value
  }
}

Safe has a generic parameter for the object that it’s wrapping and a parameter determining the read and write rights we have on it. Let’s put it to the test!

We can start by creating a protocol signaling that we can read the title of the book:

protocol ReadTitle { }

And we can say that when the Rights conform to ReadTitle, our Safe implementation will expose the title as a read only property:

extension Safe where Value == Book, Rights: ReadTitle {

  var title: String? {
    return value.title
  }
  
}

Well that was easy. Now let’s do it with Writing to Title:

protocol WriteTitle: ReadTitle { }

extension Safe where Value == Book, Rights: WriteTitle {
  
  var title: String? {
    get {
      return value.title
    }
    set {
      value.title = newValue
    }
  }

}

enum TitleRights: WriteTitle { }

let book: Safe<Book, TitleRights> = Safe(value: Book())

book.title // works
book.title = "Don Quixote" // also works
book.author // doesn't work

And Presto! You can now slowly make sure that instances of code that use Book, can only read and write what they’re supposed to and you can think twice before a method wants to read and write every property.

Now of course this technique is very powerful and can be used in very elegant systems. You can read more about it in Sebastian Sellmair’s post on the topic.

So? What’s the point of all of this?

Mainly? To say that not everything is black and white. Rewriting a system might be the cleanest solution for many. And it’s clearly a lot more fun. However, sometimes we can take pride in writing clean solutions around not that clean codebases and feel proud we made something better.

Of course, most of my solutions here are not ground breaking or even perfect. But it goes to show that every piece of code can be rescued and maybe even turned into art.

P.S.: Here’s a cute cat or whatever


Copyright 2016-2022 Mathias Quintero
Built in Swift using
Publish
Ship ❤️