Nate Davis Olds

Ideas. Presentations. Showcases.

Things That Have Changed the Way I Code

| Comments

If I were to graph my programming skills over time, I think it would look something like this.

Imagined Programmer Skill Graph

Every once in a while, I experience a shift in the way I approach writing code. These AH-HA explosions are triggered by moments of clarity followed by a rapid transformation of my programming practice. It is my theory that the frequency of these AH-HA moments is a more accurate measurement of coding skill than the amount of time spent working as a programmer.

I’d like to share one such AH-HA moment I’ve had in the last few years.

Represent key concepts with domain objects instead of core data types.

When coding, I’ve shifted from querying core data types, like String, Array, or Hash, in favor of creating small domain objects. This practice aids the conceptual understanding of the problem; making reading code, changing code, testing code, and improving code efficiency easier. Let me show you what I mean.

Here’s a code representation of our example business problem.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
# Anyone has income less than $1000
class OfferingOne
  def self.eligible? household
    household.people.any? do |person|
      countable_incomes = household.incomes.select { |i| i.person == person }
      countable_incomes.map(&:amount).sum < 1000
    end
  end
end

# Someone has pension that is less than 300
class OfferingTwo
  def self.eligible? household
    household.people.any? do |person|
      countable_incomes = household.incomes.select do |i|
         i.person == person &&
           i.income_type_key == 'pension'
      end

      !countable_incomes.empty? && countable_incomes.map(&:amount).sum < 300
    end
  end
end

# Total earned income < 1500
class OfferingThree
  def self.eligible? household
    countable_incomes = household.incomes.select do |i|
       i.categories.include?('earned')
    end

    countable_incomes.map(&:amount).sum < 1500
  end
end

There are three offerings in which we need to find out if a household is eligible. Each offering has a different set of criteria. Offering one iterates through each household person, gathers up the countable_incomes for that person, and then compares the sum to under $1000. Offering Two is similar. It also iterates over each person but then isolates on pension income. Finally, it determines eligibility by checking the presence of pension income below our limit. Finally, offering three collects all household earned income. Then compares the total to the limit of $1500.

As you might imagine the key object here is the Income class.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
class Income
  attr_reader :amount, :income_type_key, :person

  def initialize options={}
    @amount = options.fetch(:amount, 0.0)
    @person = options.fetch(:person) { Person::Nobody.new }
    @income_type_key = options[:income_type_key]
  end

  def categories
    case income_type_key
    when "wage"
      ["earned"]
    when "social_security"
      ["unearned","government"]
    when "pension"
      ["unearned"]
    else
      []
    end
  end
end

An income is represented with an amount, an income_type_key, and a person. All these attributes are passed in a familiar fashion.

Categories holds a logical mapping of income_type_key to a list of categories. As we add various types of income we will need to update this map to make sure our income has the correct categories.

Another way to represent categories is through a hash.

1
2
3
4
5
6
7
8
9
  def categories
    category_map = {
      "wage" => ["earned"],
      "social_security" => ["unearned","government"],
      "pension" => ["unearned"]
    }

    category_map[income_type_key] || []
  end

I suspect that this code seems familiar to you. I know I write code like this all the time. And there is nothing wrong with it. It will function exactly as expected. However, in dynamic applications where we have a long-term commitment to the code, we owe it to our team and to ourselves to write maintainable code.

Whether it be with a hash or a case statement, when I see this style of code I know it is hiding another object. To get it out, use composition.

Composition is a style of coding which combines simple objects into more complex ones. In this case, Income has the smaller IncomeType inside it.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
class IncomeType
  def categories
    []
  end
end

class WagesIncomeType < IncomeType
  def categories
    ["earned"]
  end
end

class SocialSecurityIncomeType < IncomeType
  def categories
    ["unearned", "government"]
  end
end

class PensionIncomeType < IncomeType
  def categories
    ["unearned"]
  end
end

If we create a IncomeType class with a #categories method we can then create a class for every type of income we want to represent. We can clearly see and reason about the properties of each type.

Back in our Income class, we create a private method of income_type.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
class Income
  attr_reader :amount, :income_type_key, :person

  def initialize options={}
    @amount = options.fetch(:amount, 0.0)
    @person = options.fetch(:person) { Nobody.new }
    @income_type_key = options[:income_type_key]
  end

  def categories
    income_type.categories
  end

  private

  def income_type
    @income_type ||= begin
      "#{income_type_key}IncomeType".constantize.new
    rescue
      IncomeType.new
    end
  end
end

