I have been working as Ruby on Rails developer since last five years with Josh Software, I felt that I should write down my learnings about the best practices followed by the RoR developer. How I learned …? of course to learn something you need to commit the mistakes, thats how we learn right?
Let’s see, What all you should follow to be a ‘Good’ Ruby on Rails developer.
1. Your migrations are “thoughtful” …
Whenever you come across database table schema design do you think through all the aspects like
The table which is being designed where its going to be used? How much it might grow in terms of the data size? (Imagine the worst future of your design)
Have I kept correct data types, defaults, constraints if any? Most of the times we really don’t need integer columns, We can use
smallint
instead for smaller set ofintegers
, similarlyvarchar(10)
vsvarchar(255)
vstext
.Have I added indexes wherever necessary? Thinking through What kind of the queries this table is going to handle?
A special point…Do you write multiple migrations for same table? if yes, it's a bad habit.
Often we don’t think through all the points mentioned above and end up creating multiple migrations for same table which causes codebase to look scary.
Instead you should use up
and down
on the migration to fix or alter the table, change in the requirement is an exception to this.
2. You always follow the single responsibility principle
We all know a convention of “skinny controller and fat model”, some of us already follow this but do we follow it wisely.
We are living in the Rails 5 era, so Why overload models?
Why not to follow “keep everything skinny move extra fat to concerns or service objects from the models”, the classes in the codebase should be designed to handle single responsibility.
I came across the following posts about how to organise controllers and using service objects in Rails.
3. You write test cases to test the “code”
I have seen many applications whose CI builds takes ages to finish, What exactly they are testing?
Your test cases should be testing the “code” not the machine performance, better test suits
- Share objects between different examples.
- Uses method stubs and avoid the repetitive calls to the methods.
- Don’t test same code twice, if you have sharable piece of code and used at multiple places then don’t write test cases in multiple places.
- Does not creates unnecessary test records, unknowingly many developers end up creating unnecessary test records.
If your are using gems like faker , factory_bot_rails and database_cleaner to create and clean test records then creating unnecessary records can cost you time and speed.
Simple example,
create_list(:user, 10)
Much better will be reduce the list size, if you are not doing anything special with 10 users.
create_list(:user, 2)
4. You keep production environment healthy
If you are an engineer and reduce efforts of others, then you use the utilities of other engineers to reduce your efforts.
A healthy Rails production environment always have
- Monit – Is everything up and running? if not get notified.
- logrotate – rotates, compresses, and mails system logs.
- crontabs with whenever, schedules work for you.
- Database backup scripts running in maintenance window.
- Exception notifiers like Sentry or Rollbar or ‘anything that suits you’.
5. You follow basic git etiquettes
If you are working in a team and using git then you follow the git etiquettes like
- Don’t commit untracked files – we often keep git untracked files like
something.swp
,backup.sql
, ‘schema.rbor
structure.sql backups,
some.test.script`, you should not commit such files. - Branch naming – naming something is always difficult but you have to do it, the feature branches should have sensible names, don’t use names like
something-wip
,somthing-test
. - Delete the feature branches after merge – no explanation required.
- Commit messages – your commit messages must have
Github issue number
orany project management story number/link
,brief description about feature/task
6. You don’t ignore README.md
Remember you are not the only one who is going to work on particular application for your lifetime. Someone will takeover you and he should not waste his time in figuring out that how to setup things.
Your application repository must have updated README.md
with detail steps about setting up an application for the first time.
7. Secrets are “really” secrets for you
We often use credentials for database configs, secrets.yml, third party api’s like AWS, payment gateway, sentry etc.
You should not commit such credentials/secrets/environment variables to the Github instead you keep them secure with gems like dotenv-rails, figaro or simple dot files that are not committed to the repository.
A sample file of such credentials should be committed and updated regularly.
8. You do code reviews and discuss feature with team
While working in a team you should get your feature reviewed from another team mate or before starting on any feature discuss it with the team thoroughly, advantages of the code reviews or feature discussion are you will come across many scenarios that are not thought of.
If you are the only one who is working on a application then you must criticise your own code and cover all the scenarios in test cases.
9. You are up-to-date and keep updating
In open source community we get frequent updates or releases for ruby, rails and gems, you must keep yourself aware and informed by subscribing to the repositories or mailing lists and update your application libraries.
Also you should stay alert on security fixes about the production operating system, database so you can take necessary action on time.
10. Need not to say…
You write clean and maintainable code and your codebase is
- Properly indented
- Only 80 columns wide
- Maintainable with smaller methods, less complexity – To know more on this make a habit of using code analyzer like rubocop, Code Climate
- Codebase follows Ruby best practices and style guide.
Well there are many more points that can be included in this list but I feel these are the most important to fill in first into this list, If you find that I have missed anything more important then you can comment on this post.
Thanks for the reading upto here, hope this will help you to become a ‘Good’ developer.
PS: I am moving out of wordpress this is a cross post.
Top comments (8)
Nice points Pramod! If you want to be even more awesome to your teammates, make sure with those migrations that you tested running both the up/down! Maybe your local development database is a good spot, but someone else may need to run that migration a couple times.
Thanks for the feedback Christine! Indeed testing is important.
Some great tips here!
As someone who’s worked with Rails for almost a decade, here’s my biggest tip for Rails developers:
Know when to move beyond the comfort of the Rails framework. MVC are great abstractions but they’re not the only ones needed for an app of any size
Thanks, indeed a great tip from you. What pattern you follow in such cases?
The big idea really is “It’s okay to make objects that aren’t MVC”.
Here are some ways that thought can play out:
Service objects for handling domain model operations
Business processes often affect multiple domain entities. Stuffing process logic into models can result in the algorithm for processes being smeared across lots of files.
Having service objects that own the business processes centralise the algorithm and logic for a process in one place. This makes testing the process easy, and takes code out of your models (making them much simpler)
Controllers only handle HTTP wrangling
Don’t make your controllers do anything except call a service object and report on the result. This makes your controller tests simple and very very fast.
Decouple an asynchronous job from the action or task it performs
An async process has 2 components:
If you implement this with 2 objects (a job class and a service object that does the work) then you have two sets of easy tests:
I’m sure readers can suggest others.
I highly recommend Sandi Metz’ book POODR and her talk “the magic tricks of testing” for practical discussions of the big ideas.
Note that unlike smallint vs int, varchar(10) does not use any less space than varchar(255) nor text. They all will size themselves to fit the data, and the database might also compress. "varchar" is short for "variable-length character string" as opposed to the fixed sized "char". The "10" is just a constraint. See dev.mysql.com/doc/refman/8.0/en/st... and postgresql.org/docs/current/dataty...
Most text fields have no objective sizes. For example, 8 bit color will never need more than a smallint, but a name or email address has no inherent limit. Cherry Chevapravatdumrong will be disappointed their name is truncated because the schema designer decided names are varchar(20). Constraints on text fields are typically subjective business rules, liable to change at any time, and should not be hard coded into the schema. Enforce them via validations which will give better feedback and are a simple code change.
In general, avoid prematurely optimizing your database for disk space. Disk space is rarely your most pressing database issue, and it's rarely because you use an integer (4 bytes) instead of a smallint (2 bytes). Stingy schemas restrict your app's ability to grow and adapt to changing circumstances, "the worst future of your design". For example, using integer IDs instead of bigints because you will "never" have more than 2 billion rows... until you do, then it's a nightmare to update all the references.
Database size issues will be things like storing large files in the database when they should be in ActiveStorage. Or redundant data because of a lack of normalization. Or using a string when an enum (integer) would do. Or storing JSON as text. Or too many indexes. It's only when you get into tens and hundreds of millions of rows that different integer sizes become relevant.
Thanks for sharing valuable information ☺️. Though on TXT column I will verify your suggestions. But 'int' vs 'smallint' vs 'bigint' everyone can take a thoughtful decision many times we really don't need 'int' for small tables like roles, permissions, status etc. I do agree to use higher range for tables that are definitely going to grow.
Awesome!
Just found my love in Ruby some months ago and trying to improve my knowledge. Getting one day a full rubyist ❤️