Some things that might help you make better software (2016)
drmaciver.com
drmaciver.com
For example, someone might send an API that has a minor bug or even purposely add a typo instead of a proper fix. A front end engineer would have to actually use the API, spend a few hours scratching their heads on why it isn't working and whether it's their fault, before contacting the API maintainer on it.
I liken it to traffic congestion. It works fine when you scale something up to around 50% capacity. But nearing 70% capacity, things start to slow down, and at about 90% capacity, you get total gridlock.
[1] https://youtu.be/03GsLxVdVzU
[2] https://mechanical-sympathy.blogspot.com/2012/05/apply-back-...
It's even worse than that in a lot of places. Sometimes, you know your management doesn't understand quality to the extent that they would prioritise it over their other desires. However, they say that quality is the most important thing. The programmer thinks, "OK, maybe I won't be rewarded for quality, but since they say that they want it, I'm just going to do it. I want it, and that is good enough". But in reality, the programmer is often punished for implementing quality above what management thinks is necessary. You sometimes get into a situation where management no longer trusts the developers because the developers are working on things that management doesn't understand (quality related). Management then resorts to micro-management to force the developers to do what they want.
What is most important is sales, without sales you have no revenue, you can't pay the bills, you can't pay your employees, and you will go bankrupt.
Next, is customer success. For repeat sales you need customers succeeding with your software. You need to bring the value your customers are looking for. Otherwise, long term, you don't have sales.
Quality is important, as it is one aspect that is valued by customers and that will help them succeed with your software. Features are another important aspect required to ensure benefits for customers. Quality without features is nothing.
Of course there are many benefits from having quality, most importantly reducing risks, lowering costs, and improving time to market, so it is really important, but not the most important thing.
Probably what you meant is that level of quality needed is only as much as is needed to generate the requisite level of sales. The problem then becomes one of judgment: management consistently under-estimates the level of quality required, or they focus on the wrong sort of quality. The world is full of bad products simply because of such issues.
You want the level of quality the customer cares about.
Quality is not an absolute thing: you either have quality or not. Quality is a range, from very bad quality with no validation to 100% full coverage, full testing, works in all situations.
Usually customers are not willing to pay for 100% and as a business you do not have the time nor budget to build for a 100% quality.
How was your tenure at Equifax?
Seriously, though... A workplace with this mentality has a high-turnover rate from burnout. Things keeps breaking, things are perpetually behind schedule, and a toxic work culture usually clouds the office. This perspective drives companies into the ground and pushes engineering teams towards mental breakdown. This is not a sustainable model.
However, there is a reckoning happening (right now) for all of these shitty businesses in the form of security breaches. Your lie "Quality is important" will bitch-slap you in the face when there are serious economic penalties for bad quality. GDPR is that reckoning and the US will soon follow.
One item I would like to add explicitly (or emphasise more) is making use of static type checking - be it in the form of a compiled language or type checkers like mypy/typescript. It not only prevents runtime bugs but might even increase productivity when used with good tooling. In a conference talk (can't find it rn), an Airbnb engineer said around 38% of their JS runtime errors in the past could have been prevented by using TS.
Edit: here's the conf talk https://youtu.be/P-J9Eg7hJwE
Additional points:
I like the article moderates the unit testing craze. I like that he mentions integrated tests (basically testing the whole or bigger part with many different inputs) and asserts - in combination, they are more efficient than individual unit tests.
Aside from tests and asserts, a third important method of ensuring quality is to have proper abstractions. They let you encode the domain assumptions and write less code more correctly in the first place.
CI and test automation is good as long as it not used to replace QA as a role. Good QA is a methodical assertive nitpicker who loves to break things, which is often a different personality than developer. (I personally can somewhat switch but it takes me a week or two to get into the other role.)
I am not convinced about CD. I don't think it works well when you're delivering a 3rd party software which relies on stability of some API - then the client needs to make sure they have the correct version of the 1st party product in order to have 3rd party product working reliably for them. I suspect CD actually hurts 3rd party software developers, because they now have a moving target and are between a rock and hard place. And I am not sure it leads to quality software, I think having certification at certain API version, and longer release cycle, is better for quality software. Maybe it depends on the type of software.
Plan to always have more capacity than work
No Long Working Hours
Good Work Culture
They're not very effective. People will agree with the rules, follow them to the letter, and completely miss the point. Painting a car red and calling it a Ferrari doesn't work.
I suspect that's why so many shops have trouble getting good results with unit tests.
You've got to have a team leader who is experienced enough to be able to tell when literal adherence to the rules is suboptimal.
Also, code is already consistent by it's syntax. I can't think of any example how this strict formatting helps anyone.
Does that make up for the constant annoyance of having automatic formatter screwing up your code? Depends on how much code you write, I guess. If you write code a lot, you'd rather have your code retain the original formatting and put up with reading the code of others in their formatting style. This is not such a big deal, btw. A professional developer should be able to comprehend code in regardless of formatting (unless it's truly horrible, of course).
I notice that people who insist on mandatory use of code formatters don't actually write code that much. So they don't care that their code gets reformatted.
This feels completely made up. As a reader of code, auto formatting makes my job slightly better due to consistency. As a writer it's a huge improvement. Not needing to think about where to put newlines and the like lets me focus on what actually matters.
My experience is similar to the author's - most people who are against code formatters change their tune quickly if you can convince them to try it.
I especially love it when working on a project with a few different developers that used an auto-formatter.
Most of the things that get covered by a formatter are eminently sensible.
Does anyone know about a reference repo that I could take a peek?
My understanding is that Google does this internally, which is why gopath works the way it does. It's meant for monorepos.
Yes, property-based testing is great. Of course, you need code that actually has some nice properties. Typically that is the case for well-designed code, so it's a win-win.
First of all most software developers have no idea what a quality software developer is until they see somebody who delivers 10x productivity and even then they still cannot typically extract what makes that one developer so much more productive. This blindness is often present in organizations that don't know how to hire or who value their subjective considerations over objective criteria.
Secondly, there is little or no incentive to hire a good developer. A greater developer may deliver up to 4-10x productivity on only a 2-3x salary, but it also typically costs more to find good developers. This problem is deeply compounded by the previous point in that many organizations cannot identify what a good developer is.
Third, most organizations don't want high quality software. They want software that is popular and appealing to entry level developers. As an example search just about any article for simple versus easy and then consider what you are reading against some of the processes, configurations, and piles of abstractions you have to go through at work to make things easier.
Fourth, and perhaps most importantly, most organizations cannot account for economic considerations until they become huge, as in retaining hundreds or even thousands of developers. Economics, particular software economics, is not something vision that is well understood either academically or in practice.
I mostly agree with the rest of article except for the extreme praise of code coverage. Artificially boosting code coverage with unnecessary tests is one of the greatest contributors to tech debt, as all tests are ultimately debt never seen or appreciated by the end user. Code coverage does not account for whether tests are positive versus negative tests, whether collisions of features uncover unexpected behavior, or test quality. It also, in many cases, does not even account for whether the code is working. It isn't supposed to. Code coverage simply lets you know what code is unnecessary to your automation.
Instead think of covering code like this:
* If there is critical code there should be some manner of test automation to account for it in the various ways it is executed by a user. If that critical code is removed existing tests should break, the code is actually not critical at all, or you have missing tests. Developers should be rewarded for removing unnecessary code.
* Tests take time to write and execute. That wasted time is a form of debt. This wastes people time. You want to ensure the software works correctly and that features do not introduce untended defects or regression but you don't want to spend more developer time on test execution than writing software. I have seen this at a major .com.
* Code coverage is useful to determine what code is executed during testing and what code isn't. That is all it is useful for. When tests are written to artificially boost code coverage analysis the analysis becomes a meaningless way for developers to justify increased effort without contributing value back to the application. Instead, use code coverage analysis to make decisions about what code to remove, refactor, or rearrange.
A previous codebase I worked in was terrible to refactor because of the insane amount of tautological unit tests and abuse of mocking.
For new features we stopped writing tests that were too specific and started writing more integration tests. We achieved a leap in quality and ease of development.
1. cross multiple boundaries (integration test) by asserting that some system two degrees away from itself is being run/invoked (not a unit test's duty)
2. test descriptions read along the lines of, "it should work for valid use cases". This one made me laugh when I first saw it. This made refactoring a HUGE undertaking as I had to comb through all of it to understand it
3. mocking systems that weren't created by "us" -- this resulted in blind spots in various places
Test/code coverage is only one of many metrics to consider. I think it's useful, but its utility heavily relies on the quality of tests that are written.
I'm beginning to think that a hallmark of a good developer is one that understand what tests need to be written and what assertions must be made. This shines when the tests are written such that the developer can see how API design affects testing. I've worked in both functional and imperative languages and FP testing is harder to screw up as it forces the use of dependency injection. The idea of DI and inserting role players in imperative langs makes testing easier and shows that someone has thought about a reliance on behavior rather than concretions. So when I interview people, I always ask about dependency injection and polymorphism.
But working with seemingly more experienced (on paper) than me, I know that experience is also a terrible metric to rely on.
4. Instead of integration tests (or static typing), all systems made by a couple programmers only had unit tests. The call boundary was NEVER tested, and everything relied on RSpec's "allow(obj).to receive" mocking.
So, not only it was very difficult to refactor (because I had to change two or more different sets of tests + mocks), the tests for dependencies didn't fail when I changed function signatures, or even if I removed chunks of code randomly. I had to find which test to change by myself.
In the end we had tests and we had coverage, but they didn't test anything properly and made maintenance a major pain in the ass.
I don't know that I even agree 10x productivity implies they are good. Or perhaps I should say I don't even know how one measures productivity?
I worked at a startup on the Android team. We had to implement the exact same stuff as the iOS team, and the iOS team was always ahead of us in terms of how close they were to the spec because there was this one guy who was insanely fast at implementing features.
However, I found out later that when we were really close to releasing, the iOS team actually struggled to get that last mile in because they took shortcuts which was how they were able to implement things so much faster. Consequently the Android app was actually able to ship first.
I don't think this is an uncommon thing either though.. Sometimes people make decisions which are terrible for long term sustainability but they get praised for their quick turnaround. The problem is that those people get rewarded and might not even be there when the problems eventually come back to haunt the team.
What is a quality software developer? 10x compared to whom? Are you saying they can write the features in 1 hour what someone else would take 10 hours to do or they would think of scenarios and edge cases that a newbie would not think of attending to.
It is like the difference between average chess players and grandmasters. Grandmasters do not necessarily think any faster than regular players; they think better. For example, they are better able to prune out useless lines of analysis, thus making more efficient use of their cognitive resources