Healthy reaction, constructive reaction, can start from a wrong idea clearly defined, whereas mere muddle effects nothing whatever.
A while ago I wrote about how Clojurescript was a square peg being hammered into a non-existent hole to complete indifference by everyone.
So has anything changed? Well Clojurescript has continued to be developed and it seems to have lost some of the insane rough-edges it launched with, it seems possible to use it with OpenJDK now for example.
The appearance of core.async for Clojurescript is in my view the first genuine point of interest for non-Lisp fans. It provides a genuinely compelling model for handling events in an elegant way.
David Nolen, while being modest about his contribution, has also contributed some excellent blog posts about the virtues of Clojurescript. The most essential of which is the 101 on how to get a basic Clojurescript application going with core.async. This is an excellent tutorial but also is underpinned by hard work on getting the "out of the box" developer experience slick via the Mies Leiningen template.
Let's be clear about what a difference this makes. At the London Clojure dojo we once had a dojo about using Clojurescript, after a few hours all the teams limped in with various war stories about what bits of Clojurescript they had working and what was failing and why they thought it was failing. The experience was so bad I really didn't want to do Clojurescript as a general exercise again.
In the last dojo we did Clojurescript, we used Mies and David's blogpost as a template and all the teams were able to reproduce the blogpost and some of the teams were creating enhancements based on the basic idea of asynchronous service calls.
When someone pitches a Clojurescript idea in 2014 I'm no longer in fear of a travesty. That is a massive step forward.
And that's the good news.
In both languages practitioners of the language are deeply aware of the corner cases of their language. Since they are constantly working with it they are also familiar with the best practices required to make sure you don't encounter those corner cases.
Clojure on the JVM brought power, simplicity and a model of programming that made reasoning about code paths simple.
Visual Basic isn't the best language in the world, it's certainly not the best language for creating apps on Windows. However for organisations and programmers who have invested a lot of time in a language and a platform it normally takes a lot to get them to change.
Usually, it will take an inability to hire people to replace those leaving or the desertion of major clients before change can really be countenanced.
There's no lack of demand for good looking websites and browser hackery to differentiate one web product from the next.
Sometimes there are real advantages to sticking close to the devil.
For me the most interesting area of Clojurescript is being able to write Clojure and treat V8 as an alternative runtime.
People are already noticing some odd performance characteristics where some things run better on Node than they do on JVM, most particularly around Async.
It is still going to be a niche area but it is much more likely to happen than in the client-side.
The talk had two main threads. It served as a helpful review of Clojure’s state-handling, concurrency and parallel processing features. Useful for beginners but also a helpful recap for the more experienced.
The other was a discussion of what we mean by concurrency and parallelism. Something that I hadn’t really thought about before (although I was aware there was a difference). Tommy referenced this talk Concurrency is not Parallelism (it’s better) by Rob Pike.
In the talk Rob gives the following definitions:
Concurrency: programming as the composition of independently executing processes
Parallelism: programming as the simultaneous execution of (possibly related) computations
In the talk Tommy gives the future function as an example of programming to indicate concurrency boundaries and the reducers library as an example of parallelism.
Rob’s presentation is worth reading in full but his conclusion is that concurrency is not a guarantee of parallel execution but that achieving parallelism without concurrency is very hard or impossible. Tommy’s talk uses an Erlang example to make the same point.
While discussing reducers Tommy finally explained something that I struggled before. A lot of type champions point at reducers and shout Monoids! As if that was some kind of argument.
During his talk Tommy explains that parallel combination function needs to be able to return an identity so the function always returns a value and that because ordering of values is not guaranteed (unlike the implied order in a regular reduce) it needs to be associative.
That makes sense. Turns out that those are also the properties of a monoid.
Fans of type systems throw terms like Monad, Dual and Monoid not to help add understanding to a discussion but to use them as shibboleths. It was far more enlightening to see an example of where the needs of a problem were driving to a category of function with certain properties. If that is common enough to deserve a shorthand-name, fair enough, but the name itself is not magical and knowing the various function category names is a feat of learning rather akin to memorising all those software pattern names from the Gang of Four’s book.
I don’t do masses of CSS in my work but this year was an interesting one because there was acres of CSS being created due to the general acceptance that we just need to get on with implementing the responsive web. Leaving the fixed-width grid also meant having to rethink the structure and architecture of CSS and modernise the legacy styling which if we’re all honest is actually created organically and piecemeal as requirements drift in.
I struggled and fought with SMACSS but I’m now over it and think that the result in practice has shown that it is the most sensible way to do things today.
BEM felt overly complex and fussy while covering pretty much the same ideas as SMACSS. OOCSS was off-putting due to its weird appropriation of object-orientated programming concepts.
I did like its idea of using multiple classes to allow for composition of styles. But using the idea of multiple inheritance as a metaphor for this seemed to be bizarre. Don’t these people know how painful inheritance is?
One of the big things I took from SMACSS is that isolation is more valuable than re-use. Using a system that guarantees that your styling rules are not going to have side-effects is massively powerful.
When you then try to abstract components and share rules between them you lose some of that isolation and you begin to recouple components.
Seeing CSS as a conflict between isolation and duplication was a powerful metaphor for making decisions as to how to structure things.
I’m pretty sure that when we look back at 2013 the invention of Turing-complete CSS pre-compilers is not going to be a high-point. The CSS generation languages have been important as a way of pushing the CSS specification forward and of proving ideas in practice. I’ve certainly been grateful to be able to use Less in prototyping for example.
The agreement of the need for CSS variables and for being able to do calculations with those variables is a credit to the pre-compilers. The problem they create is the complexity of their abstraction. Turning a declarative language into something more programmatic is problematic for all the reasons that programming languages have problems. DRY is good but compilation errors in your CSS doesn’t feel like progress to me.
Just as with user agent extensions I think that pre-compilers are a great test bed for innovation but what they need to lead to is a better syntax for declaring intention rather than a new language.
Having new ideas for organising and structuring CSS is great but we also need to reflect our new ideas in our old work. Well, that’s easy right? Now we have new ideas we’ll just call all our existing assets legacy and re-write the whole thing. It’ll probably only take three months or more…
For the project I worked most on I applied a rule of thumb that seemed to serve pretty well. All the new CSS architectures organise themselves around a concept of components or modules. If your existing CSS is more or less built around the same concept you should be able to adapt whatever structure you choose and retroactively apply it to your existing code.
If your existing code though is designed more around concepts of pages or tag styling then you need to rebuild it piecemeal. Introduce the new component with its styling build on the new standard and then go back and
I was quite taken by the idea of having the file of shame. However in practice developers preferred to have commented sections of the files with hacks in. And before long we had people accidentally adding non-hack rules after the hack commment-line and we also have hacks liberally sprinkled all over the place.
I lost the battle but the result has convinced me that you want one place for the hackery and you want it right at the bottom of the cascade.
The incentive should be to one day delete the file of shame.
Clearly this year the only person who was talking any sense in CSS (apart from Jonathan Snook) was Harry Roberts as I also liked the presentation where he pointed out that design needs to be regularised in the name of sanity. If we have some components that have a margin of 1rem and and some with a margin of 1.1rem because it looks better we need to be taking into account the cognitive burden of having those additional rules.
Creating independent components encouraged me to allow every one to be a special snowflake. It was good to have a counter-balancing principle to make sure that principal of least surprise applied.
Harry also made the sensible suggestion (in 2012!) that padding and margins be defined in just one vertical and horizontal direction. Thing about flow from top to bottom and left to right also helped me to stop make special cases and look for a more general declaration of what I was trying to describe.
No-one does Waterfall any more of course, we’re all Agile incrementalists. It is just that a lot of things are difficult to tackle in increments. You can’t get a great design, for example, or a visual style guide without a lot of user testing and workshopping. From a technical perspective you need to make sure your scaling strategy is baked in from the start and to help support that you will also want to have a performance testing framework in place. You’ll also want to be running those test suites in a continuous deployment process, because its hard to create that after the fact.
In short apart from the actual software you want to do everything else up front.
Waterfall existed for a reason, it tried to fix certain issues with software development, it made sure that when you finished a step in the process you didn’t have to go back and re-visit it. It made you think about all the issues that you would encounter in creating complex software and come up with a plan for dealing with them.
Therefore I can see all the exciting enticements to make sure you do something “up front because it will be difficult to solve later”.
However Waterfall had to change because it didn’t work and dressing up the same process in the guise of sensible forethought doesn’t make it more viable than its predecessors.
It can be really frustrating to have a product that looks ugly, or is slow or constantly falls over. It is far more frustrating to have a stable, beautiful and irrelevant product.
Occasionally you know that a product is going to take off like a rocket, as with fast-follow products for example, and it is going to fully payback a big investment in its creation. However in all other cases you have no idea whether a product is going to work and therefore re-coup its investment.
Even with an existing successful product major changes to the product are just as likely to have unexpected consequences as they are to deliver expected benefits. Sometimes they do both.
What always matters is the ability to change direction and respond to the circumstances that you find yourself in. Some aspects of software development have seen this and genuinely try to implement it. Other parts of the discipline are engaged in sidling back into the comfortable past under the guise of “responsibility”.
Ever since we’ve had access to increasingly more comprehensive and easy to comprehend metrics there has been a conflict between the artisan and craftsmanship elements of software development and the data-driven viewpoints.
There are lots of situations where two approaches result in the same metrics outcome. It is tempting to give in to the utilitarian argument that in this case what you should do is simply choose the lowest cost option.
That is too reductionist though and while it may lead to an optimised margin-generating product it feels to me that it is just as likely to create a spiral of compromise that jeopardises the ability to make further improvements.
It is here at the point where metrics are silent that we are put to the test of making good decisions. Our routes forward are neutral from a data point of view but good decisions will unlock better possibilities in the future. It is at this moment that I feel our preferences for things like craft and aesthetic and our understanding of things like cost and consequence matter. Someone able to understand how to achieve beauty and simplicity in software for the same cost as the compromise while achieve very different outcomes.
So we need to be metrics-first so we know we are being honest with ourselves but once we are doing things in a truthful environment, our experience and discretion can make all the difference.
A lot of dynamic languages actually use strong underlying type systems which means that you can’t interchange between strings and number types, you have to explicitly convert.
A typical web example is a http url or parameter that represents a number. All HTTP is string-based but when acting on the value we often want to compare its numeric value against other numbers.
One common technique is to convert the string value to a native type invisibly in the framework but I think that in practice what is more useful is to treat all HTTP content as strings, exactly as it comes off the wire.
Then in the context of the response handler you explicitly convert it to a number when you need to, at the point it needs to be converted.
I think this makes it easier to read the code: parameters passed from the request are always strings. Once the string is bound to an identity that identity should never be rebound to a different type. If we need the value of that identity in a different form we perform an explicit conversion at the site where the different value is needed.
If we use that value more than once then DRY suggests that we create a different identity, say parameter_as_number (unless we have a better name), that also has a consistently typed value, number.