Use Response Objects to reduce bugs and improve your code
A Response Object is a value object that improves the communication between the different classes and modules in your application, making bug hunting easier and improving the readability of your code.
Basically, a Response Object provides a simple interface to ask if an operation succeeds or if it fails and allows you to provide any additional information that you would require.
A Response Object responds to at least two methods: success?
and failure?
and can have any data associated with it:
response = SimpleResponse.success(user_id: 1)response.success? # true
response.user_id # 1
response.failure? # false
Real Life Example
Let’s suppose that you are retrieving posts from a third party api. You could write something like this:
posts = ThirdPartyAPI.get('posts')
if posts?
puts "Post retrieval succeeds."
puts "We retrieve #{response.posts.count} posts."
else
puts "Error retrieving posts"
end
The example above isn’t very good. It works, but what will happen when bugs begin? You’ll have to modify both ThirdPartyAPI to raise an exception (which are slow) or return a detailed error in case there was one and adapt our previous code to handle this changes (for example, to rescue some exceptions or receive a Hash or an OpenStruct response). What if you want to get additional information like the time that took to retrieval our posts? You’ll have to make the same kind of changes I mention before.
As you can see, the code above works, but it is far from robust and flexible.
Basically, with the code above, you are not able to respond fast nor adapt to new error cases easily.
You could enrich your code and the feedback that you obtain from your functions by using Response Objects:
response = ThirdPartyAPI.get('posts')
if response.success?
puts "Post retrieval succeeds in #{response.retrieval_time}"
puts "We retrieve #{response.posts.count} posts."
else
puts "Error retrieving posts: #{response.error_message}"
end
Now we have a better code than before. If something fails, you can know exactly the reason. Also, you get more feedback from your methods by adding extra information to your response.
If after some time you need to be more specific about the errors that you get from your third party api calls you could write something like this:
response = ThirdPartyAPI.get('posts')
if response.success?
# ...
elsif response.credentials_error?
puts "The provided credentials are invalid"
elsif response.connection_error?
puts "There was a connection error"
end
Or if you want, you could delegate the message generation at all:
response = ThirdPartyAPI.get('posts')
if response.success?
# ...
else
puts response.user_readable_error_message
end
Conclusion
As you could see, by using Response Objects you will be able to improve the robustness and flexibility of your code. Also, you’ll end up with a code that is more readable.
If you want a simple way to start using Response Objects today, you could use the simple-response gem, which is a lightweight gem that will allow you to create Response Objects in an easy but robust way.
I hope that this article has been useful for you, make your code better, reduce the number of bugs in your code and make its hunt easier!