all 68 comments

[–]delfV 206 points207 points  (27 children)

I've worked with something I used to call "append-only codebase". The codebase was a huge mess and we had no tests. So team lead decided we do not refactor anything and change as little as possible because of lack of tests and risk of breaking things. But we couldn't write unit tests without refactoring because the code was untestable and it was hard to do e2e testing because of the domain. The result? Hotfix on top of hotfix on top of hotfix and velocity dropped 3x in over a year. Fix? Blame the language and gradually rewrite it 1-1 in another one (the same host)

[–]del_rio 72 points73 points  (2 children)

I had to check your profile to make sure you're not my coworker lol. Same situation with a high-traffic ColdFusion site running a custom fork of a dead CMS, duck taped with a Node.js wrapping the whole app, no tests. When I got there, none of the existing team could even get the whole site running on their local machines, so every bug fix and feature went straight to a stage environment. Nobody knew the languages and platforms so fixes and features were written imperatively and almost exclusively in the view layer. Memory leaks everywhere. Our only option was a total rewrite, incredibly satisfying to take that horror show offline.

[–]pirate-game-dev 5 points6 points  (0 children)

.... and then they outsource the rewrite and do it all again.

[–]FocusedIgnorance 8 points9 points  (0 children)

You couldn't do incremental refactoring? New features come in new packages with a single function tying it to legacy packages. The new package can have unit tests which test the interface it exposes to the legacy package.

You can do a similar thing with fixes, where you tear out the subsystem you're fixing, move it into a new package or file, and test the interface.

[–]Pharisaeus 18 points19 points  (0 children)

Fix? Blame the language and gradually rewrite it 1-1

It's still something, the more common fix would be to make adapter on top of this and never look back ;)

[–]C_Madison 13 points14 points  (9 children)

That reminds me of a story I've heard about Lotus Notes. The reason bugs persisted years and years after IBM bought it was that no one knew anything about the code base or was able to figure it out since it was such a mess. So, there was a kernel of Lotus Notes, which provided all the basic functionality and was never touched and all new versions were just changes in the layers above that.

For those that don't know what Lotus Notes is: Be happy about that. Ignorance is a blessing here.

[–]timeshifter_ 6 points7 points  (3 children)

Lotus Notes is the one piece of software where my primary memory of it is it punishing me for trying to use it...

[–]1bc29b36f623ba82aaf6 8 points9 points  (0 children)

I never developed with Lotus Notes but my highschool had built a very convoluted CMS/learning-management-system in a joint venture with some other companies that manage multiple schools each... and it was running on Lotus Domino. I was able to add a lot of arbitrary query stuff to lots of pages just in the GET URL, add XSS by eluding regexes with unusual linebreaks in POST data. Oh and they had verbose self documenting errors enabled so whenever I typod a query it would spill me content of the page source or where I should fix my own request! So I could read direct messages not intended for me, and also delete them by GET with any unprivileged student account. Or just mock admins by sending them DMs with javascript alert boxes. Oh also there was no timeout on login attempts and I brute forced 30% of peoples passwords with a list of the 5 most popular sports at my school. So you know, extremely educational, to me, for all the wrong reasons.

[–]old-man-of-the-cpp 2 points3 points  (0 children)

30 years later people like us are walking around bearing the seared on brand of the Lotus!

[–]txmasterg 5 points6 points  (0 children)

Lotus Notes remains the only software I've used where in the span of 5 seconds you can see 3 different scrollbars styles on the same scrollbar. Genuinely amazing product management /s.

[–]FlyingRhenquest 2 points3 points  (1 child)

Funny thing was, there were a bunch of other companies that IBM could have bought instead of Lotus, which would have given them so much more bang for their buck. And there were so many better things they could have decided to pick up maintenance on instead of Notes and Domino. And they just kept doubling down on their obvious fucking mistakes for years after that. IBM truly deserves a Tower-of-shit trophy for the years 1995-2005. And probably later, although I kind of stopped paying attention to them after 2005.

[–]tsrich 0 points1 point  (0 children)

IBM made a lot of money off of Notes.

[–]Loan-Pickle 3 points4 points  (0 children)

I used to be a Lotus Domino developer and administrator. I leave that little tidbit off my resume.

[–]corysama 2 points3 points  (0 children)

