Let’s Get Excited About Maintenance(nytimes.com) |
Let’s Get Excited About Maintenance(nytimes.com) |
What it really should be called is "refinement." The innovation ends up being incredibly crude but it gets the job done. How can we build on that, make it better and less coarse than it was? How can we make it more efficient?
I don't think the name would matter in any way. It's more a problem of what voters value, or what politicians think that voters value.
I have recently come to realize that, at least in my world, source code older than five years is basically doomed. Developers simply refuse to work on it.
The code that makes it to five years is extraordinary as most of it "dies" before reaching the eighteen month mark.
As a result I have recently been shifting my view to support replace-ability vs maintainability whenever possible. I'm not totally sure how to achieve it, though. Most current trends seem to be towards increasing baggage. (docker)
Data lives on and on and on, however. Data is king. :)
We can use automation to gather data we've never had before. We can use this data to help prioritize maintenance tasks, and get them done faster with less interruption to service.
https://www.strongtowns.org/journal/2017/1/10/poor-neighborh...
https://www.strongtowns.org/journal/2014/8/19/is-a-street-an...
https://goo.gl/maps/uFkLJoKU1DB2 https://goo.gl/maps/767CYu5Mwd62 (it actually looks worse than this up close)
I'd be interested to find out what the track record is of maintenance of infrastructure by private vs public entities.
So a person from the 70s who was instantly transported to today would feel like the only difference is that instead of having our own servers we ship things to Heroku? Please...
The thing is I get very little credit for fixing something that is broken, but creating something new generates accolades and the illusion of productivity...
New features are also pretty easy to measure in terms of throw money in, get features out. Maintenance... how hard do you go? How much is too much? Do you just need a light check-in? Do you need full reviews? Or is that just wasting money for no reason?
Is this exaggeration? Would any reasonable person say that the Oroville dam nearly collapsed?
Would any reasonable person say that the Oroville
dam nearly collapsed?
According to Wikipedia [1], "Erosion at the base of the weir—which was expected—progressed much faster than anticipated. The headward erosion of the emergency spillway threatened to undermine and collapse the concrete weir [...] Fearing a collapse, the Butte County Sheriff's Office issued an evacuation order of the Oroville area. [...] Engineers worried that [...] damage to the main spillway could grow uphill to the point that it endangered the main spillway gates, leaving no safe way to release water. [...] By February 13, 188,000 people in the vicinity were reported evacuated. About 23,000 National Guardsmen were ordered to be ready for 'immediate deployment if the dam spillway should fail' to help with evacuation and relief efforts."That sounds a lot like a near-collapse to me.
Of course, you could argue the authorities acted with a surfeit of caution - perhaps there was only ever a one-in-a-thousand chance of the dam collapsing, and the threshold for 'nearly collapsed' should be a one-in-five chance of collapsing. However, I think most reasonable people would say that a one-in-a-thousand chance of killing 188,000 people living below the dam is several orders of magnitude too high.
[1] https://en.wikipedia.org/w/index.php?title=Oroville_Dam_cris...
Not only this, but I've lost count of the number of young guys I see come into my company (especially the machine learning guys), spend a year exploring some new technology, then jump ship to a different company when it comes time to integrate it with the existing legacy code base.
Pretty much hits the nail on the head, although I want to note this does not exclusively apply to Americans (but maybe a bit more than Europeans; technology is often a lot cheaper in the US: it is not uncommon that the amount of dollars paid for an item is lower than the amount of euros, even though euros are worth quite a bit more).
It is especially bad for phones. Many people I who are (almost annoyingly) aware of the environment buy a new phone every year.
I am guilty myself too. My current phone is about two years old. It has a full HD screen, a luxury that I don't even need on my laptop (about half of the time, I work on a 1440x900 thinkpad). And, to be honest, it is getting quite sluggish. When I open dropbox or tinder, I experience a delay up to 10 seconds, which is quite ridiculous (it especially bothers me that software seems to get slower, more bloated, and more abstract and complicated). People's first reaction to hearing this is "Just buy a new phone, man". I shouldn't be, but I am indeed considering this.
I recommend Raymond Chen's blog, The Old New Thing, for some cool stories about how and why ancient Windows/Office components were written a certain way, and what the effects down the line have been. Among other things. https://blogs.msdn.microsoft.com/oldnewthing/
What you're saying is probably more true in the web dev world.
Fun times. It shouldn't surprise me that since the code from that time uses Hungarian notation.
Any world in which OOP is the primary paradigm. Then again, I've seen truly horrid procedural code as well. Do you have any specific ideas on why the code you're working with seems to be the exception to the rule? Or is it pretty much all in that blog you linked?
1. Pervasive, maximal frameworks that favor terse magic over clear explicitness. At first this allows you to spin up a website in a few lines of code, but years down the line you're spending all your time reverse-engineering a workaround for a bug in Ember 0.2 so you can implement the same functionality in Ember 17.3 when the controller that it referred to is no longer in the codebase and the naming convention for tying together models and views has changed twice.
2. 0.x versioned libraries which solve the problem you have today, but cause 100 problems tomorrow when the maintainer deletes the repo.
3. Global state, which lets you bypass having to pass data through to components until later when you want to have more than one component per page.
The issue is more one of fragmentation; figuring out which file(s) / method(s) are responsible for some item of state can get to be impossible without a powerful debugger, and constantly changing frameworks / libraries don't help.
What world are you living in? I work for one of the big 5 and 75% of the software stack features I use have been in continuously developed for over 5 years.
I get some of what gp is saying, some older stuff gets abandoned and not improved much, while other stuff gets modified so much that it's sorta like that "at what point does a ship become a new ship though gradual replacement of all timber?" question.
This is one reason the not acquiring or correcting technical debt is so important for the long term health of a company.
Now I agree that data is king, but if you have to rewrite you code base every 5 years you are doomed.
Even if people don't believe that all code over five years old is doomed, writing code to be easy to rewrite still seems like a useful idea. You're preserving optionality, you're making it easier to try out multiple designs, and you'll have an easier time recruiting collaborators because they'll have more fun projects to try, and so they'll be more likely to progress 'down the funnel' from using a project to hacking on it to contributing it all the way to taking over its running.
- Customers don't want major versions to be continuously deployed. Each deployment involves validation and training. They want the software to be left alone, perhaps with the occasional bug fix.
- The business needs new features to stay competitive.
- So you're left actually needing to host multiple versions. All the major versions the customers are on, and want to stay on, and one latest-and-greatest version for winning new business.
- Never force a new feature on a user. It becomes obvious that you're building things that most of your customers don't want. This means don't create a major version and automatically deploy it.
- Moving data between systems is hard. Plan to never move data between systems, or major versions of the same system. Users prefer to see their data where they left it, looking exactly how they left it. A major version should be empty. If you constrain a new version of your software based on old data, sooner or later you're stuck, either because of schema or because of volume.
- So if you have a big new feature, you save it for the next rewrite.
- Once you've decided that at some point in the future you're going to do a rewrite, things fall into place nicely...
- You avoid the situation where your dev team is mostly useless apart from the few guys who originally wrote the system.
- You avoid the endless accumulation of data.
- You avoid being commanded by the product team.
- You avoid being hated by your users, and your clients.
- You avoid spending huge amounts of time and money on things you didn't really need to do.
- You avoid the end of your business, which is inevitable given ~10 years of 'current best practice'.
- The part that I don't know yet is... developers have been avoiding rewrites for so long, we haven't really got good at it. We need to do it, do it often, learn how to do it well, and share that experience.
There is wast amount of code used daily that is decades old, especially if those systems are not user facing.
I'm curious what kind of environment you work in where where most stuff stops being used after 18 months...
There's an assumption out there for some that library code is flawless, and there's an imposter syndrome type aversion to touching it, with the developer fearing the code was made in a certain way for a certain reason and that they're not skilled enough to work on it.
This is made worse by the few brave developers that will dive in getting all the anger if they make a mistake, at a massive scale if the library is popular.
Rather than dismiss these observations as isolated cases of people not practicing good behaviors, I tend to see them as evidence that we should be creating libraries far more conservatively, freezing interfaces far more late in the life cycle, perhaps even decades late.
If I'm right, we are also overusing industrial notions of assembly lines and division of labor. Libraries with non-trivial functionality take a long time to get right, and in the meantime they are produced more like guilds of craftsmen than factories. (Even if the products themselves permit factory-like operation at scale.) In that initial bake-in period we are ill-served by conventional metaphors of software components, building blocks, etc. We should be dealing more in vertically-integrated self-contained systems rather than plug-and-play libraries. More OpenBSD, less `gem install`.
I've been thinking about this for at least five years, ever since http://akkartik.name/post/libraries. More: http://akkartik.name/prose
I'd disagree, docker for example makes it easier to create infrastructure as code which in turn makes it easier to replace pieces of that infrastructure. Same with micro-services which allow you to eventually replace isolated pieces of your infrastructure. The more modular and isolated pieces of code and infrastructure are the easier they are to replace piecemeal.
Although, I concede Docker is the bees knees for local dev.
Easy to rewrite, replace, and deploy.
One of the most crucial keys is: make your code greppable. For example, don't treat OOP classes as a license to use generic method names ("add", "set", "close", etc.), or it'll be difficult to weed those classes out.
Not just naming conventions, or assignments in if-clauses, but files there the first indentation level is three spaces, and the rest are all four...
P.S.: And because it's that old, the change-history of a given line can be very important, so it's too late to mass-reformat everything. So you either make the file uglier by mixing "standards", or you have to hand-tweak all your changes to match.
There are many ways into the walled gardens, but none out.
I can't speak for other languages, but in Go, the ability to navigate to the definition of any documented symbol via GoDoc has been most interesting for learning about how the sausage is made in certain areas. I don't have a comprehensive knowledge of all of Go yet, but I've learned that environment variables, for example, are backed by a `map[string]string`.
Perhaps something like that might help with the imposter syndrome about it?
For a start, one does not persist "local state", and this is a clear give-away:
> state cannot be cheaply recomputed or regenerated like other live values
The author seems to be arguing against a global state encapsulated into a tree of disjoint accessors. And his solution:
> our programs become stateless logics manipulating a stateful substrate
Is verbatim the FP-way of avoiding working on global state.
A friend of mine is working for an internet security company that seems to have the enlightened attitude towards software, everything is test driven and the majority is C++ and Java. This code will be around in 20 years, and will bring in millions of dollars of revenue with minimal maintenance.
- Windows is (mostly) a platform, not an end application. So you need...
- Backwards compatibility. It is a pretty hard requirement, as one of the major selling point of Windows is that your existing stuff will keep working. Programs targeting 16-bit Windows from the early 90s still work on Windows 10 (though they recently removed the 16-bit subsystem from 64-bit Windows). I believe it's the same with Office document formats. You already have the code that handles all of the old APIs and functionality, so...
- If it ain't broke don't fix it. The old code has been thoroughly battle tested. Obscure edge cases have been addressed. Bugs have been fixed over the course of many releases. There is no chance that your rewrite will avoid regressions, and you'll almost certainly introduce new bugs too. It's better to make necessary changes to the old code than to try to start from scratch. And...
- It's a lot cheaper too.
Joel Spolsky has a great blog post about rewrites: https://www.joelonsoftware.com/2000/04/06/things-you-should-...
This is the main difference l see between maintaining old Java code and e.g old Delphi code:
In maven/java I can run a couple of commands to build it, open it in any of my three favourite IDEs (Netbeans, IntelliJ and Eclipse in that order) and it just works.
In other languages there is often some dependency hunt involved before you can even start. Bonus for dependencies that must be installed using .exe installers, in a specific order (hint: if you don't get it right - good luck with cleaning the registry before trying another installation order.)
I might have been very unlucky in my encounters with legacy code in other languages but so far every encounter makes me love the Java ecosystem more.
(Although I'll happily admit that parts of it might be related to the fact that Java developers seems to avoid using non oss code to a much larger degree than anyone else - maybe except from php and js devs?)
It's not a question of sinking tons of hours into this stuff, if you're using good tools it just becomes the way you work. Could you gain 5% efficiency by just blasting out the ugliest code you can? Yes maybe, but if it's actively developed code you could easily cost future developers much more.
[1] http://clang.llvm.org/docs/ClangFormat.html#script-for-patch...
Unfortunately, it often felt that we were having to write everything from scratch; you can barely find anyone talking about this model, or any tools designed to handle it. Everyone seems to be either fully multi-tenant or manually launching individual servers (which is not feasible for low price SaaS).
I often wish I worked at one of the SaaS product companies that target small-business.
Plus if you have different processes per client, you can provide better security, particularly in terms of leaking customer data to each other. In our case, we just used different Linux and Postgres users for each client, but even just that meant that a few security bugs discovered in the application couldn't be used to read/write data of other customers.
Paraphrasing: "My code will be gone next year, so I don't care about code style"
> "I'm not good at this because I don't try, so I won't try"
> "Girls don't like me because I have bad hygiene, so why should I bother with hygiene?"
etc.
This would only apply to what I wrote if my code was disappearing because it's not formatted to pass a linter. You and I both know that this isn't the reason code gets deleted. It gets deleted because it gets refactored, or the feature/product it's implementing gets killed.
Furthermore, code quality is not the same thing as code style.
I'd focus on making it easier to migrate between libraries, easier to improve interfaces, and so on. (I'd argue to a certain extent that's already happened, and that's part of why we're using more and smaller libraries).
I did misparaphrase you. My apologies for that. Fixed.
But as for the other argument, I think the comic's examples and your case represent feedback loops in which two factors are both cause and consequence of each other.
I believe you that you started not caring about code style after you noticed your code tends not to last. Similarly, life was short already before bacon existed. Would you agree that your code is more likely to dissapper now that you don't care about style?
At scales above the absolutely trivial I think libraries evolve more flexibly based on social rather than technical considerations. It's about not pissing people off when you change the interface. Even something as complex as Go was able to make incompatible changes pre-1.0.