Thoughts on soft-wa.re

A blog of various opinions and ideas on soft-wa.re development

Demos subscribe via Podcast

Structuring: Using Sane Defaults

Here I would like to argue for a style of code I have come to like. There are a few phrases I associate with it.

  1. Using sane defaults
  2. Write your code so that it is always true.
  3. Null object pattern
  4. Dynamic Dispatch

Now it’s not that 3 and 4 are 1 and 2, but rather it is because I find Null Object’s to be sane defaults, and Dynamic Dispatch to be a way to write your code so that it’s always true. I’ll leave discussion of Null object’s and Dynamic dispatch for another time.

A recent issue that came up put this at the forefront of my mind. It involved updating a pie chart. Now this pie chart could have many states, but two basic ones, we will throw in a third for good measure.

  1. Loading
  2. Empty
  3. Populated

Now during the pie chart initialization code, I saw something like

const pieChartEmpty = {
   text: 'This pie chart is empty, something broke!'
}
const pieChartLoading = {
   text: 'Please wait while the data loads...'
};
const pieChart = {
};

Do you see where this is going? Let’s attach that loading state.

   attachPieChart(pieChartLoading)

Let’s fetch some data.

function fetchData() {
   fetch(fromSomeEndpoint)
       .then((data) => {
           if(isEmpty(data)) {
               attachPieChart(pieChartEmpty)
           } else {
               pieChart.data = data
               attachPieChart(pieChart)
           }
       })
       .catch(() => {
           attachPieChart(pieChartEmpty)
       })
}

Maybe the user manipulates the data in some way.

handleSomeUserInteraction(data) {
   if(isEmpty(data)) {
       attachPieChart(pieChartEmpty)
   } else {
       pieChart.data = data
       attachPieChart(pieChart)
   }   
}

My issue is why are we creating special cases? I am sure this empty pie chart and the loading pie chart aren’t going to be that far off from the normal pie chart. We probably only need to feed in the right data for it to work correctly. The primary problem here is that in the developers mind they are creating these special scenarios where we need to start littering the code with if/else checks to see which scenarios we are in and then run a different set of instructions.

A more robust way to deal with this solution is to

1. Validate your input/Use sane defaults

2. Make your target component more robust/Write your code so that it’s always true.

3. Choose where your complexity is.

Now let’s try it again with some of these suggestions.

const pieChart = {
   text: 'Please wait while the data loads...'
};
attachPieChart(pieChart)

Ok, only one thing to think about.

function fetchData() {
   fetch(fromSomeEndpoint)
       .then((data) => {
           //We will do this here, but if it's the backend that is calling an external api, the backend should verify the input.
           return data.map((val) => {
               if(isNumber(val)) {
                   return val;
               else if(isNull(val)) {
                   return 0;
               } else {
                   throw new Exception("Unhandled Input");
               }
           });
       })
       .then((data) => {
           pieChart.data = data
           pieChart.text = 'Click on a section'
       })
       .catch(() => {
           pieChart.text = 'This pie chart is empty, something broke!';
       })
}

The attachPieChart function will probably need some additional robustness to handle responding to a changing object. That’s fine, that’s a feature.

tags: