Amar Shah

Working Compassionately with Legacy Code

Working Compassionately with Legacy Code

by Amar Shah

In the presentation "Working Compassionately with Legacy Code," Amar Shah shares insights from his experiences as a software developer dealing with legacy code. Shah emphasizes the need for compassion in working with challenging codebases, likening the relationship between developers and their code to that of partners or caregivers.

Key points discussed in the video include:

  • Perspective on Legacy Code: Legacy code is often seen as a burden; however, it can also serve as a great teacher, presenting real-life use cases that push developers toward learning and growth.
  • Emotional Challenges: Developers frequently experience frustration and anger toward legacy code, often blaming previous developers. Shah suggests that these feelings should be recognized and reframed using cognitive restructuring techniques from therapy.
  • Two Applications Case Study:
    • Shah recounts his experience with two legacy applications at the same company:
    • The first application was abandoned and later scrapped after recognizing its insurmountable flaws.
    • The second application was in production but suffered from significant usability issues and a lack of automated tests.
  • Coping Strategies: Shah discusses how he learned to cope with the stress of legacy code by focusing on collaboration, communication, and kindness, both towards the code itself and the humans involved in the process. He encourages developers to be compassionate to themselves and the original authors of the code.
  • Cultural Reflection: The talk highlights the negative effects of blame culture within organizations that can hinder productivity and learning. Shah emphasizes creating a supportive culture where developers can collaboratively manage legacy code rather than taking sole responsibility.
  • Joy in Learning: Ultimately, Shah concludes that legacy code can be challenging but also provides opportunities for learning and growth when approached with the right mindset.

In conclusion, Shah highlights that fostering a culture of kindness, both with code and amongst team members, leads to better outcomes in software development and personal fulfillment. He encourages developers to approach legacy code as a partner they can learn from rather than an opponent.

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!