Skip to main content

Why You Should Focus On Writing Code With Clarity Discussion

General • Asked by Chris Oliver
9a72f29436f2547f85eb8b8d713cdf09
Roman Alvarado M.

Good article Chris, ruby has the clarity implied, programmers don't...
however "ubiquitous language" is something that could help to
programmers on this, thanks for share your thoughts!


2108bd79ebf93890738cfc54a2fa86f4

1.What's your take on defining methods purely to clarify the actions therein? for example, to cover up extremely ugly, unintuitive instances of operations like mapping and regex

2. I envision one of the oft-asked questions regarding this subject being "how long should method names be?" So I'll pose it also:
what's a better metric or guideline for method names than their length?

Ce795239ba5dd2384fc2f88ffaff5451

1. Often times in Ruby you'll see one or two line methods. This can be useful. In fact, user_signed_in? could be as simple as User.find(session[:user_id]). If it finds a user, you're signed in and it should return true. If it throws an exception because it can't find the record, you're not and it should return false.

But this is just one way of handling it. You may not choose to pull the record out of the database to verify they are signed in. It seems wise to both verify the user_id in the session AND load the user.

The merits of writing a method called user_signed_in? are such that you no longer have to care how the verification works. You just simply trust that it does its job and go about your business. In fact, I would venture to guess that a large amount of people haven't even contemplated how user_signed_in? works if they have never tried building an authentication system from scratch.

2. Related to point #1, your method names should be as concise as possible while still conveying clarity. We could have methods named check_if_user_is_signed_in but far too dramatic.

The way you describe the code in words out loud to a coworker often give insight into how the code should ideally be written. If you tell a programmer "okay, so we want this to happen if the user is signed in" translates almost directly to:

if user_signed_in?
the_thing_we_want_to_happen
end

I think the closest thing to a metric I can give is how similar your code is to the way you speak. The closer your code reads to what you speak means that understanding can be conveyed at higher bandwidth.

There are no hard and fast rules to this as it changes between industries, environments, and even countries that you live and work in. Culture affects this strongly.

The way to learn this is to begin reading LOTS of source code for large, well-established, and well known projects like Sinatra, Jekyll, and Rails. See how they go about their naming schemes and find the style that's most appealing to you that also provides clarity.

As you see examples in other projects, you will be able to pick up on the subtle nuances that make the difference between directly naming something and naming with an added dash of clarity.

2108bd79ebf93890738cfc54a2fa86f4

Awesome answer for #2. The "say it out loud bit" rings of truth and practicality.

For #1, let's take it a level deeper: what about refactoring out of a method for clarity? For instance, moving the really_unintuitive_ugly_logic into its own function

def some_user_function
User.explains_action.another_method
important_result
end

def explains_action
really_unintuitive_ugly_logic
end

Ce795239ba5dd2384fc2f88ffaff5451

This is hard to talk about in the abstract, so here's an example from an app I built recently. We have a Campaign object that, depending on its type, has multiple ways to be "expired".

def expired?
published? && ( (timer? && expires_at < Time.zone.now) || (quantity? && subscribers.shared.count >= quantity) )
end

Now in the current iteration, I've already abstracted out published? to handle the logic for how publishing works. The other pieces of logic are dependent upon the type of Campaign.

The simplest approach is to simply dump in the logic as you see here.

The better solution is to refactor it into other methods.

def expired?
published? && (timer_expired? || quantity_expired?)
end

def timer_expired?
timer? && expires_at < Time.zone.now
end

def quantity_expired?
quantity? && subscribers.shared.count >= quantity
end

You should be able to instantly see the benefits in clarity.

Campaigns can only have their timer expired if they are a timer based campaign and the time has elapsed. expired? encompasses a higher level definition of what being expired means. It's very clear now that an expired campaign has a few paths to their "expiration" and also allows for easy modification of individual expiration methods. You can also add new types with relative easy without adding much confusion.

Is that a better example?


Login or Create An Account to join the conversation.

Subscribe to the newsletter

Join 18,000+ developers who get early access to new screencasts, articles, guides, updates, and more.

By clicking this button, you agree to the GoRails Terms of Service and Privacy Policy.

More of a social being? We're also on Twitter and YouTube.