mercredi 8 juin 2016

Polymorphic directives in AngularJs


This is a short write up on how to perform ReplaceConditionalWithPolymorphism for directives in angular

Recently I had to add some functionality to a menu-bar that handles navigation between different screens. It is implemented as a directive. The problem was the same directive was instantiated by several controllers, and from some controllers it needs an instance of something, lets call it Book, and from one other controller it needs an instance something else that we’ll call Page.

I’m going to use the syntax of javascript classes to explain the problem, as it is rather clear and not specific to a framework. At the end we’ll look at the angular version.

class MenuBar {
     constructor(book, page) {
          // either of book or page are undefined
     }

     goToView(viewItem) {
    if (onBookView()) {   // i.e. page == undefined
        handleRedirectionFromBookViewTo(viewItem)
    } else // on page view
        handleRedirectionFromPageViewTo(viewItem)
    }
}

}

It is awkward and subject to error to allow either book or page to be null/undefined as it is difficult for another developer to know what is a valid way of instantiating it. Can both be undefined? If I define page, to I have to provide book? As far as testing goes, we have little confidence that it is instantiated with the right arguments in every view, so we're kind of forced to test all functionality in every view to be sure we don’t get a runtime failure. A combinatorial problem.

In addition much of the cyclomatic complexity of this class is unnecessary. Basically one set of branches are used when we have a book and a completely different one when we have a page. This is a clear cut for polymorphism :

class MenuBarForBook {
     constructor(book) {...}
    
     goToView(viewItem) {
    handleRedirectionFromBookViewTo(viewItem)
     }

}

class  MenuBarForPage {
     constructor(page) {...}

     goToView(viewItem) {
     handleRedirectionFromPageViewTo(viewItem)
     }
}

With this design it is unlikely that a constructor won't be called with the right arguments. The combinatorial problem is solved and we've lowered the testing burden.

So how can we do this in angular. Easy; create two different directives that expose the same functions and use the same template.

angular.module('menuBar', [])
    .directive('menuBarBook', [
    function () {
        return {
            templateUrl'src/menu/MenuBar.html',
            scope: {
                book‘=‘    // constructor argument
            },
            linkfunction ($scope) {
                $scope.goToView function () {    // function goToView()
                    handleRedirectionFromBookViewTo(viewItem)
                }
            }
        }
    }])
    .directive('menuBarPage', [
    function () {
        return {
            templateUrl'src/menu/MenuBar.html',
            scope: {
                page'=',
            },
            linkfunction($scope) {
                $scope.goToView function () {
                    handleRedirectionFromPageViewTo(viewItem)
                }
            }
        }
    }])

Conclusion

Polymorphism is a powerful tool both for making the code more usable to other developers by making it more explicit how to use a piece of code. Also, removing if-statements not only makes the code simpler but also makes the tests simpler. I just discovered this could be done with directives without too much overhead. It is worth naming directive inheritance here. However to my understanding it solves a different problem, namely sharing code.

jeudi 2 juin 2016

It's not a configuration issue. It’s a design issue

Consider this piece of code

url applicationConfig.publicationUrl relativeResourcePath
it contains a source of error, namely data.relativeResourcePath is of the form files/document.pdf and publicationUrl is 
of the form http://someserver/. So when someone changes the the applicationConfig to say http://otherServer:81 the download is not going to work anymore as we dropped the trailing slash. So url would be http://otherServer:81files/document.pdf which obviously won’t work

Ok so this is a configuration issue. What a pity, can’t do much about that. Even if we do TDD, testing configuration effectively isn’t easy. 

But wait! This code suffers from a Code Smell called Primitive Obsession. A better design would be the following:

url applicationConfig.publicationUrlFor(relativeResourcePath)
Poka Yoke

Now it’s easy to add the extra slash in case it is missing within the publicationUrlFor method and this type of configuration issue is gone forever throughout the application. Besides publicationUrlFor() is testable.

This is a simple example to highlight the idea that we can design away many of the bugs that we live with in our projects. By designing away sources of errors we make our code more usable, it can only be used in the right way. In Lean this is called Poka-Yoke. Every situation needs a different design to eliminate the possibility of misuse, but the general idea is the same - Design away sources of bugs.


For inspiration have a look at this other example of how to design away bugs due to temporal coupling: section Eliminate Exceptions in this post.




dimanche 13 mars 2016

Usable code and TDD

There’s a strong link between TDD and the usability of a code base, they go hand in hand.

By usability I mean how easy it is to steadily add features to it (you can read more on the concept by A. Bolboaca). The relationship between TDD and usability is that whenever it is difficult to use TDD in some piece of software there’s a reason for it - its usability level is very low. It follows that if developers work with a low usability tool (the code base), then development is not fast.

Let me explain why inability to use TDD on some codebases also makes it not usable for any other type of development. To understand that we need to look at what we need for writing a test before the code. Besides training in TDD, we need to know:
  • How to put the system (or class) in a relevant state => SETUP
  • Where the new behaviour will reside  => ACT (which class/function to call)
  • Which state or side effects to expect as a result of an action => ASSERT