It tries to find a class based on the income_type_key otherwise it creates a blank income type. Now, in the categories method it is a simple call to the income_type to get the categories. Adding an income type is as simple as adding this value class.

In this way we’ve removed the comparison to strings or hashes and instead have conceptual domain object (IncomeType) to provide the information we need.

Back to Offerings

There are other decisions being made through comparisons.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
# Anyone has income less than $1000
class OfferingOne
  def self.eligible? household
    household.people.any? do |person|
      countable_incomes = household.incomes.select { |i| i.person == person }
      countable_incomes.map(&:amount).sum < 1000
    end
  end
end

# Someone has pension that is less than 300
class OfferingTwo
  def self.eligible? household
    household.people.any? do |person|
      countable_incomes = household.incomes.select do |i|
         i.person == person &&
           i.income_type_key == 'pension'
      end

      !countable_incomes.empty? && countable_incomes.map(&:amount).sum < 300
    end
  end
end

# Total earned income < 1500
class OfferingThree
  def self.eligible? household
    countable_incomes = household.incomes.select do |i|
       i.categories.include?('earned')
    end

    countable_incomes.map(&:amount).sum < 1500
  end
end

The comparisons i.person == person, i.income_type_key == 'pension', and i.categories.include?('earned') are classic examples of feature envy. Feature envy is when a method is more interested in a class other than the one that it is in. In these cases we are querying information from income then comparing to something else. Shouldn’t Income be the class that knows if it for a person? or is an income type? Or has a category? If we let this continue, these logical comparisons will litter our code. If any of these comparisons change, we would have to find all the places in our code we compare and then change those. That isn’t something I want to maintain long term.

To solve it, the comparison is moved into Income.

1
2
3
4
5
class Income
  def person? candidate
    person == candidate
  end
end

Now the offerings can ask income if it is for a person.

1
countable_incomes = household.incomes.select { |i| i.person? person }

and

1
2
3
4
countable_incomes = household.incomes.select do |i|
   i.person?(person) &&
     i.income_type_key == 'pension'
end

Income should also know which category it is in and if it ‘is’ as certain type. However now with our composition changes the IncomeType is what should know if it is of a type. So, let’s forward the decision to income type.

1
2
3
4
5
6
7
  def category? candidate
    income_type.category? candidate
  end

  def is? candidate
    income_type.is? candidate
  end

Moving categories and is? to IncomeType, the result looks like this:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
class IncomeType
  def category? candidate
    categories.include? candidate
  end

  def categories
    []
  end

  def key
    ""
  end

  def is? candidate
    key == candidate.to_s
  end
end

class WagesIncomeType < IncomeType
  def key
    "wages"
  end

  def categories
    ["earned"]
  end
end

class SocialSecurityIncomeType < IncomeType
  def key
    "social_security"
  end

  def categories
    ["unearned", "government"]
  end
end

class PensionIncomeType < IncomeType
  def key
    "pension"
  end

  def categories
    ["unearned"]
  end
end

Now, our offerings ask the income if it is of a type or category or for a person.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
# any person in the household makes less than a 1000 a month
class OfferingOne
  def self.eligible? household
    household.people.any? do |person|
      countable_incomes = household.incomes.select { |i| i.person? person }
      countable_incomes.map(&:amount).sum < 1000
    end
  end
end

# pension and is less than 300
class OfferingTwo
  def self.eligible? household
    household.people.any? do |person|
      countable_incomes = household.incomes.select { |i| i.person?(person) && i.is?('pension') }
      !countable_incomes.empty? && countable_incomes.map(&:amount).sum < 300
    end
  end
end

# total earned income < 1500
class OfferingThree
  def self.eligible? household
    countable_incomes = household.incomes.select { |i| i.category? 'earned' }
    countable_incomes.map(&:amount).sum < 1500
  end
end

The advantage comes when there are changes to the business rules we are building this code on. Especially when adding a new income type or when an income type changes its category. We don’t have to touch the logic to introduce another income type to the configuration.

The code is cleaner, but there is one piece that I would like to take bit further. The approach of adding classes that represents each type bothers me. Aren’t they all instances of the IncomeType class instead of classes of their own? So, I’ve written a gem to help with this problem. I call it identitee.

With identitee, we can identify a code block with a key. The block is executed to build an object (in this case IncomeType). Later, this same object can be retrieved through its Identitee key and be used in our code.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
require 'identitee'

