In reply to: Three Good Laws of Software Architecture

Posted: May 28, 2012 in architecture, Programming
Tags: , ,

What is the secret to good architecture? While there are plenty of posts written about this topic on the internet, I found this article on DZone (originally posted here) intriguing.

The article is written by Niklas Schlimm, whom I do not know personally. The article can be summarized with three points:

Three [proposed] Laws of Good Software Architecture

  1. Good architecture is one that enables architects to have a minimum of irrevocable decisions.
  2. To make decisions revocable you need to design for flexibility.
  3. To make use of flexibility one needs to refactor mercilessly.
CYA Engineering?
  1. What I think Niklas is trying to say is: you will get it wrong, and sadly, you’ll get it wrong most of the time, so design an architecture where you can fix your mistakes with a couple of swaps. Is designing an architecture that allows you to revoke your decisions at whim really fair? Does the CEO get the same privilege?
  2. Flexible is not durable. They don’t build make buildings out of rubber. We’ve probably all worked on over-engineered legacy systems that were “flexible.” Most times, good intentions turning into dancing circles around libraries and frameworks in an unholy ritual of abstraction.
  3. You should be refactoring mercilessly, all the time. But do you need 10 layers of abstraction to do this? Do revocable decisions allow you to revoke custom code?
Alternative laws

Lets address the problem here. Code doesn’t age, or stop working, it’s Human’s that forget how things work, why decisions were made, and becomes disenchanted with the past. The input to the system changes, usage levels increase, and people leave the organization. The only real constant is the code itself!

Given that, I present:

Laws of software developed by Humans

  1. Humans cannot predict where software will be extended in the future. Instead trust in YAGNI and dependency injection.
  2. Humans cannot predict where software is slow. Instead we have profilers and the three rules of optimization.
  3. Humans cannot predict when or how business direction will change, the economy, or future technology enhancements. That’s why we have iterative development: Agile, <a href=”http://en.wikipedia.org/wiki/Scrum_(development)”>Scrum and XP.
Refuting the laws given with the alternative laws
  1. Good architecture is one that enables architects to have a minimum of irrevocable decisions.
    Alternative law #3 says you won’t be able to predict which decisions are irrevocable. Instead of designing an architecture with revocable everything, design the minimum possible architecture that barely scrapes by to get the job done.

    Instead of developing your own bash build script, use Maven, and don’t do anything silly with it. “</amvn clean install” and “mvn clean deploy” should be all the commands you need to send your artifact onward.

    Instead of getting locked into a particular open source project or vendor, use JEE6 standards like JSF2.0, JPA2.0, JMS, and EJB3.1, or commit to using Guava and Guice. Simplicity is key, less is better. Using tools they way they were intended saves time.
  2. To make decisions revocable you need to design for flexibility.
    Alternative law #1 says you stink at designing for flexibility, so don’t do it. Rather than designing for flexibility, design an exit strategy document for each technology you use. This includes frameworks built in house: how will you exit from those once they become legacy code? (The best way is to abstain from writing them.)

    Alternative law #2 also applies here, don’t use obscure technology like a NoSQL database until you actually determine you’ll need a a NoSQL database by profiling. It you’ve truly designed minimum architecture and opted for simplicity, it will be simple to change out your backing store with a different database. It’s good to remember that you are not Google. If you design simple architecture, you’ll have plenty of time later on to switch to NoSQL when it’s needed, rather than rewriting a thousand lines of Redis specific JSON handling code upfront.
  3. To make use of flexibility one needs to refactor mercilessly.
    Given Alternative laws 1, 2, and 3, this brings old law #3 into new light. You should refactor mercilessly and eliminate technologies. Gage yourself: How many new technologies did you bring in versus how many exit plans did you execute?

    Develop a master engineering architecture plan. Every release should bring your closer to the master design, at which point, you should update your exit plans then update your master architecture plan. What technologies could minimize the architecture? Evaluate them… do they require glue code to be written? What frameworks can we exit from and what technologies aren’t working out? Get rid of them, quickly. What in-house utility projects (aka future “legacy code”) has been written? Open source it, replace them, or better yet, observe that YAGNI has manifested itself.
Conclusion, flame wars

When it doubt, don’t write it. Change your processes so you can use a tool without modification. Don’t dance around frameworks with unnecessary abstraction. Above all else, simplicity is key!

Finally, remember this is an attack on complicated software, not the author of the original post. I’ve enjoyed reading his blog. I look forward to your comments!

