00:00:14.349
Hey everybody, thanks for coming to "Working Compassionately with Legacy Code." My name is Mr. Shaw. I'm a developer at Share Progress.
00:00:20.060
Share Progress works for nonprofits. We do some front-end and data science consulting for them, and I hack on our social media analytics platform in Ruby and Sinatra. Share Progress is a fantastic place to work, with an awesome remote-first culture.
00:00:32.989
So, if you’re interested, I would love to talk to you more about it. This talk is about compassion, so you might think that I'm a very compassionate person, perhaps a vegetarian who meditates regularly, or maybe even someone who hangs from trees. Well, I do meditate, but you might think that because I'm up here on stage, I think I'm some kind of rock star. But I'm not. I'm just like you guys. I'm a software developer.
00:00:50.629
Since you're software developers, you know that although you might spend a few minutes each day celebrating a victory, most of the day is spent failing. And when it comes to compassion, I'm no expert; I fail all the time, just like software. But that's okay. I’ve got a word for that, and that word is 'learning.'
00:01:09.799
I've been looking back on some experiences I've had with legacy code, and I want to share those experiences—maybe not as a 'grizzled old rock star'—but I want to tell you what I've learned and how I believe I could have used some compassion to have a better time inheriting a frustrating legacy code application.
00:01:41.689
This is the story of two apps and how I inherited them in the same company. The stories of these two legacy code applications ended quite differently. I was hired by a company based on some meager iOS experience I had on my resume, fooling someone into thinking I was suitable for the job. I was tasked with taking on an existing legacy code application that was bought from some contractors and had never been pushed out to production because it just didn't look solid enough.
00:02:11.600
This app was supposed to be used internally by our company's repair technicians in the field. As you can guess, it was a disaster; the UI was both boring and subtly mysterious. It was impossible to navigate, and you got lost every time. The underlying solutions were the wrong problems to solve.
00:02:36.180
For instance, if you wanted to share data between two people using the app on different iPads, you had to put them in a room together, set up a peer-to-peer connection, and zap that data over the network via email. The app relied on frameworks that were completely outdated, unmaintained, and dead. If I mentioned them now and you know anything about iOS, you probably wouldn’t recognize them because they don’t matter anymore.
00:03:09.090
Instead of constant communication with the server, the mobile app had to be synced every 24 hours with one huge data dump. If you didn't perform that sync, you weren’t allowed to continue; you just had to wait. Sometimes, requests to the server would take minutes to come back, and sometimes, they wouldn’t come back at all. It was a soul-crushing spectacle, where developers felt like second-class citizens and users were treated like an outcast underclass.
00:04:06.209
Now, I wasn’t the first in-house developer to work on this project. I was the first full-time in-house developer hired by the company, but there was another contractor who had come in for a couple of months. She had tried her best with this app and had a lot of experience in mobile. When it came time to decide whether to stay, she decided to leave. Luckily, I had her notes from her commits.
00:04:45.540
I thought I should call her up and ask for some advice because I felt lost. She was really nice to talk to over the phone, but her chilling advice was, 'Kill it, start over.' So, I now had two people on my side. I decided to approach management and say, 'Hey, this app isn’t in production; we don’t need it, and we don't need everything that could come with it, so why don't we start over?' To my surprise, they actually went for it.
00:05:02.640
So there you go, legacy code problem solved. Everyone go home! But I told you I inherited two applications. The other application was in production, and this was a Rails web app that we used internally every day.
00:05:38.960
About four or five users plugged into this app all day long, posting records and essentially taking the paperwork generated by end-field technicians and pushing it into our system. I really sympathized with these data entry operators because this app was built by the same contractor as the first app I mentioned and had all the same problems.
00:06:02.730
The UI was unforgiving; if you made a mistake, there was no way to fix it. You just had to resort to desperate measures, and enough of these desperate measures would finally lead to data that just didn’t look right. In fact, it was completely out of order. The ironic thing was that some people in the office would check in occasionally and notice that things weren't quite right, but their feedback didn't filter to the top. This was because there was a culture in the company that said, 'If you see something, better not say anything.'
00:07:25.300
When I examined the Rails app, I saw that it had no automated tests and was stuck on Rails 2.3 and Ruby 1.8.7, both of which were at the end of their lifecycle. You’ve all heard about the strategy of 'fat models'; I had 1500-line models of Ruby code, with 300-line methods. There was even something called an 'authorization loophole.' The app had both a customer portal and an administrator portal. Of course, if you were a customer, you could navigate right into the admin portal by simply guessing the URL.
00:08:16.070
Here I was with this app that my manager said was 'pretty solid,' and I was terrified that I was the only person in the organization who knew it could come apart at any minute. I felt like I was going to get ulcers from the stress. I replaced my fear with blame; I hated the developer who wrote the app.
00:08:40.680
I found his name in the Git commits, and I knew he was a big deal locally in my community. Now he was the CEO of a company that touted its software practices. I thought to myself, 'How dare you? Here you are, extolling the values of TDD on Twitter, and you left me with an app that had no tests.' Here you are writing a book on microservice RESTful architectures, and you've left me an API with one route.
00:09:23.920
I also felt angry because I remembered that I had applied to his company. You can guess what happened: I didn't hear back at all. At the time, that didn’t bother me much; I had enough offers. But as I worked on this legacy app, I began to think, 'What's so bad about me? Why am I not good enough to work at your company but just good enough to clean up your mess?' This was the emotional state I was in. To move on with my life, I gave this person an unflattering nickname based on his unique style of commit messages.
00:10:23.470
I put on a brave face and ordered some books, which helped me a lot. One of those books is titled "Working Effectively with Legacy Code," which—ironically—focuses on the same topics only with an emphasis on emotions. While I worked nights and weekends, I was hacking, squeezing, extracting, and injecting, just like Martin Fowler. I felt like a battlefield medic, unsure if we were going to survive.
00:10:54.640
In the brief moments when I could escape work to meet my non-technical friends, I’d tell them that working on this legacy app was like pushing a sick man through a desert: 'No, you can't have any more water; yes, you have to keep going; no, you can't lie down. Do you want to die?'
00:11:39.440
With time, we shed our heavy coats, replacing them with a set of seven highly predictable controller methods. We wrapped our parched throats in a Spartan layer of plain old Ruby objects, and we thought we'd never make it out alive. But over the horizon, we began to see the first flickers of green—then a veritable forest of passing RSpec examples.
00:12:24.720
We fell to our knees in an embrace, my partner and I—this legacy codebase and I. Looking back on those times, I realized that all those days I was angry at my computer, I was staring into the face of the only entity that understood what I was going through: my legacy code.
00:12:45.490
I thought about these legacy code applications and software in general as our partners. While our codebases are not people, they often act unpredictably. You never know how they will react or if they will come through for you, and their idea of coming through may not match yours. It’s hard to predict what people—or code—will do because they have histories that are opaque to us.
00:13:12.180
Are you trying to control your code? If so, please stop. It’s not only dreadful for everyone involved, but it's also impossible to do. The only thing you can do with code is surround yourself with good practices and trust that they’ll do their best. I wonder if we run into so many emotional problems while dealing with legacy code because we wish to control it, but we ought to know that it is complex.
00:14:23.330
Why do we want to control code? I believe it's because we might feel someone is controlling us. But keep in mind that code is not people and lacks feelings—it simply does its job—and while it’s true that code is just ones and zeros, we are not. Spending all day taking out your frustrations on legacy code isn't the best approach.
00:14:50.750
As software developers, we’re good at adopting processes to improve our productivity. I suggest we try cognitive restructuring, a technique from cognitive behavior therapy. This means noticing when automatic negative thoughts come in and forcefully guiding them with a Socratic method until you arrive at a rephrased perspective.
00:15:16.960
For example, I once looked at a commit message from a developer I disliked and thought, 'This guy is a liar.' That’s labeling—taking a single event, his commit message, and declaring him a fraud. Yet, I failed to consider that maybe he'd learned valuable lessons from his experience with that messy application.
00:15:51.970
Another automatic thought I experienced was about my worthlessness, stemming from my rejection by that developer’s company. That was mind-reading, as I couldn't claim to know why they didn’t respond. Additionally, I labeled myself incorrectly, when in fact my resume and cover letter simply didn’t match that company’s needs. If they had better candidates, they should choose them—there's nothing wrong with that.
00:16:47.870
We must recognize how dangerous these automatic thoughts are; they can prevent us from receiving advice and broader ways of thinking that could genuinely help us. During those months of trudging through the desert, I tweeted, 'You’re not fixing someone else’s mess; you’re fixing a mess.' That was a quote from an article about legacy code.
00:17:41.030
Unfortunately, instead of taking that to heart, I just got snarky. I wish someone else hadn't made such a mess. I thought I was clever, but it was a failed opportunity to learn the lesson. I later found the article, written by a guy named Yondal Duel Skiing, and that quote points to a fallacy developers often engage in: the idea of code ownership.
00:18:23.880
When I worked with that code, I didn’t have to think about its original author. Rather, I should treat code as person-agostic. You see, code just wants to be worked on, regardless of who is maintaining it.
00:19:40.610
Now that you all know that you ought to be more accepting of legacy code, you might think, 'You should also eat well, exercise regularly, and take care of yourself.' You can have that on your tombstone if you like it. But I’m here to tell you that you don’t have to force yourself to like legacy code; in fact, legacy code is pretty cool.
00:20:21.080
I love legacy code because I love learning. I think that most of you—or all of you—like to learn. The list of things we need to learn never remains static; in fact, it's always evolving. Learning is probably one of the things you aspire to and take pride in, and legacy code is an excellent teacher.
00:21:00.350
You learn better with legacy code for a couple of reasons: one being that it’s in production. You cannot throw it away; it carries intrinsic value. In contrast, if you’re working on an application that isn't live, you can easily dismiss it. When code is in production, you have to make choices, and you especially learn when you fail.
00:21:34.880
Legacy code forces you to confront failures, leading to learning experiences. Why else do I think legacy code is a great teacher? Because it’s there; it’s something to work with. I believe you've likely experienced this: you’re at home, tinkering with a new framework or language, and all you create is essentially a toy application.
00:22:11.450
How do you reach a point of expertise? Production use cases are challenging because someone depends on it, and legacy code applications solve real problems in production. Refactoring can be mechanical; you can extract pieces, move them to new files, rename things. It allows your brain to engage with other thoughts while maintaining progress.
00:22:48.330
Working with legacy code can be meditative. After a long day, you can feel relaxed and rested. If working with legacy code makes you feel angry or tense, consider the possibility of a toxic work culture or specific aspects of it, like blaming.
00:23:31.960
If you feel anxious about being blamed for something, ponder whether that’s an environment conducive to doing your best work. Sadly, as software developers, we often promote cultures of blame by wanting to be the one person who understands the software.
00:24:10.480
In small companies, especially when you're the first developer hired, management often defers to you, giving you a sense of autonomy. It feels validating at first, but being the only one who understands also means you carry all the responsibility when things fail.
00:24:59.383
If you find yourself in such a culture, it may feel tempting to claim that autonomy. Still, it’s better to work towards changing that culture. When in this situation, continually ask yourself two questions: 'What can I change?' and 'How much more of this am I going to tolerate?'
00:25:41.720
If you can encourage responsibility in others within your organization, you dilute the burden of managing a legacy project, transforming it into a teamwork exercise that strengthens connections. However, if you simply can't tolerate the culture anymore, it's okay to have an exit strategy.
00:26:20.500
I made a promise in the abstract I wrote long ago that you could let go of anger and fear regarding legacy code and find joy. That’s an easy promise to make because you hear it often. Let go of anger and fear to discover happiness in coding.
00:26:55.900
As developers working with Ruby, we're incredibly fortunate. Ruby is a joy to code in. While it has imperfections, Ruby culture promotes kindness. You've likely seen the saying: Matt's is nice, and so we are nice.
00:27:45.680
It may not make logical sense, but being nice is vital. If something were to happen to Matt’s character, we would still choose to be kind. Kindness has become a shared value within Ruby’s community because it’s so easy and enormously valuable.
00:28:23.778
Remember, code is communication—not just between your computer and you, but also between developers. When communicating with everyone around you, whether they are your managers, teammates, or users, aim to be kind and generous.
00:29:06.860
Kindness is the most valuable asset in the world, and it’s free. Thank you.
00:29:53.220
Alright, we have plenty of time for questions. Let's try some questions first. The first question was about how long it took to refactor the app. I think refactoring is always a process; we had to get test coverage across the whole app for critical upgrades. I started the job in April and left the following March, but I don't think I started working on that app full-time until around June.
00:30:32.300
It took some time, but the next question was important: What forced me to reevaluate my approach emotionally back then? I've always known I was making wrong emotional decisions, as anger and fear feel bad. Gaining some distance helped me reflect on why I reacted like that. I also need to credit insightful talks on humane development that suggest we should create work environments that we desire to be in.
00:31:26.820
The next question concerned advice for compassion towards the writer of the legacy code you’re working on. The answer is the same: Go easy on yourself. Remember, past versions of yourself didn’t know what current you knows.
00:32:19.860
The next question related to legacy code and the chicken-or-egg scenario regarding writing tests or changing code to make it easier to test. The answer is—do a bit of both.
00:32:46.190
Some good technical advice from Michael Feathers in 'Working Effectively with Legacy Code' states that legacy code is code without tests. His main recommendation is to add tests for new features and then incrementally increase test coverage by surrounding those features with tests. Initially, I couldn't do that because I was unfamiliar with Rails and needed to learn about testing.
00:33:37.790
The final question was about being compassionate towards your manager. There’s no simple answer, but it’s essential to focus on the idea that code is merely a tool for achieving broader goals. We can often fixate on making our code function well and forget about larger organizational strategies. It’s our responsibility to align our code’s performance with the company’s mission.
00:34:53.760
In conclusion, just as we apply compassion to code, we should also be compassionate in our personal relationships, recognizing that everyone has their unique experiences. By doing this, we maintain a harmonious work environment.
00:35:10.260
Thanks, everyone! I’d love to talk with you individually, so feel free to reach out now or later, and thank you for attending this talk!