Your Web News in One Place

Help Webnuz

Referal links:

Sign up for GreenGeeks web hosting
September 1, 2019 07:07 pm GMT

Refactoringoops, Ive been doing it wrong.

Refactoringoops, Ive been doing it wrong.

Welcome to my intervention. Im a refactoring addict and Im not afraid to admit it, but theres only one problem: Ive been doing it backward. You see, what Ive been doing could be more accurately described as premature code abstraction.

We all know about refactoring. If youve read even a single programming book, or if you spend much time on Medium, youll have heard all about it. Its an important concept that keeps code understandable, maintainable, and extensible.

At least thats what everyone tells me.

So why has refactoring not been accomplishing what I was hoping?

As I wrote my most recent library, I took some time to reflect on the evolution of my code. I realized that before I had a fully working product and before I had an ideal output in my unit tests, I had refactored my code into interfaces that I wasnt even sure I would need. I had moved code around, made it extensible, made it reusable, but why? Was that code going to give me the final output I needed? I didnt know yet.

Everything worked out in the end, but was my code more complicated than it needed to be? I believe so.

Principles Over Purpose

Have you heard of SOLID principles? I try to follow them closely. Every function that I write aims to have a single responsibility. My classes and factories aim to be open for extension while discouraging modification. I also try not to depend directly on too many things, so instead, I accept dependencies as arguments in functions and classes.

Does that like a recipe for good code? I think it does. The problem occurs when my code focuses on being SOLID, or pure, rather than on accomplishing what it was born to do. The problem occurs when I put principles over purpose.

For example, Ive been so focused on making sure my unit tests have no expensive IO (input and output). Ive occasionally had to go back and fix code that was wrong due to my incorrectly mocked dependencies.

So, whats the solution?

Remember that reflection I mentioned earlier? It reminded me of the mantra, Make it work, make it right, make it fast. Ive realized Ive been going out of order. Ive been making it right, making it fast, then making it work!

Make It Work

As Ive begun to write more it has become clear that good writing doesnt just happen. First I have to get all my thoughts down on the page. I have to see where my thoughts take me. Then I must shape them into some sort of semi-coherent and non-rambling version of what just spilled out.

The same thing can happen with code.

Get it all out there into that function. At first dont worry too much about naming, single responsibility, or being extensible youll address that once your function is working. To be clear, you wont be writing your whole application like this, just one small piece.

Once youve got the output you are looking for (youve got unit tests to prove that the code is correct, right?) begin refactoring, but dont go too far too fast! For now, stick with refactoring strategies that are in the category of proper naming, functions doing only one thing, and the avoidance of mutation; dont immediately start making extensible or reusable classes and factories until you have identified a repeating pattern.

At this point, it makes sense to use any refactoring that has a logical benefit. This means refactoring with the purpose of the code being understood, or the code being reliable.

Consider postponing refactoring with patterns that are only useful in certain scenarios.

Youll want to save those until you have a reason.

Have A Reason

Having SOLID code is not a reason. Having functional or pure code is not a reason.

Why do we make our code extensible? So that similar, but not identical, functionality can branch off of base logic.

Why do we invert dependencies? So that the business logic can be used by multiple implementations.

Hopefully, you see where I am going with this. Some refactoring stands on its own. For example, refactoring the name of a variable to become more accurate will always make sense. Its merit is inherent. Refactoring a function to be pure usually makes sense because side-effects can cause unforeseen issues. That's a valid reason.

Its best practice to use dependency inversion is not a reason. Good code is extensible is not a reason. What if I only have a couple of never-changing dependencies? Do I still need dependency inversion? Perhaps not yet. What if nothing needs to extend my code and I have no plans for anything to do so? Should my code increase its complexity just to check off this box? No!

Take a look at the following example.

// not extensiblefunction getUser() {  return {    name: 'Justin',    email: '[email protected]'  }}// Extensibleclass User {  constructor(options = {}) {    this.userData = options  }  get() {    return this.userData  }  set(key, value) {    this.userData[key] = value  }}

Which do you prefer? Which do you naturally tend to write first? Of course, the User class is far more extensible because it can handle more than just name and email. It can also be extended by a child class, maybe a SuperUser, that will have many more methods but still uses the classic get() and set() methods.

Still, that User class may be complete overkill, and now your code is more complicated than it will ever need to be.

My advice is to stick with the simplest possible pattern.

Order Of Complexity

And now, if youll allow it, Im going to make something up! I call it the order of complexity and it helps me when I make refactoring decisions. It looks like this:

Whenever I decide how to organize functionality, I refer to the list. I choose the highest possible choice that will suffice for my implementation. I dont choose again until it simply will not work. Sometimes performance will affect this choice, but not often.

Usually, I find that Ill put something in an object instead of a simpler constant variable. Or I created a factory when I only require a function.

This list keeps me grounded. It prevents me from prematurely refactoring.

Balance

I recently heard that if you say in a meeting, its all about finding balance, everyone will nod their head at your meaningless comment like youve said something profound. Ive got to give it a try soon.

Here, though, I think balance is important. As programmers, we have to balance code quality, performance, maintainability, with the good old-fashioned need to get things done.

We have to be vigilant and make sure both needs stay in their correct place. Our code cant be maintainable if it doesnt work correctly. On the other hand, its hard to make bad code work correctly.

Still, code may be refactored, but what if its been refactored past the point of what is useful? These are important questions to keep in mind.

Next time you write your code, please, refactor! But also, maybe dont?

Hi, Im Justin Fuller. Im so glad you read my post! I need to let you know that everything Ive written here is my own opinion and is not intended to represent my employer in any way. All code samples are my own and are completely unrelated to my employer's code.

Id also love to hear from you, please feel free to connect with me on LinkedIn, Github, or Twitter. Thanks again for reading!


Original Link: https://dev.to/justindfuller/refactoring-oops-i-ve-been-doing-it-wrong-33ge

Share this article:    Share on Facebook
View Full Article

Dev To

An online community for sharing and discovering great ideas, having debates, and making friends

More About this Source Visit Dev To