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.


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






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