Now this is difficult if interactions are complex because it is difficult to learn and memorise what to expect and assert for. Basically we’ve scored badly at two of the five usability criteria. Say we’re in a situation where we know not so much of the necessary outputs, we don’t know what to assert for, then our major concern is not to use TDD (to raise the chance that we’re implementing what we think we are) but to find out which outputs we weren’t aware of in the first place. This is often done by switching to the trial-and-error approach: change something, run the application, change something, run ….  But remember, the reason we switched from TDD to trial-and-error  is because it is difficult to cognitively master the application

Is the trial-and-error approach slow? Not always, but it goes with quite some manual testing and chances are we’ll still leave a few bugs in there to be discovered and fixed later and that is far from free. In addition we’ll avoid refactoring to not break more than necessary thus leaving more than necessary complexity in there and to further slow down the next feature.

I claim that IF it is difficult to do TDD on an application THEN it is in a state where even good developers have a hard time mastering the complex interactions and everyone will work slowly all while making the problem worse! The good news is that I’ve seen this problem being pretty much solved in various applications. It also means that if you do TDD or at least write good tests you’re likely to create an application with a high degree of usability, simply because you’ll have to remove accidental complexity.

Stay tuned an example will follow



lundi 22 février 2016

Inheritance dead end

Please use more object composition!
image: www.funny-potato.com

TLDR; There are problems with inheritance. Often composition is a better alternative. Below is an example where inheritance is employed for code reuse, but it ends up forcing duplication! The post continues with showing the more flexible alternative, object/function composition, and exposes several of its advantages.

Too often I come across codebases where there are big inheritance hierarchies. But it doesn't even have to be huge, I get suspicious when I see more than one level of inheritance or more than one overridden method in a subclass. Reluctance to refactor or lack of knowledge of alternatives drives those hierarchies to grow and become inflexible and difficult to grasp.

As an example take a restaurant that served only a single menu to start with. Then as business grew it added two variations of its menu MeatLoversMenu and GourmetsMenu. Its single public method serveMenu() serves an apetizer, then the main course, then dessert and finally coffee. For variation in which mainCourse() and which dessert() is served it uses TemplateMethod overriding the default implementations. 


7Vldb+o4EP01SLsPrfIBlD42tPfuQytV26vdZ5OYxKpjcx0DbX/9ncHjfBC2wFK2Wqm8EE/ssT3nHM8YBvG0fPlu2KJ40BmXgyjIXgbx7SCKwvB6CF9oeXWWq+DaGXIjMurUGJ7EGydjQNalyHjV6Wi1llYsusZUK8VT27ExY/S6222uZXfWBcv9jI3hKWWyb/1bZLbw+xrTNvDFH1zkBU09icbuxYylz7nRS0XzDaJ4vvm41yXzvmijL4Fresev1L6uJ1KdFb1pXXYMhldN9Gi3ohsQxVadOaVQz934zLTJuGl1iu8AXaM1OMKn8mXKJSLswbuK4pRFYxYMh8PJkKcXzvW3Q7vX8TVc0WJPdRk7lysmlxSOhFf2L2w+cLV0byv76iGu1qKUTEErKWwpwRjC41wr+0SdsM2kyBGBFNaJEUpW3FgBRLmhF1YvwJoWQmb37FUvcTeVBRb4VlJoI97ALfNzwGtjifPAm3aPJxwJZmBB4pB99CHCkc50zyo0YJ9US8kWlZjVCy6ZyYVKtLUbomAnv9NvQsqpltoB7XkZJwvJhLrIDefqAFgIOowD93qvKQMHAtclt+YVuU1vr4l3dBaEAbXXjbJqbhYtUYXeyIitee27IQY8EDcO5Mmox5MeNUAgW7SorNHP9VHQJobkcwR5mxalyDJ0l1QLlgqV/0Ca3ELwasv9ZuBt3Fj+pK2jyWjLLHOwIoaSzbh81JWwQqN/4/omCy2U3YRnlAxGtxuLsVOtYMWAKrrjQJc1SKGFNHMhfB9oL6j9QBOw/gzch+vkDKjS1B1UE0SVmxXpfywxBBBrYHkL7fHPJR5zCYJ+4Zd5A13CS/Dh38JTjt+//e4dwRKdL/fCmzOxesd0gftecAsqNh1X7w8DtW6Sh1BTvTQVx6HAClzlz6VIC46nujaIODwe5RTSLMTItjzOIH0qscfPXu+401TP53yz2N2DtmQHNNucl43s9ojMnb1dPQ37ekLTuhCWP4Ed51pD0QI2Df7mUq/BUoBc4fTr666rrwTYPA0uR6i0aAptEIRvHyw+PGZhclyjReXEOM859BhTEbZXjySeDxUkibwlyAfO7D3GvPrKx5+Zj6+66Tia9NNx6G2ddOzz9ofyJOwT5e7FcpVVPYaA8QZre2jNpEZcEjARcCECB00MKsW5RaPjQkpLAlrk/J/6kGZ41rlI9IPejuqYAmi4ZFasulX7rqiSu0c8hBoAPTh+RAU5IeXUqV0yb42LhlsD3QZ7AzcY1lv4d7DS9eXUKmvekojSm/7/y8LrcNKdVG7t1O05yi1/T+/ge0zZAsCCtOAloAZx/SoQPqBAOJpBOwqEnQwan6NACH3iaij0HVgCjr/qg0+tD+LRAQWCv9P/BwUCZY6vVHJwKqmldVIu2QXxWXJJ/5e7I26rqeElXn9TZliJv0J/ZZLTM8nxBNqVSnYR6DyppF9tfvodgiLoavM9Yf6Qi4aH6YqQ8L+2ehR2XUQOv3Nsu61vkUdfQsbjyyAexdeTKA6CyYR+jt1e7clXFGg2/1+47s1fVfHdLw==




