Stuff about programming, programming style, maintainability, testability. Dedicated to my coworkers and friends. Everyone is welcome to leave comments or disagree with me. This blog does not represent views or opinions of my employer.

Tuesday, March 27, 2012

It is imperative to have many curlies

For the life of me, I could not memorize the term imperative programming (opposite of declarative and functional; the staple of traditional Java). I tried everything and nothing worked. In my brain, the word imperative did not want to associate itself with the whole concept. I guess I get it, the term is derived from commanding the computer to do something, but I just could not remember it! That is until I came up with the pun phrase: “It is imperative to have many curlies”.

Everyone is laughing when I tell them that a good programming is about removing curly brackets. Still, I have persisted in my determination and counting the curlies became a new way for me to measure my code.

Obviously, a simple way to achieve code perfection would be to change the language to one that does not have curly brackets, but that is not the point, the curlies may be still there only they would not look like curly brackets… For the sake of this argument, anything that defines a block of code, indentation in Python/CoffeeScript or Ruby’s end keyword is a curly.
The concept is simple, if I implement stuff, I use curlies, if I declare the behavior or use things like functional composition, then I don’t.
Languages like JavaScript and Groovy (GRAILS) are a good to showcase curly evil. Both are hybrid languages in the sense that you can do very imperative style Java like coding or do something else.

Let me start with a JS example. I am using Ext JS 4 in my current project. Ext comes with methods like: AbstractComponent.setDisabled(boolean disabled).

So if you want to add logic to disable/enable buttons, you can write it commending the browser to do your bidding and that would be with curlies. The code would look like somewhat similar to this:
1:  Ext.define('myView' ,{ 
2:   extend: 'Ext.form.Panel’, 
3:   ..., 
4:   
5:   items: [ 
6:      ..., 
7:      { 
8:        xtype: 'button', 
9:        label: 'save', 
10:       ... 
11:     },{ 
12:       xtype: 'button', 
13:       label: 'refresh', 
14:       ... 
15:     }, 
16:     ... 
17:   ], 
18:   
19:   enableDisableControls: function() { //curly! 
20:    //lots of if statements (curlies galore) defining when each button is 
21:    //enabled and when is disabled ... 
22:   } //another curly! 
23:  });

//  remember to add calls to enableDisableControls() each time:
//   -view is opened,
//   -refreshed,
//   -user makes changes to the data, etc, etc. (that is lots of additional curlies!)
//   -repeat the process for next 35 views you need to write...

Instead of this Object Oriented spaghetti, how about this code: (Note Ext JS adds a concepts of mixin to JS.)
1:  Ext.define('myView' ,{ 
2:   extend: '...’, 
3:   mixins: { 
4:    disableEnableOnDirtyState: '...', 
5:    disableEnableOnSecurity: '...', 
6:    disableEnableOnEditMode: '...', 
7:    ... 
8:   }, 
9:   
10:  items: [ 
11:    ..., 
12:    { 
13:       xtype: 'button', 
14:       label: 'save', 
15:       disableIfDirtystate: 'clean', 
16:       disableIfNotSecurityrole: '..._CAN_MODIFY', 
17:       ... 
18:    },{ 
19:       xtype: 'button', 
20:       label: 'refresh', 
21:       disableIfEditmode: 'new' 
22:       ... 
23:    }, 
24:    ... 
25:   ] 
26: });

The declarative definitions of buttons tell the reusable logic in the mixins that the save button should be disabled unless changes have been made to the form (dirtystate=’dirty’) and unless I have a security role allowing me to make changes or create new entries. The refresh button makes no sense for a new entry before it is saved on the backend so it stays disabled until that happens (editmode) … And I can be adding more and more orthogonal declarative conditions for enabling/disabling buttons!

Note the new version of myView is declarative, it does not implement the functionality it needs, it declares it. Also think of testability. Traditional Java code can try to place some disabling/enabling logic in the ancestor creating hard to test fat ancestors. Unit testing enable/disable mixins is very straightforward. (Note to declarative purists: this code has clear side-effects. It has to. The point is, however, that they are clear. ;)

Also note that some logical decoupling needs to happen since all of these orthogonal conditions compete for one boolean (component.disabled) (see Sencha Discussion Forum Post).

Finally a note for Ext programmers: some tweaking to Ext mixin preprocessor might be in order. Unlike SCALA Traits (or even Groovy mixins), constructor (yes, Ext adds constructor concept to JavaScript as well) is not automatically invoked for mixins so if mixin needs to, say, listen to dirtychange event it has problem arming itself.

To me, this approach is clearly a better code reuse, better code maintenance, it is also clearly better for TDD.

There are many other examples that come to mind:
GRAILS/GORM: GRAILS Domain Classes and GRAILS plugins can provide phenomenal examples of declarative programming where simple declarations load lots of functionality without any coding.

SCALA provides a great way of controlling the curlies in the code. If you coding style is very declarative and functional you will be able to code with very few curlies in SCALA.

So are curlies a measure of code quality? I hope to write more posts about my take on curlies soon.

This post continues here: Next Curlies Bashing

No comments:

Post a Comment