Simple vs. Complex

1 view
Skip to first unread message

Sean Copenhaver

unread,
Oct 20, 2011, 3:43:42 PM10/20/11
to ColaCodeDojo
Pretty interesting talk by Rich Hickey (creator of Clojure I believe):
http://www.infoq.com/presentations/Simple-Made-Easy

Would love to hear some thoughts. I'm going to try and listen to it properly (was working with it in the background) tonight.

--
“The limits of language are the limits of one's world. “ - Ludwig von Wittgenstein

"Water is fluid, soft and yielding. But water will wear away rock, which is rigid and cannot yield. As a rule, whatever is fluid, soft and yielding will overcome whatever is rigid and hard. This is another paradox: what is soft is strong." - Lao-Tzu


jed schneider

unread,
Oct 20, 2011, 3:55:22 PM10/20/11
to colaco...@googlegroups.com
saw it in person at Strange Loop. Great talk, very much worth the time weather you end up agreeing with him or not. 

-- 
jed schneider
Sent with Sparrow
--
You received this message because you are subscribed to the Google
Groups "ColaCodeDojo" group.
To post to this group, send email to colaco...@googlegroups.com
To unsubscribe from this group, send email to
colacodedojo...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/colacodedojo?hl=en

Sean Copenhaver

unread,
Oct 20, 2011, 5:52:02 PM10/20/11
to colaco...@googlegroups.com

-- 
Sean Copenhaver


Sent with Sparrow

Sean Copenhaver

unread,
Oct 20, 2011, 6:27:02 PM10/20/11
to colaco...@googlegroups.com
Also got this out of Uncle Bob's post, but another (related) talk by Hickey:


-- 
Sean Copenhaver


Sent with Sparrow

Sean Copenhaver

unread,
Oct 21, 2011, 8:45:45 AM10/21/11
to colaco...@googlegroups.com
I think I got three things out of all of this. All of which I completely agree with. In my own words; No process/discipline is better then knowing what you are doing, everything has trade offs that you have to consider, finally you have to be able to understand and reason about the problem and software. That last one came up in both of the talks I linked to.

I loved his criticisms for agile and TDD, because they are sometimes true. You have to have technical discipline for agile to work and tests do not replace a system that is easy to reason about. Although I think that people who dig into testing find that tests help you keep your components small and manageable. That might still mean they are very intertwined though.

Seriously you guys should at least check out the first talk. Loved his focus on trying to differentiate "easy" and "simple". Hearing him discuss these things actually makes me want to check out Clojure.

Bryan Matthews

unread,
Nov 2, 2011, 10:27:23 PM11/2/11
to colaco...@googlegroups.com
Sorry to rehash an old thread, but I've let my inbox run away recently.

I enjoyed the talk and heard a lot of good points in it.  It was refreshing to hear a talk about software focus on simplicity.  This reminds me a lot of the vibe I get from Douglass Crockford.  The practices he advocates stress simplicity and consistency, which I don't think get enough attention.  A lot of errors I see come from either carelessness, which could be helped by following conventions and doing code reviews, or excessive complexity (or "cute code"), which can be avoided in favor of the simplest and most obvious solution.

That being said, there are times when complexity cannot be avoided.  Software is by it's very nature a complex beast, so the goal should be to avoid any complexity that can be avoided and manage it when it can't.  I think that code should be written such that it is easy to understand (which requires no comments or explanation), doesn't surprise someone who reads it, doesn't rely on unspoken assumptions, and avoids anything that increases the likelihood of error, confusion or ambiguity (language features, coding style, patterns, etc.).  We should be proud when we delete lines of code or when we turn a complicated piece of code into a few lines that are easy to understand.  When you find yourself in a situation where the solution can't be expressed in simple terms (most likely because it is a complex problem, go figure) then fallback to thorough testing, documentation, lots of input from colleagues, and code reviews.

I do think it's interesting that we've created so many overly-complicated abstractions for forms over data, which should be a fairly simple problem that doesn't require added complexity.

As for testing, I'm still trying to solidify some of my thoughts on the subject.  It's true that no amount of tests can make up for crappy (or "complected") software.  However, I do think it's unprofessional to consistently neglect to verify and ensure the correctness of your software.  That shouldn't be open for debate at this point.  But I've also heard horror stories of code coverage metrics being mandates from on high or tests required for each check in (which devs find ways to game the system).  Writing tests isn't a silver bullet either, which I think was his point.

Sean Copenhaver

unread,
Nov 3, 2011, 8:34:03 AM11/3/11
to colaco...@googlegroups.com
Interestingly some of the things you said reminded me of Python and their 'Zen of Python' PEP [1]. Mostly because they value consistency and trying make things obvious. Basically the anti-perl. I swear there is a van Rossum (creator of Python) quote where he said Python was an experiment to see how expressive a language could be while still allowing everyone to be able to read your code.