Now, a few months later, it would like to offer a NoGlutenMenu as there is a lot of business in this niche. 
In theory it could serve the main course from the MeatLoversMenu and the dessert from GourmetsMenu as they don't contain any gluten. It's a simple need, but impossible to satisfy without duplicating some code given the current architecture (without multiple inheritance), where there's no way of inheriting the code of both MeatLoversMenu and GourmetsMenu.


7XxZs6rIEu6v6Yh7H7qDScBHKGZRJkXhjXFQJpkGf/0p1tK919R76O7d59y4SyMUkiKrKofKrC/R33BQTGLj1em2CqP8NwwJp99w7jcMQ9E1Ab8WyvxMoZD1MyFpsvDe6CvBym7RnYjcqX0WRu2rhl1V5V1WvyYGVVlGQfeK5jVNNb5uFlf5615rL3n0+JVgBV7+nnrMwi59zIu8T2O5IEVZkt67pjHy+ULhPRrfZzIhz6ePO+f7+foLp/JVl7eqKl4Rmqj9Kp77dLLXMy694VWfeVZeXgvAr5owal40wnmovqaqIKPlqJhAlC8qfGiHwvDAw0gPIQiCJqLg92fWwo82/yLAJirvg/27LPFnloOX93dxsFHb2cvpNir756ttNz902I5ZkXslPGPTrsghEYWHcVV21r3Rcu7lWbJoIIDjXCTEDlHTZdASmPuFrqohNUizPFS9ueqX2bSdF1weZ2xaNdkNsvUefcDLTXc3amgYL1tYy52QDK2Afdas/hDRcuczSfXahbC0Cao89+o2878MuPCaJCvZquueDGVp9JipkOU5qPLqWdF4/PSC1+vcy8rfkyaKyrsM4Ryjh7P+gKae2tzVJEZVEXXNvNj2ncP6bnd3Z0eR+/n41XW+2Gb6wmvQB9G7W2vyhfdXw4AHd9v4QTtZvbOTd6YBHeSNWbRdU12++PpLw8ijeFHyW7MosjBc2LFt7QVZmewXM+GgpL5Q1KcbOfwrxbxPfSE1Ved13rNaFx3mnh/letVmXVYt/JvntmxdZWX3JJ4V+9uKe6I0HahKOGKo1YVdBM1lhK7wQtPeswh/WtFPPvZe0XfFPha57+mV/gVavXf9SqvsotWoGe7+T+aLCKCsoZW/0DZ57Zdljl2U/vtjmAxsgv4BeTyuwqNk+f4///fBCA7xmdfzhQc5zIZvkH5f5l1HHfTi5hWrb98GvfUpeGQlqPqmjZZboVUso7z2WZBGy6peNYvG4eFPMYVxFMqoe8HRh/GxzL7D57vcl5kGVRxHT4P9+KY3bgdN8Wm9/Op233Gy57X3tT8R7/1pIY1p1kUWpC99jTArgbQK8ovzaoSUFLorXP3e+91r/2KhNQPkj9XiaRiA59BpHuc/7HzLMgs7X8bYLZ6DL/38Cn/E71nWd/3x7jz/qEPenfyFQ24jr1MXmbef8fi/GY+p1+EYo9+HY/RBexWOH3H7H7UT9L2h8FMXlWH7zkIgkVmSd3jm59WiFxaS7opDF8XB00Wodzm/MKN3Io3Cdxn+NwR6HyO0kyT6szZPTvRe6C+lSt4F2ES512XD6wF8JNU7O31ZhL4q8KGcxx0tjAlBdG/0MmV+cx9GvLnxeT7vbnzS4Zcp/DW13rcvfzfLil+4SFk9tf9/MvH6a378ZHY/k2596Le/It16bMRf6fdn0haoWOhJ8CLUGpTrZ4LwaxKEb1vQBwnChxZE/ooEAb2P/4UJidBKIOPP/OC/mh/gqx9IEB57+n8hQbhHjs9Q8ndCybO3/VQs+UjFvySWvEfufmK3GjRRsWx/A6/xigVm/owkvySSfMeAPgolHxnQrwkl985fWNCuEvMebiM+Q8k3Q0notWm0iPXDTdI/G1ewR3i4m8wKufN8iU882vwLceUfAoL/P48rT673U5DwRyr+JXHlI0z4n9+j/Cns+xNIM/EHUU/vweafj3kfIdJ+8z3w9jM4/t3g+G0v+AiI/cgLfk1wfA/F/O8BbPc2z0jWdzaMfwWFe+iSumviUYp8pCgfoXQ/Dsi9ZfsFYv1phI4k/0DwFb6mMRxBaPoeot6O9l/A7x51gn/PapZmcLynpdUfBLkEuieCs7T9A4Hh+k7QoyaDU3t6XuGry/4Ce7sr9Zv29rx5+XODo99Yxge1779gcCRcq16yJd5Wyn/U4HCE/AOHdgXHiRBrhKKp18N94Hz/hsX9wD6/TWHxFB5mxdMDOqzX1s+P98TZtKSx7P0CF8LgAWPl8ykm1GUCA0Rms5o5IhsxqRj42lmHlD8k8EheTgF8O/Cb4/RCUhcKWyiqiRgw4goj7F1gdFhTTgYv2sOLKnXIecM2iVLDwohibdvEpaVBUF3ljE2zzEnOBX+m2MLi9sLWNGx7O/EcCOcGCI3TGa27ui3t5yn29uR1Pslwz2Jam4leJZ66MhKka0kSbBQluPGAlKsNI1A5zJRYTO8uRKzG3vIoVd1QuI6FkOzgLk1tsWJYDzDkCwtwwvZr+FASSBBxBDdmIzLaluGdYiC2e9EwtpTmT2tCQkdpUCjkmuzifA3sNEoimKXI8HbGKkYBuWxGCWeCgJvGncRcWjFKiLPDqgGbOaw07pnTkc2qhp/2GmPs14kuMa7IWKsLpmemmzAxY9CSIXSX07GGA+MTjLfhxgRgFY8lJX/1Cc5np43RbGpeTFpahpkXsRsj25uHhu8w/Szi0ngRxkvP6kmPrK7bDEEygThwTNrl6I07CEKg+slkTodjlq6MEziC8xkDScPmDHz8CWM3RED4eyesaG30RbDCd4bsC5c2Ag6mHw3NMClwIjJM8TirSjpprHtbzdAMn9hAgZIxIvG26ml5n6DhgMApgJFQiEDkmmGbx6GK2pQ5e+eDW6xoAWccuzjYRICOTLM9lqsdfukugGJW1j4wkNHQJ208UQy2nfqE0oYiVmxCrPMwsQIfeglbhUlfsHu2gOLS3FbikpSWb6mxpek0vWosP5pHUI/7Tow5d8OdJYGIt7KXbOJ071gbDJRjpwmQ0WzKfsAm9VZAx0UMksvFYSvYm+5KJkdGH2OMPe/koucP4+7s62JinvkVfmR7hS4xDse4G8VuBabwfKebxCOgCKhCVkjbc4eknnnphc0oj9LT0xYsfV7ZAjsm0fZyo+2AR8a9jek3EtRl7xNN4q9WHWLJjlR3cT4xgSKci0s0eysRvwqr3t9MiqTxkNE4X3dhnlTaeYt27JiJ0fGG7dp+2yUxv+oPajKQYB5tX9/lVXpcvBNTR8YrF5tfjP9E6/AhPzhQt9tvmEQTbrd0tj1VOHXbi3TGjGR96TJ3sESJjOxY9iW4oAkmTh351KnsNKghj9Ec6csxMSUT8CbvqDrIqZujwoaUEOlEETHiHsHd0ublFQPAYBz0SOVSjtodYRtu0nMbDmGPrQYHWFfgoXBHj+hFKhkFqGhz0GArl3EbDxjsZUoO4SaacbtkGQ8cpBnctovdUnQxTBrrUnhNnJLspu4dIaZ0K64kVGWLUTnG3cViZEWxziEHuG3E85MRthFSrBGlbvs17IbNDPhh77UrInOs1d6uwzxrI8PjSJr2sx35XoxUa2tWToC5afzRXncheekVZC834Z4PKsmASzora2d878sTTaY3EHpqUrU8PTalxYQuQ+2XHchg+mWUq/F0mIgNDs5ESaOnQfIO+1reJeVuKtmCipVt07p+QAhl7Z72hF2cdpRez4kH/SzJC21XDscuADfJ6AJUz3eq3YM1n0b1Jgj8owM7Us09PZJi0jgq10MZhfLmwEuTt8q38xEfdt2MVpdCF067nToUNn5hN8Cbbl3oTTvZIuEYoytHR4TODSy1GnbguMccdCpYKCkB6RzWDPJhHgIAzN0lrGUuuY4rjExZus2gJFzYag29EjtiuQ0wVlvJpwyc+PX5tHbdKaYln0uhKwu6cTTbzB4TERQJAdOFZfPCaqo8ZJZBekN9FmjM3BBGyOp+obFbvNmsJU/ilhCKGRu3BeaY9Lszq5caOWMTPp76Y3FETErTlL124fOU2V4GRKnK05XsLOMG4mNXeYsb3TToqP2YajsVeoOws3fyJtaOJuIkLKjNnWOIhB+eQzwPhXlGpuNmDU46p4ZJ0BG1VpDM6qKHgutjvWXf6ktAipyDOaKSHyjDHNM+bDil1avtiaOQQpHZ1pcpktEvXRncmj3JlWgFxzHwFxcPcjhYabhwBeLhXQszDdYnOYVEYxglzkxxxA/8EGzOnOkfpCu1uBmqDRvA7NX8ykhgQyLdlodh68TKBiHq3NaafTknGWfmbbv19yAL8yNFObrZZEFdemwzCzfDhQkCNMu2I+m8XclCSxpWLIcK76vLUiv0YxX4QgnDBsP7AmC5nqUJwdGxAGGoHMal0bB5ldvSjchd12mshe612BMy38on4hhADk7WjOToVsB1/fq8rN4ggUFdzHI3rhNLuIJFldyZ5TQGn/YBsMnbHi5Z7AWUt4C+CnbeF1xVWkCKgeaeqpJF0wH2QVhZTOg316nhFNgyG7BdqbQtgkUgKBh5hFNYS92x9dd7t9QHK5IT0TxrY0Xv98yy9BxvTNlKRwZ32fVqs5oMe48D7lS3jZSIfNdjUzN7nVOUmdJ3yDxsGs6mr+Ja3e0kw9U0cJzPZ/+AN8yOORCE4ou07pPrTCeT5gxpCH6QuoQce6dZExcxlRjgeTWatOKJDC1Cc9RuzJkWyUxt2/G32E5OnsrSV5+3dKUE4AIFhpGN48OxEoFXX5ZFCjuPmCN16EBtNoPna+S2XTwm0Lj9OFI6AjIWN49Ncnb2lGmBSGXBNggVqo2yM1ILKR97O7Pk2fFcLSufjDXNqvHi9Bj41eyMKMNS7G3DNiKOnIR4sQ0NldjDuoRCQ7KOsGaOiAhPJdMlmCCxnnKrfSa3c7/BUlU+AbhdhzlY6azjg7uXDvBR7+q4UhWRd1Em2JCcX8S2e+MC2dFCdcorfpMmuCMk56utYaPNwYQxE0e0PR+502VrZlWWahctrSPKji00cHt7NLAYs50RYQSPoXjlllbbHj0dbaS97ESY6wltkXPxBTcu/PpWVu1pawA/D3kqVLh94pPMLe+41qDAQFlACU+TdnK1FAS1o2/LXJJqlKEFTGr7GMk3knpyhAGUrmqRjnyQSZKh+WhbLrLBao+iJ4wN3YI8pf56ZweZedhFx0RlU4PK16fJDRV1Qg3CbVAGquhCybirXtS5uk63DTmgV4mCEVc59/6OB3LhqrIaNcTQHrdArglGklbF0WiRg5qxSZccgUywGMwnhEV5qBw7gjnJeK0qFUwqUZ40qnleIeXuBqbmoHKXLkcMBYing5SchRlMA25PodVU/FmadodD3qMOc+5YHuISbNcHmAfV6C4OCZM9jV1WgGME9wjsjmX8lsNsmj+62xJJ2ZkzqTUcT8uR2yNnQU20gtlC/xbGg7tDtiYOp7WsYuH+5DYbRrwhq7FGpkStwxIhjvqezrb7Xliv8Wx0ZynFjDxwYQzsAT2jpGusmGqwUsOAa2NyqNd8mG5by5O2a2qsDzdOpmgwLrnMJojl+MYfZgObNpOrOCncNwjH60EWjeAwGHLYCdLYZjvSNihGhwnTySW2ZwMEyroD2m2ZrJ2B/oiBoyNCzuVBP/fOhgfmadMoN0Fcp4KonUNTGOEmpQ1kmHbAuc6GYBSnjaiFK6tCCVeeWEkEXCteGr4MCBhsIwyuMkKDoJwMr0QuEch6r4fHE9mi69VBX+3G+LwFB0sk4HagjJpaVbVz5xlzQm8E6ZIhV6QU2b1iYtAi1uuTHeVFgu3i/cwYXbxb7Q+Qv+eAkpAOB9qQQE3gitbBLAPK/dQy40XOzxS+YWowrA4SUMU+43haMEZ7duGSrIsUVg0ihgCDsFR9xx/kjZ1kdLNWR0wWLXIWYQcK5aXrkFLgGiBGbSUtmzU9soxmNHtgjRYFsVnWP9mz0RHpYQ5wLe7K1IpcGoULiiINLox/agkwf6O3iuKmXKvcdOY4YcveEb/l9RImBm6v3PBdC0ReBKojS2y4PUSj2fYa6ZH6Bu63BP00ldHhNLfBOpUw6SbtS68pB1l3BTuBSToyHcxeanmM4FyVUgf0ZIg1G6f05I4it5iFxqiAU9Rc0tjY2J6gX9LsbdR0pqBP8uJWcCpt6qyK/e7gFNtxnoL05BEdwbvCKUFcILoNYHK2HqVSYYXoZDssNW4GRaWbJI6mw5JIRhCYYnX5yuxGYV9VvCmi7SV1JfpGFjpjz9dR6XfziAgFGSfWsqhfWA816z12O/RKd4F7vCW81xcOZnJsuIPHVwKY4v7G1BeWGArQpaOjNx6i+G6Fq4t/auMZy9FLdrYRZXs0qXHJ9QVMPxiSo+5dzsGdPNzYMGFwJKWFRT8YMZJ0KywB2UuSi7Lk5EJ+nXo/YqvNmY2DhgKKZXdy2uKbFb1GaeV0FW8sLub00DK01VtCt4Lpz/oojpSQEnM09uXMQmsQ5kHfVge04DArA42CnaglKbREh/O4qeC5gyKyu5OMXhk2YLlxt7VhyuhKc3u4JXANwxwvNKdRF70lOUnOgHKXrR7c0ghlG/K4lBVM0XK5e1BATzNwcRtBcHPHVIRRZzSLLVZVQTkY21sU9biGb1C6WzKKcVfz2J6/CWhv4kfjFM1VCtwhiV1ogSwf5CWMIQvKwTDWwdbMzQo4sryAKy+R8KXO8FeR8G/DYcQd03ngVg8c6wUctrrXgl4C4w/a3wHG0YBEAwqLKNqnfDpAHxjgB+WhpRL8YeVmufD78++tnuo29EdVG66vc1gdeSrGYUgFoygSZV0K8cqv5ZfnHr5bQvp7A4HfXrEUWEq/Xb7eFLlgxXKBDV+3eVFs+uZgf7qE9Fw4fVMo/Ubt9E+r7l+qpz9aSnqq6z+j0dD8ns9f1MIJbnn/IoMn3tS8ifX9YZeXpaAPn6V6VC//UZN/D7H+q6A+vv5hUD+asu75rkVly9lyy+8IvOd+/r9VBvj6q8mPfwL3pgzwwNX/Xhngy6853i6nP1sGQFevx4ev3zyU/s/h/u9s8gcew/iE/T9h/0/Y/xP2/4T9P2H/T9j/E/b/hP0/Yf9P2P8T9v+E/T9h/0/Y/xP2/4T9/7dhf/zNP0D9Qth/WZe+/G3ZMzz19S/ocP4/






