70

In a couple of months a colleague will be moving on to a new project and I will be inheriting one of his projects. To prepare, I have already ordered Michael Feathers' Working Effectively with Legacy Code.

But this books as well as most questions on legacy code I found so far are concerned with the case of inheriting code as-is. But in this case I actually have access to the original developer and we do have some time for an orderly hand-over.

Some background on the piece of code I will be inheriting:

  • It's functioning: There are no known bugs, but as performance requirements keep going up, some optimizations will become necessary in the not too distant future.
  • Undocumented: There is pretty much zero documentation at the method and class level. What the code is supposed to do at a higher level, though, is well-understood, because I have been writing against its API (as a black-box) for years.
  • Only higher-level integration tests: There are only integration tests testing proper interaction with other components via the API (again, black-box).
  • Very low-level, optimized for speed: Because this code is central to an entire system of applications, a lot of it has been optimized several times over the years and is extremely low-level (one part has its own memory manager for certain structs/records).
  • Concurrent and lock-free: While I am very familiar with concurrent and lock-free programming and have actually contributed a few pieces to this code, this adds another layer of complexity.
  • Large codebase: This particular project is more than ten thousand lines of code, so there is no way I will be able to have everything explained to me.
  • Written in Delphi: I'm just going to put this out there, although I don't believe the language to be germane to the question, as I believe this type of problem to be language-agnostic.

I was wondering how the time until his departure would best be spent. Here are a couple of ideas:

  • Get everything to build on my machine: Even though everything should be checked into source code control, who hasn't forgotten to check in a file once in a while, so this should probably be the first order of business.
  • More tests: While I would like more class-level unit tests so that when I will be making changes, any bugs I introduce can be caught early on, the code as it is now is not testable (huge classes, long methods, too many mutual dependencies).
  • What to document: I think for starters it would be best to focus documentation on those areas in the code that would otherwise be difficult to understand e.g. because of their low-level/highly optimized nature. I am afraid there are a couple of things in there that might look ugly and in need of refactoring/rewriting, but are actually optimizations that have been out in there for a good reason that I might miss (cf. Joel Spolsky, Things You Should Never Do, Part I)
  • How to document: I think some class diagrams of the architecture and sequence diagrams of critical functions accompanied by some prose would be best.
  • Who to document: I was wondering what would be better, to have him write the documentation or have him explain it to me, so I can write the documentation. I am afraid, that things that are obvious to him but not me would otherwise not be covered properly.
  • Refactoring using pair-programming: This might not be possible to do due to time constraints, but maybe I could refactor some of his code to make it more maintainable while he was still around to provide input on why things are the way they are.

Please comment on and add to this. Since there isn't enough time to do all of this, I am particularly interested in how you would prioritize.

Update: As the hand-over project is over I have expanded this list with my own experiences in this answer below.

4
  • 2
    Focus on documenting the why's of the optimized functions!
    – user1249
    Nov 8, 2011 at 6:52
  • I hope the code is under source control. If so, you will benefit from the comments entered for each change (if any).
    – Bernard
    Nov 9, 2011 at 20:56
  • Good call on using Michael Feathers' Working Effectively with Legacy Code. Definitely need to start getting those test cases written around the modules that you think are most likely to need modification. If you start now it will be easier to get expectations correct. Nov 9, 2011 at 22:37
  • There is a phase before refactoring, which I have a doubt for which Internet seems to be poor on answers: What do top programmers do to understand someone else's complicated and illegible code?
    – sergiol
    Apr 26, 2017 at 0:44

11 Answers 11

27
+50

As you have access to the developer you code ask:-

  • Which modules were the most difficult to code/implement. What were the problems and how were they overcome.

  • Which modules have generated the most bugs.

  • Which modules have resulted in the most difficult to solve bugs.

  • Which bits of code he is most proud off.

  • Which bits of code he would really like to refactor, but, has not had the time.

These questions will give you an insight into whats going to cause you the most problems, and, perhaps more importantly a handle on the thought processes and perspectives original developer.

2
  • I like the idea of picking the parts you mentioned. Intuitively, I would have followed a top-down but that way the most nasty parts buried deep in the code might not have come up until very late, maybe too late in the process. Your way makes more sense, I think. Do you have any suggestions for the "how to document" part? UML? Text? Nov 9, 2011 at 18:54
  • @PersonalNexus. You can carry this approach over to documentation as well. Ask which documents are most useful, and, which documents are unreliable or out of date (believe me 95% of documentation falls into the last category!). Nov 10, 2011 at 3:21
21

