Sunday, February 10, 2013

Design approach: "Find the path" vs. "All paths are obvious"

Change the good to the bad

I've been fiddling around with CSS recently, and got a whole lot of new impressions and emotions. :) No, they were not all negative, as you might have guessed, though I don't object that the way stuff is done with style sheets is complete crap, obviously.

After working in C++ professionally for a considerable amount of time, chances are that getting into a clean dynamic language may sometimes open one's eyes and mind. Another way of thinking about programming, an extremely useful experience. Many people do realize that; I'm not going to tell anything new. The usefulness lies in changing one's point of view, and in exploring new paths that lead to the same destination.

Likewise, when you've been using a good thing for a long time, you may find it mind-opening to try to use an utterly bad one. That would just help you to realize why the former thing was good. You'd start to appreciate its goodness better.

CSS was such a "bad thing" to me.

The Scheme way

Consider the Scheme programming language. The Scheme way reflects how mathematicians think: they think systematically, trying to discover the order and harmony wherever they are able to. Mathematical harmony is all about generalization and orthogonality. Make a fixed-size minimal core of primitive tools, then invent some ways of composition and abstraction. You'd be able to build programs of (virtually) any complexity and size out of primitives: just take some primitives and compose them into a complex thing, then name that thing and treat it like a primitive by abstracting off any non-significant details. Then it is possible to combine those complex things in even more complex blocks, because your means of abstraction allow you to treat them as primitives. This is the best way to combat the complexity of software development.

(There's another way to overcome complexity: hire lots of cheap manpower, give them tools that prevent each of them from causing much harm, and there are pretty good chances that you'll end up with a viable product that you will be able to sell. This way works better in real life. God damn it.)
Scheme/Lisp semantics are well-defined. Basically, any piece of Lisp code is either a special form ("primitive"), a macro form or a function call. There's no distinction between expression and statement: everything is expression, and any form can appear at any place where expressions are allowed. This is orthogonality. You can write, for example:

(+ (if (> x y) 0 1)
   (let ((x (get-some)))
     (* x x))),


which adds two expressions together; both of them are special forms, and this is perfectly okay.

The CSS way: find the path

Now contrast Scheme with CSS. CSS have no means of generalization (to the extent Scheme/Lisp has), neither is it orthogonal.

The lack of generalization is not that critical if we take into account that most programming languages in widespread use are quite poor in this regard, too. That's why things like SASS have been created. Yet another abstraction layer over CSS.

But the second flaw I mentioned is really critical, at least it does bother me. It is barely possible to predict what you get when you apply these properties to those elements. Creating rules that do what you intend is much like solving a puzzle: you should guess by trying different variants. And then look what you get in IE, and guess which ugly hacks to apply. And then keep guessing and trying and googling until you're satisfied, if ever.

(Yes, I do know that those standards were created with backward compatibility in mind, and they had to be compliant with the way HTML and older versions of CSS had worked already. This is probably one of the main reasons why CSS is such a crap. Backward compatibility has never been a sufficient excuse, though.)

In Lisp, any combination of core syntactic forms, function calls and macros has well-defined semantics. That's like when you certainly know where to go to get wherever you want. There might be several possible ways, but any one is clean and well-defined.

In CSS, things are very different. You should make your way through mess, stepping forward in various directions and see where you find yourself.

For some time, I had been searching for a way to solve a relatively easy (at least easy-looking) UI task. I had not found any better solution than to employ table-based layout. Recently it was the second time I discovered that table-based layout does the job best of all. I referred to a friend of mine who had much greater experience with front-end development than me. What I saw did surprise me a lot: she managed without table-based layout, but in many places there were pixel hard-coded values. Like, you know, this bar should be 336 pixels wide, and margins for that picture should be 0, 5, 5, 2 pixels, etc.

I drew a conclusion that those CSS/Web UI/front-end guys do not just take things as systematically and elegantly as I wish to do. They don't expect Scheme-like elegance from tools they're using, and that's why they're much happier than people who do expect this kind of elegance.

You need a markup like that ? No problem, I'll figure out what all those margins, paddings, borders, widths and heights should be and write styles. Oh, you don't like this font and would prefer some bigger one ? No problem, I'm going to set whatever font you like and then spent 15-20 minutes fixing broken margins and paddings of half the other elements of the web page. How do I choose new class names for a large web page I didn't write from the very beginning ? I just pick any name I like and search HTML source for it; if something is broken (seldom), I try another name. How do I choose IDs for my elements ? Very much alike.


Hackable CSS

Honestly, I don't know why UI development has a bad reputation. Creating good UI is challenging, it is not a straightforward task like most people think; well, at least if we look at the task itself and forget for a moment about instruments we are forced to use to make it. There's a bunch of programming abilities required to produce responsive Web interfaces. Being able to drag and drop standard components on a form is not enough.

Let's see the truth: CSS was created for non-professional programmers (or even for non-programmers) to help them accomplish (relatively) simple formatting tasks easily. This explains all. No decent means of generalization, abstraction and composition, and no orthogonality. The latter goodies are long-term weapons, and if you aim long-standing purposes, you inevitably lose at proximate ones (to some degree). This is exactly our case: sacrifice long-term purposes (such as abstraction and orthogonality) in favor of short-term ones (such as being able to easily write down selector which selects the element you wish to set visual properties for).

It's interesting, but those non-professional people gradually begin to understand the importance of long-term things. That's why new selectors, CSS properties, W3C standards and interfaces appear.

What is true is that we cannot change any of these Web-related standards, they are firm as concrete. What I think we can try is creating a hackable interface atop of existing JS/CSS/HTML. In fact, this is being done all the time: CoffeeScript, TypeScript, (already mentioned) SASS, ParenScript, etc. Whole zoo of abstractions. Each of them is most probably more powerful and convenient than native CSS/JS.

Yeah, you're quite right if you're saying that this won't make CSS any better. High-level things which are built on top of bad low-level things are almost always bad, too. But I do believe there should exist a beautiful Lisp which brings some more of real elegance and power atop of existing HTML/CSS/JS. It would be then possible at least to abstract away (to hide) some IE hacks and other typical CSS boilerplate.

As far as I know, there's no good Lisp that would translate into JavaScript, like CoffeeScript. I'd love to see this possible to write CSS and HTML in that same language, and have those translated into real CSS and HTML. Maybe the time hasn't come yet.. we will see.