In this case we'd be much better off using the StrategyPattern or the CommandPattern for serving the main course and the dessert.


Lets refactor the code so that Menu is a concrete class that calls an object of Type MainCourse to serve the main course and Dessert to serve the dessert. It does NOT know which one it is serving, it doesn't care. When the chef composes a noGlutenMenu he simply creates a new Menu instance using an instance of FiletMignon and CremeCaramel as shown in the bottom right corner of the diagram.


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





We have gained less coupling:
  • No more duplication of the logic of serving filet mignon and creme caramel
  • The chef is really happy as he can add new MainCourses and Desserts and compose menus as he like!
  • It is a lot easier to test classes like FiletMignon than MeatLoversMenu as there is less setup code involved, and less duplication between tests.
  • We even have the flexibility of opening up the restaurant in the afternoon serving only desserts. I.e. Reusing the small objects outside the context of a Menu.


Conclusion
Consider composition every time you override. If you can't visualize what the composition alternative would look like, then practice it. Your code is going to be much better off if you master this technique!


There are some general guidelines on when Composition over inheritance applies. Additionally Steven Lowe has some interesting insights. My personal experience tells me that I was a poor judge before I was experienced in composition and in particular knew how to refactor away an inheritance hierarchy.


Here’s a simple example of the refactoring


