December 31st, 2015
(written by lawrence krubner, however indented passages are often quotes). You can contact lawrence at: email@example.com
This post uses the language of Object Oriented Programming, but its point would also be true to all forms of programming. In Clojure, if you have HashMaps that you then convert to JSON and save to MongoDB, then why would you ever allow the HashMap to exist in an invalid state? Real immutability might imply that the HashMap is created with everything that it will eventually need. This is an interesting idea.
Why do we validate data? Typically, to make sure that invalid state doesn’t leak into our systems. If it’s so essential to make sure that invalid state is not allowed then…why do we allow instantiating objects with invalid state? Especially when we’re dealing with such core objects like an Active Record model which deals with so called business logic. This sounds like a really bad idea.
When it’s possible to instantiate an invalid object, chances are it’s going to happen when you don’t really expect it.
class User < ActiveRecord::Base
validates :email, :name, presence: true
user = User.select(:id).first
We state that a user must have an email and a name but then it’s possible to create its instance by projecting only :id attribute. When something is possible, it means it’s going to happen. Especially in big code bases. ActiveRecord is at least kind enough to raise a meaningful error when you try to access an attribute that was not loaded from the database.
This kind of errors are probably not very common, since in most of the cases you rely on default behavior which is to load all attributes, but the fact that it’s possible to load an object into memory that in some contexts could crash your app feels like a bad strategy.
Using same objects as your “wall of defense” against untrusted input and for implementing core application logic is a mistake. Since these objects accept invalid state, their lack of type safety makes them a shaky foundation for building complex systems. You can’t treat them as values as they are mutable. You can’t really rely on their state, because it can be invalid. You can’t treat them as canonical sources of information as their state depends on the query logic which can be dynamic as the example above shows.