#195 - Working Effectively with Legacy Code and AI Coding Assistant - Michael Feathers

 

   

“Legacy code is a code without tests. If you have code, and it has lots of tests, it’s relatively easy to change. But if you don’t have the tests, you’re really in serious trouble.”

Do you dread working with legacy code?

Michael Feathers, renowned software expert and author of the classic “Working Effectively with Legacy Code,” joins me to discuss the challenges and strategies for working with legacy code, a topic that remains highly relevant even after 20 years!

Michael explains why he defines legacy code as “code without tests,” emphasizing the crucial role of automated tests for code maintainability, rather than simply defining it as an old inherited code. He also provides insights on the psychological challenges of working with legacy code and stresses the importance of approaching it with curiosity and a sense of adventure.

The conversation also explores the evolving world of AI assistant in software development, drawing from Michael’s forthcoming book, “AI-Assisted Programming”. He shares how AI can assist developers in various tasks, such as explaining code, identifying potential issues, generating tests, and exploring new possibilities.

Listen to this episode to explore the intersection of legacy code, AI, and the future of software development!  

Listen out for:

  • Career Journey - [00:01:24]
  • “Working Effectively with Legacy Code” Book - [00:02:05]
  • Definition of Legacy Code - [00:04:55]
  • The Importance of Automated Tests - [00:06:39]
  • Understanding Legacy Code - [00:09:47]
  • Mindset for Working with Legacy Code - [00:11:15]
  • Rewrite vs Fixing Legacy Code - [00:13:50]
  • Microservice for Legacy Code - [00:15:36]
  • Approach to Dealing with Legacy Code - [00:17:33]
  • Seams - [00:20:03]
  • Strangler Fig - [00:21:42]
  • Understanding Refactoring - [00:22:48]
  • Testing Pyramid - [00:24:28]
  • Code Nobody Wants to Touch - [00:26:10]
  • AI for Understanding Legacy Code - [00:27:53]
  • AI Churning More Legacy Code - [00:30:06]
  • “AI Assisted Programming” Book - [00:32:47]
  • Prompt Engineering - [00:34:16]
  • Doing in Small Steps - [00:35:09]
  • Best Use Case for AI - [00:37:29]
  • Developer’s Fear of AI - [00:39:16]
  • SudoLang - [00:40:59]
  • AI as Test Assistant - [00:43:42]
  • Context Window - [00:45:19]
  • Waywords - [00:47:14]
  • Managing AI Sessions - [00:48:53]
  • Using Different AI Tools - [00:50:30]
  • 3 Tech Lead Wisdom - [00:52:28]

_____

Michael Feathers’s Bio
Michael Feathers is the Founder and Director of R7K Research & Conveyance, a company specializing in software and organization design. Over the past 20 years he has consulted with hundreds of organizations, supporting them with general software design issues, process change and code revitalization.

A frequent presenter at national and international conferences, Michael is also the author of the book Working Effectively with Legacy Code.

Follow Michael:

Mentions & Links:

 

Our Sponsor - JetBrains
Enjoy an exceptional developer experience with JetBrains. Whatever programming language and technology you use, JetBrains IDEs provide the tools you need to go beyond simple code editing and excel as a developer.

Check out FREE coding software options and special offers on jetbrains.com/store/#discounts.
Make it happen. With code.
Our Sponsor - Manning
Manning Publications is a premier publisher of technical books on computer and software development topics for both experienced developers and new learners alike. Manning prides itself on being independently owned and operated, and for paving the way for innovative initiatives, such as early access book content and protection-free PDF formats that are now industry standard.

Get a 40% discount for Tech Lead Journal listeners by using the code techlead24 for all products in all formats.
Our Sponsor - Tech Lead Journal Shop
Are you looking for a new cool swag?

Tech Lead Journal now offers you some swags that you can purchase online. These swags are printed on-demand based on your preference, and will be delivered safely to you all over the world where shipping is available.

Check out all the cool swags available by visiting techleadjournal.dev/shop. And don't forget to brag yourself once you receive any of those swags.

 

Like this episode?
Follow @techleadjournal on LinkedIn, Twitter, Instagram.
Buy me a coffee or become a patron.

 

Quotes

“Working Effectively with Legacy Code” Book

  • I wanted to refactor. And they were also saying things like, you should write your tests first. Why would you do it any other way? Then I understood after I did it for a while. It helped me realize I could reduce the stress of programming a great deal.

  • Going back to my book, as much as it’s very technical and has a lot of code in it, I’m only realizing now how much it was really about going and helping people keep their morale up and have a positive outlook to what they can do and know what they can do within codebase.

Definition of Legacy Code

  • The one I’m kind of known for is basically that legacy code is a code without tests.

  • I knew at the moment that it really was at odds with traditional definition. You get code from other people and that becomes legacy code. Or code that you’re scared of and don’t quite understand. With all these definitions, they’re pragmatic in a way because they’re used to highlight something that you basically want to change.

  • With this one, I had this intuitive sense that if you have code and it has lots of tests and it’s relatively easy to change; if you don’t have the tests, you’re really in serious trouble. It’s a strong qualitative difference between those two different types of code bases. And so I was trying to get that across.

The Importance of Automated Tests

  • Most all of us walk around with an idea in our heads about what the system does. And the thing is, it’s kind of like the system has its own idea about what it does. It’s not an idea. It’s what it does, right? We quite often get so caught up with what we think the system is doing and what we think we want it to do. And we forget to even think about what it currently is doing. So to me, that’s a very grounding perspective.

  • You really know what the system does. You have a great base point to go and decide what to do next. And over and over again, I’ve run into situations where people, once they’ve learned a bit more about what the system actually does, they have different ideas about what’s possible. And without that baseline of knowledge, you just really don’t know that.

  • One of the things I talk about in the book, something I call characterization tests. And quite often people call this like pinning tests now, sometimes. And the idea is that basically you write tests that you use to describe the current behavior of the system. So you’re not writing them first, you’re writing them after the code has been written. And you’re writing them to go and ask a question of the code base. And once you get the answer, you basically take that answer and you put it in as the expectation.

  • Sometimes this is called golden mastery testing in a way. It serves like a poor practice, but I think when you have an existing code without tests, it’s just a way of going and actually understanding what you’ve got. And you can basically put that off to the side and distinguish it from the test that you write first to go and actually figure you towards creating a feature and understanding when you’re done. The test is a way of grounding our knowledge of a system for the most part.

  • It seems like I’m finding fewer and fewer places that still do much manual testing at all. Especially with DevOps and the Accelerate book and everything like that. The idea is to go and get something in place with tests and have it out there within an hour if you can, so it doesn’t really leave much time with that. So generally I am talking about automated tests.

Understanding Legacy Code

  • If you don’t have any tests, I think it’s appropriate for you. That’s the best way to go and put it.

  • Legacy code is code we don’t understand.

  • There’s a lot more that we can do now with in order to go and actually understand the systems that we have. When using AI for this quite often, just like taking a lot of code and sort of like put it into a session and asking questions about it. And the results have been mixed. I can kind of see the advantages of this now.

  • This technology is only going to get better over time. And it’s really important for every programmer to learn how to use it well and understand its limitations are.

Mindset for Working with Legacy Code

  • The mindset has a lot to do with it. And also there’s the ambition of creating a new system. With a lot of modern systems, you may be working with older code, but you get to go and sort of like create this little space where you have a new service and you can write the code from scratch and do this. And you get very happy about this, because you get to sort of display your creativity.

  • But some people actually enjoy debugging. It’s this thing of trying to understand something. And if you approach it as an adventure, I think that’s something which is really kind of good in a way.

  • The thing which really affects whether we feel good today is what our expectations were. It’s like our expectations set our experience to a strong degree. And if you can actually cultivate the curiosity about what does this system do or the desire to help people in that context, it can be very rewarding work. You may just have to go and put aside your expectations a little bit.

Rewrite vs Fixing Legacy Code

  • A lot of it comes down to business reason rather than technical reason, because at the end of the day, it’s a question of whether there’s payback for this particular thing, but the business case needs to be made.

  • You don’t have to rewrite an entire system most of the time. You concentrate on the things which basically are going to have growth in the future and also are presenting difficulty to you in the meantime.

  • Usually what I like to do is I like to go and actually try to do some refactoring, try to do some planning for some refactoring, look at prospective features. And then, having all that stuff together, think about whether a rewrite is justified or not.

  • Doing spot rewrites of a particular thing is really pretty powerful. And quite often for people, it’s like an all-or-nothing proposition, and that’s really a horrible position to approach these things from.

  • The thing with rewrites is that it’s great if you have tests. If you have tests, you’re really in a golden space. And if you don’t, then you’re kind of like dealing with the situation of oh, I need to write this thing and I don’t understand what it does. And it’s like, well, now you’ve got two problems, right?

  • That’s rewrite when you basically are dealing with technical debt directly. But there are these other rewrites which are really all about architecture that really have a different set of considerations leading into them. And these are the big architectural ones are usually much more extensive.

Microservice for Legacy Code

  • It’s an interesting thing to actually move things around to different places. And so it’s really at a macro level, the same thing we do at a micro level with classes in many ways. But as far as I think of you should be able to rewrite it in a day or so, I think that’s a great goal. Hard to see it in practice though.

  • There’s this intrinsic thing about software that basically tends to grow and grow and grow. And quite often it grows to the point where you basically hard to go and do anything like that.

  • I remember reading through some research years ago about how big does a class need to be before you actually go and refactor? Where do we have the most bugs in the biggest abstractions to the smallest ones? Turns out the answer is really the ones that you touch the most often. We all have a feeling for when things get to be too big, but quite often, it’s kind of like there’s no set point. It’s kind of like a subjective sense in that way.

  • There’s a lot of stuff that was a dream for microservices. It’s a shame that we kind of fell away from some of that stuff. The thing of being able to use almost any language, be able to throw things into production almost immediately. Being able to go and rewrite them when we need to.

  • We only get the resilience systems we need when we stress them a bit. If there’s a reason to start rewriting things, then it’s good. Because we actually gain the skill to do this and don’t think of it as being an atypical thing.

