Software Craftsmanship has been a hot topic as of late. Joshua Kerievsky posits a possible counter-perspective to the underlying "code must always be clean!" ethos of the craftsmanship movement; something he calls "Sufficient Design". Learn about what Joshua means, and hear thoughts also from Bob Martin and Ron Jeffries on Kerievsky's ideas.

Kerievsky began what appears to be a possible series of posts on his "Sufficient Design" idea with this problem statement:

...some programmers argue that the software design quality of every last piece of code ought to be as high as possible. "Produce clean code or you are not a software craftsman!"

Such advice is well-intentioned. Many of us have seen the near paralysis that comes with high technical debt.

Yet ultimately the craftsmanship advice fails to consider simple economics: If you take the time to craft code of little or moderate value to users, you're wasting time and money.

The fact is, some code simply doesn't need an excellent design, whether that code is a start-up experiment or a corporate application feature.

Joshua goes on to tell a story about his own development team's decision to leave a known design smell in what refers to as the application's "plumbing code", regarding the return value contracted by the inherited "processWith" method of all the application's concrete Action classes. After multiple years of knowing about this smelly code segment, and even a couple failed attempts to refactor it out, he explains it still exists, but that it does not get in his team's way. He asserts that spending time on cleaning up this non-obstructive problem would be unwise as it takes time away from working on more important features. The moral:

We need high design quality for stuff that is critical to our products and less design quality for stuff that isn't critical.
...
The art of software design is now defined by how well an individual or team can adjust the Design Dial on a feature basis to produce software that people love and which makes money.

There is no one-size-fits-all approach to software quality.

If you're a feature junkie, pushing one feature after another into your product with little thought for software design, your technical debt will paralyze you starting around release 4.0.

If you're a quality junkie, you will over-engineer every last thing you do.

Sufficient Design is where Lean meets Craft.

Uncle Bob Martin, well-known for his leading part in the latest Software Craftsmanship movement, quickly responded with a note that, possibly to some people's surprise, ultimately endorses Joshua's message:

It seems to me that Josh was behaving exactly as a craftsman should. He was worrying about exactly the kinds of things a craftsman ought to worry about. He was making the kinds of pragmatic decisions a craftsman ought to make. He was not leaving a huge mess in the system and rushing on to the next feature to implement. Instead he was taking care of his code.

Martin does also take a moment to clarify his stance that the Craftsmen's message does not ring of "perfection or perish!" as Joshua may have implied:

Craftsmen are first and foremost pragmatists. They seek very high quality code; but they are not so consumed with perfection that they make foolish economic tradeoffs.

Equally expedient was a followup note by Ron Jeffries, another out-spoken proponent of taking time to keep your programming playground clean. His message essentially boils down to a two-fold message, first that design debt is a "pay me now or pay me later" game, and second that we should strive to be able to go fast and go good:

If slacking on quality makes you go faster, it always comes at the cost of longer term quality.

Turning that around, if we were better than we are, we could go faster without cutting quality. We need to improve. Today may not be the day to make that improvement: Today we may really need speed more than we need quality. But the handwriting is on the wall:

If slacking on quality makes us go faster, it is clear evidence that there is room to improve our ability to deliver quality rapidly.

Before long, Kerievsky published "part 2" (of what he implies to be many) of the "Sufficient Design" message, this time stating flat out that sometimes "sufficient" means doing it indeed poorly. He tells another story from Industrial Logic's development vault, this time about a seriously "Large Class" that arose while speedily implementing a "Playlists" feature for a big client release of his eLearning product:

Based on a year of living with the Playlist feature and studying usage data, here's what we know:

Our users are definitely using Playlists.

No user has ever complained about Playlists.

Our users don't rave about Playlists the way they rave about other features in our product.

So are we paying the price for incurring high design debt on the Playlist feature?

No.

Here's why:

No New Behavior — we haven't added or changed any behavior of the original Playlist feature during the last year.

Unchanged Code — We've made only trivial changes to UserLibrary (main source of the Playlist design debt) during the last year and those changes had nothing to do with Playlists.

An Isolated Problem — The poor design we do have for Playlists is isolated: it hasn't gotten in the way of new feature development in the last year.

Playlists were an "accessory" thrown in to a deal to make our largest client happy.

The feature has been useful but isn't on the critical path of our product development.

The code smells in the Playlist code, such as Large Class and Conditional Complexity, have not slowed us down.

And here's an insight into how we manage quality:

If we decide to give users a more sophisticated Playlist feature, we will happily pay down design debt before making new progress.

