Representing boolean conditions as domain concepts
Tags: programming, ruby, ddd
Published: 2022-12-29 10:25:37

Booleans. These program control switches, they introduce branching in code and do not allow to have linear path for code execution. That is fine, because in the real world, everything is the result of another action prior to itself.

A boolean method is a method that returns a boolean result, either true or false, or truthy or falsey values. You rarely see methods being created just for the sake of in/equality checks. It is preferred to perform the check inside the code as it's more obvious what attribute are we checking the equality for. 

Writing equality checks inside boolean statements does not give any context as to why this attribute is checked and not another attribute. In other words, the domain knowledge is lost. 

The domain is the problem which the code tries to solve.

Imagine a set of objects that looks like this,

```ruby
class Person
  attr_accessor :name

  def initialize(name)
    @name = name
  end
end

class Car
  attr_accessor :person

  def initialize(person)
    @person = person
  end
end
```

If we want to determine if a car is owned by a business. We usually perform a check against the person attribute of the Car object. 

```ruby
john = Person.new "John Doe"
alyn = Person.new "Alyn Oakenfist"
ford = Car.new person
```

Given these three objects above. To determine if ford belongs to john or alyn, we can write a conditional that looks like this.

```ruby
if ford.person.name == john.name
  puts "owned by John"
else
  puts "owned by Alyn"
end
```

Notice the condition we're checking. There is no context given around the code as to why we're checking the person attribute. Some domain logic is lost here, we know why we're checking. But what about someone who did not write the code, or even, our future self. 

I've grown very fond of the idea of representing these conditions as domain concepts--methods of an object. I like to ask myself why the check is performed? The answer is: the check is performed to determine if car is owned by a person. In the answer, i can extract the domain concept, i.e ownership of a car, and give it a (method) name. 

Let's do that, let's add a method inside the Car object that determines if this Car is owned by a person or not.

```ruby
class Car
 def owned_by?(person)
    self.person.name == person.name
 end
end
```

The condition above then, can be simplified into

```ruby
if ford.owned_by? john
  puts "owned by John"
else
  puts "owned by Alyn"
end
```

Not only the resulting code is simpler. It also saves the caller the pain of having to memorize attribute names `.person.name`, they can simply call the `owned_by?` method without having any knowledge of it's underlaying implementation. Another bonus is that this code is more maintainable. Because the reference to `person` is only made inside the Car object, in the future, if this attribute is changed, or the attribute we check the equality for changes, it's a simple one-line change instead of finding and replacing everywhere we're accessing `person.name`.

Some domain concepts are bidirectional. Both objects can perform the equality check. In this example, a Car can be owned by a Person. Also, a Person can own a Car. In these cases, i like to add the method to both objects. At first glance it might seem like duplication. But as with everyday life, the context in which the code is written differs. So, having different methods exposed on different objects enriches the vocabulary used inside the code. 

```ruby
class Person
 def owns?(car)
    name == car.person.name
 end
end
```

Instance methods that return a boolean results are an important part of the program. They allow to capture domain concepts and gives the a name inside the code as opposed to letting them float inside the codebase.

Hope you enjoying this. Have a wonderful time coding.