Approach to Dealing with Legacy Code

  • The main thing is to go and figure out exactly where you need to make changes and you move outward from there. There may be cases where you need to change two or three lines in a method, for instance. Or you need to go and actually sort of like add five or six methods to a class, but maybe you’re thinking about creating a new class. And then what you do is basically you think about what would be involved in getting tests in place for each one of those places. And you kind of like crawl the tree upward and see if there’s a common place for those changes. And you try to pragmatically figure out where you want to go and have your tests.

  • If you have code that doesn’t really have very many tests in place, chances are the code isn’t really able to accommodate tests yet. And they have to do quite a bit of dependency breaking work in order to go and actually put the tests in place to go and solve these problems. And that’s really what my book is mainly about is going and breaking the dependencies and writing the tests to go and do these things. But at a micro level, that’s what you kind of need to do.

  • In the more macro level, the important thing to go and remember is that, essentially, this is the kind of stuff where you’re never going to go and have complete tests on a code base unless you started that way. And that it’s okay to live in this limbo space, and you probably will for a long period of time, where you’re going to have some areas of great coverage and other areas of not so good coverage. And it’s just normal.

  • But at the end of the day, the cool thing is that the things that you’re about to change right now, chances are you’ll be changing them in the future. So what you do to go and get tests in place for those things, it’s really kind of valuable if you need to go and actually start to make changes later and chances are you will. So you’re going to start to get like very quick returns from doing this sort of thing.

  • There’s also the psychological thing of basically doing that enough to get to the point where you notice the difference about how it feels when you have an area of code that’s easier to work in versus one that doesn’t. Quite often I run into people that have even independent of whether you have tests or not. They’re not used to working a good code base at all. And so they’re in pain, but they don’t know they’re in pain. And that’s really a tragic situation to be.

Seams

  • Essentially, when you look at a class or a set of classes, there are places where it’s easier to go and actually sort of replace things, replace behavior than other places.

  • Let’s say you have a method and it’s basically doing something crazy with I/O. And you want to get it out of your way so you can write tests for the class without actually doing the I/O. If it’s a virtual method, you can basically go ahead and override it in the subclass, and then it’s out of your way. So that part of the method is a seam.

  • It’s kind of like a seam on your shirt. It’s a natural breaking point where you can actually go and replace one thing with another, replace one behavior with another. It’s an opportunistic way of looking at software to go and say, what can I do to actually, without changing things drastically, be able to go and get areas where I can get understanding and coverage?

  • Quite often, if you’re going to make a change and you don’t have all day to go and refactor everything, you’re going to have to go and get that change in a way which is not going to be disruptive, has very high quality, things along those lines. And it just might be a spot change, and it’s good to know where that’s possible.

Strangler Fig

  • With strangler, you are kind of building things in parallel. You’re diverting flow to one area of the system so you can go build out another one.

  • Parallel replacement is a term that people use in other engineering disciplines. Generally, that’s what a strangler fig is. It’s selectively rewriting areas by going to allow yourself to go and have the old path to fall back on. So in terms of seams, I guess you do have to find seams in order to go and actually understand where you can make these diversion points. So I guess that’s the commonality.

Understanding Refactoring

  • I think it was Ralph Johnson who said this many, many years ago when the book first came out. He says if you want to teach good design, basically teach people the things to avoid, and everything that’s left is good design.

  • And that’s really the way the book is organized. It’s kind of like, here’s all these code smells and your job is to go and look at these code smells and get rid of them. And if you do, your design is going to be better than it was before. And it’s a great way of going and conveying design sense, what is better than the other thing. It’s a very valuable thing just in terms of understanding systems.

  • In general, in terms of dealing with systems, it’s extremely valuable. Because refactoring is all about clarifying things to the point where basically you can understand them, and where change becomes easier. It’s not just refactoring itself, but understanding the predecessors, like the code smells I mentioned, but also design principles. Once you have that, you’re going to just be able to go and sort of make things better for yourself in the future and the people around you. And that’s a wonderful thing.

Testing Pyramid

  • There was BDD, behavior driven development, that came out many years ago. And of the interesting things there is they were concentrating on high-level behaviors and sort of writing tests that would deal with collaborations of classes at once. I run into these people all the time that are writing like one test case class per class, and that you’re in this weird situation with that.

  • When I’m working with legacy systems, I’m trying to find some vantage point that I can write tests at. Which isn’t too far from the behavior I’m actually going and covering, but goes and covers the behaviors that I care about. And these clusters are really more than just one class quite often. That’s just the way things go.

  • So I think that the conversation we have about whether something is a unit test or an integration test is not terribly productive in a way. It’s really about testing behaviors. It’s just a really valuable thing to go and look at is that you’re testing behavior. So you need to go and find the places where it’s best to do that and move forward with things.

  • In testing pyramid, you’ve got unit and you go all the way up to like acceptance and stuff like that. The lower level tests that you have are things that you build upon in terms of understanding the system. And there’s no way generally to go and have tests at an extremely high level and cover everything that you care about. I try to concentrate on the lower levels and then know that’s going to make the higher levels easier when I need to approach those.

Code Nobody Wants to Touch

  • I’m really in favor of going and actually just really trying to go and make your changes supported by tests. Because even though today it looks like nobody’s going to change this, it’s just the same thing to do. The fact that you have that code around still means it has value. So you don’t want to be in a situation where you’re just making it worse.

  • Of course, people are gonna be pragmatic about this. It really depends upon how much other work they have in front of them. Even going through the exercise of trying to write tests for something which doesn’t have many tests is really, really difficult. Using appreciation for, you know, I’m never going to do this again. And none of my teammates are, because we know how bad this is. So it’s really always a valuable exercise. Try to get the tests in place to support the change you’re going to make.

  • This is not an uncommon thing. People in business all the time are trying to figure out how much to invest in particular things. And we have the same thing as technical people. There are no easy answers to this question.

AI for Understanding Legacy Code

  • It’s really kind of hard to go and actually see where things are going to go, because they’re changing all the time.

  • The thing that people are most concerned with right now is the hallucination problem, where it’s kind of like you ask a question, you get an answer, and you just really don’t know whether it’s right or not. And I want to take that as a given. It’s going to get better over time, but I think the thing that’s important is really to go and understand that if you can’t trust what’s being generated, there still is value there.

  • A lot of this is really about going exploring alternatives. If I’m about to do something, quite often I’m like, okay, well, let me go ahead and ask for a different way of doing this. Let me ask for three different ways of doing this and just compare them side by side and understand what’s possible in this space and quite often get ideas I wouldn’t have gotten otherwise.

  • For things that we can verify easily, like to ask a question about a particular API and it gives you the answer. And of course, you put it in place and you find out very quickly whether it works or not. It’s kind of brilliant for that.

  • I do use it to explain code to me quite often. One thing I love is this thing where I call it lensing, and it’s kind of like you drop in a giant area of code and you’re kind of like, this giant class that I have here, what responsibilities does it have? And it goes and gives me a list of them. And usually, it’s kind of like eh, so-so. And you start to interrogate and ask other questions about it.

  • I love to do this thing where you’re like, okay, you gave me 10 responsibilities. Just give me six. Basically, if you had to look at this fresh, what are the six most important responsibilities? And by scaling back and forth with this, you start to go and understand where perception can change of a class in terms of what the responsibilities are, depending upon the level that you’re looking at it. And it can give you ideas for refactoring. So I find that very, very useful as a strategy. So there are a ton of other little things like that that are kind of handy.

AI Churning More Legacy Code

  • There’s the GitClear report. One of the things that they were mentioning there is it seems like there’s a lot more churn of code. Code’s being put in public repos much faster, but there’s much more churn and change after it has been.

  • It’s easier to write code. And it’s a bit hard to understand it.

  • For me, I’m always dealing with this fatigue issue. It’s like I’ll look for three different ways of doing something. And then I’m doing a code review for all these things. And it’s kind of like at what point is that productive and at what point is that counterproductive for me. We have to review code that other people have written or that we’ve written a long time ago and had forgotten. And this just goes and increases the burden in that space, and it’s kind of tough.

  • An area that I think is really kind of interesting is the entire thing about going and writing tests. Because I was kind of shocked in the beginning to see vendors basically go and say, hey, we’re going to write all your tests for you. As a TDD guy, you’re looking at this and you’re saying, oh my God, no, right?

  • But for characterization testing, it’s really kind of powerful because, if you’re not changing the code, it is a document of what the behavior currently is. And you can go and have tests written for this. And if they pass, then they are actually showing you real behavior. And so that’s useful.

  • The thing we have to get used to with this is the idea that tests can be disposable and temporary sometimes, and just use them to get insight or to facilitate change. So I think that’s very valuable.

  • All the time. It’s just for exploring alternatives, for the most part. And it’s like even things that have nothing to do with code. It’s an interesting thing to admit, but I’m just so curious about things that I haven’t thought about. Something in culture or something kind of like science. That kind of thing.

  • In general, any domain that you want to dig into, it’s easier to do now. The advent of search browsers gave us a lot more ability to go and discover things and sort of learn things. And now, it’s off the charts, so I think that’s just really incredible.

“AI Assisted Programming” Book

  • What was interesting to me is I felt like it was an interesting way of going and actually talking more about how we work in a way. And I felt like there are some of the things we confront with AI are things we’re confronting with right now, but haven’t really talked about all that much. One of those is that fatigue issue that I mentioned a little bit earlier.

  • Another one is sometimes, it’s quite often you’re working in an IDE and basically it gives you code suggestions all the time and you’re looking at this and it’s kind of like, can I accept this? How much trust can I place in this? And the same thing is true with code that you get from somebody else. Where’s my trust? How do I focus on this particular thing?

  • And then there’s the general thing of ideation. One of the sections I have in the book talks about the loss potential if basically you ask a question of AI and you accept the first answer. Because quite often, you just ask this prompt again, you get a different answer and a different answer and a different answer. And I find that so valuable because it sort of opens the possibility space in a way and gets you thinking about different things that poke your mind in a different direction, which quite often gives you better ideas about things.

  • The other thing as well is that basically it makes us better question askers. We get better at it, because we have to go and sort of ask questions to interact with it. So it’s really a capability amplifier.

Prompt Engineering

  • With my book, it’s less about prompt engineering and more about approach. But it’s interesting. It’s just having a mental model of how these things work at a behavioral level so that it can help you with your prompting.

  • It’s almost like you can imagine you have this giant net. If you ask a question, it pulls some of those things towards you. And then basically you ask another question, it pulls other things towards you. And quite often, the way that you ask questions goes and leads you on a different path.

  • It’s kind of like what are you pulling into active memory when you’re going in, sort of like asking questions? Little things like that quite often make us better at doing these things.