class IncomeType
  include Identitee

  def self.find_or_none income_type_key
    type = find income_type_key
    type == 'Unknown' ? UnknownIncomeType.new : type
  end

  def is? candidate
    key == candidate.to_s
  end

  def category? candidate
    categories.include? candidate.to_s
  end

  def categories
    @categories ||= []
  end

  def categorized *categories_to_add
    @categories = [*categories_to_add].map(&:to_s)
  end

  class UnknownIncomeType
    def key; "unknown"; end
    def category?(candidate); false; end
    def categories; []; end
    def is?(candidate); false; end
  end
end

Now in the income_types, folder we can write definitions for each income type.

incomes_types/wage.rb

1
2
3
IncomeType.identify "wage" do
  categorized "earned"
end

income_types/social_security.rb

1
2
3
IncomeType.identify "social_security" do
  categorized "unearned", "government"
end

income_types/pension.rb

1
2
3
IncomeType.identify "pension" do
  categorized "unearned"
end

In income, we now can find an income type by key. Income has be become a value object. Easy to maintain.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
require 'income_type'
require 'person'

class Income
  extend Forwardable

  def_delegators :income_type, :category?, :is?
  attr_reader :amount, :person

  def initialize options={}
    @amount = options.fetch(:amount, 0.0)
    @person = options.fetch(:person) { Person::Nobody.new }
    @income_type_key = options[:income_type_key]
  end

  private

  attr_reader :income_type_key

  def income_type
    @income_type ||= IncomeType.find_or_none income_type_key
  end
end

Back (again) to Offerings

Now let’s look back at our offerings. We are working a lot with arrays of Incomes. We filter by category and by type. We group by people. We total all incomes. There is a bunch repeated logic that would be best to standardize. We can do that by using Enumerable.

Enumerable is a mix-in providing collection classes with several traversal and searching methods, and with the ability to sort. Enumerable methods are familiar methods like map, select, inject, and each. Let’s start by creating an Incomes class and getting Enumerable to work.

1
2
3
4
5
6
7
8
9
10
11
12
13
class Incomes
  include Enumerable

  def initialize incomes=[]
    @incomes = [*incomes]
  end

  def each &block
    incomes.each &block
  end

  attr_reader :incomes
end

This gives us the standard methods but let’s create some that filter our list of incomes.

1
2
3
4
5
6
7
8
9
  def categories *candidates
    new_for select { |income| income.category? candidates }
  end

  private

  def new_for ary
    self.class.new ary
  end

Let’s add a filter for types

1
2
3
  def types *candidates
    new_for select { |income| income.is? candidates }
  end

Let’s add group by person.

1
2
3
4
5
  def group_by_person
    group_by(&:person).collect do |person, person_incomes|
      new_for person_incomes
    end
  end

Finally, totaling the incomes.

1
2
3
  def total
    map(&:amount).reduce(&:+)
  end

Going back to the offerings we can use our filters to make eligibility methods very readable.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
  # any person in the household makes less than a 1000 a month
  class OfferingOne
    def self.eligible? household
      household.incomes.group_by_person.any? do |incomes|
        incomes.total < 1000
      end
    end
  end

  # pension and is less than 300
  class OfferingTwo
    def self.eligible? household
      incomes.types('pension').group_by_person.any? do |incomes|
        incomes.receiving? && incomes.total < 300
      end
    end
  end

  # total earned income < 1500
  class OfferingThree
    def self.eligible? household
      incomes.categories('earned').total < 1500
    end
  end

The only comparison is the one needed for the eligibility itself. this comparison is exactly in the correct place.

Take away

Representing key concepts with objects instead of core data types makes code easier to maintain. This is essential for long term relationships with complex problems.

Eliminate Feature Envy. Breakdown into domain objects using composition. Encapsultate collections using Enumerable.

I hope this also changes the way you code.

Building Coreisma

| Comments

A while back, I watched Scalable JavaScript Application Architecture by Nicholas Zakas. It describes an architecture made up of isolated modules communicating through a central sandbox. These concepts resonated with me. So I decide to write this basic architecture as fun exercise. Turns out, it wasn’t difficult to implement.

The result is Coreisma.

Coreisma is a lightweight module manager for javascript. It provides a clear way to encapsulate javascript snippets into modules, facilitates communication between modules through event notifications, and exposes shared code in through extensions.

In this article, I’d like to share the steps I took to build it.

Core Philosophies

I believe that good software is written deliberately. Meaning the choices that a programmer chooses should come from a set of philosophies. For Coreisma, I these philosophies to:

  1. Create a simple architecture pattern; not another framework
  2. Not tie myself to a particular framework (ie. jQuery, Prototype, YUI)
  3. Use TDD to ensure test coverage.

The Small Steps