Joshua explains that the prospect of dealing with this when a future feature requires it doesn't bother him, in large part because of his team's skill and discipline with TDD, but also simply because he understands and accepts that, just as sometimes low craft is in order, sometimes the dial needs to be turned to high craft too. He summarizes:

So are we happy with the Playlist code from a year ago?

We are happy that we didn't invest more in Playlists than needed at the time.

We'd like to clean up the design but will wait until the time is right.

That is Sufficient Design.

What do you think? Is Joshua's advice applicable generally? Have you succeeded with similar approaches on your own projects? Failed miserably? What else might need to be considered to further the discussion?

The definition of Sufficient Design presented here reeks of oversimplification of the user stories associated with design "activity" and the criteria used to assess design "quality". If one accepts a definition of design "smell" as misalignment with sustainability, performance, or any other metric designated relevant to the development context at hand, then design smell is simply code waste that could have been avoided.

This is especially true if software development is approached as a lean and agile engineering discipline, instead of a lazily executed black art. The choice of whether to maintain poorly crafted code falls outside of the realm of design activity. Design can only be deemed "insufficient" after the fact, never before. Engineers call such discoveries "defects" and typically assess their impact during operational or release planning. The idea of Sufficient Design is nonsensical sophistry.

The counter argument is simply that the consistent practice of continuous testing, code inspection, and related activities keeps code elegant and lean, which in turn empowers amazingly efficient levels of productivity that are truly sustainable. Do not confuse design skill or thoroughness with management tradeoffs to accept waste and often non-sustainable entropy into a system.

Yet ultimately the craftsmanship advice fails to consider simple economics: If you take the time to craft code of little or moderate value to users, you're wasting time and money.

As a Peopleware covert, I like the idea that lowering quality standards below those that a developer set for himself leads to the loss of interest and to the eventual departure of those who forced to produce low quality products. In other words, there is no justification for low quality in the long run.

It is perhaps worth pointing out that the term "Sufficient Design" is not new. I've used it for a number of years (see, for example, accu.org/index.php/journals/293), but with a different emphasis: sufficiency as a counterbalance to speculative generality. What Joshua is actually describing is "Good Enough Design", which is close but is subtly different to Sufficient Design.

Cleaning up the design can be due to various reasons. From our experience, one of the major reasons is the poor maintainability of the system or some of the components. Is "Sufficient Design" against this priciple? Is it suggested to clean up design or code only when new features are getting added or customers pay for it? This could lead to increase in the maintenance cost?

When you run a small business, you have plenty of constraints: income, payroll, customer needs/desires, quality, product improvements/bugs, etc.

My job is to balance those constraints and Sufficient Design helps me do that.

What part of our product's code has made us the most income? I can guarantee you that we spare no expense on that part of the code.

However, when it comes to parts of our code that are less important, we don't go to amazing extremes to produce the best design possible (though we do test-drive the code, so we have good automated test coverage, if and when we decide to mercilessly refactor).

Now, are you saying that all code, no matter how important, should have only a supremely excellent design and anything but that is nonsensical sophistry?

You're taking an idea and changing it into "Sufficient Design will demoralize you by forcing you to write crappy code." Nope, sorry, that utterly misses the point.

We are ultimately after making Awesome Users (as Kathy Sierra says).

Making every single line of code have a perfect design isn't the best strategy for achieving that goal, as there are *many* competing concerns in product development.

In our shop, we test-drive all code, yet we don't mercilessly refactor all code. Before we work on new features, if we feel the code is messy, we clean it up before adding the new code.

We are constantly making decisions about what a Sufficient Design is, given the needs of the business and the need to maintain high quality.

Sufficient Design can yield excellent, good, ok, poor designs -- all of which depends on constraints and context.

A team of programmers and business folks needs to work together to produce a great result for the users.

Perfect design of every last line of code will get in the way of that most of the time.

A sufficient design for the code that makes you the most revenue and is most important to your users ought to have an excellent design.

OTOH, a sufficient design for code that makes little revenue and isn't important to your customers doesn't need to have an excellent design...until perhaps it becomes super important to your business and users.

James Bach's Good Enough Software paper had major influences on how I think about bugs in software and helped me to get over the idea of 100% bug free code. Sufficient Design spans a range from Excellent to Poor design, depending on what is needed, when it is needed, what impact it has on user happiness, sales, marketing, etc. So just to be clear, I don't think of Sufficient Design as always meaning mediocre. It all depends on context, as usual. I read your paper -- thanks for the link and I'll be sure to mention it in future writings about Sufficient Design.

