Q: How do you eat an elephant?
A: One bite at a time.
Purpose of this guide is to help you write code which is easier to use, easier to test and easier to understand by your fellows. All code examples in this guide are written in Ruby but the language does not matter because they illustrate generic problems, not Ruby-specific constructions.
The guide itself is written in English because mastering English is a very important step on a way to improve as an IT specialist.
I do mean it. What natural language does you favorite programming language use as a base to draw all the names from? I bet it’s English unless you write in ДРАКОН, Рапира or BrainFuck. So improving your english skill will help you to find better names for classes, methods, variables and everything you write as a programmer. In the following sections you will see why it is important to name things properly.
Learning english will also open the doors for you to international community of programmers which is large and already documented a lot of knowledge. From blogs to official APIs and books which will never be translated into russian or will loose their applicability (BTW, do you know this word?) by the time they are translated into russian.
Here are some dictionaries which are useful to translate terminology and find synonyms:
Be careful with Lingvo, often it gives you variants of translation which nobody uses, Мультитран is much better and professional source of information.
Tests are good, right? Right, if you know how to write them. And if you ever tried doing it you know testing is very hard. What can you do about it? Write more tests and ask all your colleagues to write them too so they can understand how to create testable code.
If you have troubles testing your code because it is too complex try TDD (test driven development) which states what you should write your tests before you write your code. This is right, before you wrote first line of code you need to have tests for them. Do not try to fit everything in this tests. Leave them small and let them test the simplest things possible. For example what you can instantiate a class which you do not have yet or call a method you have not written yet.
After you did your tests you can write empty class/method implementation and see your simple tests pass. After this you can iterate and start to introduce more complicated tests and implement your code to make them pass. Do it in iterations and make tests drive your code. After each iteration refactor your code and your tests to remove duplication.
How will it help you to write better code? Well, when you write tests you specify how you would like to use your methods, you see how the code using them will look like and how you want them to behave. By doing this you make API which is more comfortable to use. This approach when you write the code which the not-yet-existing API to solve the problem in the simplest possible way first and then write the API is called wishful thinking. It is introduced and described in a book called SICP1. It is a very simple but powerful idea. Try it next time and you will see the benefits immediately.
Stop, what? I thought you already told about it in the previous section.
There are only two hard things in Computer Science: cache invalidation and naming things. — Phil Karlton
It’s all about abstraction and encapsulation.
To quote The Rspec Book2:
You may think of classes and interfaces when we use the word abstraction, but here’s another way to look at it: names are abstractions. That applies to names of systems, components, packages, namespaces, classes, methods, and even variable names.
So if you write code like this
class Issue
def css_classes
if due_date.present? && !status.is_closed
if due_date == ::User.current.today
"issue_warning"
elsif due_date < ::User.current.today
"issue_alarming"
end
end
s
end
end
stop for a minute and think: what does due_date.present? && !status.is_closed && (due_date == ::User.current.today)
mean? It has something to do with dates and current day. Ah, it checks if issue’s deadline is today. It is a good idea to extract this logic in the method. Why? Because it helps you to write self-documented and understandable code. Just have a look at this code:
class Issue
def css_classes
if self.have_deadline_today?
"issue-warning"
elsif self.deadline_passed?
"issue-alarm"
else
""
end
end
end
Is it easier to understand? Definitely yes. You can read it almost like plain English and there is no need to dive into details what is deadline if you only need to fix class name.
By extracting code like this into method you create more methods with domain-specific-language so you can express more code in domain-specific-names. This is what DSLs (Domain Specific Languages) are all about, not magical metaprogramming.
As a bonus you can easily test/spec this methods.
Always describe why error happened and how to solve it. The worse thing you can do is not to show user an error and the second worse thing is to show meaningless error message like “Error happened, ooops”.
And remember: developers are users too and we do need helpful error messages to diagnose them faster.
Let’s have a look at a short maintenance script which updates issues in redmine:
for issue in issues
issue.priority = max_priority
if issue.save
puts "Success: priority of #{issue} was changed to #{max_priority.name}"
else
puts "Error: priority of #{issue} was not changed"
end
end
What error message does it generate?
Error: priority of Feature #1: Visualize issues connections was not changed
As a developer who runs this script I really want to know what is wrong with the system:
- is issue invalid?
- is max_priority invalid?
- did we lost connection to DB?
- maybe something else happened what I can not even think about?
Additional information would help me to understand the issue and solve it faster.
For example:
Did not change priority of "Feature #1: Visualize issues connections":
PGError: not connected
Did not change priority of "Feature #1:":
Issue validation errors: Tracker can't be blank, and Tracker is not included in the list
1 Structure and Interpretation of Computer Programs — Probably one of the best books about programming you can ever read. It improves your coding skills no matter what programming language you use and it helps you to form a foundation on which you can easily learn new languages, libraries and technologies. This book is the text supplementary of the course taught at MIT. You can get old but good videos of this course too.
2 The RSpec Book: Behaviour-Driven Development with RSpec, Cucumber, and Friends