Software Modernization Is a Habit, Not a Project
I hear the same three sentences in client conversations, in different industries, almost every week.
"We want to modernize, but the daily business always gets in the way."
"The system is so screwed, there is no way around a big bang."
"Technical debt is growing faster than we can reduce it."
These look like three different problems. They are not. They are three symptoms of the same belief: that modernization is something you do separately from building software. A project. A budget line. A program with a steering committee. Something that needs a quiet quarter, a strategic alignment, and a slide deck approved by someone two levels up.
That belief is the problem. It is also the reason nothing ever changes in a healthy way.
The Modernization Paradox
The conversation usually ends the same way too. "We need a big clean-up, but not right now."
Right now there is a deadline. Right now there is an outage. Right now there is a feature the business committed to before anyone asked whether the codebase could carry it. Right now is the wrong time, and next quarter will be the right time. And next quarter will arrive with its own version of right now.
In my experience, "right now" lasts for years.
While it lasts, the system gets worse. Modules that were easy to understand grow more complex. Boundaries that were quite clear get blurrier. TODO-refactor comments pile up. Documentation drifts away from what the code actually does. Tests get skipped in the build because nobody wants to deal with the flaky ones. Each of these decisions makes sense on its own. Together, they create a compounding downward spiral for the system.
This is the paradox. The longer we wait for the right moment to modernize, the bigger the modernization has to be. The bigger it has to be, the more risky every change becomes. And the more risky every change becomes, the harder it gets to test anything with confidence. So we are less and less likely to find a moment big enough, safe enough, and testable enough to do it. The project mindset sets a bar so high that the bar itself becomes the obstacle.
The system that needs a six-month cleanup will not get a six-month cleanup, for political, budget, or feature-request reasons. I can already hear it: "we pay for features, not refactorings". It will get a sequence of hurried and superficial three-day patches, and each patch makes the eventual cleanup a bit harder.
Modernization as Cadence, Not Spectacle
Let me propose a different way of thinking about modernization.
Requirements change all the time. Teams change all the time, because people join, leave, rotate, and learn. The systems we build also change, even when we do not touch them, because the world around them keeps moving. Every dependency upgrade, every new compliance rule, every shifted business priority puts a small amount of pressure on the architecture.
If everything around the system changes constantly, then keeping the system healthy cannot be a one-off event. A modernization that happens every four years against a world that changes every four weeks will always be behind.
So continuous modernization is not a project we run once. It is a small, steady practice the team does every day, in tiny steps, at roughly the same speed at which change shows up.
That reframe sounds small. It is not. It moves modernization out of the category of things we plan and into the category of things we do. It stops being an item on a roadmap and becomes part of how the team works. Once it is part of how the team works, it stops competing with the daily business, because it is part of the daily business. No spectacle, no kickoff, no big reveal. Just the work, done a little better than yesterday.
The rest of this post is about how to make that real. Not as an aspiration. As a practice.
Habit vs Project Mindset
The 1% Method
Imagine you decide to start running. You have not done any sport in years. On day one you do not actually run, because that would hurt. You go for a brisk walk for ten minutes. It is unimpressive. You cover almost no distance, and nothing about that ten minutes makes you feel like an athlete.
You do the same the next day. And the day after. After a week or two, the brisk walk gets easier, so you start mixing in a minute of slow running here and there. After a month, you can run for five minutes without stopping. After three months, you can run for half an hour. After six months, a 10K is a realistic weekend goal. After a year, you might be looking at a half marathon.
None of the individual sessions was remarkable. The compounding was.
This is the basic idea behind the 1% method, popularized by James Clear in his book Atomic Habits. The argument is simple: small changes that look insignificant in isolation produce remarkable results when they accumulate. Clear writes about it mostly in the context of personal habits. What I want to do in this post is apply the idea where Clear did not go: into the architecture of software systems built by teams.
Imagine every member of a team spending around ten minutes per day on something tiny. Improving a name to match what the business actually calls it. Extracting a method. Removing dead code. Adding a missing test. Updating one dependency. Fixing one warning. Improving one paragraph of documentation. Deleting one obsolete configuration flag.
None of these things is impressive on its own. None of them deserves a Jira ticket. None of them would survive a prioritization meeting against a feature request. And that is exactly the point. They are too small to compete with the daily business, which is why they can actually happen alongside it. They happen quietly, under the radar, in the margins of the day.
(A small hint aside: if you work in an environment where someone tracks your work in ten-minute increments, this post will not help you. My advice in that case is different, and it is: run, if possible)
Small improvements are easy to do. They are also easy not to do. And they are impossible to ignore once they accumulate.
Why Intentions Are A Trap
If you talk to engineers about any of this, almost everyone agrees. We should improve the code a little every day. We should refactor small bits as we touch them. We should avoid letting small problems pile up until they become big ones. Nobody argues against the principle. I have never had a developer push back on the idea that small, continuous improvement is a good thing.
And yet most teams do not do it.
The reason is not that engineers are lazy or undisciplined. The reason is that intentions are weak under pressure. Look at any normal week in a delivery team. There is on-call duty. There are critical production bugs. There is a sprint goal that started slipping on Tuesday. There is the "one more feature, ASAP" request from a stakeholder who promised something to a customer without checking with anyone first. A team member is on holiday. Another one is sick. A third one just told you they are leaving for a different job in six weeks. The release date does not move. The roadmap does not shrink. And the deadline that felt comfortable two months ago now feels tight.
In a week like that, the small improvement does not happen. Not because the engineer forgot, and not because the engineer does not care. It does not happen because in the moment, between the production bug and the slipping sprint, a five-minute refactoring is the easiest thing on the list to skip. There is always a more urgent thing. There is always a more urgent thing.
This is the trap. If improving the code or the architecture depends on motivation and good intentions, our codebases end up looking like gyms in March. Crowded with ambition in January, half empty by February, more or less abandoned by spring. The intent was real. The structure to support it was not.
The fix is not more motivation. The fix is structure that makes motivation unnecessary.
You Already Have Habits
When I give talks on this topic, I often ask the audience a question. "What is the first thing you do on your computer once you sit down at your desk in the morning?"
The answers are almost always the same. Check email. Open Slack. Open Teams. Look at the calendar.
Then I tell them: "Congratulations, you have a habit."
You walked into the office. You grabbed a coffee. You sat down at your desk. You opened your laptop. You checked Slack. You did not consciously decide to check Slack. You did not motivate yourself to check Slack. You did not write "check Slack" on your to-do list the night before. You just did it, because the chain of small actions before it pulled you into it. The cue was the open laptop. The response was the click on Slack. The reward was the small hit of "now I know what is going on."
Habits do not need intentions. That is the whole point of them. They run on a track that the brain has already laid down, so the conscious mind does not have to spend energy on them.
So here is something I always recommend at this point in the talk: start doing this for yourself first. Tomorrow morning, before you open Slack, spend ten minutes on one small code improvement. Rename a confusing variable. Delete a dead method. Add the test you have been meaning to add. Then open Slack. Put a small habit card on your desk and tick it off when you are done. Do this for two weeks, on your own, without telling anyone. You do not need permission for this. You do not need a meeting. You do not need a ticket. You just need to put it before Slack in your morning routine.
Two things will happen. First, you will start to feel the small daily improvements compound in the parts of the codebase you touch. Second, and this is the interesting part, somebody on the team will notice. The habit card on your desk. The unusually clean diff in your pull request. The dependency you quietly removed last week. People are curious. They will ask. And once they ask, you have a conversation, not a sales pitch.
That is how this scales. Not through a kickoff meeting. Not through a process change. One person starts, the team gets curious, and the practice spreads sideways. But for the spread to actually take hold, the practice has to become a team habit, not just a collection of individual ones. And that is a different design problem.
From Personal Habits to Team Habits
A personal habit only has to survive your own bad days. A team habit has to survive everybody's bad days at once.
That sounds like a small difference. It is not. The personal habit only fails when you are tired, distracted, or busy. The team habit fails when anyone on the team is tired, distracted, or busy enough to skip it, and then the next person sees them skip it, and the routine starts to lose weight. Within two weeks, the habit is something the team used to do. Nobody decided to stop. They just stopped.
And sometimes someone actively decides to stop it for the team. There is always a senior person who says "not today, we have a deadline" and the team complies, because the senior person has authority. One skipped day becomes two, becomes a week, and the habit is gone. I have also noticed something more subtle: the people who push hardest against these small improvements are sometimes the same people who draw their status from knowing all the dirty corners of the codebase. The mess is what makes them indispensable. A cleaner codebase, where everyone can find their way, quietly threatens that position. This is rarely conscious. But it is real, and worth naming.
So a team habit needs to be designed differently from a personal one. It needs to be wired into something the team already does together, so that no individual has to remember it. It needs to survive the engineer who is on call. It needs to survive the workshop on Wednesday. It needs to survive the new joiner who has not heard about it yet. The structure carries the habit, not the willpower of the people inside it.
Clear gives us four useful design rules for habits in Atomic Habits: make the cue obvious, make the craving attractive, make the response easy, and make the reward satisfying. These rules transfer to team habits, but they need to be re-pointed at team-level artifacts rather than personal ones. The cue is not on your bathroom mirror. It is in your pull request template. The reward is not a feeling at the end of your day. It is a metric on a dashboard everyone in the team can see.
A personal example: I put my Peloton bike in my living room, not in a spare room, not in the basement. Right in the middle of where I spend my evenings. I did not become more motivated to exercise. I just made the cue impossible to ignore. Every time I walk past it, it quietly asks me whether today is the day. That works remarkably well. The same principle applies to teams.
Here is what each of the four rules looks like once you point them at a team:
Make it obvious. The cue lives in the artifacts the team already touches every day. A line in the pull request template that asks "did you leave this code a bit better than you found it?" A visible improvement backlog on the team board. A short Slack reminder that the documentation minute starts after standup. An architecture dashboard on a screen that everyone walks past. The point is to make the cue impossible to miss.
And for the days when someone sits down and thinks "I want to do my ten minutes but I have no idea what to touch today": put up a flipchart or a Miro board with small improvement ideas that anyone on the team can add to. Rename this class. Delete that unused config file. Add a test for this edge case. Some teams I work with use anonymized names on the board, things like "Batgirl," "Princess Peach," "Super Mario," or "Mr. Burns," which keeps it playful and avoids turning the board into a tracking tool. The board is always full, because every engineer notices things they do not have time to fix right now. Give those observations a place to land, and they become fuel for someone else's ten minutes tomorrow.
Make it easy. Ten minutes per person per day. No approvals. No tickets. No meeting to schedule the improvement. No estimation in story points. No review committee. The autonomy is the design. The moment a team has to ask permission to improve the code, the habit dies, because the permission step takes longer than the improvement itself.
Make it attractive. Celebrate the small wins out loud. Mention them in standup. Visualize the streak on the team board. Introduce a team habit streak: we have done our daily improvement for 14 consecutive working days. Put it on the board. Make it visible. A streak creates a gentle social dynamic where nobody wants to be the person who breaks it, and reaching a new record becomes something the team is genuinely proud of. One important rule: holidays, sick days, and conference or training days always count as continued streaks. Nobody should feel pressure to work on a day they should be off. The streak tracks the team's working days, not individual attendance. If three people are in the office and they do their ten minutes, the streak continues. Use common sense here. The list of valid reasons should not become so long that it enables cheap excuses, but it has to protect the things that matter. The team knows the difference. Trust them with it. A team that sees its own progress wants more of it. A team that does not see its progress assumes there is none.
Make it satisfying. The satisfaction has to be visible at the team level, not just the individual level. Metrics moving in the right direction. The number of warnings going down week over week. The dependency graph getting cleaner. The documentation actually answering the questions a new joiner asks on day one. These are not vanity metrics. They are evidence, shared by the whole team, that the small improvements are doing what they are supposed to do.
One important warning here. The moment someone outside the team turns this into a formal tracking procedure, the idea is dead. If a manager starts measuring how many improvements each engineer made this week, you have turned a habit into a KPI and the intrinsic motivation is gone. This only works when the team owns it, tracks it for themselves, and uses it as their own internal signal. The habit streak on the board is for the team. It is not a reporting metric. Keep it that way.
There is one more idea from Clear that transfers especially well to teams: habit stacking. The easiest way to build a new habit is to attach it to an existing one. Teams already have routines. The daily standup. The pull request review. The retrospective. New habits stick faster when they ride on top of these. A "documentation minute" right after standup. A "leave this code better than you found it" check inside the pull request review. Three minutes of warning-cleanup at the start of every pair-programming session. The existing routine carries the new habit on its back.
This is the move that takes the 1% method out of self-help territory and into engineering practice. The habits are not personal. The structure is not personal. The improvement is not personal. The team owns it, the team designs it, the team benefits from it.
Architecture Is What You Do Every Day
Most of the time, when we talk about architecture, we talk about decisions. Which database. Which communication pattern. Which deployment model. How to split the monolith. Whether to go event-driven. We write ADRs, we draw diagrams, we have review meetings. And all of that matters.
But let me ask you something. When was the last time your architecture actually got worse because of a decision made in a meeting?
That is not where architecture erodes. It erodes on a Wednesday afternoon when someone adds a shortcut because the sprint is running late. It erodes on a Friday when nobody writes a test because the weekend is calling. It erodes across a quiet month where a module grows from 300 lines to 1,200 because every new feature landed there and nobody stopped to ask whether it still belonged. It erodes when a dependency that was supposed to be temporary six months ago is now load-bearing and everyone is afraid to touch it.
Nobody made a bad architectural decision in any of these moments. Nobody even made a decision. Things just happened. Small things. Ordinary things. Things that do not show up in any review or any ADR.
And yet, taken together, they are the architecture.
Architecture is the accumulation of everyday behavior across the whole team, over months and years.
The decisions set a direction. The daily behavior determines whether we actually go there. And if the daily behavior is not aligned with the direction, the behavior wins. Every single time. No diagram survives contact with a team that has no habit of keeping the code clean.
This is exactly why the team habits from the previous section matter so much more than they might seem at first glance. A single ten-minute improvement will not fix a broken module boundary. Of course it will not. But a team that has the habit of noticing boundaries, naming problems, cleaning up small messes, and keeping documentation honest will, over time, produce an architecture that is fundamentally easier to change. Not because someone made one brilliant decision in a meeting room. Because hundreds of small, ordinary behaviors pointed in roughly the same direction, day after day, month after month.
Fewer hotspots in the codebase. Lower complexity in the modules people touch most. Tighter boundaries between components. Clearer ownership. More predictable dependencies. Documentation that a new team member can actually use on their first week. None of these things happen because of a single action. All of them happen because of a sustained pattern of behavior.
There is a concept in martial arts that captures this perfectly: muscle memory. You do not start by winning fights. You start by perfecting a single strike. You repeat it hundreds of times until your body does not need your brain anymore. Then you learn katas, sequences of strikes and blocks that flow together. You repeat those hundreds of times too. And then, one day, you step into a sparring match and your body does the right thing without you thinking about it. The strike comes out clean. The block is in the right place. Not because you decided in that moment what to do. Because you trained the pattern so deeply that the decision was already made.
Architecture works the same way. A team that has practiced small improvements daily for six months does not need to think about whether to clean up a confusing name or remove a dead import or tighten a boundary. They just do it. The pattern is trained. The architecture reflects the training.
And here is what makes this truly powerful: a team with strong architectural muscle memory does not just maintain the current architecture. It makes future architectural change safer. When the moment comes for a bigger move, a service extraction, a module split, a technology migration, the team that has been keeping boundaries clean, dependencies predictable, and documentation honest for months is the team that can actually pull it off. The big move is not safe because someone planned it well. It is safe because the ground it lands on has been prepared, one ten-minute improvement at a time.
The Compounding Curve
There is something important I need to be honest about. The first few weeks of doing this will feel like nothing is happening.
The code will not look dramatically different. The metrics will barely move. The architecture diagrams will not change at all. And someone on the team will say "see, I told you this does not work."
They are wrong. But they are also not lying about what they see. The compounding curve has a shape that punishes impatience. The early phase is flat. Almost invisible. The improvements are real, but they are too small and too scattered to show up in anything you can measure or point to. This is where most teams give up. Not because the approach failed, but because the feedback came too late.
It is like running. After four to six weeks of daily training, you feel good. You are faster than you were on day one. You have a routine. You feel like a runner. And then one morning, someone your age passes you in the park without breaking a sweat. Suddenly your progress feels like nothing. You were proud of your 10-minute kilometers, and this person is doing six-minute kilometers like it is a warm-up. The temptation to quit is enormous, because the comparison made your improvement invisible to yourself.
The same thing happens to teams. You have been doing your ten-minute improvements for six weeks. The code is a bit cleaner. The team feels good about it. And then another team in the company ships a big, visible modernization project. New architecture. New tech stack. A presentation to leadership. Applause. Your quiet, daily, invisible work looks like nothing by comparison.
This is the moment that separates teams who build lasting habits from teams who tried it once. The team that quits here was relying on visible progress as motivation. The team that continues has something better: a structure that does not depend on how the team feels that week. The habit just runs. That is why we built it as a habit in the first place.
If you stick with it, the curve bends. Not suddenly, but noticeably. Here is roughly what I have seen in teams I have worked with:
Weeks 1 to 4: Invisible. The improvements are happening but nobody outside the team can tell. The diffs are a bit cleaner. A few names make more sense. A test that was missing now exists. The value is real but it is only visible to the person who made the change. This is the hardest phase, because the effort feels pointless. It is not.
Months 2 to 5: Noticeable. The team starts to feel it. Code reviews get faster because the code is easier to read. New joiners find their way around a bit more quickly. The number of "what does this even do?" conversations in standup goes down. Nothing dramatic. But the friction is lower, and the team notices.
Months 6 to 12: Measurable. The metrics start to reflect what the team already felt. Warning counts are visibly lower. Complexity scores in the modules the team touches most have dropped. The dependency graph has fewer surprising connections. Documentation covers the things people actually ask about. You can put a chart on a screen and show someone outside the team that things are improving. Cognitive load on the team is lower. And if someone asks whether the ten minutes are worth it: the team is delivering features faster, because the code they build on is no longer fighting them.
Months 12 to 24: Transformational. This is where the compounding becomes hard to ignore. The codebase is not just cleaner, it is structurally different from where it was two years ago. Boundaries are tighter. Modules are smaller. The team moves faster on new features because the ground they build on is solid. And the big architectural moves that felt impossible two years ago, a service extraction, a module split, a technology migration, are now realistic, because the preparation happened one ten-minute improvement at a time.
The compounding curve is not a promise that everything will be fine. It is a description of how small, consistent effort accumulates. The shape is always the same: flat, then gradual, then steep. The only variable is whether the team stays with it long enough to reach the steep part. And that is exactly why this has to be a habit, not a project. No motivation lasts two years. No project sponsor keeps attention for two years. A habit does.
The Compounding Curve
How to Start, This Week
If you have ever picked up running, you know the answer to the question "when is the best time to go out for a run?" The answer is always now. Not tomorrow. Not next Monday. Not after you have bought the right shoes. Now.
I usually tell people the opposite after conferences. Do not fall for every hype. Do not do CDD, which stands for Conference-Driven Development. No career-limiting moves based on a 45-minute talk you heard between lunch and the afternoon coffee break.
This time I am telling you the opposite. Start. Now. This is not a new framework. This is not a risky technology bet. This is ten minutes of cleaning up code you already own. The worst thing that can happen is that a variable has a better name tomorrow. Go.
This week: Tomorrow morning, before you open Slack, spend ten minutes on one small improvement. Any improvement. A better name. A deleted method. A test. A paragraph of documentation. Do not tell anyone. Do not ask for permission. Do not create a ticket. Just do it. Put a habit card on your desk and tick it off. Do this every working day this week.
This month: Talk to your team about it. Show them the habit card. Share what you have been doing. If they are curious, suggest that everyone tries it for two weeks. Set up the improvement ideas board, on a flipchart or a Miro board, so nobody has to wonder what to work on. Start a team streak. Track it on the team board, not in a reporting tool.
This quarter: Bring it into your retrospectives. Talk about what is working and what is not. Pick one or two metrics that matter to your codebase, warning count, complexity score, dependency count, documentation coverage, and start watching them. Not as a KPI for someone else. As a signal for the team. Let the team tune the habit to fit their own rhythm. Some teams do their ten minutes first thing in the morning. Others do it right after standup. Others do it as part of the pull request. There is no right answer. There is only the answer that your team will actually stick with for 12 months.
No framework to adopt. No tool to buy. No budget to approve. No steering committee to convince. The barrier to entry is ten minutes and a willingness to start before you feel ready.
If You Want Help Getting Started
Most teams I have talked to about this get the idea immediately. The challenge is rarely understanding. The challenge is the first four weeks. The flat part of the curve. The part where the habit has not taken hold yet and the old patterns are still pulling the team back toward "we will do it later."
That transition is where I can help.
I offer a Continuous Modernization Kickstart format designed to get a team from zero to a running habit in the shortest possible time. It works like this:
A 4-hour Ignite Session with the team. We look at your specific codebase and your specific pain points. We surface the right starter habits for your situation, because the right ten-minute improvements for a legacy monolith are different from the right ones for a microservices landscape. We design the routines, set up the improvement ideas board, define what the first team streak looks like, and agree on one or two metrics worth watching. The team leaves the session with everything they need to start the next morning.
A 2-hour Follow-Up at week 4. This is where the flat phase hits. We look at what stuck and what did not. We talk about the moments where the habit almost broke. We adjust the routines based on what the team actually experienced, not what we assumed in the Ignite Session. This is usually the session that saves the practice, because week 4 is exactly when most teams would quietly stop.
A 2-hour Follow-Up at week 10. By now the team is in the "noticeable" phase. The habit is starting to feel normal. This session is about tuning: are we improving the right things? Are the metrics telling us something useful? Is there a bigger architectural theme emerging from the small improvements that the team should be aware of? This is also where we talk about how to spread the practice to other teams, if the team wants to.
That is it. Eight hours of my time, spread across ten weeks. Enough structure to make the habits real. Small enough that it does not become another modernization project that gets deprioritized.
The goal is simple: after ten weeks, the team has a running habit that does not need me anymore.
If this sounds interesting, get in touch.
Start Tomorrow
Two years from now, your codebase will be the sum of every small decision your team made between now and then. That is true whether you start tomorrow or not. The only difference is whether the direction and the attitude are deliberate.
You do not need a modernization project. You do not need a budget. You do not need permission from anyone. You do not need to wait for the next planning cycle, the next quarter, or the next quiet phase that will never come. You need ten minutes, a habit card, and the willingness to leave the code a little better than you found it.
The teams that do this will not notice the change at first. Nobody will. But a year from now, they will look at their codebase and wonder when it started getting easier to work with. The answer will be: on a quiet Tuesday morning, before anyone opened Slack.
Architecture becomes what you do every day. Not what you plan once.
Start tomorrow. Ten minutes. After grabbing a coffee. Before Slack. Before E-Mail. Before anything else.