I learned a lot of things in the Marines, but one takeaway which applies directly to programming is the acronym KISS: Keep it simple, stupid. Why were we taught this? Overthinking the problem is a surefire way to make things more complicated and introduce more potential points of failure when coming up with solutions. Especially in startup situations where money and time are tight, time-busting optimizations and over-engineering can kill a project before it gets off the ground.
Let’s cover a couple of common scenarios where developers can choose the quick, reliable (albeit a bit inflexible) way to get something working for an MVP (minimum viable product).
Admin access
When you’re first building an app, you’ll typically write two classes: the “thing” (what your app’s all about) and the user. Envisioning authentication and authorization, you prepare to add roles, since they’re flexible and you’re trying to add admin capabilities. Stop. Take a deep breath and resist the urge.
Instead of introducing another gem, think about the feature you’re adding:
admin access. For an MVP, this typically means a check to make sure they can
access certain controllers and actions. All you need is a boolean column
(admin
) on user. When adding a second role (super-admin, content-editor,
etc.), resist the urge (again) to introduce a more complicated system. Chad
Pytel goes so far as to say that
introducing role-based access too early constitutes a Rails
anti-pattern.
Follow the rule of three; once you need to add another user flag, consider using roles. Until then, keep your code smaller and more straightforward.
State machine
State machines are pretty trivial to add but usually should be avoided. Imagine a system where a user can sign up for a paid subscription. In order to speed up getting the user into your system, you move credit card processing to a background job since communicating with an external service you use can take a second or more.
If the order fails, instead of adding a state machine and introducing transitions to manage behavior, just track when it failed with a timestamp. Handling the failure case (with behavior like delivering an email to the user explaining his credit card didn’t work and deactivating the account) can be done in callbacks or observers until more states are required.
You Ain’t Gonna Need It
It’s easy to introduce components like state machines or role systems, but if
you’re not actively feeling pain from it, leave the code alone. No one wants
you to spend half a day of precious time during a four-week MVP freshening up
on your state_machine
understanding or catching up on the differences
between load_resource
and load_and_authorize_resource
when using
cancan. As long as the application does
what it needs to do, save yourself time up front and keep it simple!