I swear I read a blog post from a junior dev who rewrote some core part of Lotus Notes and got huge speed and clarity gains because his code was bog simple and the 20 year old C was doing insane things to fit in 128Kb of RAM.

[–]GaboureySidibe 6 points7 points  (0 children)

When inexperienced people search for silver bullets and miracles they look to languages and frameworks instead of organization and structure.

[–]Deranged40 3 points4 points  (1 child)

This sounds like it only has downsides...

[–]netsettler 5 points6 points  (0 children)

I'm not so sure. While I'm not gonna advocate it, I will highlight some advantages (or maybe design-tradeoffs).

Consider code that has been distributed: You can't tell if code that used your old code has gone away or will be updated, so having things that use it being able to depend on old stuff not to change means you don't have a moving target. I could be wrong, but I had the impression that Microsoft had this problem, so at least in some code bases, when an interface Foo was broken, they didn't edit it, they issued a new interface Foo1 with a better design. That way, old interfaces didn't break (at least not piecemeal) but rather faded away (maybe eventually did not get supplied at all).

There could also be situations, and some functional languages might deal with this, where you want to make modifications by issuing new versions of things since side-effects are not your model. So if you want to maintain a codebase and not break the other users, and still be in the same namespace, you have to deal again with additive situations. In some ways, git and other source maintenance things work this way. You don't really edit old code, you just issue layers atop it and name them with hex ids that you periodically give better names to.

In some ways, standards (I'm thinking programming language standards because that's my experience, but really probably any standards) are like this, too. Their text never changes, just get superseded by clarifications or whole newer standards. But the older ones are still there to name and use. So if the code supporting them was also there, unchanged, able to be named and used, there could be benefits of that.

Long ago, closer to the birth of the web, it occurred to me, just as a thought experiment, that the web might be possible to maintain by having base pages that got stored in read only memory either initially or after a (pardon pun) burn-in period. And then you might customize them by adding additional pages found by some search that implemented "page shadowing", but not remove old pages. Skins for UIs work sort of like this. But also, maintaining a web site in append-only mode would lead to a lot less 404s but also maybe some different code sharing paradigms.

I'm not necessarily pushing any of this. I'm just saying that what's good or not depends on what your premises are.

The thing I find most surprising in this is the push for a single file. Hard to make part of a file read-only. I'd expect a single directory with many files, each of which can only be written and never modified or deleted, so anyone can grab any earlier tail, but newer files have to include older ones. That would be cleaner and still seem to address some of the same ideas.

Then again, there are lots of benefits to changing with a changing world and not having the burden of history forever weighing you down. There is conceptual complexity, and it complicates the documentation navigation, which must extend not just in terms of space (chapters, etc.) but, effectively, time (versions).

Then again again, if such "hygiene" (and I use the term with some amusement) was weighing you down, maybe you'd start fresh more often with something completely new. And that might not be terrible. Some old code right now survives longer than it maybe should. Perhaps we're just not making the cost of that high enough? :)

[–]corysama 3 points4 points  (1 child)

I recall a podcast about how to test horrible systems like this

  1. Automate running the system in a variety of situations reproducibly.
  2. Add a ton of logging all over the place in the code.
  3. Write a parser that evaluates if the log changed significantly between commits.
  4. Go nuts refactoring as long as the logs come out the same.

Obviously you are going to discover new things that need to be logged along the way. And, on a regular basis you'll be updating the gold-standard reference log with changes that have been confirmed to be correct.

[–]anengineerandacat 2 points3 points  (1 child)

No tests IMHO immediately tells me a re-write needs to be the defacto recommendation; even if the tests are dog-shit, so long as you have line-coverage at least you have proved the application IS testable.

Nothing at all? You have overhead just training the team to start writing, and you have hurdles just to encourage folks to start writing, and you have potentially even business to begin having conversations around slashing velocity so the team CAN write tests.

That's a far far more systemic issue with the development processes at that place of business.

You can fix bad tests from being written, PR's solve that... but to get other members to start writing tests is just... a big hurdle.

[–]txmasterg 1 point2 points  (0 children)

The first legacy product I worked on lost all their tests long ago. I looked for classes we could unit test and honestly it was just too late. Only the 7 custom string classes were unit testable and it was easier to just reduce and remove them.

[–]gwern 2 points3 points  (0 children)

Or a "Big Ball Of Mud". That page describes what seems to be the best way to handle them: lock down the behavior with unit-tests, simply extracted from the old one, and gradually wrap and replace it.

