📜 ⬆️ ⬇️

Refactoring does not happen much

Hi, Habr! I present to you the translation of the article " Refactoring - oops, I've been doing it backwards " by Justin Fuller (Justin Fuller).


I am very dependent on refactoring, and I am not afraid to admit it, but there is only one problem: I always did it back to front. You see, what I was doing could be more accurately described as a premature code abstraction.
We all know about refactoring. If you have read at least one book on programming or have been sitting on Medium for a long time, you have probably heard about it. This is an important concept that makes the code understandable, maintainable and extensible.
So why did refactoring fail my expectations?

When I wrote my last library, it took me a while to think about the evolution of my code. I realized that before I had a fully working product, and before I had perfect results from my unit tests, I converted my code into an interface, although I wasn’t even sure if I would need it. I moved the code, made it extensible, reusable, but why? Will this code give me the final result I need? I didn't know that yet.

In the end, everything worked out, but was my code more complex than necessary? I think yes.

Principle of Principles over Purpose


Have you heard of SOLID principles ? I try to watch them closely. Every function I write is focused on the principle of sole responsibility . My classes tend to be open to expansion , ignoring modifications. I also try not to depend directly on too many things, so instead I accept dependencies as arguments in functions and classes.

Is this a good code recipe? I think yes. The problem arises when my code focuses on conforming to SOLID principles, rather than executing what it was created for. The problem comes when I put the principles above the goal.

Remember my thinking at the beginning? It reminded me of a mantra: “Make it work, do it right, do it quickly . I realized that I did not follow this order. I did everything right, quickly, and then I did it so that it worked!

Make it work


When I started writing more articles on Medium, it became clear that a good writing style did not come right away. First I have to put all my thoughts on the page. I have to see where these thoughts lead me. Then I have to turn them into some kind of semi-cohesive and illegible version of what has just spilled out.

The same thing can happen with the code.

At first, you should not worry too much about naming, sole responsibility or extension - you will solve this problem as soon as your function works. You are not going to write the whole application at once, only this one little piece.


As soon as you get the result you were looking for (you have unit tests to prove that the code is correct), start refactoring, but don't go too far! Stick to refactoring strategies that fall into the category of proper naming, functions that perform only one task, and avoid changes; do not immediately start building extensible or reusable classes until you define a duplicate template.

Consider deferring refactoring with templates that are only useful in certain scenarios. You will want to keep them until you have a reason.

Have reason to refactor


The presence of a SOLID code is not the cause. The presence of a functional or pure code is also not the cause.
Why do we make our code extensible? Thus, similar, but not quite the same functionality can deviate from the basic logic.

Why do we invert dependencies? In order that the business logic could be used by several implementations.

I hope you understand where I lead. Some refactoring is needed on its own. For example, refactoring a variable name to become more accurate will always make sense. His merit is inalienable. Transferring a function to a pure state usually makes sense, since side effects can cause unforeseen problems. All this causes.

“It’s considered best to use dependency inversion” is not the reason. “Good code is extensible code” is also not the reason. What if I only have a pair of unchanged dependencies? Do I still need dependency inversion? Not yet. What if nothing is needed to extend my code, and I don’t plan to do that at all? Do I have to complicate my code just to check this box? Not!

Look at the following example.

// not extensible function getUser() { return { name: 'Justin', email: 'justinfuller@email.com' } } // Extensible class User { constructor(options = {}) { this.userData = options } get() { return this.userData } set(key, value) { this.userData[key] = value } } 

What do you prefer? What do you usually write in the first place? Of course, the User class is much more extensible, because it can handle not only the name and email. It can also be expanded by a child class, maybe SuperUser , which will have many more methods, but still uses the classic get() and set() methods.

However, the User class may be redundant, and your code may become much more complicated than it ever needs.

My advice - stick to the simplest pattern.

Complexity order


And now, with your permission, I'm going to come up with something. I call this the complexity order, and that helps me when I make refactoring decisions. Here's what it looks like:


Whenever I decide how to organize the functionality, I refer to this list. I will not choose again until it just starts working. Sometimes performance affects this choice, but not so often.

Usually I put something in an object instead of a simple constant variable. This list keeps me in control and prevents from premature refactoring.

Balance


I recently heard that if you say at a meeting, “in fact, it all comes down to finding the right balance,” everyone will nod their head at your meaningless comment, as if you said something clever.

However, I think the balance is still important. As programmers, we need to balance code quality, performance, and serviceability with the need to get things done.

We must be vigilant and ensure that both needs remain in place. Our code cannot be serviced unless it works correctly. On the other hand, it’s hard to make bad code work properly.

The next time you want to refactor your code, think, is it worth it?

Source: https://habr.com/ru/post/437708/