Sufficient Design is about adjusting the quality dial based on needs and re-adjusting that dial when needs change. Depending on the context, we find ourselves refactoring before, during and after coding features. We don't refactor code that isn't so important, as we have more pressing items. However, if that code becomes a trouble area for us, then yes, we work hard to improve it.

What do I believe? Based upon your extensive descriptions, I simply believe that you have misapplied and misinterpreted the results of agile best practices for management and development during your attempts to balance constraints.

I believe that you are now attempting to rationalize the results. Nothing more and nothing less.

I believe that I perfectly understand both your position and that of your critics.

I believe that Sufficient Design is one possible definition of a set of symptoms for the underlying disease responsible for the destruction of quality throughout the software engineering profession. Thank you for the precise definition.

Like Alzheimer's, this disease is an emergent systemic problem, a result of a human system failing to balance operating constraints.

I believe that you misunderstand the thread running through the arguments of many of your critics, as if they just do not get your point.

The cure for the disease of Sufficient Design is the solid application of software engineering practices. Nothing more and nothing less.

Do the projects in which I am involved always hit the mark or achieve the ideal? Certainly not! We are only human, and we fail.

However, do we choose to defend our failures within the guise of a newfangled method or muddied practice? No. We acknowledge the failure, inspect and adapt, in order to reduce the frail points.

Failure is failure is failure. Sufficient Design is failure. To represent it otherwise is disingenuous at best, cancerous at worst.

Thanks for the reply and I hope you can be patient with me as I try to understand your perspective on the serious mistake you think I'm making.

It will help to get specific.

I wrote about the design flaw in the command pattern implementation we have for handling incoming and outgoing web traffic (bit.ly/afZJzO).

That code works, only I don't like the design. Yet that design isn't inhibiting us, isn't slowing down development, isn't hurting users. It's just an issue of beauty - if I had 54 hours in a day, instead of 24, I'd have already cleaned it up. And as I wrote in the blog, I did try.

Given the many constraints, I'd much rather build an awesome new product (we're working on one) than cleanup the design flaw in the command pattern implementation.

So...are you suggesting that I'm making a huge mistake in that choice, that there is simply no excuse for noticing and not cleaning up a design smell, even if it is quite minor and isn't hampering development or the user experience?

I do sincerely want to understand your perspective.

I've been coding professionally since the late 80s and doing XP/Agile nearly non-stop internally and with clients around the globe since 1999, yet I still have more to learn and hope I can stay humble enough to be open to people/ideas that contradict my own.

You also said: the cure for the disease of Sufficient Design is the solid application of software engineering practices.

What do you mean by solid? Can you give me an example of a solid software engineering practice, and one that is not solid?

As you are no doubt aware of, having concluded that "software engineering is gravely hampered today by immature practices", www.semat.org, has set out to "refound software engineering based on a solid theory, proven principles and best practices". Do you agree with SEMAT that there is currently no rigorous, theoretically sound basis for software engineering practice, and that it needs developing? What definition of software engineering practices do you use? where can I find it?

I am reading this article and comments again, 4 months after tweeting about it and I still find it one of the most thoughtful propositions I've stumbled upon in months.This is just Good Economics.Where I work, we often have to develope features that customers might look, or not... Does it make sense to invest in 2 months of reaching 100% test coverage and 4-5 refactorings if the feature is seldom, if ever, used? Who would pay for this??Obviously, as Ron Jeffries pointed out, ideally testing and refactoring should not cost more... but it does...

It also reminds me of an article where Kent Beck was critized for admitting that he does do TDD all the time... How shocking!

I'm glad we're finally starting to put things in perspective.

BTW Scrum and other frameworks help with this, by TIME BOXING. Think about it.

Is your profile up-to-date? Please take a moment to review and update.

Email Address

Note: If updating/changing your email, a validation request will be sent

Company name:

Keep current company name

Update Company name to:

Company role:

Keep current company role

Update company role to:

Company size:

Keep current company Size

Update company size to:

Country/Zone:

Keep current country/zone

Update country/zone to:

State/Province/Region:

Keep current state/province/region

Update state/province/region to:

Subscribe to our newsletter?

Subscribe to our industry email notices?

You will be sent an email to validate the new email address. This pop-up will close itself in a few moments.

We notice you're using an ad blocker

We understand why you use ad blockers. However to keep InfoQ free we need your support. InfoQ will not provide your data to third parties without individual opt-in consent. We only work with advertisers relevant to our readers. Please consider whitelisting us.