As the hand-over project is now over, I think I would take the time and write up my own answer containing those things that worked best for me.

  • Get everything under version control: After making sure everything I needed to build was under version control, I also searched at the old developer’s hard drive, to look for additional scripts or utilities that would be helpful to deploy and/or test the application but weren’t checked in.
  • Top-down: I would start off with a high level look at the major classes and a guided tour with the old developer of the main areas. Then I would dig deeper into the rest on my own, flagging things that didn’t make sense to me with //TODO markers.
  • Write all documentation myself: While I had the old developer look over my writing to make sure I got it right, I insisted on writing everything myself. This way I would be sure the writing made sense to me and not only the old developer.
  • Comments everywhere: I added XML documentation summaries to every class and every method. This way I made sure I had at least looked at every piece of code and have enough of an understanding to summarize what it did in a sentence. It also made understanding the methods using summarize methods/classes easier as IntelliSense picks up this information. I could also easily identify areas of the code that I still had to look at.
  • Document close to the source: In order to make the connection between the source code and documentation easier, I put most of my documentation right in the source code. For high-level documentation that describes the interaction between various sub-systems, I used a wiki, as putting this information in just one place in the code didn't work. All of the documenation should be electronic and full-text searchable.
  • Diagrams: For a basic overview I used class diagrams of various granularities for the different sub-systems. For the concurrent parts, object and interaction diagrams have been really helpful; see also my other question on the topic.
  • Refactoring as a pair: While I did some refactoring with the old developer to get a feel for the code and make things more maintainable, this was a time consuming and also risky process, because of the lack of good refactoring tools and a bunch of nasty dependencies among the various parts. Michael Feathers' Working Effectively with Legacy Code is a really good help for this, even though refactoring without proper tool support is still painful. While refactoring I would let him have control of mouse and keyboard, as it was more fun for him tis way (see also my last bullet point) and I was free to write down what I was learning.
  • Separate check-ins for comments and changes: After I accidentally introduced a bug by writing a comment over an override, I have been careful to make comments and changes in separate check-ins. I used a little utility to strip all comments from the source code before checking something in, so a diff of a comment-only check-in would show 0 differences. All changes (e.g. removal of unused fields) were carefully peer-reviewed with the old developer to make sure I wasn’t removing things that were still needed.
  • Line-by-line walkthrough of critical passages: For the most optimized/complex passages, I would go over the code line-by-line with the old developer and sometimes even with a third colleague. This way I got a thorough understanding of the code and as more people vetted the code, we actually identified a few bugs as well as some things that could be further optimized.
  • Be quick and keep the old developer motivated: I noticed that the old developer was less and less interested as his last day was coming closer (not surprisingly). I would therefore make sure the most critical parts were handed over first, leaving the rest for me to figure out on my own, if necessary. I also tried to leave the more fun things (e.g. control of the keyboard when pair-programming) to him and do the boring things like documentation writing myself.
  • Identify feature requests: I found it helpful to ask the old developer for a list of features that people had asked for but that weren't added yet. There were a few things that to me looked simple to add, but where there was a good reason they weren't added as they would have broken other things when implemented they way I had thought at first.
0
17