The values of Python and it's community attract me. Ruby and it's values do as well. They are two fairly different worlds though.

Anyway, you hit on the idea that I believe Brooks (in Mythical Man Month) divided into essence and accidents of software. The essence of course is the complexity you can not avoid because it's the actual problem. Then the accidents are the complexities we add during production that are not related to the real problem.

I feel that accidental complexity come from a few sources:
  • misunderstanding of the problem
  • blinders or forcing that round peg in a square hole
  • lack of time to simplify down to the essence
    • you have to realize you may not have been given the essence to start with
The second item could relate back to my targeted vs general technology arguments. Where we are always taking a hammer and an overly sized square peg and forcing it into every circle hole we come across. It usually works (rarely in the allotted time since most projects go over schedule and budget), but how much accidental complexity did we create for ourselves in the process?

How could you know if you don't understand the problem, distilled it down, and reasoned about what the actual needs are before decided how to implement a solution. I think this is a key argument of Hickey's talks. Understanding and reasoning about the problem, then implementing a solution in the simplest way possible. Listening to the man and what he values makes me want to check out Clojure to see what he has come up with.

[1] http://www.python.org/dev/peps/pep-0020/

jed schneider

unread,
Nov 3, 2011, 9:22:39 AM11/3/11
to colaco...@googlegroups.com
I think in particular Rich likes to think in higher level abstractions and compatibility, which he believes are fundamental to simplicity. In clojure, for example, all collections are built to the same interface (a sequence) and therefore the vast API for sequences work on all types of collections. You also concern yourself less with the type of collection you are dealing with, rather than worrying if it is a concrete ArrayList, just a List interface, or some other type of concrete member. I think Rich would argue that having to remember that X Class takes a specific concrete list type while Y Class takes another concrete type is too complex to remember and reduces you capacity to reason about it. The dynamic typing of Python and Ruby come close to solving this problem, but i'm sure Rich's biggest complaint would be that the sequences in both those languages are mutable, which creates another level of complectedness. From the Clojure site:
---------------------------

Collections

All of the Clojure collections are immutable and persistent. In particular, the Clojure collections support efficient creation of 'modified' versions, by utilizing structural sharing, and make all of their performance bound guarantees for persistent use. The collections are efficient and inherently thread-safe. Collections are represented by abstractions, and there may be one or more concrete realizations. In particular, since 'modification' operations yield new collections, the new collection might not have the same concrete type as the source collection, but will have the same logical (interface) type.

All the collections support count for getting the size of the collection, conj for 'adding' to the collection, and seq to get a sequence that can walk the entire collection, though their specific behavior is slightly different for different types of collections.

Because collections support the seq function, all of the sequence functions can be used with any collection.
------------------

And an example of this from clojure's repl:


-- 
jed schneider
Sent with Sparrow

Sean Copenhaver

unread,
Nov 3, 2011, 10:07:10 AM11/3/11
to colaco...@googlegroups.com
Yeah the consistency and high levelness of Python I love. They have this idea of protocols which are sort of like the natural interfaces you follow to represent things. So a collection of any kind has a protocol of couple of functions that they provide. This goes all the way from dictionaries, to file objects or strings. Python does have an immutable collection type, but that's not the focus of the language at all.

Another example of Python's consistency is that a callable object is always executed as <identifier>(). Examples:

Creating a new object (the class object is callable, no new keyword):
    obj = MyClass()

using an instance of a class that is callable:
   result = obj()

calling a function (lambda or predefined):
   value = func()

Does a class constructor not do it for you anymore? No problem because a function call is the same, just point that MyClass name to your factory.

Or how do you get the size of something?
   len(obj)

No count(), or length, or size. It's always len(obj). If an object doesn't support it there is a default behavior specified I believe and you don't have to be a collection for this to work.

The Python community strives for this kind of consistency and considers this Pythonic (1 obvious way).

Getting back more on topic. A key idea to object oriented design is programming to an interface. You are not suppose to know the implementation just the basic conditions of an interface. I believe Gang of Four book tries to point out the different between a type and its implementation. A class provides both and an interface provides only the type information. In .NET world (at least) we get pretty stuck on is this a class or is this an interface. Easiest example is why do you need to prefix interfaces with an I?

That said if the problem required you to worry about resource usage and performance then you might not have the luxury of thinking in high level concepts provided by newer platforms and languages. A C extension in the right place could limit the area effected.

I'll cut this off with a nice quote from Alan Kay (look him up if you don't know the name) since Jed mentioned dynamic typing:
"I'm not against types, but I don't know of any that aren't a complete pain, so I still like dynamic typing."
Reply all
Reply to author
Forward
0 new messages