Coreisma starts, as all very abstract cores should, very small. I simply provided a means to extend the object itself. Pass a json object or more powerfully a function that receives Coreisma itself.

1
2
3
4
5
6
7
8
9
10
11
12
13
var Coreisma = {
  extend: function(extension) {
    var extensionMethods = (typeof extension === 'function') ? extension(this) : extension;

    for (var property in extensionMethods) {
      if (extensionMethods.hasOwnProperty(property)) {
        Coreisma[property] = extensionMethods[property];
      }
    }

    return extensionMethods;
  }
};

Then, using this extend function, I exposed a more developer-friendly way to add an extension. I boringly called this function addExtension.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
Coreisma.extend(function(core) {
  var extensions = [];

  var addExtension = function(extensionFunction) {
    if (arguments.length > 1 && typeof arguments[0] !== 'function') { extensionFunction = arguments[1]; }

    var extension = (typeof extensionFunction === 'function') ? extensionFunction(core, core.hub) : extensionFunction;

    core.extend(extension);

    extensions.push(extension);

    return extension;
  };

  return {
    addExtension: addExtension
  };
});

I wanted a way to name extensions. It isn’t retained or used in any way but it is a nice way to briefly describe what the extension does. Maybe one day this will allow for some simple self documentation.

Likewise, addExtension stores all extensions in a, you guessed it, “extensions” private variable.

addExtension passes core and a hub to an extension. At first hub is undefined, but coreisma wouldn’t be useful without it, so I figure it is a safe assumption that some “hub” will be there.

I probably should have broken the next extension up into three separate extensions: addHub, addModule and getModule, and finally start and stop of Coreisma. I believe that the root of this was because I was TDDing. I could not seem to think of a way to test addHub without starting Coreisma. Seems like a good candidate for a refactor, but for now here is the “Hub” portion of Coreisma.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
Coreisma.addExtension("Hub", function(core) {
  var addHub = function(hubFunction) {
    core.hub = (typeof hubFunction === 'function') ? hubFunction(core) : hubFunction;
  };

  var addModule = function(moduleName, moduleFunction) {
    if (core.hub) { core.hub.register(moduleName, moduleFunction); }
  };

  var getModule = function(moduleName) {
    return (core.hub) ? core.hub.find(moduleName) : {};
  };

  var start = function() {
    core.hub.broadcast('startup.modules', core.hub);
  };

  var stop = function() {
    core.hub.broadcast('shutdown.modules', core.hub);
  };

  return {
    addHub: addHub,
    addModule: addModule,
    getModule: getModule,
    hub: {},
    start: start,
    stop: stop
  };
});

Despite the name “Hub” of the previous extension, we haven’t defined a working hub yet.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
Coreisma.addHub(function(core) {
  var modules = {},
      callBacks = {};

  var broadcast = function(eventName, data) {
    var eventCallBacks = callBacks[eventName];

    for (var i in eventCallBacks) {
      if (eventCallBacks.hasOwnProperty(i)) {
        eventCallBacks[i](data);
      }
    }
  };

  var listen = function(eventName, module) {
    if (!callBacks[eventName]) { callBacks[eventName] = []; }

    callBacks[eventName].push(module);
  };

  var register = function(moduleName, moduleDefinition) {
    var module = (typeof moduleDefinition === 'function') ? moduleDefinition(core, core.hub) : moduleDefinition;

    modules[moduleName] = module;

    if (typeof module.init === 'function') { listen('startup.modules', module.init); }
    if (typeof module.shutdown === 'function') { listen('shutdown.modules', module.shutdown); }
  };

  var find = function(moduleName) {
    return modules[moduleName];
  };

  return {
    listen: listen,
    broadcast: broadcast,
    register: register,
    find: find
  };
});

The Hub exposes four functions: register, find, listen, and broadcast. They do what you expect them to do.

  • register makes a module known. It passes the core and hub to the module to work with and automatically sets up a modules init and shutdown functions

  • find retrieves a module by name.

  • listen setups up a callback when a certain event happens.

  • broadcast declares that a certain event has happened to all listeners.

Wrapping up

A scalable javascript architecture brings stability and standardization to any project. Coreisma is my attempt to implement the ideas from Nicholas Zakas. I am proud of how straight-forward Coreisma turned out.

At Benefit Data Trust we have be been using Coreisma in production as a trial for months now. As we start to migrate all of our javascript to use coreisma, I suspect best practices and patterns will emerge. We will be able to distinguish what should be an extension. Or standardize the format for data passed between listener and broadcasts.

There is room to grow with Coreisma but I think this spunky architecture has a bunch of potential.