Note: object composition has lost a lot of boiler-plate code with the introduction of lambda-expressions in most languages. Nowadays we don't have to create interfaces for Dessert and MainCourse and no classes for the concrete implementations (unless we chose to for explicitness). An example of a modern strategy/command pattern in java

vendredi 23 octobre 2015

Tests uncover Design Smells

TLDR; Tests, even written after the code, help tremendously in pointing to production code that could

use an improved design. If writing a tests hurts, then it is often the designers fault, not the tests.

Tests, wether written before/during (TDD) or after pushes us to choose a design that will make both tests and code relatively painless. That easiness is of course bounded by the design options we already know of. Many times in life my tests have hurt, without me knowing what to do about it. But then weeks or months later I discover a new way of designing my code that would have made it better. My default assumption whenever I can’t find a way to make my tests painless, is that I have something to learn about software design. I believe this is a state of mind that is very useful if you want to have better code on your project.

Here’s a stripped down typical example of a piece of untested code. I came across this recently and I’ll show how the tests point me to a weakness in the design, and one way to deal with it. First let's have a look at the tests to know what the code does.

$ mocha test/LangBuilder.spec.js 

  LangBuilder.buildLang()
    lang.id
   
   ✓ is the language found in the pdf file
   
   ✓ can be explicitly overridden
   
   ✓ is french by default
    lang.face
   
   ✓ is a collection of pages in the pdf file
      every face
     
   ✓ has the width and height of the first page
     
   ✓ has a unique id