Having been in a similar situation, I believe the following would also be worth consideration:

  • Make sure you can make, and test, a deployment: Do your own deployment of the product, from scratch - and verify that this is identical to one done by the person who's leaving. This would make sure that any scripts and instructions are clear to you, and would catch any accidental oversights such as ingredients not having been checked in to your version control system. (I'm not saying that this would happen, just that if it has happened, it will be a lot easier to deal with now, before the person leaves)

    (This may not be relevant for you, e.g. if you already do Continuous Integration or Continuous Deployment, but it's worth mentioning, just in case...)

  • Writing more tests: This is a really good way to test your understanding of a system. It will enable (or force) you to look more closely at areas of the code, and will either confirm that the code is as bug-free as you suspect, or will reveal areas where you thought you understood the intention, but that actually you need to ask your colleague for clarification before he leaves

  • Pair-writing of documentation: This is an effective way to write overviews. I'm suggesting that you get your colleague to describe a feature or area, and then you write it up, in documentation, in your own words. We found this was massively easier when done by two people together.

I'd put the writing of tests as a higher priority than writing of documentation, personally, as the tests will probably give you more - or firmer - understanding.

Regarding Refactoring using pair-programming, the only thing I'd say is that there's a danger that this can become a bottom-less pit, especially given that you said you've only got high-level tests. You might find it ends up using way more of the available time than you'd intended.

0
13

+1 for the answers you already have in your question!

Guided tour
10k lines of code is a lot, but I think it's still not impossible to have the other guy give you a 'guided tour'. You sit down together in front of the code and he takes you on a trip from the top to the bottom, working down the 'layers'. You'd need to do it in short bursts - all in one go would kill both of you.

Zoom-in, zoom-out
The advantage of doing this is that while he's explaining it to you, he will almost certainly have some "oh, yes, there's this as well" moments that he might not if he was just trying to document it on his own. And your questions will help to focus in on the obvious-to-him-but-not-to-anyone-else bits. This kind of zoom-in/zoom-out interaction is only possible one-on-one, trying to write or read something like that is unwieldy.

Documentation
I think you should both be independently documenting stuff - he should start at the bottom (in case you don't have time to get there together), and you should start at the top, on the basis of what you've understood of his guided tour and as if it was for someone else [in a previous job I inherited a load of 'legacy' code, and only just had the time to document it before leaving myself :)].

Where's what?
The aim of most of this is for you to be able to get a feel for where stuff happens. So that given a particular bug or modification, you can very quickly find the place in the code which you need to concentrate on. You could test yourself by taking the list of old bugs and seeing if you can accurately predict where the problem was.

Pump him dry
It doesn't matter if he ends up hating you (smile), your job is to get as much information out of that guy's brain as you possibly can in the time available. Make sure that you get management on your side, and that they prioritise knowledge transfer over "just fixing those last few bugs before he leaves" (unless you're fixing them together...).

2
  • 1
    "It doesn't matter if he ends up hating you" -- careful, "it's a small world" ;)
    – retracile
    Nov 10, 2011 at 22:29
  • Also, open up a word document and document the living heck out of everything, including a ton of screenshots. It's saved me plenty of times when you're in an information overload state!
    – Ben Power
    Aug 9, 2018 at 3:29
9

I suggest the following (in addition to what is already identified) - First, ask your manager to give you time to work with this guy as much as possible and try to sit with him whenever he is tasked of doing a change. You don't have to know everything he is doing but try to catch as much as you can. Most important be friends with him.

Treat the hand-over as a project and put a plan in place and involve the management.

0 - Make sure you know how to use the system.

1 - Make a clear inventory of the solution components, the source of each and where it lies (in diff. repositories)

2 - Get and if possible, manage, the passwords for the different servers starting now. Make sure you have all the admin account information

3 - Get the licenses of each external component unless its outside your scope (e.g. special dlls, database, etc.)

4 - Get a written report about the current status of the system from the developer and your customers (if they are local to your company)

5 - Get the documentation for the business rules, calculation formulas, etc. You can do this with him. Ask him for emails, meetings information, user requirement documents, design documents and the like to be given to you.

6 - Get a list of scheduled events (monthly runs of jobs, weekly runs of jobs) that the software has to respond to

7 - Learn the backup/restore procedures

8 - Understand the framework(s) used in building the application

9 - Get to the know the requested/expected/planned modifications and the status of any pending user requests. Begin trying to identify how to do those on your own.

10 - Make sure your test and development environments are very similar.

11 - Try to identify major dependencies (on other systems or between components) that can't be easily spotted.

12 - Identify and document the required versions of each software use and its vendor contact (if necessary)

13 - Identify any special tools he was using that you don't have, in case it could help you.

14 - Get a high level system flow. and start building your documentation library

15 - Understand how to manage user security for the application

16 - Get the bug log and try to understand the actions and how the action affected older data (if applicable)

17 - Know processes that takes too long and what do you need to watch for (e.g. unusual file sizes, ftp of duplicate files, etc.) where applicable.

18 - Check the production server clock

19 - Identify where the configurations are and compare each environment configuration with the production to know what parameters are different and why

20 - Get this guy's contact information

21 - If the system is internal, schedule a a meeting with the system users (you need to know who they are and what the role each plays) and be introduced to them. Listen to what they have to say about the system and about their current problems if any. Make sure you are included in emails as early as possible (after your manager's approval)

22 - Assess your understanding 1 week before he leaves and report any problems you see as a risk

Since you mentioned you don't have a database, this list got shorter.

Good luck.

2
  • The numbering of the points implies an order. If so, why is "Get a high level system flow" way down at #14? Seems to me that this should be way higher.
    – ximiki
    Feb 11, 2020 at 15:27
  • @ximiki, you are sort of correct. In this case, the numbering of the points does not imply importance of task sequence. I used numbering so that if someone has an issue with a point they could easily refer to it, similar to what you did :)
    – NoChance
    Feb 11, 2020 at 20:20
6

I would consider the most complicated, optimized-for-performance parts first. I would get him to first document those parts and explain them to you one at a time, then I would try to write tests against those parts (incuding before and after performance tests, so you can see if a new optimization makes things better or worse) and have the other person review the tests. This way, he documents and explains, you use the explanation to write tests (while he is documenting a different area), and his review will help make sure you understood what you should be be testing. That way you also get additional test converage for some of the most critical parts of the application and documentation of the specialized performance optimizations.

If there is time after covering those, I would next go through a similar process with the parts of the application which have most frequently needed change through the years but which are not in the first group of things documented.

Then document anything that's left.

5

I think the best way to grok some large code is top-down approach. Try to understand the big picture first, and then gradually dig deeper into components one by one.

Now at each level of digging, ask him to prioritize the parts that need most attention. Have him explain you as much as possible, but always document it yourself.

The best part about documenting it yourself is that when you'll come back later, you'll have no problem recollecting the same cognitive state you were in, when he explained it to you. You can far more easily understand what you wrote than what someone else did. In my experience two people documenting the same piece of code don't produce similar looking pieces of text.

This, I guess also solves your "what & how to document" issues. When he explains you everything, you can then decide yourself what you'll wish were documented when you return to the code -- and document only those parts.

The idea is to first completely understand the code (in his presence), and then write/do everything that will make it possible for you to grok it later (in his absence).

By completely understanding the code I mean you need to get a feel of the big picture -- and how each component relates to this big picture. I've found it particularly helpful to keep track of how each piece adds up the whole. Don't try to comprehend anything in isolation -- never lose the sight of it's context.

Lastly, once you have done the above, proactively take the control. Decide yourself what pieces you need unit-test coverage for. what parts need to be (or can be) optimized, how can you refactor some component, etc. Trust that if you know the system, you can take all the decisions once he is gone.

2
  • how are you supposed to document it? plain text ? wiki ? comments in source code ?
    – c69
    Nov 8, 2011 at 12:30
  • Anything that makes it possible to restore the same understanding of the code you had when you were writing the docs.
    – treecoder
    Nov 8, 2011 at 12:57
5

I feel for you.

A few suggestions:

  1. Tape every conversation you have with the leaving programmer!
  2. Ask for the motivation behind the "big" issues. It's good you understand the API, but dig for the internal decisions - why was the code partitioned as it is? what are the responsibilities.
  3. Make an effort to really study the code. When you assume maintenance and support duties there is sometimes the pressure to "study the code while making progress". Resist if you can, and really study the code.
  4. Look for scenarios. You know the API - see how the code behaves. An example that comes to mind is that of a Fax module. As a user of the API, you preheps had to prepate a page image and send the code a command to transmit the page. Ask the leaving programmer to trace with you on the code to see how this scenario carries through. Then, of course, go the "receiving page" scenario.
  5. 80/20 - try to cover the more common scenarios first.
  6. Consider a re-write. If the code is old and the interfaces are well defined, maybe technology has changed enough to justify it.
  7. I hate to say this, but consider looking for a new job.
0
3

If you want decent documentation reasonably painlessly buy a copy of Pascal Analyzer (PAL) I have used this on Delphi projects and it was great - they may now have split the documentation functionality off into a product I'm not familiar with (Pascal Browser) so you may have to buy both (< 300 USD) but PAL was a great tool for understanding where variables were being used where functions were being called from etc & picking up all sorts of potential issues with the code.

Use PAL to get an idea of how the code's structured plus probably a list of about 1000 suggested improvements if my experience was anything to go on. Working through the list will improve the quality of the code, simplify it greatly & make your life easier for the future. Delphi itself supports refactoring in recent versions (the last 5 years or so). You did need to include everything in the dpr file for it to really work properly back when I was doing it so bear that in mind.

If you want unit tests, download DUnit & start creating some tests with the original coder - that's probably a constructive way to use at least some of their time.

2

Though you have not mentioned about a backend database but assuming there is one you should

  1. Get the data model documented especially the columns and PK-FK
  2. Setup a sql trace and record all the queries which are fired while using the application.The order of execution of queries will give you a good idea about the flow of the application and also help in debugging
0
2

I am in same situation where our Architect moved to Australia and left over lot of legacy as he was with company from last 8 years. He him self inherited legacy stuff from previous Architect who was a contractor.

You and others have already mentioned good points but here is problems we faced after he left may be you can prepare better ...

1) (Technical Person) Contact details of the customers he is dealing with.

2) His account under which he bought softwares licences , keys which need be renewed every year and processes/costs to renew them.

3) Document of Setup of third party software libraries/components and products which integrate with your products. We struggled for 4 days to bring back a machine which was lost due to IT clearing up space and some wrong instruction passed to them.

4) Documents/steps he is used to deposit source code to software Deposit companies eg Escrow.

5) There is still long list but may not be applicable to you also No amount of documentation can replace a real person so Keep his details handy , stay in nice terms and good luck :)

Also I dont know if this is first time for you. For me I have worked with 5/6 employers and have always inherited code with bad documentation or no documentation at all. So along with all the documentation just stay positive :)

Not the answer you're looking for? Browse other questions tagged or ask your own question.