1- Shield away from dependencies. Use languages that are robust (no JS, no PHP) and if possible, generate native .exes (Delphi, Rust, Go,...).
Langs with large runtime/deps (Java, .NET, Js) are always trouble in the long run. I re-enter with .NET Core and have regretted heavily it (because maintenance, not performance or dev productivity).
ie: If a lang/tool/ecosystem is for large teams (java, .net, c++), is not for zero maintenance.
How easy is to setup and get running something (without resort to auto-installers or docker images) is a high evidence in how good will be for this metric.
2- If possible (mobile) use iOS. Android is not robust at all for long term prospects
I made a enterprise iOS app that is also nearly worry-free. My only job is to upgrade xcode and recompile from time to time.
I enter android late in the game, dreaming that android become more or less good. Not.
3- Important! If possible, split the programas between what could be "zero maintenance" and high maintenance.
I have made one in Delphi that is running 10 years in some places with zero calls after the first 3 years of tweaking.
Is split in 2 parts: The Delphi side have stay solid, and
the "business" side that requiere more changes are in scripts in python that I integrate with the Delphi side.
Even the python side is now near worry free, but I need to do changes here and there.
4- If need JS, pick VERY carefully how use it. JS is the anti-tesis of zero maintenance. The web is hostile in this area. You could lower damage if VERY carefully know what to use.
5- Stay away of stupid "is for scalability" traps. Micro-services, nosql and similar are the best way to destroy productivity. Modular code yet running in a monolithic (or maybe in a REST api + client) will be more than enough by long margins when coupled with postgresql or sqlite. Again, a solid RDBMS is what most need. "Eventual" consistency is a stupid choice most of time.
P.D: I'm solo developer, and have not time or high pay to cover for bad choices, so i try to perform very well in this metric.
> 2- If possible (mobile) use iOS. Android is not robust at all for long term prospects
You can't use mobile at all. Apple requires you to update your app every year to support their new tooling. Just in iOS 13, if your app uses FB login, you need to add Apple Login.
Or, every year, you need to re-generated and update your push notification certificates.
Apple releases a new iPhone and then you have to update your marketing images in the iOS store with the new pixel dimensions. Its never ending.
>Starting April, 2020, all iPhone and iPad apps submitted to the App Store will need to be built with the iOS 13 SDK or later. They must also support the all-screen design of iPhone XS Max or the 12.9-inch iPad Pro (3rd generation), or later.
If you want to properly support iOS 13, that also means implementing dark mode support and breaking your application delegate apart to a scene delegate for multiple instances. In addition to the notched screen "safe area" changes that most developers have probably caught up on by now but are becoming mandatory.
Previous years it's meant supporting flexible sizes for new devices, sizes for split screen multitasking, drag and drop, siri intents, adding @3x retina assets, changing out UIWebView to the (not directly compatible) WKWebView, and a million other things.
For a simple app with minimal support for iOS's growing featureset, maybe some years you can get away with loading it into this year's XCode, clicking the automatic code update button, and compiling. But polished iOS apps put a lot more work into keeping up.
I don't have any knowledge of how Android compares, but iOS is definitely a moving target and Apple isn't afraid of deprecating things or mandating support for newer features.
> once per year? That is so close to zero maintenance as is possible to get.
Compare that to a static site with Netlify or AWS S3, which never requires an annual package update and rebuild.
You also didn't address how Apple requires you to update the marketing screen captures. You will need to brush off the dust of your faked out app data and spend a few hours tweaking them in an image editor.
I coded that to run in every browser I could get my hands on. Browsers of the last 10 years have been very good at maintaining backwards compatibility, so no updates needed, at all. They may rewrite the OS cores from scratch (or in Scratch) and replace all the current instruction sets, browser vendors may come and go, and new features will keep on being added, but none of that will break my game.
JS today is a bigger mess. Is possible to avoid problems
I use vue, without npm, package managers or anything else than direct link in the head. But I need to be care-full in what to code and check support across browsers.
---
About "not robust". In fact what need to be defended is how is possible to call it robust!
But anyway: JS is a badly designed language, have weird edge cases, and will fail silently (the worst of all) in many ways.
A robust language not only catch stupid errors, but have a better std support (like having integers!) and better defaults and ways to do data transformations.
Exe is exactly what I think of when I think of bitrot though. None of the games from my childhood can run on a modern OS.
If you're running js or python etc, even if the interpreters are no longer widely available in the future, people using your code can still try to port it themselves (instead of demanding that you support them throughout the eons).
.EXE games do not work out of the box but because of existing overall backwards compatibility support and the effort of some enthusiasts, they are still the most likely to work compared to anything else.
For Win32 pretty much anything can be made to work with Windows' own compatibility settings, dgVoodoo2 (for games) and minor tweaks. I have many applications and games from the 90s and 2000s, both in digital and physical form and the only issue i face to make them run in modern Windows 10 is the DRM some games in the mid-2000s had (i avoid anything with DRM nowadays).
For 16bit Windows on 64bit OTVDM (https://github.com/otya128/OTVDM) should make most stuff work (especially games). This is also great for installers.
For DOS, DOSBox for games and vDos for applications should run pretty much anything better than when they were new. DOSBox also works if you have Windows 3.1 installed. Yeah these aren't exactly native (vDos does try to use some OS services though) but the UX is pretty much the same with what you'd get even back in the 16bit Windows days when trying to run a DOS application.
> For Win32 pretty much anything can be made to work with Windows' own compatibility settings
I have never had something not work and then work after running in compatibility mode.
When I've (had to use Windows and) had reason to try it, I've tried every OS in the list and ended up thinking it's just a dummy wrapper that doesn't do anything included to make you feel better about Windows but think the program really is a lost cause after all.
Well, i had several things (mostly games) work by changing these settings. Also in many non-game cases the program did work but it had visual glitches (a common issue with some older apps is when they draw directly to the screen - this is slow with regular compositing, but by enabling a pre-XP2 compatibility mode Windows seem to render the windows in a different way - i guess some canvas outside of DWM - that is faster to directly access for such programs, you can notice that these windows bypass the DWM decorations).
> None of the games from my childhood can run on a modern OS.
I don't think that's within the time horizons that OP is trying to consider. That's kind of like saying "no one (or very few people with great effort) can read the books that we wrote in the middle ages!"
If you know what you are doing you can write zero dependency code that works well with old and modern browsers alike. This isn't as hard as it sounds either.
Zero JavaScript dependencies. The only dependency is Bootstrap and that's just used for hassle-free layout and styling. The application works just as well without it.
Admittedly, it's not a huge application but there's nothing in principle that would preclude a more complex application.
The use of const prevents Internet Explorer up to IE 10 to run the application but that's a small trade-off I was willing to make in favour of more robust code.
Sure you can, but it might take you 2-3x as long to get the same results as you could have got by using modern JS features and APIs that aren't supported in older browsers, and it might take you 10-20x as long if you also have to reinvent the wheel for everything instead of using a few good libraries. For most projects in the real world, that is not going to be a trade-off worth making.
The only way that is true is if your friendly abstraction is producing your test automation for you.
Having no understanding of the DOM and the standard APIs then writing without dependencies might take 1000x longer. I was assuming a competent developer when I mentioned this isn’t that hard.
I will disagree there. I have an application generating revenue running on apache / php for the past 2 years unattended. Basically I have no spare time anymore to maintain it, just paying the server costs and it keeps going.
You might want to ssh in there and do a "df -k /" just to see that your system isn't near running out of disk. Systems that log will do this sooner or later and no house keeping in 2 years makes you a prime candidate. Nice work building a revenue generator that can run untouched!
"Robust" has different meanings. I think the OP is equating robust with strongly typed and compiled.
I have found well written PHP code requires very little unplanned maintenance. When I package the application in a docker container along with its dependencies and a webserver (nginx), I find that I can run a PHP application for years without having to worry about it.
In this sense, PHP code can be very robust in the sense that there are little surprises once the application goes into production. The PHP ecosystem is very mature.
not true, I have lots of experience in PHP and if I write code in go sure it will have more bugs than my PHP implementation. how familiar are you with your current stack matters a lot. Also, That does not mean you should use a runtime where 100 things can go wrong (talking about node).
if the goal is to maintain an application and catch issues at compile time. go with a better type system Haskell/Ocaml/Rust.
Another option would be to use generative testing where you have tight control over what gets in, for example, Clojure/Spec.
Furthermore, you can package a JDK or JRE with the application, such that the application uses the packaged JDK/JRE, and ignores any that may be installed on the OS. JDK/JRE's are open source, and binaries are available from AdoptOpenJDK, Red Hat, Azul Zulu, and others. "Maintenance" might be to simply swap out one JDK with a newer one and then make sure the app still works -- which it should.
But there ARE some ancient things in Java that are being deprecated. Or moved out to separate libraries not bundled into the JRE.
I would also point out that with Docker you could package every possible dependency into the container. The container is now portable and has no dependencies outside of what is packaged in the container. To the user, they don't care what technology or Rube-Goldberg contraptions exist within the container.
* bundled xerces around 1.6, breaking apps that also carried their own xerces
* removed sun.misc.Unsafe from v11, breaking legit apps the apps that use off-heap memory
* sun and later oracle made everything to make applets useless, creating ridiculous security requirements and no clear way for a user to whitelist trusted applets. same for java web start. they had no problem disabling MD5 and RSA in their SSL impl, breaking the old clients.
Is similar with .NET and other environments (C++, js), where is possible to get his metric IF you know what you are doing. But the ecosystem push harder away from this.
Every part of the stack will need maintenance every now and then. Some parts even introduce breaking changes and force you to alter your own code. The slimmer the stack, the less often you have to fix it. And the less often you have to fix or refactor your application.
2: A stack that values stability
Linux is a good example. Linus Torvald: "We do not break userspace!"
PHP is a another one. The core developers rarely introduce breaking changes. And when they plan to do so, there is usually an intense fight over it.
3: Acceptance Testing
In the simplest form that means sending http requests to your web application and check if it returns the expected output. In my experience, acceptance tests find more real world issues then unit tests.
4: Write less code
Writing the same functionality with less code has multiple advantages. One of them is that it will break less often. Much more could be said about it. Paul Graham brings up the value of terseness frequently:
* sqlite says it's "zero maintenance" because nobody has to keep a database server running, and your .sqlite3 files don't need a defragmentation step or similar.
* There are middlewares like RabbitMQ where an upgrade through the OS installer generally Just Works [TM], no additional steps necessary. Yet somebody should monitor the RabbitMQ instance, just in case the service does go down, or reaches resource limits
* There are tools that have very limited scope and API surface to stay stable for a looong time, those are also kinda "zero maintenance".
In my experience, all serious business applications that automate workflows or otherwise create value do need some kind of regular maintenance.
Depending on the installation base and maintenance effort, striving for zero maintenance might not be cost effective.
> How do you as a developer, not become a lifetime maintaimer?
A maintainer is a developer.
Depending on the project, things you can do if you don't want to burden yourself with maintenance:
* Build a community around the project, and hand maintenance to the community
* abandon a project
* leave lots of documentation that makes it easy for others to maintain it
* pay somebody to maintain it
* work as a consultant/contractor, and fire the client after the initial development phase (might not be the best for your reputation, could be OK if you are up-front about it and make a very good handoff).
* If most of the maintenance is keeping it up at all, engineer for availability over consistency (if applicable to the business domain).
* Accept that maintenance is part of the normal lifecycle
The appropriate strategies highly depend on the kind of project.
I spent quite a bit of time getting it off the ground, but over the last 2 years, I've spent maybe ~10 hours in total keeping it running.
The only times when I've had to invest time into it, is when a certain piece of my tech stack gets deprecated or discontinued. For example, I had originally done login-auth through a SaaS provider, which then got acquired by a larger company which discontinued their API. I then had to go through their migration process to keep the site running. However, the above doesn't happen all that often, especially if you choose stable technologies and companies.
Besides that, I had consciously designed the site to be completely free of manual maintenance, even if it involved more upfront costs. Examples:
- Going serverless via Heroku
- Using SaaS services like RDS, S3, SendGrid etc
- Using scripts and cron-jobs/heroku-schedulers to automate anything that needs periodic maintenance
- Relying on "push" alerts as opposed to "polling" alerts. Ie, when something goes wrong, your server should notify you immediately. Instead of waiting for you to periodically check some dashboard
Two things are going to make Zero Maintenance kind of difficult. Assuming Ubuntu on an AWS EC2 instance here.
First one is taking OS updates that are security critical - as anytime you take an update theres a chance something somewhere gets broken.
Second one is AWS instances themselves being switched. From time to time (very infrequently in my experience) Amazon will send you an email indicating your EC2 instance is being migrated to a new physical host and to initiate this you must manually restart your instance.
As for the rest, a script in root's crontab that does:
1 - Delete log files older than X (because running out of disk space is not a good situation)
2 - Hit Lets Encrypt for new certs if necessary ( because expired certs give a lousy customer experience)
3 - Preemptively bounce any application servers (Nginx, PHP FPM, Tomcat, what have you )
4 - Setup all hosts such that your critical software restarts at boot time in the event of an unexpected reboot situation (gives you the ability to cron schedule nightly reboot command)
Additionally:
* If you're running any database regardless of where, be sure you allocated enough space that you don't end up running out of database storage
* Implement some downtime monitoring to tell you when there are issues
* It's a good practice to be changing passwords on any authenticated resource at some interval too
The practices listed here (off the top of my head - not an all inclusive list) are about as close as I attempt to get to Zero Maintenance myself. Customers pay for systems to be developed and they should expect some level of ongoing care and feeding as entropy is pervasive.
But its a good excuse to sell your customers a maintenance contract right?
I personally like to stop/start any application server or web sever running on my hardware over the weekend with cron. I say "Preemptively Bounce" on the assumption that which is not periodically rebooted will at some point crash. Id rather take a few minutes outage at a time of my choosing. It's basically just cheap insurance for the paranoid.
I've built 4-5 web apps over the last 5 years that have required zero/little maintenance.
There are only three reasons I've been drawn into some projects:
1) A bug occurs and needs to be fixed
2) An external dependency breaks something
- Write tests and/or have high confidence in code/infrastructure behavior (using tools you know really well helps). Avoid cognitive complexity in code constructs aggressively.
- Limit integration w/ 3rd parties EXCEPT the ones that reduce your goal of zero-maintenance.
- Create interfaces/tooling which make automating tasks easy.
- Get notified when things break
No-maintenance software must live in an environment which never changes (certain microcontroller code, and kiosk-type installations fit this definition). If you are devloping software exposed to the "normal" world, then change is inevitable as the environment evolves around you. Maintenance is a part of life. The key is to minimize the cost of that maintenance through good architecture and robust error handling.
Even if your business requirements never change, security updates are a thing. Many libraries have stated support policies after which a given version no longer receives updates. Fixing your application at a point in time and never updating dependencies etc is a liability. Assuming you update dependencies, at some point, you'll have breaking changes. (not really getting into the nuance of whether or not everyone will obey the rules of semantic versioning)
This all assumes your application is like most being built these days: you're using a framework on the web. If you put your application on a machine that never is exposed to the web, or you create an application with zero dependencies (including OS-level dependencies) you might get away with never updating it.
Think about it this way, every line of code you write will become obsolete one day (e.g. business will change or new version of the language comes out). Every external dependency, where you deploy, how you deploy, the OS where you host the application, even how the user consumes your application will change.
So to avoid any maintenance, minimize - code, complexity and all dependency and use a language and platform that can last a few years. Essentially, in today's world this will be very difficult and doing this will also cost you development time, there is no easy way around it.
For example, you can build your whole app in Clojure, which is rock solid and stable, but even then you will have to patch the OS, JVM, DB etc. With traffic changes you will have to scale up / down.
I've developed a couple of apps that only required a few hours a year essential maintenance. The biggest obstacles have been with being forced to upgrade libraries to work with changes to third party APIs (e.g. payment APIs, ad APIs), upgrades to do with OS changes (e.g. new versions of Android) and applying security patches to dependencies.
To decrease maintenance, generally you want to reduce your dependence on external services that might change, minimise the use of complex third party libraries that might have security problems later, and keep your app as simple as you can to reduce the chance of bugs.
It's hard to predict what changes are going to be required for a given ecosystem (e.g. Android, Mac, Chrome Web Store, web browsers) so sometimes it's a matter of luck unless you can guarantee the OS, hardware, APIs etc. are never going to change.
I'm currently working on a Chrome extension (https://www.checkbot.io) that doesn't require a lot of essential maintenance besides keeping up with changes Google have been making to make extensions more secure. Bracing myself for what breaking Manifest v3 changes are announced.
It's really hard to answer if you don't provide any context :) Zero maintenance for a blog, small webshop or some Kubernetes controlled madness running a zillion pods? For the first two:
1) Make everything static, HTML, CSS, don't manage your own servers
2) Use as few dependencies as possible when dealing with JS
2 a) For backend try to find a service that do the work for you without you deploying your servers
I generally agree, but eventually you're gonna start getting emails saying things like "We're deprecating Node 8.x in our Lambda / Cloudfunction / etc"
I have 100% zero maintenance software running on customer's site.
It is a Debian-powered machine, not connected to internet, which is performing various tasks and controlling some hardware. The software running on it was built 6 years ago in C++ and using OpenCV and CUDA.
The machine powers on and off itself on a specific routine due to on-site checks.
It clears old logs automatically if older than X days or bigger than Y MBytes.
Until today, no software or hardware failure occurred. The whole disk is snapshotted with dd command. If hard drive failures occur, it's easy to swap it and start again.
That’s an amazingly useful thread. My 2 cents regarding the tech stack :
1. Don’t use a build system. Use scripting language that comes preinstalled on Debian / Ubuntu. Peel 5 is still my weapon of choice for robust small web apps. Look at python too.
2. Avoid JS / Ajax. I can bet that security restrictions will break it in the future, however good old form POST works still pretty good.
3. Use own hardware. Raspberry PI with HDD or some banana PI works quite allright. Also provisioning is easy by keeping a copy of your image.
4. Don’t use managed services. Use database on the very same machine that you host the app itself. Backup is an extra step you can achieve via those, but don’t use External service, since it will most probably break.
Apps can not be zero maintenance by definition. Apps are literally alive, apps mature, evolve, get older, there will always be some kind of maintenance. As world changes, apps change with it.
If ZERO maintenance is a HARD requirement, then think about total isolation. No packaging, and NO ENVIRONMENT CHANGES. With constant, isolated env, it is possible to have a minimal maintenance app.
also FYI, with zero maintenance requirement Agile approach will not work. Throw anything agile out of the door, you need a strict top to bottom waterfall with set requirements.
Another argument that Agile can not be a hammer for every nail. Common sense with project management and architecture is extremely important.
In order not to become a lifetime maintainer, you need to end-of-life applications. For technical reasons, we aspire to making applications have a long life, but from a business point of view, it's both unnecessary and difficult.
Don't plan for an application to live for more than five years, especially v1. Put enough work into architecture and maintainability to be able to throw it out and redevelop after five years. Be clear about this upfront. In five years' time you won't even be able to find devs to maintain what was developed today.
In order to 'maintain' an application properly business needs to keep investing in modernization of the application, which is more than just maintenance. Let's say they need to invest 30% of the original cost per year. Most will not do that saying 'It is a capital asset that I paid for and it should work as expected for as long as I need it' - okay but in five years time it will be so out of date that it will need to be redeveloped.
No. The only code that requires no maintenance is the code you do not write. In other words, "No code is easier to maintain than no code." Add that to the nihilist coding attributes:
Any code written will require some amount of maintenance.
The actual effort required to maintain the code will vary depending on what the code does, the environment the code runs in, and the needs of the code's end users.
Unmaintained code will ultimately fail the same way that all other things that humans build do. If someone does not maintain the code, it will eventually degrade and fail.
Anytime you write code, especially for a long-lasting endeavour, you should consider how the code you write will be maintained and what might cause it to fail sooner than expected.
That doesn't make any sense. I have code running on micro-controllers, that has been running 24/7 for 10 years. It's never going to "degrade", the hardware may fail but the code is solid.
Entrepreneurs occasionally ask me to take their idea and make it a reality. Their most common request is for me to build them a website so that they can sell stuff. Sure, I could take their money and build it, but it's much better for them to sell on an existing e-commerce site or learn how to use a CMS.
Have it do one thing very well and document it clearly so users can build it into their own processes.
If it is more complicated than that ( i.e. must do several things very well with ever-changing needs ), document it clearly and include a link to the source code and build instructions.
I think the implication here is that you have to 'maintain your credit card'. Not an issue until you switch banks or have some sort of issue with a corporate card that you use with your AWS account.
I think it's being nitpicky for the purposes of this discussion but I think there are probably several HNers who could tell you about how their product hosted in AWS went down because of a credit card issue.
Exactly what I was thinking. Static content hosted in an environment you don’t have to patch, reboot, worry about things breaking after patches, etc. and the fact it’s static html and css means no runtime config, updating libraries, compatibility issues, etc.
Unless you're building an application that doesn't interact with external systems, chances are your job is never finished, even if you choose to consider it finished.
If you don't want to be a lifetime maintainer, then you have to transfer ownership to someone else or consider the project to have reached its end of support.
Consider an analogy to building houses, it may appear that the builder has finished their job since the house is fully constructed, but like any system, it requires maintenance for the entire duration of its lifetime.
You don't. You develop it as sloppy as possible and then make yourself indispensable to your company by being the only one who can maintain the pile of junk.
Seriously speaking the following things help alot:
1.Reduce external dependencies. The less integration with 3rd party apis and services the less maintenance you will be doing.
2. Reduce external dependencies.
3. Reduce external dependencies.
4. Unit Tests
5. Integration Tests
6. End to End Tests
7. Reduce external dependencies.
I have some simple serverless code that has run 500M+ times without issue. It took some extra work to get setup and monitored, but SQS and Lambda are amazing beasts.
a few thoughts from someone who makes a living designing and building stable-multi-year projects.
1. KISS, keep it simple, stupid.
Keep your code as simple and straight forward as possible. You can do that in a few ways:
- As others have said, focus on keeping dependencies to a minimum. This can include libraries but also other 3rd party vendors/external apis.
- try to keep feature creep out. the more complex the codebase the more likely it is to suffer failures. Keep things focused on solving specific problems.
2. Build software that is meant to be delegated.
You can't remove all dependencies. Whether its libraries, external apis, or hosting, every piece of software needs something to run. If you don't want to be stuck as a lifetime maintainer, then you'll need to ensure your code can run without you. There are many ways to do this:
- use existing, well tasted, stable technology that is supported and maintained by your org, not something new and fancy for each project.
- enlist others to help early on, sys admins, hosting providers, or whomever. Build your software in a way that is supported by those providers.
1. Try to make the software tolerable to the wrong input.
2. Develop tools which allows end-users to adjust the software, make as many settings as possible.
I don't think that those options are actually good in the end. If your software is tolerable to the wrong input, it might just work wrong and nobody will notice it. If there are too many options, nobody will know all of them and in the end they'll either ask you or configure it wrong. If you'll have too much of flexibility, then developers who will need to extend your software, will be forced to work bounded by inevitable restrictions.
I like software that's precise and does only one kind of thing. It crashes on wrong input, so I can either blame someone who's responsible for wrong input (I mean service, not ordinary user) or fix software. It must not be flexible, but it should have flexible architecture so I can just adjust or extend code to adapt it as necessary.
Zero maintenance is not the same as becoming a lifetime maintainer.
You haven't provided enough context here, but since we even patch software on Mars I doubt you can built a bug free, feature complete software that will last "forever", so you'll need to find ways to delegate maintenance to someone else.
By keeping it simple. Probably too simple -- If your app has any complexity, in the code, the infrastructure, or the features, it will need maintenance. If your app is literally just a static web page that does one thing, and never will need a new feature, then it can sit up on the web without maintenance.
But the odds of something that simple meeting your goals is unlikely.
Any application with dependencies will require maintenance at some point. applications without dependencies don't exist. You may remove all your node modules. But you'll still depend things like a programming language, hardware, lightning strikes and solar storms not happening,...
- write code that you expect to fail, handle all errors you can anticipate and keep monitoring up for those that you can't resolve programmaticly
- use a managed hosting service for webapps like heroku
- aggressively reduce code complexity. single responsibility principle is key.
You can program defensively, which is a learned skill, and your app might run for years without complaining. But some dependency might change something and a regular push bring everything crashing down until you fix it.
So program defensively and expect to have to do the occasional bit of maintenance.
Maintenance means change. Any time something changes, you will need to update the application.
An application with zero maintenance means that it either has a very, very targeted function that doesn't change, or it isn't being used after a certain period of time.
I think your code and documentation should empower others to become experts in your place - write simple code, be very consistent, use minimal dependencies, test it thoroughly.
Desktop, web or mobile? My guess is that you'll get very different results based on this.
Overall stick with technologies that have been around for a long time and have proven themselves to be stable and their developers do value stability. Sadly most developers prefer to run fast and break things, regardless of tech, so your options will be limited. Also avoid anything latest, greatest, shiny and new - even if their developers promise stability, at least for the initial versions until the tech matures a bit.
If you see anything that uses semver run away. Semver might sound like a good idea on the surface in that any breaking change means increasing a major version. But the flip side of that coin is that by choosing semver the developers communicate that they do plan on breaking backwards compatibility at some point. Despite the excuses a lot of semver enthusiasts will tell you, there are very very VERY few reasons to break backwards compatibility and the vast vast majority of them are imposed from outside (e.g. the sort where your OS drops 32bit support and there isn't anything you can do about it or the architecture you were relying on isn't supported by anyone anymore).
On the desktop stick with languages that either have multiple independent implementations (independent not only in terms of who developers it, but also in terms of codebase) based on a standard, like C and C++. This way you can switch between implementations in case something goes bad. Also do not use the latest versions of the standard unless every implementation (and by "every" i mean "really, truly, every" not just the popular ones) implements it with more or less the same features (stick with the least implemented ones). This gives you a greater set of choices to switch when you decide to switch.
For desktop UI on Windows use the Win32 API or roll your own. If you plan on being cross platform, roll your own anyway since the only thing you can rely on (at least for the foreseeable future) on Linux is X11 - anything else is bound to break and/or not exist in your users' computers. Note that if you also plan on supporting macOS rolling your own may not be liked over there and you should seriously consider if it is worth the hassle since as Apple has proven many times they do not care about backwards compatibility so you'll need to maintain your app regardless (though you can try and minimize that to just a recompile).
For web i do not know much, but i'd stick with stuff that do not break. PHP and Java seem stable. Client-side things tend to be very stable though Google does give me the impression that they'd like to flex their muscle to drop some stuff they consider "bad".
For mobile abandon all hope, it is the most ephemeral platform.
Beyond that, make either very small programs that you can easily modify or make modular programs that you can swap out things without much hassle.
Personally i work with desktop. For my own stuff i stick with C89 and Free Pascal. The former doesn't change, the latter does change but very very infrequently and it is all statically compiled anyway so assuming the underlying stuff do not change they'll work. Lazarus on Linux will eventually be an issue because Gtk2, but there isn't much that can be done about that (the author of FPGUI - that only relies on X11 - says that it can be used with the LCL FPGUI backend, but personally i haven't tried it and i think the backend isn't very mature). Win32 stuff is practically eternal (and funnily enough on Linux Win32 via Wine is the stablest ABI - essentially making x86+Win32+C89 the most stable combo even if Microsoft drops it :-P).
1- Shield away from dependencies. Use languages that are robust (no JS, no PHP) and if possible, generate native .exes (Delphi, Rust, Go,...).
Langs with large runtime/deps (Java, .NET, Js) are always trouble in the long run. I re-enter with .NET Core and have regretted heavily it (because maintenance, not performance or dev productivity).
ie: If a lang/tool/ecosystem is for large teams (java, .net, c++), is not for zero maintenance.
How easy is to setup and get running something (without resort to auto-installers or docker images) is a high evidence in how good will be for this metric.
2- If possible (mobile) use iOS. Android is not robust at all for long term prospects
I made a enterprise iOS app that is also nearly worry-free. My only job is to upgrade xcode and recompile from time to time.
I enter android late in the game, dreaming that android become more or less good. Not.
3- Important! If possible, split the programas between what could be "zero maintenance" and high maintenance.
I have made one in Delphi that is running 10 years in some places with zero calls after the first 3 years of tweaking.
Is split in 2 parts: The Delphi side have stay solid, and the "business" side that requiere more changes are in scripts in python that I integrate with the Delphi side.
Even the python side is now near worry free, but I need to do changes here and there.
4- If need JS, pick VERY carefully how use it. JS is the anti-tesis of zero maintenance. The web is hostile in this area. You could lower damage if VERY carefully know what to use.
5- Stay away of stupid "is for scalability" traps. Micro-services, nosql and similar are the best way to destroy productivity. Modular code yet running in a monolithic (or maybe in a REST api + client) will be more than enough by long margins when coupled with postgresql or sqlite. Again, a solid RDBMS is what most need. "Eventual" consistency is a stupid choice most of time.
P.D: I'm solo developer, and have not time or high pay to cover for bad choices, so i try to perform very well in this metric.