Resurgence of Software Design in 2025?
Augusts Bautra

Augusts Bautra @epigene

About: Senior Rails developer from Latvia. Avid gamer. Longevity enthusiast. #keto-dude

Location:
Riga, Latvia
Joined:
Feb 22, 2017

Resurgence of Software Design in 2025?

Publish Date: Jun 6
12 2

Summer vibes are in the air. With Grug Brained Dev's book coming out and Uncle Bob discussing software design with John Ousterhout, I, too, am getting into a philosophical mood.

Grug's Book

One problem I have been thinking about for the past several months is how to improve software maintainability, specifically, how to write code that makes common extension scenarios as simple as possible. Where's the space for new code to go?

As an aside, this is probably because at work I've been tasked with seemingly simple updates to existing old functionalities only to come up against very steep technical debt walls - Backbone JS views preclude simple field additions (never mind discovering what the controller -> json -> JS -> Backbone view event path is); existing exporters are such a tangled mess of branching and poor cohesion that adding a column breaks everything.

Putting those woes aside, the relevant SOLID principle here is Open/Closed — focused on ease of extension. And another thread I want to pull on here is the idea of The Seen and The Unseen from economics.

👁️ Making the Unseen more seen

Space in file structure

Consider this directory:

Unclear how to extend directory

At this stage, it's still possible to guess that the intended extension path is to define a new exporter and likely inherit/include the logic from base.rb. Unfortunately, even at this early stage we see that the base is mixed with actual implementations and will eventually disappear completely.

I don't have a perfect solution for this, but separating the base from the actual implementations (either in a higher or more nested directory), and leaving an example file could help:

Clearer how to extend directory

Space in code

More on the Base topic, communicating the contract for dependents (I've previously talked about this in terms of specs) is also an issue. Consider this opaque base class:

class BaseClass
  def process
    items.sum
  end  
end
Enter fullscreen mode Exit fullscreen mode

How to make the reliance on summable #items clear? This is arguably a hard reality in Ruby, but defining, documenting and speccing an example method is a start:

class BaseClass
  def process
    items.sum
  end  

  private

  # Override this in inheritors to return the array of items to be summed.
  #
  # @return Array
  def items
    raise("Expected to be overridden")
  end
end
Enter fullscreen mode Exit fullscreen mode

Clean up, then tactically place tools in places where you want future building to occur. Leave the toolbox open™.

leave the toolbox

🧹 Eliminating the Unseen?

Consider this filter class code:

filter :state, as: :string, exact: true
filter :name, as: :string

def filter_by_state
  collection.where(abc)
end

def filter_by_name
  collection.where(xyz)
end
Enter fullscreen mode Exit fullscreen mode

How do we communicate that a new filter parameter is added by adding a macro and a correspondingly named method? One idea is to combine the two steps:

filter(:state, as: :string, exact: true) do
  collection.where(abc)
end
filter(:name, as: :string) do
  collection.where(xyz)
end
Enter fullscreen mode Exit fullscreen mode

This is a substantial increase in code cohesion in a way I believe even SRP does not discuss.

🏠 Making room

Breathing Room

Derek Prior's "Breathing Room" idea is what started me on thinking about this admittedly abstract topic. I have two examples.

The first is from Derek - define classes for domain concepts that may be absent in code.
In my experience, doing actor analysis - focusing on the many different types of users that act within a system - often reveals under-represented aspects. In my current project Element is a god-model which turns out to be servicing at least four different actor groups - engineers, supply staff, internal manufacturers, and construction site managers. Defining new Manufacturing::Element is a way to make room.

Image description

Elbow Room

The other example comes from a quick comment by John Ousterhout that designing classes to be slightly more generic than is initially necessary has proven to be a boon.
This aligns with my experience. I think developers tend to combine the warning against premature optimisation with laziness and end up with classes that are purpose-built to the task at hand. Future additions often hit a wall because there's no space built in for growth.
An example for my current project - a model called Api::Token where a generic Token would have worked and created space for any other type of token.

Image description

So, having this space offers two benefits, a mental and a practical one. First — and this is profound — it makes reasoning about related problems easier. With a well-scoped domain, we deal only with appropriate concepts. Second, it keeps the code simple and easy to find and change.

Design is back in focus — and that’s a good thing. A little extra effort to leave breathing room today makes a big difference tomorrow.

Comments 2 total

Add comment