My first “real” day job as a software developer was for a large and well-established company. When I started the software teams followed the Scrum form of Agile.
I strongly dislike some of the terminology used in Scrum, the two main offenders are “velocity” and “sprint”.
Poor naming aside, the general approach to software work in Scrum, and many other capital-A Agile methodologies, is to treat the work as a never-ending stream of tickets to be completed over time.
This, I suppose, is a fairly intuitive way to manage a list of feature changes. However, it tends to ignore the fact that software engineering is often as much about discovery as it is about implementation.
In common capital-A Agile methodologies, the tendency is to equate one ticket (or card, or sticky, or story) with the code required to implement that behaviour. In other words, these methodologies tend to discourage writing code that is either not part of the feature, or will not remain in the code that makes it to production.
There are benefits to being able to write code outside the bounds of a ticket. Two examples are: An investigation before implementation starts (spikes) or cleanup/improvements of code encountered while writing the feature (I'm calling this a warm down).
A spike is a quick-and-dirty implementation for learning and experimentation. Hard-coded values, ignored error conditions, pre-seeded data, basically whatever it takes to get something minimal functioning to see what's possible, or desirable, before spending the time to actually implement it properly.
The company mentioned earlier transitioned to “learning first product development” during my time there. Basecamp uses the concept of a hill chart for a similar purpose: To decouple learning/investigation/experimentation time from implementation time.
Code written as part of a ‘spike’ could be reused, but it can just as easily be thrown away. Once the developer is happy with the API, or the UI flow is ironed out, the developer can use the knowledge gained to implement the feature. They may reuse some of this ‘spiked’ code, they may not. The idea is to get to a state where there are no more big unknowns about the feature, and it is just a matter of doing the work to implement it.
Even less common than spikes are companies that allow some form of “warm down”, that is, work carried out beyond the scope of the current ticket.
It's not uncommon to encounter bugs, inefficiencies, or just places where the code could be cleaned up while implementing a feature. In typical Agile shops, these findings are either ignored or a ticket is created and added to the backlog, in the “one day when there's time” priority near the bottom.
Allowing for a warm down gives a little bit of “breathing room” between tickets. This doesn't even need to be an officially stipulated time period, so long as engineers understand that if they see things to fix they are free to do so as part of their current feature work.
Of course, engineers shouldn't bite off more than they can chew, but this gives them the freedom to take a short break from feature work. It also allows them to fix things while they still have the context in their heads and is a great time to take care of small technical debt buildup.
There are many benefits to this - developers get to have some autonomy over their work, they get to touch parts of the codebase that they may not otherwise change, reduced technical debt, etc etc.
When applying a process to software development we have to remember one thing - the process is meant to reflect how we work, not impose the way we wish we worked. If we treat development as a series of concrete features to be implemented, we'll undoubtedly face incorrect estimates and slipped schedules. Software development has a lot of unknowns, a good process should respect that allow engineers some flexibility to find answers and care for the codebase as a whole. Teams and companies, which do this will undoubtedly have more maintainable codebases as a result.