Code reuse can prevent bugs

I am as surprised as you are at the title. The statement does seem like “Duh!”, but much to my embarrassment, I have seen enough code in many code bases to need to reiterate this.

The latest example was the following bug that I spotted. First some background. The caller to this function can choose any subset of a given set of ‘modes’ or ‘features’. The caller represents this via a bit-mask. So 1 represents feature 1, 2 represents feature 2, 4 represents feature 3, 8 represents feature 4, and so on. So, if the caller requests with bit-mask 3, then it represents features 1 and 2, and bit-mask 10 represents features 2 and 4.

The following piece of code is support to filter out requests depending on the requested set of ‘modes/’features’.

if ((bitMask & ModeEnum.FEATURE_FOO.getValue()) == 0) {
  // FEATURE_FOO has already taken care off the by some other module. So do nothing here.
  return null;
}

/* Some more code here */

if ((bitMask & ModeEnum.FEATURE_BAR.getValue()) == 0) {
  // For now, we process the request only if caller explicitly specified FEATURE_BAR.
  return null;
}
/* more code to process the request with FEATURE_BAR. */

The code above has a bug because the comment inside the first if-check does not match the if-check’s logic. The intent was to skip processing the request if FEATURE_FOO is enabled. Instead, it does the exact opposite.

The naive way to fix it would be to replace

if ((bitMask & ModeEnum.FEATURE_FOO.getValue()) == 0) {

with

if ((bitMask & ModeEnum.FEATURE_FOO.getValue()) != 0) {

However, this misses the more important point of why this bug occurred in the first place. The simple answer to that question is that this bug occurred because the author ignored the principle of code reuse. By putting that principle into practice, a cleaner way to write this code (and therefore fix this bug and prevent similar bugs in the future) is as follows.

We first encapsulate the logic to detecting various modes via this function

boolean hasRequestedFeature(int bitMask, ModeEnum feature) {
  return (bitMask & feature.getValue()) != 1;
}

With that function in place, the new code looks as follows

if (!hasRequestedFeature(bitMask, ModeEnum.FEATURE_FOO)) {
  // FEATURE_FOO has already taken care off the by some other module. So do nothing here.
  return null;
}

/* Some more code here */

if (hasRequestedFeature(bitMask, ModeEnum.FEATURE_BAR)) {
  // For now, we process the request only if caller explicitly specified FEATURE_BAR.
  return null;
}
/* more code to process the request with FEATURE_BAR. */

This make the code more readable, and as long as we reuse the hasRequestedFeature() function, such bitwise operation fragility will not reoccur in the code.

Is this obvious? I think so. Was it necessary to belabor the point? Empirical evidence seems to scream “YES!”.

Git may not be the best for SaaS companies

Yes, I realize that this is going to be pretty controversial 🙂 Let’s dive in, shall we?

In the past half decade or so, Git has sky rocketed in popularity and is becoming the defacto choice for version control. While I understand its popularity, I have found it to be a poor fit for one specific, but popular, environment: SaaS development in a medium to large size enterprise.

Let’s take a quick look at what developing software in a SaaS enterprise is like. For the most part, it involves a significant number of developers concurrently committing code to a single master branch with frequent releases to prod and no long lived branches or versions. In a services environment, it also includes coordinated deployment of multiple services that have complementary server and client API spec.

While Git has been used in such environments with varying degrees of success, I have seen teams really trying to work around Git rather than Git just work for them. I have seen Git get in the way when teams get large, when teams get siloed into their own branches, when teams starts working with junior developers, and when having to develop across multiple services. While there are mechanisms in Git workflows and tools to mitigate this, it only adds additional complexity to developing software instead of taking it away.

Continue reading “Git may not be the best for SaaS companies”

When should you build for survival?

source: http://beaconbusinessmarketing.com/success-vs-survival/

Previously, I wrote about building for survival vs. success. Briefly, when building for survival, your only goal to get the product working for the specific usecase, and in contrast, when building for success, you are building to solve a bigger class of problems within the broader context of your solution space. In this post, I will talk about when you should be build for survival, and when for success.

Continue reading “When should you build for survival?”

Are you building for survival or Survival?

Source: https://www.youtube.com/attribution?v=oW2i6QpnmyY

In my experience, the approach to building a software artifact often falls into one of two types: building for survival, or building for success.

When building for survival, your only goal to get the product working for the specific usecase(s) that will save your skin. In contrast, when building for success, you are building to solve more than just the immediate problem; you are building to set up building blocks that is incidentally used to solve the immediate problem, but can also be adapted to solve a larger class of problems within the same context.

This post is not about when to choose what approach. Instead, it is about what each of the two approaches look like, and what purposes they serve. A subsequent post will talk about when I think each approach is appropriate.

Continue reading “Are you building for survival or Survival?”

Object Composition for Service Migration

Object Composition is a very powerful and pervasive software design technique. Yet, paradoxically, it is an underutilized design pattern whose lack of usage is the root of many anti-patterns in software development. One that I continue to come across regularly has to do with not using composition to test and migrate a piece of software from one service to another.

Briefly, Object Composition is combining two or more objects to create more complex objects while keeping definitions of the constituent objects unchanged (unlike inheritance, which extends these definitions)

Continue reading “Object Composition for Service Migration”