Refactoring essentially means improving your existing code without changing its functionality.
It’s all about code quality and optimisation – not product redesign. Users never see the changes. So why do it?
Because ultimately, refactoring can prevent your app from generating huge upkeep costs and save you money – making your business more successful.
This article covers:
- Ruby on Rails and refactoring – why do it?
- How to verify the quality of a development agency using Ruby on Rails
- First three things to do after receiving a new Rails project
Refactoring Ruby on Rails – why do it?
The basic aim behind refactoring is as follows: to fix problems in the code but keep its current functionality.
You modify and restructure what you or other developers on the team have written, but the product stays more or less the same. Refactoring is not about improving users’ interactions with the product – it's about the developers’ interactions with the codebase. Refactoring makes the code more readable to the current (and, importantly, future) developers working on it. It’s then easier – and cheaper – for them to continue developing and maintaining the product.
A ‘refactor’ means a single change in the code. To make or do a refactor means to introduce a particular fix which, in accordance with the above definition, enhances the code’s quality.
Here are some extra reasons to do it, if you weren’t convinced already.
1. Scout’s Rule
If you think about it, making errors when coding is inevitable. Maybe there are geniuses out there who always write clean and flawless code, but if so, they are rare. You can’t expect super-human performance from your development team, and you have to accept that their mistakes will be part and parcel of the development process.
Just like refactoring, fixing those mistakes is a part of the process.
If you see a code fragment that could have been written better, improve it. Immediately. If you don’t do it often enough, your product will suffer as current risks lead to future problems.
2. Improved Understanding of the Product
Refactoring helps developers understand how the product works and what it’s supposed to do.
They are more engaged in the project, can easily delegate tasks to other developers (who should now have no trouble reading and working with more understandable code), and can take full advantage of others’ work thanks to, for instance, clearer methods. It’s best to put everything a developer needs to know into the code, so comments and remembering a lot of information become unnecessary.
3. Better Information Architecture
Clean code means that developers can easily see which fragments hold the most business value.
Actually, clean code means developers can more easily spot separate elements in the code. You might think it should be obvious from the beginning which functionalities will matter most, but that’s a fallacy. It’s something you need to learn anew for every product you work on, because every product is different.
4. Lowering Costs
Projects get really expensive when you need to fix legacy code months or years down the line.
With regular refactoring, developers find bugs more easily, which means a smaller QA budget and fewer hours spent on scrutinising the code by developers themselves. There will be no need to constantly go back and fix something that has become a blocker. By preventing problems from occurring rather than reacting to them, you will be able to achieve faster development. And obviously, the development work is the most expensive part of building a digital product.
5. Experts Say You Should Do It
Martin Fowler is a proponent of refactoring, and he knows what he’s talking about, because he’s been doing this for years.
Fowler and other experts agree that building a product without any refactoring is a massive risk. Here, have some quotes:
- “I’d always been inclined to clean code, but I’d never considered it to be that important.” – Martin Fowler
- “When you feel the need to write a comment, first try to refactor the code so that any comment becomes superfluous” – Martin Fowler
- “Almost all the time the problems come from methods that are too long” – Martin Fowler
- “If extracting (a method) improves the clarity, do it, even if the name is longer than the code you have extracted” – Martin Fowler
- “It is not enough for code to work” – Robert C. Martin (Uncle Bob)
- “So if you want to go fast, if you want to get done quickly, if you want your code to be easy to write, make it easy to read.” – Robert C. Martin (Uncle Bob)
- “Clean code always looks like it was written by someone who cares.” – Robert C. Martin (Uncle Bob)
- “Of course bad code can be cleaned up. But it’s very expensive.” – Robert C. Martin (Uncle Bob)
- "No matter how slow you are writing clean code, you will always be slower if you make a mess." – Robert C. Martin (Uncle Bob)
- “Don't make more versions of your source code. Rather than add more code bases, fix the underlying design problem that is preventing you from running from a single code base.” – Kent Beck
- “Any fool can write code that a computer can understand. Good programmers write code that humans can understand.” – Martin Fowler
Quick Guide to Ruby on Rails Refactoring
All right, now that we’ve established that your project needs regular refactoring, how should you go about it?
Before you even start thinking about it, make sure the code under scrutiny has been tested. Extensively. Never refactor before you’ve written tests, that’s just asking for trouble. I mean it. Never. If you have no tests, write them. Then come back to the idea of refactoring.
Where to Refactor
Here’s a list of warning signs that almost always mean that particular fragment of code needs a refactor and some basic guidelines on what you can do with them:
- Long methods: nobody likes to even touch methods that are 300 lines of code long. Write short, specific and understandable ones. They will be easier to test, explain and change in case that becomes necessary.
- Huge classes: avoid them if you can. It’s easier to deal with code that contains 50 classes, 200 lines of code each, than code with 5 classes, 2000 lines of code each.
- Code repetitions: if you see basically the same code in several different places, give some thought to the structure of your application. It might have some kinks that need ironing out.
- Long parameter lists: if an action or method takes 11 parameters, there has to be something wrong with it.
- Strange dependencies: if a change you make in one part of the code forces you to make changes in another 5 places, your code is not good code.
- Dozens of variables: if there’s a fragment of code where a lot of variables are created and handled, figure out why, and if there’s no good reason for it, refactor. A method with 15 local variables is the opposite of easy to understand.
- Weird code: developers like to show off sometimes. Or metaprogram. If you spot really strange solutions that are super hard to understand, try to simplify them.
At Netguru, we enjoy using RoR so we’ve picked up a few tricks over the years and we are always happy to share our knowledge.
Refactoring is a wonderful tool, as long as it’s done well.
In some situations and without the necessary experience, it may do more harm than good. If you aren’t sure that refactoring will bring business value to your product, don’t do it.
Stakeholders will naturally view refactoring as a waste of time. They will usually be wrong, but it’s important for the product owner to establish what’s most important for the project at any given time. Should we focus on time to market or future refactoring debt? The latter may seem like a problem that can be taken care of later, but many people who have thought so, have suffered by adopting this approach.
Finally, refactoring should always have a clear goal: improving the code behind one functionality. If it’s about a very general value, such as efficiency, you will simply never reach your goal. It’s too big a task for a single refactor, and it can be a waste of resources. Moreover, without a clearly defined goal, you won’t even be able to tell whether you’ve achieved it or not.
Refactoring: The good and the bad
We’ve witnessed refactors doing wonders for projects, and we’ve witnessed refactors going really, really wrong.
One example of the former is a project that involved generating reports from questionnaires. It used a really old gem that had had no support for 6 years. It took care of the whole functionality, but seriously complicated the code, which means that adding features to the product was pretty much a heroic feat. And expensive. We talked to the client and did a refactor, which resulted in dumping the prehistoric gem and building a custom solution with the same functionality. The database shrank from 15 to only 2 tables, a critical component of the app started working more quickly, and the behaviour of the whole product became more predictable. The code was, of course, easier and cheaper to maintain and develop further.
A less cheerful example is a client who wanted a refactoring for its own sake. The whole process wasn’t well thought out, we had too little information and instead of completing the refactor in 3 months, as we estimated, we laboured over it for half a year. During that time, no new code was produced, which obviously set the project back quite a bit. Eventually, we managed to get the development work going at full speed and the project is doing quite well, but doing the refactor was a waste of time and resources.
These stories show you that, while refactoring is crucial and should be an integral part of your process, there must a time and place for it. Refactoring comes with a risk that can be mitigated by an experienced team. So, if you are thinking about refactoring your project, feel free to contact us about any questions or doubts you might have, and we will be happy to share our knowledge and experience with you.
How to verify the quality of a development agency using Ruby on Rails
A lot of businesses decide to start a collaboration with an external agency to help them optimize their Ruby on Rails application.
As using remote support is becoming more and more popular in different businesses, it is crucial for stakeholders to understand both the opportunities and the potential risks of such an approach, and to be able to verify the skill and experience level of a software development agency.
A Single Developer is Not the Same as an Agency
When hiring an external Ruby on Rails development team, you may not realise that you aren’t just getting people who will build your product.
You’re not only hiring people – you’re also tapping into the whole organisation behind them, their shared knowledge, and the processes developed collectively by the company.
That’s a lot of value for both your product and your company.
Battle Tested Development Process
When working with an agency, pay attention to their processes – do this for two reasons.
Firstly, you want to make sure they know what they’re doing, and they are well-organised. Secondly, if you’re a startup, or you have just embarked on your business journey, you can learn a lot from a mature company and pick up their tools and processes instead of reinventing the wheel.
A professional external development team should be Agile. Don’t worry about applying the methodology to the letter, but you should see clearly defined practices that align with the Agile ideology.
Next is communication, which can make or break a good business relationship. Plenty of communication channels should be available to you so that you can reach your development team whenever you need to. Slack, Google Hangouts, email and a regular meeting schedule are the basics.
At Netguru, we strive to be completely transparent with clients – we share our style guide, our internal documentation, and code review practices, because we believe in sharing our knowledge and building trust.
Just because another company doesn’t do the same doesn’t mean they are doing something wrong – you simply have to ask about the processes and practices when choosing an agency and make sure you’re comfortable with how they do things.
Top Tools and Practices
Expect and require only the top tools from your development agency – this is a big part of why you’re hiring them in the first place – to avoid costs of providing an internal team with tools, equipment, office space, etc.
Their practices have taken the agency years to implement and master, and you get to skip the hard part and get to access them right away.
We’ve put together a list of some of the tools we use at Netguru – they are not the only existing options, but they certainly are some of the best ones.
- Github: it contains our code repositories. We take advantage of all its powers and have made Git our default distributed version control system.
- Circle CI: it’s our default continuous integration tool. It tests all new changes to the code and, depending on results, deploys them to the staging or production environment. It also performs security checks.
- Jira: our default task and issue tracker, perfectly crafted for Agile needs.
- Rollbar: we strive to maintain exceptionally high code quality, but sometimes something unexpected happens on the server. To catch such exceptions, we use Rollbar. It tracks errors so that we can reproduce them and quickly fix them.
- CodeClimate: it's our default choice for maintaining code quality. It measures our code against various metrics such as simplicity and code coverage
- Slack notify: it’s our go-to communication tool, so it was only natural to try and get more out of it. We have connected notifications from many other tools, and now, we know immediately when something happens on production servers (notification emails serve as a backup).
- Security: In our projects, we use `bundler-audit` and `brakeman` gems by default to spot all security issues as fast as possible (security checks are performed each time in CircleCI). It’s really important to keep all libraries up to date and spot all potential security pitfalls.
The Hidden Value of Good Ruby on Rails Agency
Measuring the value of such tools in US dollars is actually an easy task. Here are some basic calculations, though they don’t include all of our tools.
Team account: Starting at $25 / month which includes your first 5 users.
At least 4 containers (x4 parallel).
1-10 users cloud hosting.
Bootstrap variant for small teams.
1 user ($16.67 USD per user).
4 users calculated, though there might be more ($8 per user).
Heroku 2x - 1 dyno.
Total monthly cost:
This might not seem like a lot, but keep in mind that most projects are developed over at least several months, and that this is only part of the hidden value offered by every development team.
If you hire your own developers, you will have to cover similar costs for a somewhat lower value, because you’ll have to develop the processes and practices that an external team would bring to your project.
It’s common knowledge that working with an external software development agency is the cheaper option.
You don’t have to provide office space, equipment, and testing equipment – basically none of the material stuff necessary for building an app. You can also forget about recruitment costs. You don’t need to worry about software and a test infrastructure. You can skip trying to gather the exact set of skills necessary for your project – a good agency will offer Devops, backend and frontend development, UI and UX design, as well as product and graphic design.
All in all, it often makes sense not to invest in your own team before you even have proof of concept for your product.
First Three Things to Do after Receiving a New Rails Project
Going it alone?
If your developer team have received a new Ruby on Rails project here are some tips from our Senior RoR developer Jakub Naliwajek:
First of all, grab pen and paper. I’m not kidding.
At the end of the day, you may toss these notes in the trash but for now your notebook is your most valuable tool. Ready?
Go through all the points below – if you encounter something that doesn't meet the 'Rails way' then write it down.
Step 1: Read the README
It sounds obvious, but bear with me – more obviousness coming your way in a second.
Every software project should have a well-documented README file with a detailed description of the codebase and the application's business model. If your new project lacks one, then – guess what – write it down. TO-DO: create a good README from these notes.
If your README is good, then don’t get caught in the trap of reading it all right now. Read the introduction. Maybe skim through the general sections about architecture, patterns and third-party services. Skip detailed and long paragraphs. You will return here later.
Step 2: Browse the Directory Structure
Again, this is obvious – told you. There is no need to open your editor yet. Just go to your project directory and execute:
This should give you a long list of all the folders, subfolders and files in the project. Here are some questions you can ask yourself:
Do You Recognise All Names?
Maybe there is a folder called app/policies that you don't recognise? Something that is done in a non-standard Rails way? Are there more directories in the root of the project itself? Maybe a folder with assets actually keeps a dozen front-end applications?
Remember to note anything suspicious, weird, non-standard, longer or shorter than usual, and so on. Write it all down.
Is Any Folder Particularly Full of Files?
If your assets/images directory has a lot of cat pictures, it's a good indicator of possible issues. The same goes for many other directories. Even a shallow in-depth /lib directory with a large number of files may indicate possible problems for you if you ever need to modify those files. It would be a great place to mark for future refactoring.
Step 3: Browse the Gemfile
This is what I like the most. Dive right into your Gemfile and see what gems and technologies your new application uses. Even if the README from the first step is missing, you should find a lot of answers here.
Visit the Homepage or Browse the Source of Every Gem
Go through them one by one. Presumably, each gem will have its own repository which you can visit. Skim each README you find. You don't have to learn everything now, but it's important you know about the possibilities.
Keep Note of Locked Versions
If your Devise version is locked at 4.0.1, you should check why. Browse the git history and read the commits' messages. If you are lucky, maybe previous developers have left a clue there. Otherwise, search through the issue tracker and the gem's repository to find out why the specific version is so important.
A note about patch versions: according to semantic versioning, patch versions can be updated without the need to worry about backward-compatibility. So, if you find your gem in version 1.0.1 and the newest version is 1.0.3, it's fair to assume you can update it right away.
Grouping gems into groups such as production, development, test, and doc is a standard Rails practice. Any other group is a worthy anomaly to notice, though. No developer would create one if there was no purpose for its existence. If you find an extra group, grep your source files for occurrences and see what's the deal.
Read the Schema
Before we jump into reading models’ source code, it's a good idea to browse the contents of db/schema.rb. Familiarise with the existing table names and attributes. Other important things to look for, depending on your database engine, may include:
- Enabled extensions,
- Default values,
- Missing indexes for relations,
- Existence of uniqueness indexes,
- Attributes of a hstore type,
- PostGIS attributes,
- date vs datetime attributes,
- SQL views.
Ah, the models. Often fat and responsible for everything, at least when you're just starting a refactor job. A place with a lot of answers, e.g.:
You can, of course, see that in db/schema.rb, but looking at all those belongs_to and has_many keywords seems faster – at least to me. But there is an even better way to learn all the relations.
Just use gems such as Rails ERD which can graph all your relations and present them in a single PDF file.
If you need help implementing any of the advice in this article learn more about our veteran Ruby on Rails team today.
This article was originally published on October 3rd, 2017 and was updated with new information added.
More posts by this author