But its not the whole story, sure it returns a lang, but it also submits another piece of data to a message queue. Admittedly that is a violation of the Single Responsibility Principle, but I’m going to concentrate on a more subtle design smell. So here are the interesting parts of the code, in particularly we'll be interested in the _sendOffSplitJob function.




BTWYou can find a link to the full piece of code at the bottom of this post under "References"

So what could the tests for the sendOff part look like? It’d be something of an ugly stub/mock-hell that is one of the main reasons many people shy away from unit testing. Just for the record I show one of the test, but please don’t spend energy on understanding it. It's just proof of uglyness in case you didn't trust me.



Why is this test difficult to write? Well we deal with a third party library that wasn’t designed for easy mocking and certainly not designed to optimise one specific use case of our application (that’s not saying the library is ill-designed), so from the standpoint of LangBuilder we can simplify the design of the message queue library.

Imagine we had a function: submitJob(splitJobData) that took care of the queue naming retries and eventual send-off. A side-note on this example; javascript has first-class functions so I’m using function-composition by passing a function to the constructor of LangBuilder instead of passing an object as in object-composition. Here's that function



And the refactored LangBuilder



Then we could simply assert that LangBuilder calls it with the correct arguments, like so: 



In the process LangBuilder became easier to use, it doesn't have to bother with configuration related to the library. 