Doing in Small Steps

  • I remember this story about somebody in like high school and they’re taking a mathematics course. Their teacher goes and says to them, you know, there’s one secret for getting an A to this course. And everybody’s like, oh, what is it? Do your homework, okay? Do the problems.

  • The same thing is true for us in software development. The secret for a lot of this stuff is to take smaller steps. So if you are looking at generating something, generate something small. If you’re trying to understand something, paste in something that is kind of small and just get its take on things. And you’re just trying to understand with your brain what’s going on with something. Look at smaller steps and build up from the foundations.

Best Use Case for AI

  • It’s really for the areas which are low risk. One of the things I think is great is actually going to develop boilerplate code. It’s like creating a Chrome extension.

  • There are also things like that that can be like in-house tools and stuff like that, where you have some confidence that somebody’s going to find a problem before it causes loss of life or money. So I think it’s finding these low-risk environments.

  • And a place where this actually kind of works very well is if you’re creating tools to go and help you do things with your code, for instance. I feel like I’m rediscovering shell programming in a way. I’ve done a lot of shell programming in the past. But when you think about it, shell is perfect for AI generation in the sense that you’re basically building from these bigger components, the commands, and it’s very easy to find out exactly what a command does. It has wider knowledge of these things than we do, and you can see very quickly whether what it was producing, is it right or not?

Developer’s Fear of AI

  • People are getting much more realistic now. In the very beginning, people start going and extrapolating and they just get completely freaked out by the possibilities. Many developers now have had enough experience with AI that they realize it’s not going to replace them anytime soon.

  • At the end of the day, in the legal system, you can’t go and say, oh, the algorithm did it. It’s like, no! A person who works at a company did this. At the end of the day, we are responsible for what we do. That’s really important for us to go and recognize that there has to be somebody in the seat of responsibility. You have to understand what you’re creating as well. So I think we’re gonna have a place for a long time.

  • This guy basically made the case ages ago that we just need to see ourselves as problem solvers. And programming is one tool to solve a problem. Sometimes we can solve problems without writing code at all. And that’s great! But we have to basically do that thing of understanding far beyond the code. What’s the business and all these other things? Because all that information makes us much more effective. So I think it’s this thing of going and expanding out from our roles a bit. And I think a lot of people kind of recognize that’s just where the future is, and I do too.

SudoLang

  • It’s an interesting thing. Somebody wrote a couple of Medium posts about a thing they called SudoLang.

  • What the author was saying was that it would be great to go and actually create a language that’s kind of like a programming language that basically you can feed into an LLM that would go and generate code for you and do translations and all these other things. And so he described the language and had interesting features like constraints and stuff like this and a very familiar syntax and it wasn’t quite like any other language, but it seemed like it was at a bit of a higher level, because you could replace greater than with like the words greater than, for instance, and all this stuff.

  • But the further you read down in the post, the further you realize what had happened. What he did is he asked ChatGPT. Hey, I want to have a language which makes it easier for me to talk to you about programming and get the things that I want. Give me a language that does this. And actually, that’s what the system did. It created SudoLang.

  • And then it was even interesting and more tricky, because he said, I asked for this again, can you give me a syntax to work for this that’ll work even if I didn’t tell you what the spec of SudoLang was? And it’s interesting because it’s like it goes full circle at that point. So it’s really more like pointing in a direction. I don’t think it’s really like the language to learn.

  • In the book I’m writing right now, I basically talk about something I call pidgin specification. A pidgin language is a language that people from different languages adopt. They can communicate with each other. It’s usually some subset of two languages. I can write like a test case using just a very brief test colon dot, dot, dot, dot, this asserts that. I can type that in and basically say, give me this to me in JUnit. And it just gives it to me. And sometimes it’s wrong, but I’m dealing with something small enough I can actually see what the results are.

  • So I think we’re going to see an awful lot more of this, people developing like private languages in much the same way that you might with people you work with. I think we’re going to go and get into that symbiotic state with the coding assistants that we are using soon.

AI as Test Assistant

  • I basically do it and I quite often get frustrated. I’ve seen people kind of carry it a bit further. Llewellyn Falco has basically made some videos of going and doing this. It’s a powerful approach. You just need to get the bugs out of it to some degree.

  • Essentially, it’s like you write tests and then you’re going to go and sort of how to generate code to satisfy the tests. What I’ve been finding is that essentially, if you give it a whole bunch of tests at once, quite often, it’s going to do a reasonably good job for you. And you can run the test to see whether it has or not.

  • But quite often, I’ve done this thing where I basically start to go and say, okay, here’s a test. Here’s another test, here’s another test, here’s another test, and have it generate code. And I’m asking it to go and always make sure that when it generates code, that it’s going to satisfy all the tests I’ve shown it so far.

  • It’s kind of like a little bit problematic with that right now. And it has to do with, I guess, context window problems and stuff along those lines.

  • It’s moving forward in a good way. There’s so much you can learn just by going and taking a project and going and deleting all the source code and just giving all the tests to an AI assistant saying, write the code for me. The things that’s missing are things that you were missing in coverage for that kind of thing. There’s a lot of interesting stuff we can do in that space. It’s going to get better, and I think TDD is still going to be around.

Context Window

  • When you look at how an LLM works, it’s rather deep and involved, many layers of neural networks. At least for a little while ago, when it basically goes and does inference, like of your prompt and processing and things, it’s doing almost like a quadratic operation. The more that it needs in memory, the longer it’s going to go and take to go and do things.

  • For that reason, it’s kind of like you have this thing that happens quite often where you’re working in a session and then, after a period of time, you’re asking it to do something. And then it goes and gives you an answer, which makes it obvious that it doesn’t know which you gave it like 10 minutes ago.

  • I call this kind of like performance degradation. That just has to do with the physics pretty much of like how computationally complex these operations happen to be. So it puts limitations on how much we can go and basically do at once.

  • It’s just like the way humans interact with things. If I divert your attention to over there, it’s not going to be immediately on top of mind, the thing that we were just talking about and vice versa. We have attention and it’s relatively fixed, because nothing can have an infinite attention. It violates physics.

Waywords

  • It’s something I call waywords. And it’s kind of a powerful idea.

  • Suppose that you’re asking the tool to go and refactor something and you write a prompt to go and do this. It does that and you give it more test cases and you discover you need to change the prompt a bit and change it a little bit more. At that point, you probably want to name this thing. You don’t want to go and say, okay, you know, this is a, an operation called da, da, da, da, da. And then basically you can just, in English or your language, just go ahead and use that as a piece of new nomenclature and terminology. Ot’s just like introducing a method name or a variable.

  • One thing you can do sometimes is go and say, okay, now that I defined this thing, give me a summary prompt. Give me a prompt that I can use to put into another session so that we can go and actually do the same operations. It doesn’t always work, but it’s getting better.

  • I’ve really found a lot of utility in this thing of naming things as you go along, when you’re working with things.

Managing AI Sessions

  • For the most part, I kind of cheat by going and basically making the source code the thing.

  • If I know that I can transport source code from one session to another, that’s kind of good. But when I have durable things I’m working on, yeah, it gets down to copying things back and forth between sessions. Or just sort of re-describing something and quite often I can get it back to the point where I feel it’s useful. So yeah, it’s kind of problematic with that. So I’m looking forward to things getting a bit better in that space.

  • There’s somebody was talking about actually doing this and calling them skills, that you can actually sort of like make almost like plugins for particular things. And there are many different ways of going and tuning LLMs to go and facilitate this. But to the point where we can actually create user defined skills and move them across sessions, it’s valuable.

  • The other thing I’ll say is that even if we have an infinite context window, sessions by themselves are so valuable, because quite often I’ll keep one main session and I’ll basically just create small ones I dispose of.

  • It’s almost like managing tabs in a browser. And you have to kind of know when to get rid of them and when to keep them. But it’s nice to go and have a good separated space where you can actually go and do some working things and experiments without actually corrupting or degrading performance the original session you have.

Using Different AI Tools

  • Financially, in the world right now, the market is in this place where every time that you make a general LLM better, it’s kind of like you’re eating into the space where people do specialty things.

  • You can try to specialize a tool, but if people can just wait for the next general LLM to do things, then what does it do? But I think it’s starting to separate now and you’re starting to see decent coding tools that have their own utility.

  • What I like to do is even if I’m using Copilot or I’m using CodeScene or all these other tools, is have my own window open in something like cloud, for instance. Whatever I consider to be the best LLM at the moment, and basically do my more ideation work in that space. Because they aren’t clamped down.

  • Know what the tools are good for, but always keep your most capable general tool next to you in order to go and actually do the things that are gonna help you have high creative value.

3 Tech Lead Wisdom

  1. Looking for things that aren’t there is very valuable.

    • Just generally in life, if you can detect the absence of something that should be there then you’re in a good position.

    • The legacy code book came about because I realized this is a tough problem and nobody’s going to touch it. Nobody wants to touch on this problem. So it’s like, okay, might as well do this. So developing a sense for the absence of things is extremely valuable.

  2. Learn as many domains as you can.

    • Really digging into things. Because the more impressions that you get of different things, the more you have to draw upon when you’re formulating solutions yourself.

    • This is almost like how an LLM works in a way, right? It basically has read almost all the online content in the world. And one thing that makes it very effective is because it has that breadth.

  3. Just maintain your curiosity more than anything else.

    • Everybody who’s in software development is in a position to be able to learn more about many adjacent things. You’re able to learn more about business. You’re able to learn more about management and the resources available to all of us. It’s just a question of actually going there and deal with those things.

    • Those are the main things and those have served me well through my career. I don’t know to what degree people can trick themselves into curiosity if they’re not terribly curious. To me, it’s fun!

Transcript

[00:01:04] Introduction

Henry Suryawirawan: Hello, guys. Welcome back to another new episode of the Tech Lead Journal podcast. I’m very excited today to meet Michael Feathers. So we kind of like met nine years ago in one of his workshop back then in Singapore.

So I think today is the first time we met again after that such a long time. So Michael, really great to have you here. Welcome to the show.

Michael Feathers: Great, thank you very much.

[00:01:24] Career Journey

Henry Suryawirawan: Right. Michael, for people who may not know you, so maybe in the first place, can you help to introduce yourself, maybe telling us a little bit of highlights or turning points in your career that we all can learn from.

Michael Feathers: Sure. So my name is Michael Feathers, and I guess the thing I’m best, whoops, here’s the thing I’m best known for within the industry is writing a book called Working Effectively with Legacy Code. And I was involved in the early Agile movement before it was even called Agile, right? And I spent a lot of time since then just helping people with like legacy code and refactoring issues. And, yeah, that’s just been a thing I’ve been very much interested in. Prior to that, I spent about nine or 10 years programming, worked in various roles through the technical hierarchy. And um, yeah, just where I’ve kind of gone on from there.

