Ruby and KISS: Sitting in a Tree

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!