Looking at the submitJob function it became easier to use too, we didn’t just move the complexity of the queue management to a different class, we simplified it's desing with respect to our needs. In it’s original design it was mixing non changing parameters like the queue name and the number of attempts with the changing parameter splitJobData. Now we can pass those parameters at boot time creating a function that takes only the constantly changing parameter. And that simple function can be passed to any function or object that needs it.

Then we can test the submitJob function in integration with a redis server. I always put this kind of test in a different suite for practical reasons, more on that in a follow-up post. The basic idea of such a test is isolate the smallest sensible amount of code into a first-class object or function. Then test that unit extensively with the real thing.


Conclusion
Writing that test was a pain. Acknowledging it as a possible design smell allowed us to improve design as LangBuilder now respects a bit more the Single Responsibility Principle. Both the tests of LangBuilder and jobQueue are easy to write. jobQueue is now a first-class function that is easy to reuse elsewhere in the application.

Listening to tests allows us to spot where the tests and the production code could use an improved design. Of course tests help us spot problems and protect us during refactoring, but they don't find good alternative design. That's up to us developers to find and chose.

lundi 23 mars 2015

Usable Software Design - a federating concept

Design is not just what it looks like and feels like. Design is how it works - Steve Jobs
Alexandru Bolboaca applies ideas from general usability design to code :
Software design is the only type of design that seems to be userless. After all, the end-user has no idea how the software works and doesn’t care. All they do care about is to work ...Software design is not userless. The user is the developer that will have to change the code after you do....

A common goal for the team

This struck me as a very powerful way of framing discussions with software development teams. I get to work with development teams for a few months to help them adopt XP practices that are useful in their context. Typically the hard part for teams is learning TDD, object oriented programming*, SOLID principles, Simple Design etc. In my early days as a XP facilitator I often met resistance and indeed many of my friends in the Software Craftsmanship community still meet this kind of resistance, often to a point where their progress has come to a total standstill. I hope I’ll find energy to explain in detail how _I_ am changing in order for colleagues to find less need to resist my ideas, but for now lets talk about how the concept of "Usable Software Design” can be used to guide change in a team. 

First of all lets see what "Usable Software Design” might mean. Alexandru states three things : Clarity, Consistency and Minimize the unexpected. I decided to try this idea with a new team I just started working with and I reframed the ideas to “We all appreciate workable code and design … it'll have a positive effect on our performance... So what is it that makes the code easily workable?" Here's what I suggested

A team agreement to try

Usable Software Design means to us that

  1. It is written for developers to read
  2. It is easy find where to modify the code
  3. Any modification has a minimal ripple-effect 
  4. It is easy AND fast to validate that we did the right thing
  5. We don't have to do similar modifications in several places


NoDeveloperCanDisagree™! Indeed this time everyone nodded and listened intently. How we get there doesn’t matter to me as long as we get pretty close. And this is extremely important, we’re ONLY talking about desirable outcomes, not how to get there. In particular if we want to keep the federating force we have to welcome ANY SOLUTION that brings those desirable outcomes. 