[00:02:05] “Working Effectively with Legacy Code” Book

Henry Suryawirawan: Yeah, so I think your book, Working with the Legacy Code, right, uh, I think now it’s like in the 20th anniversary, so congrats for that, so I think.

Michael Feathers: So, yeah. Thanks for reminding me. I forgot what year it was to be 20, so yeah.

Henry Suryawirawan: Yeah, so I think it’s one of the so called classic software programming books, I would say. Especially people who are dealing with legacy code. So maybe let’s start from that book first, right? So since you are well known about that book. So legacy code, right? So in the first place, why did you write something about legacy code? I guess people back then may have started working on some legacy code that is difficult to work on or that’s something that you learned along the way.

Michael Feathers: Well, it’s kind of interesting with that. So, um, I went to a conference and I met Kent Beck and Ron Jeffries back in like 1999 or so. And I was starting to go and get to know some of the people that were like involved in the very early Agile movement, as I mentioned. And it was interesting because I learned so much from them. It was interesting because at that time I was a good programmer and everything, but they had really thought deeply about how to become better programmers. So I wanted to refactor, and I was doing a bit of that back in my workplace. And they were also saying things like, you should write your tests first. Why would you do it any other way? And I thought this was kind of like a very, you know, bold thing for them to go and say, but then I understood after I did it for a while. And it helped me realize I could reduce the stress of programming a great deal.

And so after that I was hired to be a consultant. I left the tech job that I had. And the job was to go around to different places and to help them acquire technical practices that are part of Agile, right? And invariably it’s kind of like you run into a situation where people have tons and tons of code. And they just don’t know quite what to do with it, right? It’s hard to refactor. And you look at Martin Fowler’s book from back in that day, and he said, okay, in a snippet, it’s kind of like, here’s all this refactoring stuff, but you should have tests. And if you don’t have tests, you’re in a bit of trouble. So I just realized that, um, this was a problem. And I just started collecting techniques for going and breaking dependencies and getting tests into place.

And yeah, it’s been an interesting ride that way. But it’s also been really kind of fascinating for me, because I started as like a mathematics major in school. I had this interesting idea of kind of like being an introvert, of course. I read about this mathematician named Paul Erdős and it was like, he lived with a suitcase and would go from place to place and sort of work with other mathematicians. And the cool thing was he didn’t even have to have a piece of paper or pencil to do this, right? He just had conversations and do these things. I thought, wow, that’s really an interesting thing to work on mathematics and just make it purely your life.

And then I kind of realized it’s kind of like, if you’re doing that, you’re not really helping people, right, directly. So I’ve had much more fun going and working with people and realizing that I can make a bit of a difference. And going back to my book, as much as it’s very technical and has a lot of code in it, I’m only realizing now how much it was really about going and helping people keep their morale up and, you know, have a positive outlook to what they can do and know what they can do within codebase.

[00:04:55] Definition of Legacy Code

Henry Suryawirawan: Yeah, I think the book itself, although it has been 20 years, I think it’s still pretty relevant, because people nowadays still work on legacy code. In fact, there might be more legacy code than last time before, right? But in the first place, let’s go back to the definition itself about legacy code, because some people might have different perceptions, different definitions. Some people think it’s like old legacy code. Some people think it’s code that they just don’t want to touch or they don’t understand. In your book, actually, you have one good definition that is probably interesting, right? You mentioned something related to tests as well in the very beginning. So maybe let’s go to your definition. What is legacy code, actually?

Michael Feathers: Oh, I’ve got many definitions, but the one I’m kind of known for is basically that legacy code is code without tests. And it’s funny about this because this happened when I was, um, working with a team and I had another consultant with me. And I got frustrated at one moment and somebody asked a question. I said, legacy code is code without tests. That’s just what you need to know, right? And um,you know, my friend, the consultant, he basically said, you know, you’ve got to put that out there. That’s a really powerful statement to say.

And I knew at the moment that it really was at odds with traditional definition. You get code from other people and that becomes legacy code, right? Or code that you’re scared of and don’t quite understand. But I think, you know, with all these definitions, they’re pragmatic in a way because they’re used to highlight something that you basically want to change. With this one, it was really just, I had this intuitive sense that, you know, if you have code and it has lots of tests and it’s relatively easy to change, if you don’t have the tests, you’re really in serious trouble. It’s a strong qualitative difference between those two different types of code bases. And so I was trying to get that across.

But occasionally, people will say, you know, who are you to make the definition of legacy, and it’s like, it’s just one. There’s many pick whichever one you want. Pick the one that helps you. I think it’s the best thing to say with that.

[00:06:39] The Importance of Automated Tests

Henry Suryawirawan: Yeah, so I think in the context of your definition, you have emphasized a lot about testing, right? I think in the very beginning, you mentioned you learned from Kent Beck about test first. Uh, maybe in the Refactoring book also it was mentioned that you refactor also along with the test. Why the test is so important in your opinion?

Michael Feathers: Well, I think the main thing is because, and this is going to be kind of like getting almost philosophical in a way. It’s kind of like, most all of us walk around with an idea in our heads about what the system does. And the thing is, it’s kind of like the system has its own idea about what it does. It’s not an idea. It’s what it does, right? And I think that that’s an interesting thing. We quite often get so caught up with what we think the system is doing and what we think we want it to do. And we forget to even think about what it currently is doing, right? So to me, that’s a very grounding perspective.

It’s kind of like, if you really know what the system does, you have a great base point to go and decide what to do next, right? And over and over again, I’ve run into situations where people, once they’ve learned a bit more about what the system actually does, they have different ideas about what’s possible. And they’re kind of like, oh, you know, it’s kind of like, people have been asking for this particular feature. And now I see it would be relatively easy to add that feature, right? I’ve always been sort of like saying, it takes three weeks to do this sort of thing, but now I know it’s much easier to do. And without that baseline of knowledge, you just really don’t know that.

So we talked about test first a second ago. One of the things I talk about in the book, something I call characterization tests. And quite often people call this like pinning tests now, sometimes. And the idea is that basically you write tests that you use to describe the current behavior of the system. So you’re not writing them first, you’re writing them after the code has been written. And you’re writing them to go and ask a question of the code base. And once you get the answer, you basically take that answer and you put it in as the expectation.

And sometimes this is called golden mastery testing in a way. It serves likea poor practice, but I think when you have existing code without tests, it’s just a way of going and actually understanding what you’ve got. And you can basically put that off to the side and distinguish it from the test that you write first to go and actually sort of, you know, figure you towards creating a feature and understanding when you’re done. So, yeah, that’s the thing to me. The test is a way of grounding our knowledge of a system for the most part.

Henry Suryawirawan: Right, when we refer to the tests, are you referring to automated tests or are you referring also for other types of tests? Like, I don’t know, people have manual tests, UI tests, regression tests, so many other tests out there, right? So are you specifically referring to just automated tests or something else?

Michael Feathers: Yeah, generally, automated tests. You know, it’s kind of like, it seems like I’m finding fewer and fewer places that still do much manual testing at all, right? And I think it’s, you know, especially with like DevOps and the Accelerate book and everything like that, you know, it’s, the idea is go and get something in place with tests and have it out there within an hour if you can, right? So it doesn’t really leave much time with that. So generally I am talking about automated tests. Yeah, it’s kind of funny. I think most of the people that are like thought leaders in the, um, non-automatic testing space have really kind of moved into calling it exploratory testing. Basically going and accenting the fact that as somebody who basically has ideas about what a system could be doing, you can just sort of verify those and look for really terrible things and make people aware of them, right? So that’s an exploratory approach.

[00:09:47] Understanding Legacy Code

Henry Suryawirawan: So I think talking about testing, right, although it has been around for many, many years, right, I think still the state of the software development practice these days, testing is still kind of like lacking in terms of quality, in terms of quantity. And I know that you have written this book since 20 years ago. Do you think the definition of legacy code is still kind of like relevant? Or is it something changing because with so many other tools, techniques, and also maybe now with AI, so is the definition still kind of like appropriate or do you think something has evolved along the way?

Michael Feathers: Well, if you don’t have any tests, I think it’s appropriate for you, okay? I guess that’s the best way to go and put it, right? But I, I think, you know, we might end up in a place where life is just a reverse. And I think it has to some degree through basically the thing that we don’t understand, right? And I think that’s another definition is like legacy code is code we don’t understand.

So yeah, you know, there’s a lot more that we can do now with in order to go and actually understand the systems that we have. When using AI for this quite often, just like taking a lot of code and sort of like put it into a session and asking questions about it. And, you know, the results have been mixed. I can kind of see the advantages to this now. And I’m thinking we’re kind of like due for, let’s see, it’s August 2024 right now, right? We’re due for this kind of backlash and people saying, oh, you know, we’re just making things up and it’s not going to help me as a programmer and stuff like that. But, you know, you can pay attention to social winds of things. But I think that this technology is only going to get better over time. And it’s really important for every programmer to learn how to use it well and understand its limitations are.

[00:11:15] Mindset for Working with Legacy Code

Henry Suryawirawan: Yeah. I think speaking about legacy code, right, I think almost all developers, I believe that they hate working with legacy code, right? No matter what, right? So either that they don’t know what the code is doing, either the code is buggy or the code is just so outdated that you can’t even change it to using the modern practice and things like that, right?

So in your consulting, I’m sure you have seen the worst of legacy code, maybe, and some which are probably not so bad. But if you can tell us a little bit, what are some of the typical challenges that people, when they deal with legacy code, why is it something that is kind of like avoided or hated a lot in the software development?

Michael Feathers: You know, I think the mindset has a lot to do with it. And I think also there’s the ambition of creating a new system, right? Um, and it’s kind of like, it seems with a lot of modern systems, you can, you know, you may be working with older code, but you get to go and sort of like create this little space where you have, say, a new service and you can write the code from scratch and do this. And you get very happy about this, because you get to sort of display your creativity. But some people actually enjoy debugging, right? Do you know some people who enjoy debugging, right? It’s the same kind of thing in a way. It’s this thing of trying to understand something. And I think I might be sort of like more predisposed to this than most people. Cause from being a kid, I’ve just always been curious about everything. Anything I could read, I would just sort of read, read, read, and try things out and that sort of thing. And if you approach it as an adventure, I think that’s something which is really kind of good in a way.