FREE-style Programming

| Comments

After solving a problem that has perplexed me for hours, I often take a few moments to sit back and bask in the bliss of a problem well-solved. But sometimes, my joy fades when I realize how little progress I made towards finishing the feature I started. I got distracted. I started out on track; but somehow, my focus shifted away from the goal—implementing the feature.

Most distractions have good intentions behind them. Sometimes I see a way to use the coding pattern I recently read about and decide to experiment. Other times I find a piece of code that I intended to refactor but never got around to; thinking it will only take a minute, I jump into that refactor. And still other times, I get distracted by formatting details, eliminating whitespace, converting a css file to sass, or attempting to make some method run more efficiently. While these are all great areas to focus on, they’ve ultimately prevented the feature from functioning sooner.

How can I complete the feature I began and still ensure my code is clean and well factored?

The State of the Code

Some the most fundamental programming techniques in the Ruby community have a side-effect of preventing distractions. Pair programming utilizes a second programmer’s perspective to discourage distractions. And yet still pair programmers may wander off together. Test Driven Development sets a rigid cycle of “red-green-refactor” to keep the focus on the task at hand. But the direction of building code is still at the programmer’s discretion. Regardless of the technique, a programmer needs a guide to remain on track.

FREE-style programming aims to be such a guide for programmers. It walks a programmer through an ordered code state.

  • Functional: Proven to work as expected.
  • Readable: Does what it says.
  • Easy to change: SOLID, documented, adaptable and extensible.
  • Efficient: Performs at the highest possible level.

This acronym gives an order to the state of the code while implementing a feature. First, you should focus on making sure to solve the problem you set out to address. For me, this is passing the acceptance test and its underlying unit tests. Next, a programmer should aim to make the code readable: DRY-ing up the code, creating small private methods doing the work called from the public methods, renaming methods to clarify what it does, or even refactoring to extract method into a class. Once it is readable, the code should become easy to change. This could be done by breaking the more complex classes into meaningful, smaller, reusable ones or by adhering to “open for extension, closed for modification”. Finally, the code should become efficient. The emphasis here is on execution performance.

When to shift to the next code state

A critical awareness is knowing when to move to the next code state. When is the code functional enough to move to readable? Or when does a program benefit from becoming more readable even though it is not yet completely functional?

Knowing when to progress is a developed skill. There is no absolute signal to tell us when to stop, go, or proceed with caution. The time to move forward is when you feel that the code stage is complete. When you sense this feeling, transition to the next code state.

Sometimes I do break this rule by taking little excursions to make the code readable without first making it completely functional. I do this only out of necessity, however. I make small adjustments to the readability of the code so that I can understand it enough to implement the next function. The F-R transition is the only time I consider moving backward. I only progress to “Easy to change” and “Efficient” stages after the code is fully Functional and Readable.

What kind of programmer are you?

In my experience, programmers are divided by what they prefer to focus on. Many are driven to make their programs function. These people are often task-oriented and they become annoyed when there are lists of stories that need to be addressed. Others, like me, are distracted by how the pieces fit together. The details of a program’s implementation feel more important than its execution. A common worry among these programmers is to commit the perfect solution the first time. Lastly, some programmers focus foremost on performance of their code. A performance-focused programmer will tinker with a single method or construct for even the slightest gains in speed, but later must re-tune the methods to meet the additional requirements.

We need all types of programmers. It would take a tremendous amount of time to get an application running if there wasn’t a drive to get features working. However, a system becomes a tangled mess if it is not cultivated. If the time required to insert a new feature into a system becomes less profitable than the feature itself, we stop implementing features. So we need the sustaining programmer to keep the system from grinding to a halt. But sometimes code can function and read well but still not be efficient. That’s when the performance programmer shines—taking the proven-complete, well-designed code and optimizing it to work faster.

A Balanced Approach

Building a software system is difficult. The demands of adding a new feature now often cause shortcuts that inhibit the development of future features. And yet, taking the time to clean up code distracts from adding features. True success of a system relies on a balanced approach to coding.

Using the FREE-style guide gives this balanced approach. Start by proving a feature is Functional. Then change the names, formatting, and method size to make it Readable. Afterward, isolate code that relates to each so that it is Easy to change. And lastly, look to improve the overall performance through efforts to make it more Efficient.

By following the FREE-style guide, I’ve been able to identify and re-focus when I get distracted. I’ve been more productive, while simultaneously writing lasting code. I hope it will help you, too.

Nothing to Say

I feel like I have nothing to say.
So, why start a blog?
To make sure I at least have a voice.