Monday, March 12, 2012

Simple Made Easy

Simple Made Easy
"Rich Hickey emphasizes simplicity’s virtues over easiness’, showing that while many choose easiness they may end up with complexity, and the better way is to choose easiness along the simplicity path."

I absolutely recommend you take the hour to watch this presentation.  It's pretty easy viewing, he's funny, and I found it very influential.

"Your ability to reason about your program is critical to changing it without fear."  This has been something I've firmly believed for a very long time, but I love how succinctly Hickey puts it here.  He even has the courage to challenge the two most popular practices of Software Engineering today: Agile, and TDD.  For Agile, he's got this line: "Agile and XP have shown that refactoring and tests allow us to make change with zero impact.  I never knew that, I still do not know that."  Agile is supposed to make the fact of change one of the primary motivators behind how the project is run, but it doesn't really make applying that change any easier in the code...  For TDD he has this wonderful quip:
"I can make changes 'cause I have tests!  Who does that?!  Who drives their car around banging against the guard rails saying, "Whoa!  I'm glad I've got these guard rails!"
He calls it guard rail programming.  It's a useful reminder that while tests are definitely valuable, they can't replace design and thoughtful coding.

Another very enlightening comment he made had to do with the difference between enjoyable-to-write code and a good program.  This rang very true with me, probably because of all the Ruby bigots these days who are obsessed with succinct or "beautiful" code, but are still writing big balls of mud.  Hickey basically said he doesn't care about how good of a time you had writing the program.  He cares about if it's complexity yields the right solution, and can be reasoned about/maintained.

Which leads to another concept he brings up of Incidental Complexity vs. Problem Complexity.  The argument that the tools you choose to use in your software can bring along extra complexity that has nothing whatsoever to do with the actual problem your program is supposed to solve.

Hickey Says I'm Wrong
I just wrote a series of posts where I was attempting to question some of the assumptions behind many of what are commonly considered good design practices in static object-oriented languages today:
  1. Interfaces, DI, and IoC are the Devil
  2. Demonstrating the Costs of DI
  3. Objects or Data Structures
  4. Service Layers or OOP
  5. Header Interfaces or Inverted Interfaces
  6. DIP: Loose or Leaky?
  7. Abstraction: Blessing or Curse?
I covered alot of stuff in that series.  One of the things I was really challenging is the practice of hiding every object behind an interface.  I argued this indirection just made things more complicated.  At about 50 minutes in, Rich Hickey says every object should only depend on abstractions (interfaces) and values.  To depend on a concrete instance is to intertwine the "What" with the "How" he says.  So, he's saying I'm wrong.

I also talked about how Dependency Injection is leaky and annoying.  But Rich Hickey says you want to "build up components from subcomponents in a direct-injection style, you want to, as much as possible, take them as arguments", and you should have more subcomponents than you probably have right now.  So, yeah, I'm wrong.

I didn't actually blog about this one, but I've certainly talked about it with alot of people.  I've been a proponent of "service layers" because I want my code to be as direct as possible.  I want to be able to go one place, and read one code file, and understand what my system does.  For example if I send an email when you create a task, I want to see that right there in the code.  But Hickey says it's bad to have object A call to object B when it finishes something and wants object B to start.  He says you should put a queue between them.  So, wrong again!

I'm also a proponent of Acceptance Test Driven Development (ATDD) and writing english specs that actually test the system.  Hickey says that's just silly, and recommends using a rules engine outside your system.  :(

And finally, and this is the biggest one, he says: 
"Information IS simple.  The only thing you can possible do with information is RUIN it!  Don't do it!  We got objects, made to encapsulate IO devices.  All they're good for is encapsulating objects: screens and mice.  They were never supposed to be applied to information!  And when you apply them to information, it's just wrong.  And it's wrong because it's complex.  If you leave data alone, you can build things once that manipulate data, and you can reuse them all over the place and you know they are right.  Please start using maps and sets directly."
Um, yeah, ouch.  I'm an object oriented developer.  I read DDD and POEAA three years ago and got really excited about representing all my information as objects!  We extensively prototyped data access layers, Entity Framework and NH chief among them.  We settled on NH.  Worked with it for awhile but found it too heavy handed.  It hid too much of SQL and clung too much to persistence ignorance.  But I couldn't really understand how to use a Micro-ORM like Massive (or Dapper or PetaPoco) because I was too hung up on the idea of Domain Objects.  So we spiked an ORMish thing that used Massive under the covers.  It supported inheritance and components and relationships via an ActiveRecord API.  It gave us the flexibility to build the unit testing I always wanted (which I recently blogged about).  It is still working quite well.  But it's information represented as objects.  So it's wrong...

In case you didn't pick up on it, Rich Hickey wrote Clojure, a functional language.  I don't know anything about functional programming.  I've been meaning to learn some F#, but haven't gotten that into it yet.  So it doesn't really surprise me that Hickey would think everything I think is wrong.  Functional vs. OOP is one of the biggest (and longest running) debates in our industry.  I think it is telling that I've felt enough pain to blog about lots of the things that Hickey is talking about.  But I don't find it disheartening that his conclusions are different than mine.  It is possible that he is right and I am wrong.  It is also possible that we are solving different problems with different tools with different risks and vectors of change and different complexities.  Or, maybe I really should get rid of all my active record objects and just pass dictionaries around!

In any case, this certainly was a very eye opening presentation.

1 comment:

  1. Dan S. pointed me to both your blog post and the Hickey presentation. I haven't watched Hickey yet but you both touch on a subject we've been talking about quite a bit at Within3 lately. I spent many years as an OO snob and I'm starting to become an OO contrarian. Every tool can be used for both good and evil. I'm starting to think we've swung the OO pendulum too far to the evil side. I'm starting to feel as though many OO "best practices" create a bunch on unnecessary complexity. We may be screwing ourselves.

    It will probably come as no surprise to you that I've become pretty obsessed with Clojure lately. I'm working on a side project with some friends and I'm doing the work primarily in Clojure. I'm loving it. One of the best things about Clojure is the strong Java interop. When OO lends itself better to a particular task you can use an OO language (Java/Groovy/JRuby/Jython/take-your-pick) then use Clojure for everything else. It's a very powerful model.