Reminds me of a story and it’s not directly about the technical work, but I was working with a team many years ago and it was interesting, because I was there for like four or five months on and off. And, you know, at the end of this, the guy who brought me in, he brought me into his office. He showed me these graphs and showed me how the quality had improved through all the time that I’d been there. We really, you know, made a big difference. And I thought, well, this is weird because I feel like a failure. Why do I feel like a failure? And what it was, this was like early days, like 2000s, like the dot com bust and all this other stuff. I I was working at a startup and everybody thought they were going to be a millionaire. They discovered they weren’t going to be a millionaire, right?

And it’s just this interesting thing of kind of like, I started saying to friends, it’s like, wow, it’s, you know, the thing which really affects whether we feel good today or not is what our expectations were, right? And it’s, you know, and I talked to a friend who was like an Eastern religion. He’s like, oh, that’s a Zen thing. I was like, okay. But it’s like It’s really an interesting thing. It’s like our expectations set our experience to a strong degree. And I think if you can actually cultivate the curiosity about what does this system do, right, or the desire to help people in that context, it can be very, you know, rewarding work. You may just have to go and put aside your expectations a little bit.

[00:13:50] Rewrite vs Fixing Legacy Code

Henry Suryawirawan: Yeah, you touched on just now, something that a lot of developers probably like to do, right, which is to create new system or rewrite everything, right? So since you write the Legacy Code book, what is your approach towards fixing the legacy code or maybe refactoring the legacy code versus rewrite, right? So when should we actually contemplate doing rewrite versus fixing the legacy code?

Michael Feathers: Yeah, a lot of it comes down to business reason rather than technical reason, because at the end of the day, the technical thing is just kind of like, we can deal with anything. You know, it’s a question of whether there’s payback for this particular thing, but the business case needs to be made. It needs to be, um, understood that you don’t have to rewrite an entire system most of the time. You concentrate on the things which basically are going to have growth in the future and also, you know, are presenting difficulty to you in the, uh, meantime. Usually what I like to do is I like to go and actually like try to do some refactoring, try to do some planning for some refactoring, look at prospective features. And then having all that stuff together, think about whether a rewrite is justified or not, right?

As I mentioned a little bit earlier, this thing of going and actually doing spot rewrites a particular thing is really pretty powerful. And quite often for people it’s like an all or nothing proposition, and that’s really a horrible position to approach these things from. But yeah, you know, the thing with rewrites is that it’s great if you have tests. If you have tests, you’re really in a golden space. And if you don’t, then you’re kind of like dealing with the situation of like, oh, I need to write this thing and I don’t understand what it does. And it’s like, okay, well, now you’ve got two problems, right? So I think that’s really just the best way to kind of approach it.

The thing is, that’s one, that’s rewrite when you basically are dealing with technical debt directly. But there are these other rewrites which are really all about architecture that really have, you know, a different set of considerations leading into them. And these are the big architectural ones are usually like, you know, much more extensive.

[00:15:36] Microservice for Legacy Code

Henry Suryawirawan: Speaking about architecture, right? So some people through the extreme, right, like doing microservice. So the one part of the definition of microservice for some people is like, if you can rewrite the whole service within, I don’t know, X days, right? Then that’s a microservice. So with that kind of, maybe, well designed microservice, you can do that. So what’s your take about this as well, right? Like when you refactor the application into a different service, is that also some strategy that you can do for tackling legacy code?

Michael Feathers: Yeah, definitely. You know, I think that’s, it’s an interesting thing to actually move things around to different places. And so it’s really at a macro level, the same thing we do as a micro level at a micro level with classes in many ways. But as far as I think of like, you should be able to rewrite it in a day or so, I think that’s a great goal, hard to see it in practice though. It’s really a weird thing. I think there’s this intrinsic thing about software that basically tends to grow and grow and grow. And quite often it grows to the point where you basically have, you know, hard to go and do anything like that, but it snuck up on you, that kind of thing.

And I remember, like, reading through some research years ago about, like, how big does a class need to be before you actually go and refactor, right? That kind of thing. And looking at actually, like, quality data, it’s kind of like where do we have the most bugs in the biggest abstractions to the smallest ones? Turns out the answer is really the ones that you touch the most often, right? And so it’s kind of like we all have a feeling for when things get to be too big, but quite often it’s kind of like there’s no set point. It’s kind of like a subjective sense in that way.

But yeah, I think there’s a lot of stuff that was a dream for microservices that I think is, you know, it’s a shame that we kind of fell away from some of that stuff. The thing of being able to use almost any language, be able to throw things into production almost immediately. Being able to go and rewrite them when we need to. And, uh, yeah, I don’t know. I tend to think that with a lot of these things, it’s kind of like we only get the resilience systems we need when we stress them a bit. If there’s a reason to start rewriting things, then it’s good. Because we actually gain the skill to do this and don’t think of it as being an atypical thing, right? So it’s actually good when there’s a bit of stress in the environment.

[00:17:33] Approach Dealing with Legacy Code

Henry Suryawirawan: Speaking about how people tackle this legacy code, right, maybe from your experience or maybe some summary of your book, right, what are the techniques that people can evaluate or maybe people can try to actually tackle legacy code in a much elegant way, so to speak?

Michael Feathers: In terms of that, I think main thing is to go and figure out exactly where you need to make changes, right? And you move outward from there. There may be cases where you need to change two or three lines in a method, for instance. Or you need to go and actually sort of like add five or six methods to a class, but maybe you’re thinking about creating a new class. And then what you do is basically you think about what would be involved in getting tests in place for each one of those places. And you kind of like crawl the tree upward and see if there’s a common place for those changes. And you try to pragmatically figure out where you want to go and have your tests.

Now, if you have code that doesn’t really have very many tests in place, chances are the code isn’t really able to accommodate tests yet. And they have to do quite a bit of dependency breaking work in order to go and actually put the tests in place to go and solve these problems. And that’s really what my book is mainly about is going and breaking the dependencies and writing the tests to go and do these things. But at a micro level, that’s what you kind of need to do, right?

I think in the more macro level, the important thing to go and remember is that, essentially, this is the kind of stuff where you’re never going to go and have complete tests on a code base unless you started that way, right? And that it’s okay to live in this limbo space, and you probably will for a long period of time, where you’re going to have some areas of great coverage and other areas of not so good coverage. And it’s just normal, right? But at the end of the day, the cool thing is that the things that you’re about to change right now, chances are you’ll be changing them in the future. So what you do to go and get tests in place for those things, it’s really kind of valuable if you need to go and actually start to make changes later and chances are you will. So you’re going to start to get like very quick returns from doing this sort of thing.

Like you’ll be thinking, you know, one day that it’s like, wow, I need to go and get in this area of code and there aren’t many tests or the tests aren’t very good. And it’s going to be a pain when I do that tomorrow. And then you get there tomorrow and you’re always like, oh, damn, well, one of my teammates was in there three weeks ago and they put tests in place and wow, yay, my job is easier than it was before.

Um, so I think there’s that, but there’s also, I guess, the psychological thing of basically doing that enough to get to the point where you notice the difference about how it feels when you have an area of code that’s easier to work in versus one that doesn’t. Quite often I run into people that have, you know, even independent of whether you have tests or not, they’re not used to working a good code base at all. And so they’re in pain, but they don’t know they’re in pain, right? And that’s really a tragic situation to be, so…

[00:20:03] Seams

Henry Suryawirawan: Yeah, speaking about some of the techniques you mentioned, like dependency breaking and being in the limbo situation, you have this one concept called seam, right? So I think that’s really a powerful thing. Maybe if you can, you know, define what is seam and how should people use it within their code base?

Michael Feathers: Sure. It was kind of funny, because I thought of this and I actually wrote a chapter in my book that came very close from going and pulling it out, because I thought it was just a peculiar way that I’ve been seeing software and it wouldn’t be beneficial to anybody. What it comes down to is this, that essentially when you look at a class or a set of classes, there are places where it’s easier to go and actually sort of replace things, replace behavior than other places, right? So let’s say you have a method and it’s basically doing something crazy with I/O. And you want to get it out of your way so you can write tests for the class without actually doing the I/O, right? If it’s a virtual method, right? You can basically go ahead and override it in the subclass, and then it’s out of your way.

So that part of the method is a seam. It’s kind of like a seam on your shirt. It’s a natural breaking point where you can actually go and replace one thing with another, replace one behavior with another. It’s interesting about this, because if you start to categorize all the seams, there’s just like lots and lots of them. But it’s an opportunistic way of looking at software to go and say, what can I do to actually, without changing things drastically, be able to go and get areas where I can get understanding and coverage? Because quite often, it’s like you’re, you know, if you’re going to make a change and you don’t have all day to go and refactor everything, you’re going to have to go and get that change in in a way which is not going to be disruptive, has very high quality, things along those lines. And it just might be a spot change, and it’s good to know where that’s possible.

[00:21:42] Strangler Fig

Henry Suryawirawan: Is this seam concept similar to the strangler fig kind of strategy when people doing microservice, you know, like or re-architecting certain parts of their API or their service?

Michael Feathers: Not really. I mean, to me, it’s like with strangler, it’s kind of like you’re… how you’re doing is you’re kind of like building things in parallel. You’re diverting flow to one area of the system so you can go build out another one. And it’s like my favorite, before it was even sort of like written up as a pattern. It’s like I used to live in Miami, Florida. And there’s like this giant bridge, a seven mile bridge that goes from South Florida to Key West. And it was kind of funny because many years ago, what they did is they’re kind of like, okay, we’ve got the old one. We’re going to build a new one next to it. And then we’re going to go and tear down the old one, right?

And it’s just, you know, I looked this up at the time. I think it’s like, parallel replacement is a term that people use in other engineering disciplines, you know, this kind of thing. But generally, that’s what strangler fig is, or, you know, it’s just thing of going and actually sort of selectively rewriting areas by going to allow yourself to go and have the old path to fall back on. So in terms of seams, I guess you do have to find seams in order to go and actually understand where you can make these diversion points. So I guess that’s the commonality.

[00:22:48] Understanding Refactoring

Henry Suryawirawan: Right. Thanks for the clarification. One thing that is always very tightly coupled, right, with the legacy code is this practice called refactoring, or you know, writing tests, maybe TDD as well. So maybe in your view, right, is it very important for us to be able to do refactoring right or refactoring well? Should we also read Martin Fowler’s book in order to be able to tackle legacy code better?

