The Jedi Master.
very very dark gray.
but just in case,
tell me the whole thing again,
I wasn't listening.
In object oriented design, a factory is a method or class whose only responsibility is to build objects of a particular type. So, an AutomobileFactory would be responsible for building Automobile objects.
Factories are often implemented as switch statements. But doing so requires you to hard code the keys in the factory, either in the switch statement, or as a hash. So, whenever you need to add a class to the factory, you have to modify the factory. This is a violation of the Open/Closed Principle which states that classes should be open for extension, but closed for modification.
One way to resolve this problem in Ruby is to use metaprogramming. In this approach, you define a convention for converting a key into a class name (e.g. :sedan maps to Sedan). Unfotunately, if your keys and class names don’t lend themselves to a convention (e.g. :convertible maps to Cabriolet), then you won’t be able to use this technique. Furthermore, if your convention ever changes, you’ll have to modify the factory, which again is a violation of the Open/Closed Principle.
Manufacturable is a gem that solves this problem. It allows classes to register themselves as “manufacturable” by a specific factory when Ruby loads the file. Manufacturable can manage any number of factories. It supports defaults, so if a factory is passed a key it does not recognize, it can still build an appropriate object. A single class can be registered under multiple keys. And, keys can be any Ruby object, including hashes, making Manufacturable factories super flexible.
For more on extension without modification, check out Extenstion without Modification.
And, then go look at Manufacturable on GitHub.
Ruby on Rails is famous for rapid application development. It is super quick and easy to setup a Rails application with some basic functionality. So much so, that Rails was the darling of startups for years.
But, Rails is also famous for applications that grow unweildy over time and become inflexible to change. This rigidity is caused by Rails’ numerous violations of basic object oriented design principles.
When classes have more than one responsibility, they become harder to test. This makes it more difficult to reason about the class. As a result, the classes will have lower test coverage, higher churn, and more bugs.
When classes are written in such a way so that extending them requires them to be modified directly, you introduce higher churn and more bugs.
When classes take references to concrete objects rather than relying on interfaces (or duck types in Ruby), they will be much harder to test, leading to lower coverage and more bugs.
A typical Rails controller violates all of these principles.
Fortunately, there are architectural patterns that can resolve these issues. The Ports & Adapters pattern (also known as hexagonal architecture) is one such pattern. It makes heavy use of the Single Responsibility Principle, the Open/Closed Principle, and the Dependency Inversion Principle, making it a more resilient choice than traditional Rails architecture.
For more on hexagonal architecture and some example Rails code, read Making Sense of Your Rails Monolith.