Crypto

Good programmers are always refactive

“Always be closed.”

The sales mantra with a hard nose of GLENGARRY GLEN ROSS has become a stenography for relentless improvement. In the same spirit (but with much less dejt), a good engineer should Always be refactoring. Here is why.

To clean or not clean

It is generally agreed that clean code is easier to understand, cheaper to maintain and much more extensible. Basically, refactoring consists in cleaning the existing code without modifying its perceived features.

A common objection to refactoring is that there is no time to do so. The teams see him as a luxury. The relentless reader for new features simply does not allow refactoring, especially because the refactoring does not change anything from an external point of view. This can be difficult to sell product landlord.

But the own code makes your life easier. The clean code is paid for itself and slows down the accumulation of technical debt.

So slip it.

That's right. I suggest a little subterfuge. A little bad orientation even. Why not clean a few things in each traction request?

Vigilant

A good engineer has a vision of the place where the code base should go. It could take a while to get there, but you know the disorderly parts, the backlog, the roadmap, the technical debt, the safety holes and the documentation gaps.

As you do your regular development of functionalities, be looking for refactorings that can advance your wider program. As one of these detectives of hyper-observant television emissions on the search for a crime scene, pay particular attention to all the code you fall.

When you notice a smell of code or something slightly near your current orientation, the alarm ringtones should be triggered: “Do not let this opportunity pass!” Take a few minutes and repair it now, before the inspiration is done.

Don't say it's not your problem. Do not pretend that you can see it. Just roll up your sleeves and do it.

A simple example

Refactoring does not necessarily mean changing thousands of code lines. It can be just a little piece of code here and there. These small micro-refeactorizations add up over time. In fact, the more you are used to constant cleaning, the less you will have to do major refactorings in the future.

To illustrate micro-refeactoring, let's look at an example of Golang “extract method”.

Suppose you are attacking a feature that requires knowing how many days it has been from the last connected user. You notice an existing method that determines if a user is dormant using the same information:

func IsDormant(user User, asOf time.Time) bool {
  days := int(asOf.Sub(user.LastLogin).Hours() / 24)
  return days >= 8
}

You want to reuse the latest connection calculation instead of copying it and paste it, so you take the internal variable, daysand extract it in a separate method, DaysSinceLastLogin::

func IsDormant(user User, asOf time.Time) bool {
  return DaysSinceLastLogin(user, asOf) >= 8
}

func DaysSinceLastLogin(user User, asOf time.Time) int {
  return int(asOf.Sub(user.LastLogin).Hours() / 24)
}

This allows you to test and reuse the last connection logic. If you write a unit test, you will find a logging box that should be managed (potential panic if a user has never connected).

This also facilitates future improvements. For example, it could be logical to do IsDormant And DaysSinceLastLogin Methods on User structure instead of being independent. Likewise, consider replacing the hard coded value 8 with something more descriptive as DormantDaysThreshold.

This is a simple example, just a few lines of code. But it's beauty. It shows that a small refactoring can add value by revealing a potential bug and pointing to future improvements.

To find out more about the refactoring profession and see all the small ways to improve your code, consult online resources such as the Martin Fowler book refactor or the refactoring guru.

A state of mind of refactorization

Having a vision of your code base is easy. Knowing how to get it is more difficult. Identifying the refactoring opportunities takes practice. One way to start is to consider the categories of refactoring necessary to transform your code.

Here are some refactor themes common to which think:

🧹 Delete duplication– collapse the copy and glued logic into a single function.

🧰 Extract the utility or the shared library– Move the common logic outside the implementations by service. Normalize integrations (for example, all services use the same Auth customer).

🧱 Add a common infrastructure– Introduce observability (journalization, tracing, metrics). Centralize the management of errors or attempts.

⚙️ Make the code more testable– Cut the logic closely coupled. Extract the interfaces so that dependencies can be mocked or truncated.

🔄 Prepare for a functionality change– flatten the complex or logical conditions nested. Reorganize files or classes to adapt to new responsibilities.

🏗️ Support a new architecture– Break a monolith. Introduce events focused on events, an injection of dependence or asynchronous treatment.

🚦 Reduce cognitive load– Divide giant files or classes into logical and targeted units.

🔐 Improve safety or compliance– Centralize the logic of access control. REFACTOR insecurity models (for example, SQL manual concatenation → Parameted requests).

🚀 Improve performance– Replace naive algorithms with optimized algorithms. Reduce the unsubscribe of memory or unnecessary calculation in hot paths.

👥 Facilitate integration or transfer– Refactor code that only “pat” includes something readable by team. Present the documents / comments / test cover in the context of structural cleaning.

The 20%

Some may oppose that all refactoring cannot be slipped. I will give you this. Let us apply the 80-20 rule and stipulate that 20% of the refactorings must be carried out on assembly and the top.

These should be easier to sell, however, because when you arrive at the point where you need a complete and honest refactor kindly, it will certainly be at the service of a wider goal.

For example, before working on a performance improvement ticket, you must first add tracing and measurements so that you can develop a finer image of current performance and identify hot spots.

Refactoring begins with tests

It is probably obvious, but I must emphasize that the refactoring is much easier (and less trying for the nerves) if your code base has a suite of tests which accompanies it before and after the refactoring. Having tests is also precious for a lot of other reasons. If your project has no solid tests, first add some tests to unlock future refactorings.

Code review considerations

My advice in this article goes against the standard guidelines so as not to mix the work of refactoring and the regular development of functionalities. The objection is that it is more difficult for the team to make code notices if unrelated changes are included. This is a right point. During the refactoring during the work of the characteristics, keep it small and (ideally) linked to the main thrust of change.

A good basic rule for any traction request is to limit it to 500 lines of code changes. A second basic rule is that auxiliary refactor changes should not exceed 20% of PR.

When you have dedicated refactor refactoring, keep it concentrated and around this size. Sometimes a PR must be more than 500 lines of code, especially when you work on a refector at the agent's scale. In these cases, coordinate with your colleagues to prepare them for change and to minimize merger conflicts.

Count each commitment

Whenever you touch the code base, you have the choice: leave it a little better or leave it a little worse. Refactoring should not be a big event. Small improvements (extraction methods, rename confusing variables, separate long methods, etc.) add up over time. They prevent technical debt from accumulating and making changes easier and safer.

If you see something, repair something.

Always be refactoring!

Related Articles

Leave a Reply

Your email address will not be published. Required fields are marked *

Back to top button