Michael Feathers: Totally. I think it’s really, it’s a, it’s a great book and it’s kind of funny. My daughter many years ago had a friend who was thinking about getting into programming. And he’s like, oh, what should I do? What should I do? And I gave him a copy of the book, Refactoring. And the reason I did this was kind of like there was, um, I think it was Ralph Johnson who said this many, many years ago when the book first came out. He says it’s kind of interesting that basically if you want to teach good design, basically teach people the things to avoid, and everything that’s left is good design. And that’s really the way the book is organized. It’s kind of like, okay, here’s all these code smells and your job is to go and look at these code smells and get rid of them. And if you do, you know, your design is going to be better than it was before. And it’s a great way of going and conveying design sense, you know, kind of like what is better than the other thing, right?

I think it’s a very valuable thing just in terms of understanding systems. But in general, in terms of dealing with systems, it’s extremely valuable. Because refactoring is all about clarifying things to the point where basically you can understand them, and where change becomes easier. It’s not just refactoring itself, but understanding the predecessors, like the code smells I mentioned, but also design principles. So you kind of understand what direction to carry things in. And once you have that, you know, you’re going to just be able to go and sort of like make things better for yourself in the future and the people around you. And that’s a wonderful thing.

[00:24:28] Testing Pyramid

Henry Suryawirawan: In terms of the structure of automated tests, do you have any suggestion or should we also still refer to the like test pyramid or maybe something around that? Or is there any kind of like a suggestion that you would advocate people when dealing with legacy code?

Michael Feathers: Well, I think for the most part, one of the things that’s kind of funny is that there was like BDD, behavior driven development, that came out many years ago, right? And of the interesting things there is they were concentrating on like high level behaviors and sort of writing tests that would deal with collaborations of classes at once. And it took me a long while to realize that, you know, I run into these people all the time that are writing like one test case class per test per class, right. And that you’re in this weird situation with that.

But invariably, you know, when I’m working with legacy systems, I’m trying to find some vantage point that I can write tests at. Which isn’t too far from the behavior I’m actually going and covering, but goes and covers, you know, the behaviors that I care about, right? And these clusters are really more than just one class quite often, right? That’s just the way things go. So I think that the conversation we have about whether something is a unit test or an integration test is not terribly productive in a way. I think it’s really about testing behaviors.

And you know, there’s many other people saying this as well as I am, but it’s just really valuable thing to go and look at is that you’re testing behavior. So you need to go and find the places where it’s best to do that and kind of move forward with things. So in testing pyramid, you’ve got unit and you go all the way up to like acceptance and stuff like that. I guess the thing to say is that you can basically, the lower level tests that you have are things that you build upon in terms of understanding the system. And there’s no way generally to go and have tests at an extremely high level and cover everything that you care about, right? So it’s kind of like I try to concentrate on the lower levels and then know that’s going to make the higher levels easier when I need to approach those.

[00:26:10] Code Nobody Wants to Touch

Henry Suryawirawan: Yeah. So what about if you mentioned something very interesting about behavior, change of behavior, right? So I think the business most likely will demand a lot of changes, right? And some program actually are not touched, because some business does not demand it to change, right? What do you think in terms of those kinds of code, right? For when it happened that we have to change the code, but there is some limited tests. Is this something that is also common in your consulting experience, right? How should people think about code that has been sitting around, still producing value, but one day it has to change, right? But it’s so difficult to change, because maybe people have left.

Michael Feathers: I think, generally, I’m really, you know, in favor of going and actually just really trying to go and make your changes supported by tests. Okay. Because even though today it looks like nobody’s going to change this and stuff like that, it’s kind of like it’s just the same thing to do. The fact that you have that code around still means it has value. So you don’t want to be in a situation where you’re just making it worse, right? But of course, people are gonna be pragmatic about this. It really depends upon how much other work they have in front of them. Stuff like this.

But, you know, I think even going through the exercise of like trying to write tests for something which doesn’t have many tests is really, really difficult. Using appreciation for, you know, it’s like okay. I’m never going to do this again. And none of my teammates are, because we know how bad this is, right? So it’s really always a valuable exercise. Try to get the tests in place to support the change you’re going to make.

Like the other thing I want to go and mention with this is that this is not an uncommon thing. It’s kind of like, you know, people in business all the time are trying to figure out how much to invest in particular things. In terms of like investing in the, you know, the current line of business, basically going and creating new lines of business and stuff along those lines. And we have the same thing as technical people. There are no easy answers to this question. I think it’s important to know that just going into it, you know.

[00:27:53] AI for Understanding Legacy Code

Henry Suryawirawan: Yeah. So one thing that could help us these days is AI, right? So if people are dealing with legacy code, maybe some people will play around and try to explain this part of the code base, right? So that you can actually understand it. So I know that you’re also writing this book, AI Assisted Programming, right? So I assume that you have been playing a lot with AI recently. So maybe let’s go there. How do you think the role of AI in terms of tackling legacy code? Maybe that’s the first question before we talk about anything in general about AI?

Michael Feathers: Well, it’s really kind of hard to go and actually sort of see where things are going to go, because they’re changing all the time, right? And I think the thing that people are most concerned with right now is the hallucination problem, where it’s kind of like you ask a question, you get an answer, and you just really don’t know whether it’s right or not. And I want to take that as a given. It’s going to get better over time, but I think the thing that’s important is really to go and understand that if you can’t trust what’s being generated, there still is value there. And I think a lot of this is really about going exploring alternatives. So it’s, you know, if I’m about to do something, quite often I’m like, okay, well, let me go ahead and ask for a different way of doing this. Okay, let me ask for three different ways of doing this, okay, and just compare them side by side and understand what’s possible in this space and quite often get ideas I wouldn’t have gotten otherwise.

For things that we can verify easily, like going and ask, you know, ask a question about a particular API and it gives you the answer. And of course, you put it in place and you find out very quickly whether it works or not. It’s kind of brilliant for that. But yeah, I do use it to explain code to me quite often. And I think…

God, one thing I love is this thing where you can sort of like, I call it lensing, and it’s kind of like you drop in a giant area of code and you’re kind of like, okay. This giant class that I have here, what responsibilities does it have? Right. And it goes and gives me a list of them. And usually, it’s kind of like eh, so-so. And you start to interrogate and ask other questions about it.

But I love to do this thing where you’re like, okay, you gave me 10 responsibilities. Just give me six. Basically, if you had to look at this fresh, it’s kind of like, what are the six most important responsibilities? And by scaling back and forth with this, you start to go and understand, you know, where perception can change of a class in terms of what the responsibilities are, depending upon the level that you’re looking at it, right? And it can give you ideas for refactoring. And so I find that very, very useful as a strategy. So there’s a ton of other little things like that that are kind of, you know, handy.

[00:30:06] AI Churning More Legacy Code

Henry Suryawirawan: So I think these days a lot of programmers have been playing around with AI. I personally also have used it. So I think you mentioned about hallucination problem, right? I think it’s also one of the risks, would AI also create more legacy code? Because like some people will just take it as it is, right? And then just plug it in and maybe deploy it without even test to verify it.

Michael Feathers: Of course, there’s something. It’s the GitClear report. I think one of the things that they were mentioning there is it seems like there’s a lot more churn of code. Code’s being put in public repos much faster, but there’s much more churn and change after it has been, right? Yeah, I mean, we’re just going to go and end up in this space for a period of time and everything.

The thing that’s tough is that it’s kind of like it’s shifting the balance in a way. It’s kind of like it’s easier to write code. And it’s a bit hard to understand it. And I think, for me, I’m always dealing with this fatigue issue. It’s like I’ll look for three different ways of doing something. And then I’m doing code review for all these things. And it’s kind of like at what point is that productive and at what point is that counterproductive for me, right? But it’s kind of like, you know, we have to review code that other people have written or that we’ve written a long time ago and had forgotten. And this just goes and increases the burden in that space, and it’s kind of tough.

I was just going to say, an area that I think is really kind of interesting is the entire thing of going and writing tests, right? Because I was kind of shocked in the beginning to see vendors basically go and say, hey, we’re going to write all your tests for you. Yay! As a TDD guy, you’re looking at this and you’re saying, oh my God, no, right? But for characterization testing, it’s really kind of powerful because, you know, if you’re not changing the code, right? It is a document of what the behavior currently is. And you can go and write, have tests written for this. And if they pass, then they are actually showing you, you know, real behavior. And so that’s useful. I think the thing we have to get used to with this is the idea that tests can be disposable and temporary sometimes, and just use them to get insight or to facilitate change. So I think that’s very valuable.

Henry Suryawirawan: Right, so you mentioned about generating test cases, right, and also interrogating code, you know, explaining code, right? What are some of the other use cases that you typically use when using AI in your, maybe, day to day work?

Michael Feathers: Oh, all the time. It’s just for exploring alternatives, you know, for the most part. And it’s like even things that have nothing to do with code. It’s kind of like, just, you know, it’s an interesting thing to admit, but I’m just so curious about things that I haven’t thought about. You know, something in culture or something and, you know, kind of like science and it’s like, damn, it’s like, you know, it’s like, how long is a manta rays, you know, uh, chin in the front? You know, it’s like, oh, yeah, there it is. That kind of thing. So it’s, um, yeah, it’s an interesting thing.

I just, I think. In general, any domain that you want to dig into, it’s easier to do now. You know, the advent of search browsers gave us a lot more ability to go and discover things and sort of learn things. And now, it’s off the charts, so I think that’s just really, you know, incredible.

[00:32:47] AI Assisted Programming Book

Henry Suryawirawan: You’re writing this book, AI Assisted Programming, I think it’s still in progress, right? Very early in the process, right? So what made you decide to write a book about AI programming?

Michael Feathers: Well, it seems like a very strange thing to do considering how fast things are moving, but I think what was interesting to me is I felt like it was an interesting way of going and actually talking more about how we work in a way. And I felt like there are some of the things we confront with AI are things we’re confronting with right now, but haven’t really talked about all that much, right? And you know, one of those is that fatigue issue that I mentioned a little bit earlier, right?

Let’s see. Another one is really the thing that sometimes, you know, it’s quite often you’re working in an IDE and basically gives you code suggestions all the time and you’re looking at this and it’s kind of like, can I accept this? How much trust can I place in this? And the same thing is true with code that you get from somebody else, right? Where’s my trust? How do I focus on this particular thing?

