Software Checklist (2014)
solipsys.co.uk
solipsys.co.uk
Of course, it's not so simple. How do you actually quantify maintainable software? Just for that one point, you could write an entire book. When you introduce other points, the process of writing quality software becomes exponentially more complex, with different aspects of well-structured designs overlapping, balancing with each other, and sometimes contradicting each other.
To bring it back to the original illustration, even if you have a flight checklist, it's not going to matter if your plane was poorly made in the garage of some beginner aviation hobbyist out of scrap metal. If your program is made of spaghetti code and poor abstractions, you're going to be working on that testing checklist for a long time.
I do agree that checklists are helpful and that more standardization would help, but we also need more quality training and certification, arguably more so. We need great aircraft designers, not just pilots.
I work on a 40 year old mainframe product and as a vendor, we provide a lot of checklists for our users (system administrators). Everything from installation and configuration to maintenance and customization is covered. This approach is an exception on the mainframe and it is virtually unknown in modern software applications. (We are not really mission-critical software, but we have a culture like that.)
Could some of our checklists be more automated? Yes. But I believe today there is this strong idea in the software world that you never ever need a technician (system administrator), because everything is so user friendly and automated and reliable. So you never need the checklist either. I think this is false and there would be a benefit from stronger culture of checklists (provided by the vendor for the end user) in software.
It was most definitely a checklist with the purpose of finding and verifying bugs.
But it was rarely used by the developers or engineers (that I know of) because of the implicit understanding that if something was in the checklist it was a) already a found bug and has been fixed or b) if a regression occurred, would be found by the army of QA testers.
So yea I agree, checklists are used in the wild but their usefulness to coders is limited. If indeed that was what the author was implying.
I've thought about automating the test, but ultimately decided against it. Part of the checklist is just making sure the tester has the proper logins to the proper servers [1]. Second, if anything breaks in the automated portion, you need to know how it works in order to fix it.
[1] yes, multiple servers. And it takes five hours to run. We've gone to length to simulate as much as possible the production environment.
(Disclosure: I co-founded CII and the BadgeApp.)
If you want to see a video that explains the badge, see "An Introduction to the Core Infrastructure Initiative (CII) Best Practices Badge" at https://www.youtube.com/watch?v=JMptmhV06j8
New projects are participating every day (see https://bestpractices.coreinfrastructure.org/en/project_stat... ). The badging application is itself open source software; its project site is: https://github.com/coreinfrastructure/best-practices-badge/
(Disclosure: I'm technical lead of the BadgeApp project. Hi Dan!)
Now understanding how to write good software, especially good UI for human operators to work, is a hugely underrated skill. Many accidents (air crashes, nuclear accidents, etc) are caused by poor or confusing UI.
For operations, or devops, I think checklists are essential, and should be automated as scripts and dashboards. But always have the ability to do everything by hand if required, to cut out some step or modify something in a critical scenario (trust me, it always comes up, and when it does, you don't want to be shooting from the hip in a crisis).
I've specifically built jenkins operations boards with a bunch of buttons to run scripts and do operations, and it works great. You also get a built in log of who's doing what when, and what happened with it.
Also, just because I think it's interesting, and related to checklists, look at the Spanair 5022 flight disaster - https://www.youtube.com/watch?v=EruTu5O9LX8 . Basically they missed a step in their checklist to make sure their flaps were at the proper setting for take off, but being distracted and in an unusual situation, they didn't run through the checklist correctly. Anything with manual steps can fail, including checklists.
Preparing for these scenarios is actually I think the key here. Having the knowledge written down after you've designed a system to handle adverse conditions is just a no-brainer (although it seems like no one likes writing things down, I do!).
Various "safe" languages are just as vulnerable to denial-of-service vulnerabilities as C/C++. Since I started fuzzing Go projects I've come across numerous parsers of untrusted data that flat-out crash if a slice is accessed out-of-bounds. Deep recursions (A() calls B() calls A() etc) can crash both Go and Rust. And in probably every general programming language you can implement logic that leads to excessive resource allocation or computation, and unintended infinite loops. These kinds of bugs can obviously be problematic for network-facing components. A royal use of runtime assertions in debug builds for arbitrary invariants/conditions combined with fuzzing usually uncovers many more bugs.
If it is a server process, it can even corrupt data for days until someone actually notices it, if ever.
Or they just crash in a totally unrelated memory segment a couple of hours later.
Crashing when the out-of-bounds takes place is a much better outcome.
I stared at the code for some time and couldn't see any mishandled edge cases. It was then I realized that I could automatically generate an arbitrary amount of unit tests, because it's simple enough to call strcat and encode that to get the correct result. So, that's what I did: generate two strings of ACTG, encode them, concat, and compare against the result against that of the encoding of the two strings concatenated. Sure enough, a mishandled edge case popped up after trying a couple hundred strings. There was probably no way I could have found that bug without this approach.
It's a really simple concept, but you need a couple of things: first, a very wide input space. Next, you need an alternate way of verifying the result. If you just want your program to not crash, you get this for free. In my case above, I could apply the two functions (concatenate/encode) in the other order to easily calculate the expected result. If you have these two things, a fuzzer is the logical thing to write to make sure your code is rock solid.
You don't need to use a tampermonkey script, they support templates :)
It's different from other static analysis tools that integrate with pull requests for a few reasons:
- It opens up a programming API, not just a configuration and rule system, which grants you more flexibility
- It's tailored to send specific messages for errors so that you don't have to rely on the PR submitter to interpret errors and warnings
- It also allows you to look at things like PR details and issue details, so you can check things like if a PR has an issue attached and much more
- It's not restricted by language, so you can do things like check if someone updated a certain code file but did not update a certain markdown file and warn them that documentation may need to be updated
Overall it just really cuts down on the endless cycle of submitter makes change > wait for reviewer to be available > reviewer gives feedback > wait for submitter to come back > submitter makes change. I really want more people to use it so it grows.
Code review guidelines or style guides come close to being checklists. There are also various kinds of static analysis like CheckStyle, FindBugs, etc. that check for common mistakes.
Of course, statically typed languages have type checking built in that prevents mistakes. Plenty of languages already have type systems and/or object constructs prevent the class of problems that led to Heartbleed (bounds checked arrays IIRC).
Isn't this principle similar to TDD? For any bug, first, add a test that fails, then make it pass.
Wait, a compiler that can differ between an assignment and a comparison? Witchcraft! What do those crazy computer scientists invent next? Type checking? Range checks? Testing pre and post conditions?
Fools! Computers will never be able to do that! Academic bullshit!
/s (just in case)
Checklists and unit tests and TDD are useful. But how about first using the right tools? I don't think they tried to repair airplanes with jack-hammers in WWII, so we shouldn't try to program complex systems with Javascript and other low-level languages.