Data and code

2019-05-08

I'm working on a project to manage visits to schools. We have a school object and this school object has many phases (primary, secondary, college). We have a wizard (shudder) for building up a school. One of the screens in the wizard is a group of check boxes for the school to select the phases they offer. This screen, like the other wizard screens, is backed by it's own form model. When the wizard is completed there's a service object to create a new School in the database from it's attributes.

class Phase < ApplicationRecord
  validates :name, uniqueness: true
end
  class School < ApplicationRecord
    belongs_to :phase
  end
  class PhaseSelection
    include ActiveModel::Model
    include ActiveModel::Attributes

    attribute :primary, :boolean
    attribute :secondary, :boolean
    attribute :college, :boolean

    # validations etc ...
  end
  <%= form_for @phase_selection do |f| %>
    <%= f.checkbox :primary %>
    <%= f.checkbox :secondary %>
    <%= f.checkbox :college %>
    <%= f.submit %>
  <% end %>

Can use see the design flaw? The lead dev on our project spotted it straight away, it was pretty impressive. The issue is that with this design we're storing business knowledge (the number of phases available) in both the code and the data, in both the columns and the rows. Doing this makes the application much harder to maintain. Now every time we create a phase in the database Phase.create! name: 'Nursery', we need to change our code if we want the phase to be selectable in the wizard.

  class PhaseSelection
    ...
    attribute :nursery, :boolean
    attribute :primary, :boolean
    attribute :secondary, :boolean
    attribute :college, :boolean
  end
  <%= form_for @phase_selection do |f| %>
    <%= f.checkbox :nursery %>
    <%= f.checkbox :primary %>
    <%= f.checkbox :secondary %>
    <%= f.checkbox :college %>
    <%= f.submit %>
  <% end %>

This makes providing an admin screen to create phases impossible. We need to pick either storing the business knowledge (the number of phases available) in the code (think database columns) or in the data (think number of rows). If we choose both we'll eventually introduce inconsistent state into the application.