And then there’s the general thing of ideation. You know, one of the sections I have in the book talks about the loss potential if basically you ask a question of AI and you accept the first answer. Because quite often you just ask this prompt again, you get a different answer and a different answer and a different answer. And I find that so valuable because it sort of opens the possibility space in a way and gets you thinking about different things that pokes your mind in a different direction, which quite often gives you better ideas about things. And I think that’s, you know, a great thing.

The other thing as well is that basically it makes us better question askers, right? We get better at it, because we have to go and sort of ask questions to interact with it. So it’s really a capability amplifier.

[00:34:16] Prompt Engineering

Henry Suryawirawan: So, do you think this prompt engineering thing is one of the skill set that any developers now need to be able to master?

Michael Feathers: I think so. I think it’s, and it’s going to change. So I think with my book, it’s less about prompt engineering and more about approach. But yeah, it’s, it’s interesting. I think one section I haven’t written yet, but I gave an online lecture about it a while back. It’s just having a mental model of how these things work at a behavioral level so that it can help you with your prompting, right? And just, I can very briefly say, it’s almost like you can imagine you have this giant net, right? And it’s kind of like, if you ask a question, it pulls some of those things towards you. And then basically you ask another question, it pulls other things towards you. And quite often the way that you ask questions goes and leads you in a different path.

So it’s kind of like this thing of going in like, what are you pulling into active memory when you’re going in sort of like asking questions? And I think, you know, little things like that quite often make us better at doing these things.

[00:35:09] Doing in Small Steps

Henry Suryawirawan: Yeah, so I think what one… I mean, one thing that if we always ask questions and we got different answers, right? Obviously reading the code is like a big cognitive load, right? We try to understand different ways of doing things, although it may be end up the same. And also at the end of the day, still the same thing, right? So we got to write the tests for it. So if we don’t, actually, it creates a legacy code as well, right? I think reading code is something that I feel is much more important these days, right? Rather than actually writing it, because the prompt probably could, you know, use a natural language and they give us a code and you read the code instead. So in your view, like how can people master, you know, reading the code much better? Or maybe sometimes like the design is something that is sometimes it’s not appropriate with the larger code base, right? So what’s your take about developers taking AI answer and just putting it into the code?

Michael Feathers: I feel like everybody knows this, but I have to say it. So I remember like this story about like somebody is in like high school and they’re taking a mathematics course. Their teacher goes and says to them, you know, there’s one secret for getting an A to this course. And everybody’s like, oh, what is it? Do your homework, okay? Do the problems, right?

And I think that the same thing is true for us in software development. The secret for a lot of this stuff is take smaller steps, right? So if you are looking at generating something, generate something small, right? If you’re trying to understand something, paste in something that is kind of small and just get its take on things. And you’re just trying to understand with your brain, what’s going on with something, look at smaller steps and build up from the foundations. And, um, yeah, there’s a skill to that sort of thing.

I think there’s another thing which hasn’t been written up all that much that I think is kind of powerful, and it has nothing to do with AI, really. And it comes down to basically seeing enough systems that you develop enough impressions of different systems, you start to see what’s common and what’s different, right? So there’s nothing that’s a good substitute for going and having very wide experience of many different domains. And that experience, even if you’re not hopping from job to job to job, there’s just new reading. There’s books, there’s open source code and stuff like this. And you start to see how people approach problems differently in different domains. And then when you see something which is totally atypical to you, you have, um, I call it sometimes the coat hangers. It’s kind of like you’re given all this information and you’re looking for the things that are like the basis that you can use to go and sort of organize your knowledge as you gain more knowledge of the thing you’re looking at. And yeah, I think that’s a valuable skill to develop as well.

[00:37:29] Best Use Case for AI

Henry Suryawirawan: Yeah, you mentioned about understanding domain. Yeah, I still think that AI still hasn’t reached there yet, right? So maybe like building the whole application end to end, right? And also maybe building a more distributed complex systems is something that they haven’t reached out yet. So in your view, what is the ideal, you know, stage where we should rely on AI more versus something that use human creativity or brain more?

Michael Feathers: I think it’s really for the areas which are low risk. You know, it’s kind of funny because there’s all different ways of looking at risk. One of the things I think is great is actually going to develop boilerplate code. So it’s like thinking well back about creating like a Chrome extension. It’s kind of like, okay, just ask you to create like a simple Chrome extension. It’s kind of like I don’t need to write all that code. It can basically, I can find it very quickly whether it’s working or not, right? But I really want to concentrate on the thing that I want the Chrome extension to do, for instance.

There’s that. But there’s also things like that that can be like in house tools and stuff like that, where you have some confidence that somebody’s going to find a problem before it causes loss of life or money, right? That’s a very important thing, you know? So I think it’s finding these low risk environments.

And, you know, a place where this actually kind of works very well is if you’re creating tools to go and help you do things with your code, for instance. And I guess, you know, also things like quite often I feel like I’m rediscovering shell programming in a way. I’ve done a lot of shell programming in the past. But when you think about it, shell is perfect for AI generation in the sense that you’re basically building from these bigger components, the commands, and it’s very easy to find out exactly what a command does. It has wider knowledge of these things than we do, and you can see very quickly whether what it was producing is, is it right or not, right? And it’s usually very brief and you can see what that is.

So going and doing that for my work quite often has been a very valuable thing. So yeah, there’s that.

[00:39:16] Developer’s Fear of AI

Henry Suryawirawan: I think one topic associated with AI with software programming is that a lot of people are worried about their jobs, right? Or the roles will evolve quite a lot such that you are becoming obsolete or redundant, right? We also see some maybe hype technologies like Devin where they claim they can write code just by itself. Um, so what is your view about, you know, all this worry about developers having to maybe upskill themselves or maybe getting redundant or things like that? So is that something that we have to fear about?

Michael Feathers: Well, I think people are getting much more realistic now. I think in the very beginning, people start going and extrapolating and they just get completely freaked out by the possibilities, right? But I think many developers now have had enough experience with AI that they realize it’s not going to replace them anytime soon, right? This, basically, at the end of the day, you know, it’s kind of like, in the legal system, you can’t go and say, oh, the algorithm did it. It’s like, no! A person who works at a company did this. At the end of the day, we are responsible for what we do, right? And I think that’s the thing that’s, you know, really important for us to go and recognize, that there has to be somebody in the seat of responsibility. You have to understand what you’re creating as well. So I think we’re gonna have a place for a long time.

And I can’t remember the name of the book. I wish I could. Maybe I’ll send it to you as show notes, if you do that. But this guy basically made the case ages ago that it’s kind of like, we just need to see ourselves as problem solvers. And programming is one tool to solve a problem, right? And sometimes we can solve problems without writing code at all. And that’s great! You know, but we have to basically do that thing of understanding far beyond the code. You know, everything around it, what’s the business and all these other things, because all that information makes us much more effective. So I think it’s this thing of going and expanding out from our roles a bit. And I think a lot of people kind of recognize that that’s just where the future is, and I do too, so.

[00:40:59] SudoLang

Henry Suryawirawan: Thanks for, you know, giving your thoughts about this. So one technique that I found in some of your talk or resources that you shared before this conversation is that, uh, one thing called SudoLang right? I find it quite interesting, right? So I think for some who may not have heard about it, so tell us what is SudoLang and how can we use it in our, you know, day-to-day work with AI?

Michael Feathers: Well, it’s an interesting thing. This is going to take a minute or two to explain, right? But I remember, I think I found it through a web search. And somebody wrote a couple of Medium posts about a thing they called SudoLang. So it’s S-U-D-O Lang, right? Just as a pun on, you know, pseudo. What the author was saying was that it would be great to go and actually create a language that’s kind of like a programming language that basically you can feed into an LLM that would go and generate code for you and do translations and all these other things. And so he described the language and had interesting features like constraints and stuff like this and a very familiar syntax and it wasn’t quite like any other language, but it seemed like it was at a bit of a higher level, because you could replace greater than with like the words greater than, for instance, and all this stuff, right?

But the further you read down in the post, the further you realize what had happened. What he did is he asked ChatGPT, hey, I want to have a language which makes it easier for me to talk to you about programming and get the things that I want. Give me a language that does this. And actually, you know, that’s what the system did. It created SudoLang, right? And then it was even interesting and more tricky, because he said, you know, I asked for this again and I asked for it, it’s kind of like, can you give me a syntax to work for this that’ll work even if I didn’t tell you what the spec of SudoLang was, right? And it’s interesting because it’s like, it goes full circle at that point. So it’s really more like pointing in a direction. I don’t think it’s really like the language to learn.

And in the book I’m writing right now, I basically talk about something I call pidgin specification, which is really kind of like, a pidgin language is a language, you know, that people from different languages adopt. They can communicate with each other. It’s usually some subset of two languages. But I can write like a test case using just a very brief test colon dot, dot, dot, dot, you know, this assert that, right? I can type that in and basically say, give me this to me in JUnit. And it just gives it to me. And sometimes it’s wrong, but I’m dealing with something small enough I can actually see what the results are, right? So I think we’re going to see an awful lot more of this, people developing like private languages in much the same way that you might with people you work with.

I remember hearing about a musical group many years ago and someone new joined the band and they had serious trouble because the other musicians in the band could talk to each other, wink and a nod, and this guy was new. He had no idea what they were, where they were going and what they were doing because these people knew. They, they knew things about each other. I think we’re going to go and get into that symbiotic state with the coding assistants that we are using soon.

[00:43:42] AI as Test Assistant

Henry Suryawirawan: Speaking about symbiotic, you know, relationship, right? Will AI be appropriate for us to do this TDD cycle where maybe we generate test first and maybe AI help to verify and also create the business code, or maybe vice versa, that kind of stuff? Like a real pair developer, although it’s virtual, right? So is it something that you have seen it working before?

Michael Feathers: Yeah, I’ve done it. I basically do it and I quite often get frustrated. I’ve seen people kind of carry it a bit further. Llewellyn Falco has basically made some videos on going and doing this. But I think it’s, it’s a powerful approach. You just need to get the bugs out of it to some degree. The thing is that, essentially, it’s like you write tests and then you’re going to go and sort of like how to generate code to satisfy the tests. What I’ve been finding is that essentially, if you give it a whole bunch of tests at once, quite often, it’s going to do a reasonably good job for you. And you can run the test to see whether it has or not, right? But quite often, I’ve done this thing where I basically start to go and say, okay, here’s a test. Here’s another test, here’s another test, here’s another test, and have it generate code. And I’m asking it to go and always make sure that when it generates code, that it’s going to satisfy all the tests I’ve shown it so far.