Advertisements
Comments
  1. Hey Jonathan,
    thx for the replay 🙂
    I didn’t read it as attack to me personally … I do believe though that the truth doesn’t lie in extremes. Of course simplicity is important. So is flexibility, and you also mentioned important concepts to achieve flexibility like IoC Containers. IoC isn’t easy to understand, but as it gets more and more “standard” many people know it now. The same is true for other design patterns. Polymorphism isn’t simple for many people but it is the most important “flexibility enabler” in object-oriented languages, wouldn’t you agree?
    I agree to all your laws. Of course its not possible to predict what’s happening. And I’m not talking about putting any silly over engineered stuff into software that is compilcated anyway. I am talking about “a necessary degree of flexibility” to make change possible without superior impact on cost and schedule. In my experience that’s key to meet the teams objectives.
    Cheers, Niklas

  2. Christian says:

    I’ve thought about the same things recently and came to similar conclusions, but I think a developer should question even the basic technology like the programming language. I found that I need significantly less code / libs / frameworks / tools when programming in Python instead of Java.

    • Jonathan says:

      I agree and disagree…

      If you use pure JEE6, you don’t need many external libraries… Maybe Apache Shiro for security, and Maven to build stuff. If you go SpringFramework, you will indeed need hundreds of external libraries, which is bad or good depending how you look at it. JEE6 really changes things, they finally seemed to have “got it right.”

      Python _is not always_ an exception to this rule… My last startup was in Python… we used DJango, SQLAlchemy, amqplib, South, Simplejson, and Fabric. DJango has hundreds of tiny submodules and extensions we had to tack on as well, and in the end, my dependency list looked just like a SpringFramework project.

      • Christian says:

        What I meant is not only the count of libs, even I feel it is lower, but the the architecture as a whole. Python helps to reduce layers of abstraction and boilerplate code. You don’t need so much upfront design, you have small “interfaces” through duck-typing (interface segregation principle is built into the language), you don’t need FactoryFactories for decoupling, you have everyting you need for AOP, you can explode a list with a simple “*” … There are so many small and little things that makes programming with Python more productive than programming with Java or C#. And as far as I can say the architectures are significantly cleaner with Python.

  3. phil swenson says:

    I’m mostly in agreement with your rebuttal. Flexibility and abstractions usually leads to madness.

    BUT:
    “Instead of getting locked into a particular open source project or vendor, use JEE6 standards like JSF2.0, JPA2.0, JMS, and EJB3.1, or commit to using Guava and Guice. Simplicity is key, less is better. Using tools they way they were intended saves time.”

    So instead of locking yourself into a particular open source project, you lock yourself into a bad standard (JSF specifically from your list)?

    I think better advice would be “Pick solid, simple, widely used standards and frameworks”. There is nothing wrong with picking Play, Rails, Spring. You will be locked into an extent – but locked into something that is of quality.

    And I maintain, if you follow a few principles/patterns like the Single Responsibility Principle, IOC, TDD, YAGNI, you will end up with a code base that can be leveraged in ways you’d never anticipate. In other words, NOT designing for flexibility – but instead writing simple, good code means you are more likely to be able to adapt your code base to new frameworks, new use cases.

    • Jonathan says:

      into a bad standard (JSF specifically)
      Phil, I assume you’re talking about JSF v1.x, which is, absolutely a horrid evil. JSF2.0 shouldn’t have been called JSF… Most everyone that tries JSF2.0 and Facelets2.0 with CDI integration loves it. If you’ve personally tried JSF2.0 and still don’t like it, I’d love to hear why. Checkout the amazing work done with PrimeFaces while you’re at it…

      My real point is that if you stick to vanilla JEE: JPA, JMS, etc, you are free to switch between:
      1) Libraries (Ex: OpenJPA, EclipseLink, Hibernate)
      2) Application server vendors (TomEE, GlassFish, Resin, Jboss, etc)
      3) Or go back to Spring (since it supports most of JEE)

      Pick solid, simple, widely used standards and frameworks
      Provided you stick to the caveats in my article (Mainly, having a plan to exit the technology when it begins to stink). That’s why I gave the examples of Guava/Guice so people wouldn’t confuse me with Adam Bien.

      In other words, NOT designing for flexibility – but instead writing simple, good code means you are more likely to be able to adapt your code base to new frameworks, new use cases.
      You nailed it, that was the point of my entire article in many less words.

    • IOC is design for flexibility, so is SRP. I have mentioned the design principles and patterns as the happy medium of simplicity and flexibility.

  4. phil swenson says:

    I don’t want to get into a big debate about JSF (yes, I am way more familiar with JSF 1 than 2), but I think my point still stands.

    There are great frameworks out there that are not implementations of specs. There are many terrible specs (JSF 1.0, SOAP, EJB 1). I guess all things being equal, being an implementation of a spec is a net positive. But I’d personally put more weight in finding the right framework for the task at hand.

    But all in all, I think we 90% agree 🙂

    • It’s naive to believe that just because something was agreed in a JSR it’s good to use it. You name the examples. 100% agreement here 🙂 there is no truth in any extreme … Java EE vs Spring, flexibility vs simplicity isn’t the right question probably …

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s