All code rots, and it rots quickly. Its the a reality of modern software.
All code rots, and it rots quickly. Its the a reality of modern software.
This may be a bit of an extreme example, but generally the unix-y APIs have been relatively stable over the decades, including X11 as we see.
% ls -l
total 176
-rw-r--r-- 1 foo staff 547 Sep 9 1995 Imakefile
-rw-r--r-- 1 foo staff 15666 Sep 9 1995 Makefile
-rw-r--r-- 1 foo staff 7545 Sep 9 1995 README
...
-rw-r--r-- 1 foo staff 33472 Sep 9 1995 oneko.c
...
% xmkmf
mv -f Makefile Makefile.bak
imake -DUseInstalled -I/opt/homebrew/Cellar/imake/1.0.8_5/lib/X11/config
% touch DarwinMachineDefines; make CFLAGS="-I/usr/X11R6/include -I/usr/X11R6/lib --include=stdlib.h --include=string.h --include=unistd.h"
cc -I/usr/X11R6/include -I/usr/X11R6/lib --include=stdlib.h --include=string.h --include=unistd.h -c -o oneko.o oneko.c
...
% DISPLAY=:0 ./oneko
If you want to try for yourself, you need XQuartz (to have X11 in the first place), and imake from e.g. homebrew, because it's apparently not part of the XQuartz distribution. Don't forget to start XQuartz. That's all.It's not even a particularly cherry-picked example. One day a few years ago, I suddenly remembered that cat, and went out to see if I can still find it. I tried to build it more just for kicks and remember being surprised when it not only "just built", but even "just ran", on my Mac, for which it wasn't even for.
Yeah, something bigger will most likely push back more, especially as soon as more dependencies than just the C library itself and X11 come into play. Though overall my track record in building ancient C stuff with an acceptable amount of changes is pretty good!
The Microsoft example is important. I've never been a fan, but I stand in grudging respect for what they've accomplished with their products as far as backwards compatibility goes, which has significant and enduring value.
Emulators are another example of how software can be long-lived with the right attention.
Personally, I think we have operating environment conceptions all wrong. We continually pay for or fête new versions and thus incentivize change for change's sake. We might do better to respect or even pay for continuing compatibility.
I was a PM for Visual Basic back in the day. A huge amount of work was done within dev and Office to work around problems with Adobe, Borland, etc. so that compat wasn't broken. It was frustrating and heartening.
C is a great example of this. Even if the ABI changes, in the worst case scenario a well-written C program only needs to be recompiled.
Run some 8 year old Clojure Github project, should be fine.
Try a Common 20 year old Common Lisp project, you shouldn't have an issue.
I wonder what intrinsic quality makes a language long lived, rather than blame communities and whatnot.
Another stalwart is Pure Data, the DSP language I am very fond of. It's based on atomic principles. Indeed the primitive processing elements are called Atoms, being irreducible ops like multiply, add, sin and cos. There really isn't much that can change. For C as for LISP, especially Scheme, it's hard to break them down any further, yet they are high enough level to be useful for programming. There's some sweet-spot to be found.
But I've had to work out weird command line incantations for various libraries that touch crypto or JavaFX namespaces. And things like Quil are still in a weird state on modern JVMs.
Just runs a lot faster. :-)
By comparison, the SPA is a nightmare of tooling and dependencies that will be unsupportable in a few years without constant maintenance and updating.
But JavaScript that worked in 1995 still works today. All of it.
Python, I agree, is a challenge. I don't use it. I used to; I concluded it was too much hassle most of the time to maintain my Python working against other people's Python. Coupled with the lack of static type checking, I pulled it off my quick-grab list years ago (though with the growth of mypy, pip, and conda I may revisit it some day if I get bored with my current tools).
Go code is pretty stable. Java seems downright calcified. And, of course, the whole C library space may as well be igneous stone. You can get FFTW version 3, for example, built from the relatively recent date of last year, but FFTW has a version 2 stable release dating back to 1999.
Frontend post react is an absolute nightmare: My experience with a fleet of semi abandoned next.js static websites is pretty terrible: just in months something stops working in my pipeline on vercel and I need to spend time to debug it. Running things locally is even worse, I just change the code, push and hope for the best.
Python is a downright nightmare: between 2vs3 and pip, egg, venv, I usually just salvage the code I need and try to make it work or convert it to something saner (eg. I did that with an opencv algorithm I found - I just transposed it to rust + the same opencv api calls). My favourite story happened literally 2 days ago. I was trying to install a dependency (keras_ocr) and I kept failing on some dependency; I tried installing that dependency manually and it worked but no success on installing keras_ocr. Eventually I updated pip and it started working.
I had huge problems running old Go software, I think I succeeded once after a lot of pain and gave up the other times.
I had fairly good results with ancient C, C++, Java and Haskell. Probably because they started before we had cool and glamorous developers on twitter selling you a course and not maintaining his 200 leftpad libraries.
I'm curious to see where Rust will sit in a few years.
- On local: `npm i && next dev` is guaranteed to be stable.
- On remote: your pipeline is guaranteed to be stable.
If you have an example where this is not the case, please let me know.
If you take any app built three years ago, you are going to have critical security vulns in libraries you depend on. With java think of the log4j fiasco. With Ruby there are nokogiri or rails things. With javascript there are probably at least a handful of downstream packages that have pretty big security issues. Now you have to update dependencies, and then the real fun begins.
If it a walled-off intranet app on a VPN, or a small CLI app, sure, maybe you can ignore that issue. But if its a public web or mobile app that is gonna see real use, you are going to have to head down the security audit + package update rabbit-hole.
I think the `npm` community is going in the right direction and learning from mistakes of the past on this topic.
Js (or specifically npm) and python were far slower to adopt this convention, to the point that I think it's fair to say that neither have fully adopted it yet.
Js at least has made almost no backwards incompatible syntax or core lib changes though, which is a point in its favor. Ruby 2 and python 3 were major breaking changes.
Ironically, this has made JS a very stable language (though APIs do occasionally drop out or change drastically for security reasons).