And it’s kind of like a little bit problematic with that right now. And it has to do with, I guess, context window problems and stuff along those lines. So, I think, you know, it’s moving forward in a good way. I think, um, there’s so much you can learn just by going and taking a project and going and deleting all the source code and just giving all the tests to an AI assistant saying, write the code for me, right? The things that’s missing are things that you were missing in coverage, you know, for that kind of thing. It’s, yeah, there’s a lot of interesting stuff we can do in that space. It’s going to get better, and I think TDD is still going to be around.

[00:45:19] Context Window

Henry Suryawirawan: So you mentioned about context window, maybe some people are not familiar with the concept. And I know that some of the LLM newer models always mention about this context thing, which gets larger and larger and larger. Tell us, what’s the difference with having larger context window?

Michael Feathers: Well, it’s like when you look at how an LLM works, it’s kind of like, it’s rather deep and involved, many layers of neural networks. But it seems that, at least for a little while ago, when it basically goes and does inference, like of your prompt and processing and things, it’s doing almost like a quadratic operation. It’s just like the more that it needs in memory, the longer it’s going to go and take to go and do things. And so for that reason, it’s kind of like you have this thing that happens quite often where you’re working in a session and then after a period of time, you’re asking it to do something. And then it goes and gives you an answer, which makes it obvious that it doesn’t know which you gave it like 10 minutes ago, right?

And so it’s kind of like, I call this kind of like performance degradation, right? That just has to do with the physics pretty much of like how computationally complex these operations happen to be. So it puts limitations on how much we can go and basically do at once. But the thing is, I’ve heard recently that some of the newer models, I think Gemini claims that it has like, you know, an infinite context window. And I haven’t really kept up in that space to go and see whether those things still have that issue. I know some of the tools I’m using today still have that issue.

But I think it’s going to be with us regardless, because it’s very much like… I took a lot of cognitive science in college, and it’s just like the way humans interact with things. It’s kind of like, if I divert your attention to over there, it’s not going to be immediately top of mind, the thing that we were just talking about and vice versa, right? We have attention and it’s relatively fixed, because nothing can have an infinite attention. It’s just, it violates physics. So we’re always going to have that thing of kind of like what’s in our attentive focus and what is not. And I think that basically understanding that’s very useful to being effective with AI right now. So I guess, I hope that’s a decent summary.

[00:47:14] Waywords

Henry Suryawirawan: Yep. Thanks for explaining that. So we have spoken a lot of things about AI. Any things that we haven’t spoken that you figure it out recently that people need to know about AI programming?

Michael Feathers: Ah, it’s funny because in writing this, it seems like I’ve had a lot of topics and it’s been like digging down deep in them. So recent isn’t really, you know, the best way of going and putting it.

Here’s one. Okay. And I just released on LinkedIn a couple of days ago, a chapter that I was writing. And it’s something I call waywords. And it’s kind of a powerful idea. And what it comes down to is this. It’s kind of like, suppose that you’re asking, you know, the tool to go and refactor something, right? And you write a prompt to go and do this. And then it’s kind of like, it does that and you give it more test cases and you discover you need to change the prompt a bit and change it a little bit more. At that point, you probably want to name this thing, right? You don’t want to go and say, okay, you know, this is a, an operation called da, da, da, da, da. And then basically you can just, in English, you know, or your language, just go ahead and just sort of like use that as a piece of new nomenclature and terminology. And so it’s just like introducing a method name or a variable.

One thing you can do sometimes is go and say, okay, please, you know, now that I defined this thing, give me a summary prompt. Give me a prompt that I can use to put into another session so that we can go and actually do the same operations. It doesn’t always work, but it’s getting better. But I’ve really found a lot of utility in this thing of naming things as you go along, when you’re working with things. It can just be, okay, well, this example I just created, call this response ABC. And then you can go back and say, well, when we did ABC, that thing, right, it’s going to create these handles along with the other things. And, um, yeah, pretty useful thing to go and use.

[00:48:53] Managing AI Sessions

Henry Suryawirawan: So speaking about this nomenclature, right, we just spoken about the context window in the different sessions. Do you have to sometimes copy and paste the prompts that you had previously in some of the notes. And then when you work on a different sessions, maybe some couple of days later that you have to paste it back, load sort of the memory or the cognitive thing to the AI brain, and then try again? Uh, is that something that is also commonly done by people who are using AI?

Michael Feathers: Oh, I think for the most part, I kind of cheat by going and basically making the source code the thing, right? It’s kind of like, if I know that I can transport source code from one session to another, that’s kind of good. But when I have durable things I’m working on, yeah, it gets down to copying things back and forth between sessions. Or just sort of re-describing something and quite often I can get it back to the point where I feel it’s useful. So yeah, it’s kind of problematic with that. So I’m looking forward to things getting a bit better in that space.

I think there’s somebody was talking about actually doing this and calling them skills, that you can actually sort of like make almost like plugins for particular things. And there’s many different ways of going and tuning LLMs to go and sort of like facilitate this. But to the point where we can actually create user defined skills and move them across sessions, it’s valuable.

The other thing I’ll say is that even if we have an infinite context window, sessions by themselves are so valuable, because quite often I’ll keep one main session and I’ll basically just create small ones I dispose of, right? It’s almost like managing tabs in a browser, right? It’s kind of like, here’s the main tab I’m working and I’ve got five, six, seven, eight. And you have to kind of know when to get rid of them and when to keep them. But it’s nice to go and have a good separated space where you can actually go and do some working things and experiments without actually sort of corrupting or degrading performance and, you know, the original session you have.

[00:50:30] Using Different AI Tools

Henry Suryawirawan: I know it’s a fast changing world these days, right? But any tools, favorite tools that you use these days, you know, related to AI and coding? Or is it Copilot still the best thing?

Michael Feathers: This is gonna be so weird, but there are so… You know, Copilot is great, but it’s one of the things I kind of am drawing a distinction between is that, let’s see, we’re in a, financially in the world right now, the market is in this place where every time that you make a general LLM better, it’s kind of like you’re kind of eating into the space where people do specialty things, right? So it’s kind of like you can try to specialize a tool, but if people can just wait for the next general LLM to do things, then, uh, you know, what’s it do, right? But I think it’s starting to separate now and you’re starting to see decent coding tools that have their own utility.

But what I like to do is even if I’m using Copilot or I’m using CodeScene or all these other tools, is have my own window open in something like cloud, for instance. Whatever I consider to be the best LLM at the moment, and basically do my more ideation work in that space. Because they aren’t clamped down. And what I mean by that is that sometimes you’ll be using a tool in an IDE and you’ll say, well, give me three other approaches for going and doing this, or tell me more about this thing in the domain. And they’ll say, no, I’m sorry. I’m here to help you with your code and refactoring and that’s it. And you don’t, you know. Know what the tools are good for, but always keep your most capable general tool next to you in order to go and actually do the things that are gonna help you have high creative value.

Henry Suryawirawan: Yeah, I personally also subscribe to many AI tools, right? So I think sometimes you just, you know, pick best from whatever AI that you use, right? And sometimes, yeah, one works best for certain contexts, and the other works best for others. So I think this landscape is changing really, really fast. So I think there will be more exciting stuff happening within this space. But one thing for sure, like what you said, I think probably developers role won’t be like gone, right? People are still having to problem solve something, right? And especially also the understanding about domain, right? I think that’s still one key.

[00:52:28] 3 Tech Lead Wisdom

Henry Suryawirawan: So thank you so much for this exciting talk, Michael. Unfortunately, we reached the end of our conversation. But before I let you go, I have one last question that I always ask my guests. I call this three technical leadership wisdom. You can think of it just like advice that you want to give to us, the listeners here. So maybe you can share your version of the wisdom.

Michael Feathers: Yeah, it’s kind of funny because I was looking back through, you know, the other, you know, some of your earlier episodes. And, um, you know, there’s a lot of things about basically managing organizations and basically dealing with people and stuff like that.

Purely from a technical point of view, the thing I want to go and basically mention is that basically looking for things that aren’t there is very valuable, right? I think just generally in life, it’s kind of like if, if you can detect the absence of something that should be there, right, then you’re in a good position. The legacy code book came about because I realized it’s like, this is a tough problem and nobody’s going to touch it. Nobody wants to touch this problem. So it’s like, okay, might as well do this, right? So developing a sense for the absence of things is extremely valuable.

The other is like, you know, number two, I guess, would be basically learning as many domains as you can, right? Really digging into things. Because it’s like, the more impressions that you get of different things, the more you have to draw upon when you’re formulating solutions yourself, right? And, um, this is almost like how an LLM works in a way, right? It basically has read almost all the online content in the world. And one thing that makes it very effective is because it has that breadth, right? So you’ll quite often see yourself, I’m reading about this and you say, wow, that’s very close to this thing over there. What is, is there a commonality here? And then you start asking questions and going deep, right?

And I guess the third thing is really just maintain your curiosity more than anything else. You know, everybody who’s in software development is in a position to be able to learn more about many adjacent things. You know, you’re able to learn more about business. You’re able to learn more about management and the resources available to all of us. It’s just a question of actually going there and deal with those things. I guess those are the main things and those have served me well through my career, you know. And I, I don’t know to what degree people can trick themselves into curiosity if they’re not terribly curious, but yeah, I hope they can because, you know, it’s fun. To me, it’s fun, so yeah.

Henry Suryawirawan: I’m sure when people opt for the programmer’s job, I think there is a sense of curiosity because otherwise, right, I mean, they can’t be a good programmer anyway. So…

Michael Feathers: Just some of the most interesting conversations that we’ve had at conferences, they have nothing to do with software. Just people are just very into things and curious, so, sorry.

Henry Suryawirawan: No problem. So thanks again for this conversation. So if people like this conversation or they want to reach out or check out with you certain stuff, is there a place where they can reach out online?

Michael Feathers: Sure, there’s my Substack, michaelfeathers@substack.com . There’s also on X or Twitter, it’s mfeathers. So just either one of those places is perfectly fine to go and reach me. You can also search for the book, AI Assisted Programming on LeanPub. And, uh, it’s early days, I’m about 15 percent done, but I’m releasing new chapters every week or so, thanks.

Henry Suryawirawan: I don’t know how far it can be like a legacy code book, right? Which is like very classic. But I think, I hope I can see the book in a full form, right? And learn how to use the AI much better. So thanks for writing the book as well.

Michael Feathers: Sure, thank you.

– End –