Wednesday, April 13, 2016

To DRY or not to DRY, it is a matter of boundaries

For a very VERY long time I've been convinced that aggressively refactoring your code in such a way that every piece of logic is repeated only once is a good thing. This practice, often referred to as DRY, or Don't Repeat Yourself, has been one of the many of my tools of choice and goes hand in hand with principles like S.O.L.I.D. Some developers just are incredibly 'skilled' in cutting and pasting code all over the place, so I've been in need of this a lot over the years. But with any 'best practice', you tend to go through a couple of phases before you realize that the world is not black and white. Just look at the adoption process of things like unit testing and mocking. So before you start to think I disapprove of DRY, don't worry, I won't. But it's important to realize that even DRY needs boundaries. It took me a few years…

So my first question is how far your efforts to apply DRY go. If your codebase comprises of several projects all available from the same Visual Studio solution (or your favorite IDE's equivalent), then chances are that that's how far you'll go. I doubt you will hunt down instances of the same code in other libraries and replace those with a single shared implementation. It probably won't even be possible. But what if that library's code was directly visible? What would you do then? The point is that the scope of your refactorings is kind of defined by the tool or source control repository you're working in.

My second question is about how you actually accomplish DRY? Do you introduce some shared project, component or folder that all your other code uses? And what appearance does that thing have? Is it more like a library that you use? Or does it feel like a framework that requires your code to implement some shared interface or inherit some common base-class? The difference is subtle but important. I'm not sure who said this, but a great phrase to illustrate the distinction is this:

"A library you use. A framework uses you."

I'm sure you have heard about design principles like Decrease Coupling, Increase Cohesion. The second part kind of that principle aligns well with DRY, but the first doesn't. Why? Well, if you decide to move everything related to a particular concept to one place (and thereby increasing cohesion) and you use that thing everywhere, haven't you really created an immense amount of coupling? And that's exactly the flipside of the coin. But that problem isn't so bad if the thing you're sharing is just some utility code that you use. You can easily duplicate the code when it's time to extract parts of your system into something new. But if that thing you're sharing relies on some well-known interface that many parts implement in order to connect them together, the problem gets worse. Especially if you're code base is large, this coupling gets sprinkled all over the place.

Now that I've explained the dark side of DRY and I've mentioned the scope of it, it should become evident that DRY still has a place in every developer's toolbox. As long as you constrain its application to a well-defined boundary, you'll benefit from it. But outside that boundary? Duplicate the code or wrap it in a really focused library which lifecycle is defined by another source control repository. If you're in the .NET space, you can solve this even nicer by using source-only NuGet packages and distribute them through MyGet. I realize that it may feel unnatural to duplicate code within the same source code repository. But imagine that those boundaries were used to split up the code in different solutions or repositories. I doubt you would try to apply DRY there. Next to that, in my experience, trying to use the same code in different places tends to put you on the path of either overly generic or leaky abstractions. Better to have two, more specific implementations instead. Frameworks are notorious for this, so if you really need a framework-ish solution, be very very careful to decouple the code that needs it from the framework (and .NET delegates solve this pretty nicely).

Identifying the right boundaries is the difficult part, although I'm fairly confident in saying that your IDE's solution structure is never the right boundary. If you're practicing Domain Driven Design and you have identified the Bounded Contexts, you have a great starting point. You still might want to find a smaller boundary within that such as for instance groups of classes that always change together, but never go beyond the Bounded Context. Architectural layers should also be seen as boundaries, even if the code is grouped in the same IDE project. A more functional view can be very beneficial as well, especially if you can identify vertical slices of functionality. Greg Young recently shared a more inside-out approach by stating that you should design your code in such a way that you can rewrite any part of it in a single day. It’s a rather extreme approach, but it will help against overzealous use of DRY.

So what do you think? Do you still believe in DRY or did you abandon it completely? And if still practice it, how do you define the boundaries and seams in your system? I'd love to hear your thoughts by commenting below. Oh, and follow me at @ddoomen to get regular updates on my everlasting quest for better solutions.

Sunday, April 03, 2016

Why software innovation is not a free pass for doing whatever you want

Somebody on Twitter recently posed the question whether innovation in software and agile development can co-exist or not. To remove any misinterpretation - something quite common for Twitter discussion - I asked him to clarify what he meant with the word 'innovation'. In short, any kind of software development that is difficult to estimate. Examples included such things as investigating the applicability of a new library or framework, the introduction of a new tool, troubleshooting bugs in production, bringing down debt, or improving the performance of a system. He argued that the inherently creative nature of these things makes them impossible to estimate and unsuitable for use with agile methodologies like Scrum or Kanban.

Lead Article Image

Having worked on all of the above at some point in my career, I'm very well aware of that creative part. I've wasted hours of my time trying to explain managers and product owners that comparing software development with industrial manufacturing is so wrong in so many ways. However, none of this gives a software developer the right to forfeit a process and just do whatever they feel like. Unless you're working on some kind of research project with enormous amounts of budgets, don't give me that "I don't need any mental structure" excuse. Most professional software teams are under some kind of budget, be it money or just development capacity. Either way, somebody is paying (for) you, so it is not unreasonable for that person to understand what they will get out of it. They may not understand every aspect of it, but if you can't reason about what you're doing in some form, I think you're being unprofessional.

Don't get me wrong, I don't like unnecessary ceremony any more than you do. But I do believe that tracking whatever you're working on is valuable to both your team as yourself. In my opinion, User Stories have many characteristics that can help you with this. They are supposed to be estimable (in particular when applying the INVEST principle), so you can use them to build up some historical data about your team as well as to maintain a burn-down chart. And the mere fact that you need to estimate something forces you to think about what you're going to do. In my experience, just discussing the scope of a story with your team surfaces a lot of aspects and edge cases that help you refine the purpose of the story. Defining the stories using the who, what and why pattern can really help here. Understanding who is going to benefit from the work and what they are trying to solve or accomplish is crucial. Because of its low threshold, I prefer Microsoft OneNote to structure my thoughts. Again, if you can't at least formulate your thought process in a couple of OneNote check marks, I sincerely doubt you are ready to do any coding. And don't worry too much about the granularity of those estimates. Small, medium and large is precise enough for most projects.

Even if you're working on something that is difficult to estimate I would still expect you schedule a time-boxed story. In other words, you assign a fixed number of days (or whatever units you estimate in), you define a prioritized list of goals you want to achieve, and re-asses after that fixed amount of time has passed. If you don't, my experience is that you end up in an ever-lasting research mode without a clear goal or a well-defined purpose. That fixed amount of time forces you to re-evaluate your findings from a high level make a conscious decision on how to continue from there. By sharing your results up to that point, you and your team might even realize that the path you were following should be abandoned. And that's exactly what the true nature of agile development is about. Trying a way of working, reflecting on that, and acting upon those results. And remember, it's an open process in which everybody can contribute. So if time-boxing doesn't work for you or your team, find another way and try again. Just keep embracing the strengths of agile development, regardless of the uncertain or creative nature of your work. Don't accept any excuses otherwise.

So what do you think? Do you agree that innovative software development is no excuse for just doing whatever you want? I'd love to hear your thoughts by commenting below. Oh, and follow me at @ddoomen to get regular updates on my everlasting quest for better solutions.