Consider using null objects to make memoization easier and remove if checks
Null objects are currently not used anywhere in GitLab (that I know of), but they can often make code a lot easier (though applying the technique retroactively is a bit tricky). Memoizing values are becomes easier. For example, instead of this:
def latest_successful_pipeline_for_default_branch
unless defined?(@latest_successful_pipeline_for_default_branch)
@latest_successful_pipeline_for_default_branch =
pipelines.latest_successful_for(default_branch)
end
@latest_successful_pipeline_for_default_branch
end
One can just write:
def latest_successful_pipeline_for_default_branch
@latest_successful_pipeline_for_default_branch ||=
pipelines.latest_successful_for(default_branch)
end
Null objects would also remove the need for a lot of if
checks. For example, instead of this:
if current_user
current_user.name
else
'Anonymous'
end
One could just write:
current_user.name
Assuming that NullUser
(or whatever we'd call it) were to implemnet #name
so that it returns "Anonymous".
Another more complex example of this pattern can be seen in https://github.com/YorickPeterse/inko/tree/master/compiler (a compiler written in Ruby). Part of this code involves looking up symbols, instead of returning nil
a NullSymbol
is returned when no symbol could be found. This then lets you do things such as:
self_type.lookup_type(name)
.or_else { mod.lookup_type(name) }
.type
.return_type
instead of something like this:
type = self_type.lookup_type(name) || mod.lookup_type(name)
if type
type.return_type
else
nil
end
For the curious, the implementation of said class can be found here: https://github.com/YorickPeterse/inko/blob/74c8fdca7d8d039da71c9556a4a70c3bc316578f/compiler/lib/inkoc/symbol.rb
https://github.com/avdi/naught and https://github.com/alexpeachey/active_null look like interesting libraries to make this process easier.