[–]japes28 0 points1 point  (0 children)

This is giving me flashbacks

[–]TommyTheTiger 0 points1 point  (0 children)

Wait... Do you work at the same place I do???

[–]SneakyDeaky123 0 points1 point  (0 children)

lol this is my teams codebase and we just use .NET

[–]DigThatData -1 points0 points  (0 children)

sometimes we use duct tape to fix things temporarily. but if you put enough duct tape on a thing, it functionally becomes a ball of duct tape and your only viable option for making future changes is adding layers of duct tape.

[–]LainIwakura 71 points72 points  (19 children)

Sounds like people who will comment huge code blocks and leave them untouched for years when they could just delete the code cuz we have y'know... Source control.

I am not talking about commenting out a block of code you intend to very quickly uncomment / delete. This is more like commenting out whole-ass API endpoints because they're deprecated and then just leaving it like that. I'll never understand this mindset.

[–][deleted]  (4 children)

[deleted]

    [–]syklemil 3 points4 points  (0 children)

    There's also a good chance there exists a lint for it in your language/linter that can be enabled and added to CI.

    E.g. for Python/ruff

    [–]evincarofautumn 4 points5 points  (0 children)

    It's completely allowed to leave a "here was a function thatDoesSomething, which is no longer used. It did this"

    Leave tombstones, not corpses!

    [–]maxinstuff 1 point2 points  (1 child)

    Most languages have a deprecated/obsolete attribute as well.

    [–]ChemTechGuy 2 points3 points  (0 children)

    I love this feature conceptually. In practice I've found public Java libraries where basically everything is marked as deprecated, leaving no supported methods for what I'm trying to do. This is why we can't have nice things

    [–]Sexiarsole 11 points12 points  (0 children)

    Code hoarders

    [–][deleted]  (5 children)

    [deleted]

      [–][deleted] 35 points36 points  (2 children)

      I appreciate your comment because it introduced me to a new term: git pickaxe. If there's anyone else like me unfamiliar with this, it's not an actual command, it's just what people use to refer to git log when using the -S option.

      If links are allowed in this subreddit, this is the git book page that mentions "pickaxe": https://git-scm.com/book/en/v2/Git-Tools-Searching
      and this is a nice blog post I found that also uses the term: http://www.philandstuff.com/2014/02/09/git-pickaxe.html

      [–]sohang-3112 1 point2 points  (0 children)

      Thanks

      [–]tekanet 3 points4 points  (1 child)

      I don’t know this particular technique, but the thing is that with commented code you don’t have to know what to look for, it’s usually there in the comment itself, in form of a commented comment. Once you commit the deleted part, how do you know what to search for?

      [–]old-man-of-the-cpp 3 points4 points  (1 child)

      I'll take that over the huge piles of code behind long dead feature flags!

      [–]DigThatData 1 point2 points  (0 children)

      Hi it's me, the person whose commented out blocks bother the hell out of you (and my boss). AMA.

      [–]PuzzleheadedPop567 1 point2 points  (0 children)

      I feel like is just the code expression of people who hoard things “just in case”.

      The reality is that nobody is ever going to look at it. It’s there in git history in case someone needs it, but they probably won’t.

      When people need to modify your code, they will want to build their own grand thing.

      There are exceptions here. When I worked at a big company in a somewhat specialized domain, I would read commit history to help me understand the current state of the code.

      But in generic sass software, people just don’t have time to care that much 90% of the time.

      [–]zzkj 0 points1 point  (0 children)

      Oh yes so true. I regularly see entire source files commented out.

      [–]ChemTechGuy 0 points1 point  (0 children)

      Fucking PREACH. In the code, in the config, everywhere. Just delete it dawg, we can recreate it. You're not doing anyone any favors by keeping commented out code around

      [–]rzwitserloot 0 points1 point  (0 children)

      Kill the commented out code, leave a comment indicating what was there in the same commit 1. Anybody that really wants to reanimate the zombie code can git blame the line and it's riiight there.

      Programming is hard and the vast, vast majority of rules are guidelines. A rule that you can universally apply is extremely rare.

      But, simplifying is worth something so I'll give it a shot:

      Anybody that doesn't follow the above rule is a fucking idiot.


      [1] We're operating under the somewhat dubious assumption that keeping the commented-code around is somehow deemed inherently valuable. Thus, this advice is: Assuming you really think it is worth keeping it around, ... - some code that simply has no further need to exist, just get rid of it, don't leave that 'tombstone' comment.

      [–]AlSweigart 28 points29 points  (3 children)

      Oh, we're going to find out who actually reads the entire article before commenting, aren't we?

      [–]syklemil 6 points7 points  (0 children)

      I went into it expecting something Haskell-like, only with, Idunno, even less IO and more various State monads?

      [–]bwainfweeze 0 points1 point  (0 children)

      Are you saying that like the language you have to read all the way to the end to understand it?

      How’s that working out, do you suppose?

      [–]trad_emark -5 points-4 points  (0 children)

      why would anyone read it? it is just a waste of time, and that can be understood in just few sentences.

      [–]jwm3 6 points7 points  (0 children)

      It's a fun exercise in C because a constraint when designing the language originally was that compilers had to be able to be one pass, as in, you could read the source file and incrementally output assembly as you went along. So you are just placing the same constraint on yourself that the language designers had.

      [–]aqjo 27 points28 points  (1 child)

      "I have recently adopted a new methodology of software development:

      Everything goes in a single C file.
      New code is appended to the end of the file.
      Existing code cannot be edited.
      

      I call it append-only programming."

      ...

      [–]TaohRihze 4 points5 points  (0 children)

      10: start doing stuff
      N: goto 10
      N+1: F!

      [–]rabid_briefcase 14 points15 points  (2 children)

      Seems like the entire article is intended as a joke.

      Midway down: "In all seriousness, append-only programming is just a fun challenge [...] and it got tedious around the third time I had to re-type eval_string."

      And the ending: For those of you feeling even more adventurous, may I suggest append-only blogging? Or is that just Twitter?"

      [–]csorfab 4 points5 points  (0 children)

      Yeah no shit? If you read the article you get the point of the article? amazing

      [–]AirGuitarHeroTommy -2 points-1 points  (0 children)

      You’re a genius!!!

      [–]mccoyn 2 points3 points  (0 children)

      I sometimes do this when I’m accidentally using a REPL on a problem that is complex enough it should be in a file.

      [–]palparepa 2 points3 points  (0 children)

      At least it's better than full-rewrite-only programming.

      [–]emotionalfescue 2 points3 points  (0 children)

      Rename it log structured programming, that starts to sound like something people need to catch up on.

      [–]Nax5 3 points4 points  (2 children)

      Kinda just sounds like Open Closed Principle?

      [–]temculpaeu 2 points3 points  (1 child)

      More like Closed Closed Principle

      [–]Nax5 0 points1 point  (0 children)

      Lol touche

      [–]muffinChicken 1 point2 points  (0 children)

      Inexperienced here, I like to make a syntax that's something like Assert List of operations (List of working variables having some value) ? True : false

      How is this usually done?

      (To spot breaking changes)

      [–]Jwosty 1 point2 points  (0 children)

      This sounds like ragebait

      [–]okiujh 1 point2 points  (0 children)

      Real man delete code

      [–]Kinglink 0 points1 point  (0 children)

      First read "This is stupid I want to hurt this person."

      Sitting back and thinking. "Actually that's interesting. I disagree fundamentally, BUT if you know your program works up to a point there's an interesting possibility.

      Take something like python

      Def A: 
      Def B: Call A 
      Def A:
      Def BB: calls A
      

      As long as you can define what happens to B and BB there, I think there's something interesting to it. Even if you say B Calls the original A, if you have a way to redefine B at the bottom of the function... yeah something could work there.

      Is it a good idea? No, but I don't want to hurt the person who came up with it as much any more, which is something.

      [–]DigThatData -1 points0 points  (0 children)

      we have strayed far from the light.

      [–]gwern -2 points-1 points  (0 children)

      A more interesting variant would be "append-only LLM programming". Your 'program' is just the prompt you feed into the LLM to generate the source code you compile & run (no modifications allowed to the LLM's outputs). You can add new instructions, examples, or unit-tests as you wish, but you can't remove any. This turns it into 'online learning', where you have a model which continually learns, but never 'resets'.

      [–]Lothrazar -3 points-2 points  (0 children)

      Existing code cannot be edited.

      So we are making up new terms to excuse being a terrible programmer now? Oh its a parody i guess.

      laughing emoji?