This post was originally written while I was at LShift / Oliver Wyman
Consider these quotes:
“Any sufficiently complicated program contains an ad hoc, informally-specified, bug-ridden, slow implementation of half of Common Lisp” – Greenspuns Tenth Rule Of Programming
“Once you add group by, filter, & join, you can no longer claim to have invented a new query language, only a new dialect of SQL. With worse syntax and no optimizer.” – Carlos Bueno
Recently I’ve needed to review some PHP web development frameworks and I’ve seen the same thing: a new Framework is created and the founders claim it’s better because it’s “simple”! Then in v2 they add ORM, database migration, async events, CSRF protection…
It’s this word “simple” that causes all the problems. In my experience, when people say “I want something that’s simple” what they really mean is “I want something I already know or can use without learning anything”. This a purely subjective measure which is why 1. it’s impossible for a group of people to agree what “simple” is and 2. “simple” changes over time even for the same person.
In user interface design, for example, you get over this problem by making the application flashy or inviting in some way so the user doesn’t notice that they’re learning a new system. Or you make the “first action” so easy that the user gains confidence in their ability and is willing to invest more time – there’s a reason why the on-off switch on TVs and computers is the biggest and most obvious even though it’s not the button you use the most.
This hatred was due to the lack of “read-simplicity”.
Is it possible for a language, framework, etc. to have both write and read simplicity?
- The type system stays out of the way.
- APIs are easily guessable, consistent, small and complete.
- Large library integrating with other services.
- “Simple” syntax (some people think that prefix-notation and huge sequences of closing parentheses is simple – let’s leave that as a matter of opinion…)
- Easily mockable for unit tests.
- Strong-enough type system so your IDE can correctly refactor code, and it’s easy to find the implementation of the method call your looking at (in duck-typing languages the IDE just gives up and shows you every class with a method of that name. In RubyMine this appears to be true even if you’re calling “self” when it should know exactly what class tree you’re expecting!).
- Enforces good coding style that reduces or eliminates intertwingledness.
- Anonymous and first-class functions are excellent – but while compactness can be impressive in algorithm competitions singlelineitis makes the brain hurt when maintaining real code.
- Very easily mockable for unit tests.
(These criterion are not complete)
The main distinction between the two lists is the existence of strict typing. Is this really the source of read-simplicity and the bane of write-simplicity? I suspect mutable vs. immutable data structures may also be in there.
Why is this important? We all like to argue about which language we think is “best”, but I don’t think that’s useful unless you’re also taking into account the context in which a particular piece of software is being written.
In the startup world a large proportion of projects will fail, and it’s important to find out which as cheaply as possible – you need to drill as many test bores as possible to find the one with oil at the other end. So for your prototype or “first version” it may even be financially irresponsible not to use a write-simple language.
But once a piece of software is taking longer than a couple of months to write or it will be maintained over a long period of time (the sort of project that LShift is normally engaged in) or, particularly, if more than one person is writing it then it becomes more and more essential to use a read-simple language. Hence the desire to find a language that is both.
Update 2018: For some reason Ceylon still has not caught on, but Kotlin is superb - any Java team should transition to Kotlin…