Today I'd like to tell you a story. I call this the story of the refactor, or how I ended up breaking (and then fixing) one functionality while trying to add another functionality.
Last week I started working with a new team (same company, but different part of the product), and my first ticket is a doozy. On the surface, it seems simple - adding a new functionality to an existing feature. To make it even easier ... this functionality already exists elsewhere in the app. I figured it would be fairly easy, at least at the beginning - find the component where the functionality already exists, then copy the code for the functionality into the feature where it needs to be. I tracked down what code controlled the feature I was working with and where the functionality I was adding existed in a different feature, and it turns out that functionality had its own component, so I started by importing the component. And that's where things stopped being simple.
The component that controls this functionality received a number of props. Those props were passed down through several levels of components ... and I got lost trying to trace it. Our team tech lead had offered to help out, so we took some time to go through and figure out a good approach. We got a little confused trying to trace everything, but eventually we found where the props were originally coming from. And it seemed like there was no easy way to get them to where we needed the functionality to be added.
It seemed like some serious refactoring would need to happen. We discussed some ideas of what needed to be done, and then I decided to spend some time moving things around to figure out the best way to add this new functionality. I even floated the idea of writing something from scratch and fitting the existing functionality into that, but it seemed like that might be too much effort and refactoring was a better way to go. And so, I opened my code editor and began to work.
I moved some things. I got the new functionality working, but some of the existing functionality was not working. So then I tried moving other things. I tried creating new components and then deleted those new components. I got to the point where everything but the functionality that I moved around the most was working, and eventually I got that working too. But even once I had the functionality working (and only a few cosmetic changes to make), I still knew there was more to be done.
With all of the functionality working, the next step is to refactor my refactor. I plan to start by going through all of the files I've touched and deleting any props or functions that are not being used anymore. I also want to separate some blocks of code into their own components, as I know that would improve readability. I may even try to simplify some of the functions that are used to validate form data, as that was one of the areas where I ran into a lot of difficulty getting functionality to work.
The last major work that needs to be done is fixing the tests I broke (and writing new tests for the new functionality). Unfortunately, our current tests are testing implementation details, not just functionality, so in changing the implementation details, I broke a lot of tests. We are in the process of converting the tests in our codebase to use a library that focuses on testing user behavior, not implementation details, but the tests for the code I was working on have not yet been converted. I'm considering rewriting the tests to no longer test implementation details, but I'm not sure if that's outside the scope of the ticket, so I will discuss it with one of my teammates and get his take on the best way to approach the tests.
All of the functionality may be working, but there's still work to be done on my refactor. I'm hoping that with all of my work to refactor I end up deleting more code than I added (which would be really cool when adding functionality), but we'll see how it goes. That's a secondary goal - the primary goal is still to have all of the functionality done and the code written in an understandable and readable way.
When faced with existing code and a task that doesn't seem easy to fit into the code, it can be hard to figure out where to get started. Sometimes it's easier to just start the new task from scratch and then fit it into the existing code, but often it's less complex to just refactor the existing code. With this particular task, I had a hard time figuring out where to get started with the refactor, but the great part about working with a team is that I had a teammate who was available to help me figure it out. Refactoring code can be tough, but it's a great way to make sure your code is doing what it's expected to do (and only what it's expected to do), and as a new person on this team, I appreciated the opportunity to work on a ticket that exposed me to more than just the functionality I was adding.