Live data from Hacker News

You've just inherited a legacy C++ codebase, now what?

gaultier.github.io

221–230 of 356 posts

Re: You've just inherited a legacy C++ codebase, now what?

#221

Earlier quoted context omitted.

Step 0 sounds so easy. Until you realize __time__ exists. Then you take that away, and you find out that some compiler heuristics might not be deterministic. Then you discover -frandom-seed - and go ballistic when you read "but it should be a different seed for each sourcefile" Then you figure out your linker likes emitting a timestamp in object files. Then you discover /Brepro (if you're lucky enough to use lld-link…

I think (well, assumed) what they meant by deterministic builds was merely hermetic builds, which are easier. True determinism is overkill for step 0.

Agreed.

Though in the last 6 years I've seen at least one case where truly deterministic builds mattered:

A performance bug only happens when a malloc() during init was not aligned to 32 bytes, glibc on x86_64 only guaranteed 16 bytes, but depending on what alloc / dealloc happened before it may just land on 32 bytes boundary.

The alloc / dealloc sequence before that point was pretty deterministic, however there were a few strings containing __FILE__. And gitlab runner checked-out codes to a path with random number (or an index? I don't remember) without -ffile-prefix-map or $PWD trick so its length varies.

Re: You've just inherited a legacy C++ codebase, now what?

#222
I've had to do this several times in the past. Honestly, my best advice would probably be make several backups, then to do as little as possible. If you need to make a small change, fine. Bigger changes? Consider if you can't do the bulk of the work in a technology or stack you understand and only make a small change to the legacy code base.

Most of the time I spend with C++ code revolves around figuring out compile/link errors. Heaven forbid you need to deal with non-portable `make` files that for some reason work on the old box, but not yours... Oh, and I hope you have a ton of spare space because of some reason building a 500k exe takes 4GB.

Keep in mind, this advice only applies to inherited C++ code bases. If you've written your own or are working on an actively maintained project these are non-issues. Sort-of.

Re: You've just inherited a legacy C++ codebase, now what?

#223

Earlier quoted context omitted.

I'm not hardcore on auto-formatters, but I think their impact on code history is negligible in the case of every legacy system I've worked on. The code history just isn't there. These aren't projects that used git until recently (if at all). Before that they used something else, but when they transitioned they didn't preserve the history. And that's if they used any version control system. I've tried to help teams wh…

SVN was a thing by the mid-2000's, and history from that is easy to preserve in git. Just how old are the sourcebases in question? (Not to shoot the messenger; just like, wow.) edit:typo

I've had issues doing decent copies from SVN to GIT. They both have different ideas about user identity, and how fragmented it can be.

Re: You've just inherited a legacy C++ codebase, now what?

#224
> If you’re not doing [CI] already as a developer, I don’t think you really have entered the 21st century yet.

Ah yes, nothing like a veiled insult towards the people that might need that advice the most, blaming them for not using a developer paradigm that you even fail to name and for which you only give a hard to (directly) search two-letter acronym ! (/s)

( CI stands for Continuous Integration :

https://en.wikipedia.org/ wiki/Continuous_integration )

Re: You've just inherited a legacy C++ codebase, now what?

#225
post #212

Earlier quoted context omitted.

>For example, if Debian updates libpng because there's a new RCE, it's ideal if they can update every package to the same new version of libpng all at once. It Debian is upgrading a dependency instead of a developer, then Debian should be ready to fix any bugs they introduce. >then this would actually mean that you have to update every dependent package to a new release that has the new version of libpng, all at the…

> It Debian is upgrading a dependency instead of a developer, then Debian should be ready to fix any bugs they introduce. That's what the Debian Bug Tracking System is for. However, if the package is actually broken, and it's because e.g. it uses the dependency improperly and broke because the update broke a bad assumption, then it would ideally be reported upstream. > This is already how it works. All vulnerable pro…

>That's what the Debian Bug Tracking System is for.

Software should be extensively tested and code review should be done before it gets shipped to users. Most users don't know about the Debian Bug Tracking system, but they do know about upstream.

>Honestly, this whole tangent is pointless. Distributions like Debian have been operating like this for like 20+ years. It's dramatically too late to argue about it now, but if you're going to, this is not exactly the strongest argument.

It's not too late as evidence by the growth of solutions like appimage and flatpak which allows developers to avoid this.

>So let's say I want to depend on two libraries, and both of them eventually depend on two different but compatible versions of a library, and only one of them can be loaded into the process space. Is this a made-up problem? No, this exact thing happens constantly, for example with libwayland.

Multiple versions of a library can be loaded into the same address space. Developers can choose to have their libraries support a range of versions.

>that's why we have shared libraries and semver to begin with

Hyrum's Law. Semver doesn't prevent breakages on minor bumps.

Re: You've just inherited a legacy C++ codebase, now what?

#226
post #77

I’m not sure why there’s so much focus on refactoring or improving it. When a feature needs to be added that can just be tacked onto the code, do it without touching anything else. If it’s a big enough change, export whatever you need out of the legacy code (by calling an external function/introducing a network layer/pulling the exact same code out into a library/other assorted ways of separating code) and do the res…

The right answer depends on the future. I've worked on C++ code where the replacement was already in the market but we had to do a couple more releases of the old code. Sometimes it is adding the same feature to both versions. There is a big difference in how you treat code that you know the last release is coming soon and code where you expect to maintain and add features for a few more decades.

Yes, you have to expect the future (or even better if your manager/boss already has expectations you can adopt to begin with) and then choose the right way to tackle the changes required. That's why I laid out 3 possible cases the last of which points out that I prefer to refactor primarily when there's a lot of work incoming on the codebase. Personally, I don't see much value in refactoring code significantly if you alone are going to be editing it because refactoring for ease of editing + the cost of editing in the refactored codebase is often less than just eating the higher cost of editing in the pre-refactored codebase and you don't reap the scaling benefits of refactoring as much. However, like I mentioned in the above paragraph, it depends. In the end it's all about managing the debt to get the most out of it in a _relatively_ fixed time period.

Re: You've just inherited a legacy C++ codebase, now what?

#227

Earlier quoted context omitted.

If we're going to visit the circles of hell, let's do it properly: Step -1: Get it under source control and backed up. Step -2: Find out if the source code corresponds to the executable. Which of the 7 variants of the source code (if any). Step -3: Do dark rituals over a weekend with cdparanioa to scrape the source code from the bunch of scratched cd's found in someone's bottom drawer. Bonus point if said person died…

Shouldn't it be step -3 to -1?

Of course not. You try to do 0 but that's impossible because you need to do -1 first. So you drop everything, try to do -1 but that's ... It's yak shaving's evil twin!

Re: You've just inherited a legacy C++ codebase, now what?

#228
I just went this very same dance with an old project, smart, which evaluates string matching algorithms. Faster strstr(). From 2013. It was in a better shape than zlib, but still.

Their shell build script was called makefile, kid me not. So first create a proper dependency management: GNUmakefile. A BSD makefile would have been prettier, but not many are used to this. dos2unix, chmod -x `find . -name *.c -o name *\.h`, clang-format -i All in seperate commits.

Turns out there was a .h file not a header, but some custom list of algorithm states, broken by fmt. Dontg do that. Either keep it a header file, or rename it to .lst or such.

Fix all the warnings, hundreds. Check with sanitizers. Check the tests, disable broken algorithms, and mark them as such.

Improve the codebase. There are lots of hints of thought about features. write them. Simplify the state handling. Improve the tests.

Add make check lint. Check all the linter warnings.

Add a CI. Starting with Linux, Windows mingw, macos and aarch64. Turns out the code is Linux x64 only, ha. Make it compat with sse checks, windows quirks.

Waiting for GH actions suck, write Dockerfiles and qemu drivers into your makefile. Maybe automake would have been a better idea after all. Or even proper autoconf.

Find the missing algorithms described elsewhere. Add them. Check their limitations.

Reproducible builds? Not for this one, sorry. This is luxury. Rather check clang-tidy, and add fuzzing.

https://github.com/rurban/smart

Re: You've just inherited a legacy C++ codebase, now what?

#229

Some good advice here, and some more...controversial advice here. After inheriting quite a few giant C++ projects over the years, there are a few obvious big wins to start with: * Reproducible builds. The sanity you save will be your own. Pro-tip: wrap your build environment with docker (or your favorite packager) so that your tooling and dependencies become both explicit and reproducable. The sanity you save will be…

> Get the code to build clean with -Wall. This is fine, but I would strongly recommend against putting something like -Wall -Werror into production builds. Some of the warnings produced by compilers are opinion based, and new compiler versions may add new warnings, and suddenly the previous "clean" code is no longer accepted. If you must use -Werror, use it in debug builds.

That's a feature!

New warnings added to new compiler versions can identify problems that weren't previously detected. You _want_ those to -Werror when they happen, so you can fix them if they need it.

Changing a compiler version is a task that has to be resourced appropriately. Part of that is dealing with any fallout like this. Randomly updating your compiler is just asking for trouble.

Re: You've just inherited a legacy C++ codebase, now what?

#230

It's funny. My first step would be 0. You reach out to the previous maintainers, visit them, buy them tea/beer and chat (eventually) about the codebase. Learned Wizards will teach you much. But I didn't see that anywhere. I think the rest of the suggestions (like get it running across platform, get tests passing) are useful stress tests likely to lead you to robustness and understanding however. But I'd def be going…

> It's funny. My first step would be

> 0. You reach out to the previous maintainers, visit them, buy them tea/beer and chat (eventually) about the codebase. Learned Wizards will teach you much.

Have you ever tried that? This is legacy code. Even if the handover was yesterday, they cannot tell you about anything useful they did more than 6m in the past.

And that's the best-case scenario. The common-case is "That's the way I got it when it was handed over to me" answer to every question you ask.

Post reply on HN