Now let me dig in to 4. because it has some unexpected consequences. I currently know of only a few ways to get this. In no particular order a) being able to launch and interact with the application in short cycles, b) automated tests at various levels, c) manual testing and shipping shortly after development. Look ma’ it’s not only automated testing that requires isolation from non testable dependencies, a) requires it too, even c) to some extent. Reasoning like this even developers who don’t care much about automated testing want pretty much the same thing as someone like me! It has a federating effect.

5. is going to make us limit duplication, even across process boundaries, to a bearable level. 3 is likely to bring SOLID principles. 4 is likely to favour TDD, and TDD will help 2, 3 and 5. 


Conclusion

As a team we agreed to try this, and because it doesn’t enforce any specific solution as TDD, DDD or SOLID it means we can evaluate any development with pretty much the same yardstick. All that matters to me is that we nail 1-5 because then it’ll be pretty nice to code in that team regardless what tools we use.

And now I'm off to Vienna to train in doing Usable Software Design with a few hardcore Craftsmen!
*Yes even Object Oriented programming is not mastered to the extent that is needed by far, at least in iterative development.

Image http://hotinfb.com/post/agree/

lundi 19 mai 2014

Refactorer legacy même pas peur

tldr; L’approche classique des tests n’est pas adapté pour le refactoring dans le legacy. Il vaut mieux écrire des tests automatiques jetables. Du fait qu’il y ait 0 besoin de maintenance et avec l’outillage adapté cela est très TRES rapide. Ex : 200 lignes en 5min.

Cette fin de semaine c’est Agile France et je suis vraiment très heureux de présenter “Refactorer legacy, même pas peur!". Il y aura du code en live bien entendu! Enfin des tests en tout cas. Ma présentation, qui est celle de Rémy Sanlaville aussi bien qu’il  ne peut pas venir, cherche à remettre en cause comment en général on conçoit les tests sur legacy. Oui carrément! :) 


Le problème

Classiquement nous rencontrons un ou plusieurs problèmes lorsque nous tentons d’intervenir sur du code legacy

  1. Il est jugé trop long d’écrire les tests avant de toucher au code
  2. On met en place des tests (très) haut niveau, souvent assez longs à exécuter
  3. Les tests unitaires adhèrent au code et peuvent ralentir certains refactorings

C'est probablement maintenant que les esprits se chauffent. Justement c’est le moment de se calmer, je vais tout expliquer ;)


Trop long

Oui, ben parfois ca peut prendre des journées voire des semaines pour mettre en place des tests, notamment de haut niveau. Ca peut être justifiable mais ca peut aussi ne pas l’être. En tout état de cause, moins l’écriture de tests prend du temps plus on le fera.


Tests haut niveau, longs à exécuter

La durée d’exécution de ces tests sont plusieurs ordres de grandeur plus lent que les tests unitaires, parfois cela requiert le déploiement du code sur un serveur d’application et on compte des dizaines de minutes juste pour un lancement. Cela fait qu’on va plus lentement, on réfléchit plus longtemps, et généralement on va aller moins loin dans le refactoring et ainsi laisser plus de dette.


Tests unitaires et adhérence au code

Classiquement on teste l’interface de chaque classe, elle est rarement bien faite et lorsqu’on souhaite la changer, on doit non seulement changer le code de production mais aussi tous les tests. Pire on a souvent envie de tester qu'une partie de la classe et on crée ainsi une adhérence à des méthodes protected. Donc bien qu’elle permette le refactoring à l’intérieur les tests freinent le refactoring aux frontières.


Une alternative

Je ne parle pas de LA solution, ce que Rémy et moi tentons de vous faire voir est une approche complémentaire qui nous a bluffé par son efficacité, est une “nouvelle” façon de réfléchir aux tests. Qu’il s’agisse de tests haut niveau ou bas niveau c’est une approche différente et complémentaire elle s’applique à tous les niveaux des tests.

Une fois que le code est bien propre, il est facile et rapide d'écrire des tests unitaires et haut niveau avec le style tests provenant de TDD  ou BDD qui pour le coup sont maintenables.

Il y a deux clés à retenir dans notre présentation

  1. Écrire une assertion pour du legacy est une forme de gaspillage. Le résultat du premier lancement est LA référence. Record-Replay
  2. Il s’agit de tests temporaires, ils sont à jeter à la fin du refactoring. Donc nous passons zero énergie sur la maintenabilité

La combinaison de ces deux points produisent un gain de temps énorme et permet d’écrire des tests pour le besoin actuel sur mesure -  des tests rapides et résistants au refactoring.

Si vous êtes curieux de comment nous faisons ça et quel est l'outillage qui en découle - venez voir un exemple et passer du bon temps à Agile France!

Notes : Outillage exemple :

  • ApprovalTests
  • Couverture de code 
  • Moco (simuler des serveurs web) (Java)
  • XStream (sérialiser objets en chaîne) (Java)  
Mise à jour : slides

Mise à jour : inclure aperçu video