If you’ve never had this experience you have my envy. You’re on a development team and one of the developers does sloppy work and there is nothing you can do about it.
Time was when everyone in software from the first-day QA trainee to the executives had some experience at coding. That is long gone and now we have layers of methodology “masters” and managers who have never written a line, and who regard any and all complaints about others’ work as insubordinate and as personal conflicts, never considering the criticisms on their technical merits.
If I say that one of the other members of the group is doing shoddy work, even if I explain politely and in technical detail, managers hear “unpleasantness” and focus all their attention on team cohesion, which means I’m the one who gets in trouble.
I was working until a few weeks ago on a distributed team for a company in England. One team member, whom I will refer to as L, not only did terrible work (more on this below) but on the daily Zoom status update was three times louder than anyone else, had a voice that could etch diamond, had about the worst English pronunciation I have ever heard, and insisted on hijacking others' computers with a compulsive screen-share that illuminated nothing, just so the rest of us could watch him wiggle his mouse.
He was mechanical. His reaction to any transition was always the same. His turn to talk? “Let me share my screen.” Get an error message? Take a screen shot. Explain a keyword? Another screen shot. Thanks, L, I didn’t know how to spell “foreign key.”
I came to dread the call because his abrasive and loud voice gave me a headache. And I had the usual reaction to his wrong-syllable accenting that most of us have when we call tech support and get one those unintelligible “helpers” who don’t even listen to the issue before telling you to reformat and reinstall.
Worst of all L appeared to get cognitively rebooted every few minutes. This company had its Git branches set up all wrong, two “master” branches in the same repo, one for the front end and one for the back. My cryptography work was in a branch off the front end “master.” We had been talking about the branches by name for about ten minutes, and it was clear as could be that I was doing my work in “frontend-crypto,” which we had both mentioned many times in the preceding minute.
He suddenly asked me, apropos of nothing, “Chris, which branch are you working in?”
This sort of thing happened many times and managers would patiently explain to him what any eight year old could have followed. They could see he wasn’t tracking but for some reason it was only a problem when I expressed my frustration at having to explain simple matters over and over.
He did a lot of work, all of it very low quality. In addition to industry standard illegibility he did the absolute bare minimum in rigor that he could get away with.
I Write an Endpoint
I needed a new API, one that would return two or more rows for recipients who may or may not already be in the database. I didn’t know Django well enough to do it perfectly, not knowing where Python ends and Django begins (I really dislike Django, it shows no coherence or idiom), but I wrote out all the logic and status codes.
Suppose I called this API seeking the encryption keys for ten people. Here are the number found and the HTTP status codes in my original bad Django:
Number returned HTTP code
10 200 (full success)1-9 206 (partial content)0 204 (data not found)
server exception 500 (exception)
If the response had fewer rows than the number requested I returned an array of their not-found identifiers.
I turned it over to L to fix up the Django syntax, not to rewrite it, but this is what he did:
Number returned HTTP code
10 200 (full success)
server exception 400
So even if not a single row was returned, he called it a complete success, and he removed my array of the rows not found, so the client had to enumerate the returned data, compare to the request and determine which ones didn’t come back. And a server exception returned 400, Bad Request, which was completely wrong. Moreover, he mentioned nothing about changing the status codes and ignored me when I tried to ask him about it.
This guy was supposed to be their back end expert. I expected him to know these codes; I don’t know every single one of them but I know the dozen or so most common ones. And even with the logic and intended status codes right in front of him he threw it all away and did it “his way.”
To be fair there are multiple schools of thought on how to handle intermediate levels of API success. I almost never see any 2XX status code other than 200; that and 500 are the only codes most developers return.
It would be charitable to allow that L had his own approach that was different from mine; in my view we have more than four status codes for a reason, and I use them. I knew however from months of working with him that he had just copied and pasted; he left my sieving logic for the cases above (0, 1–9, 10) but pasted the same line without checking.
In any case an API is a transaction and if he changed the behavior it was incumbent on him to inform me or whoever was issuing the call, expecting these more detailed status codes. Not only did he fail to do so, he never answered me when I asked him about it. This isn’t teamwork. This was a pattern in working with him. Since this project had no QA it would likely have been customers who first saw the holes in the logic.
I was furious. I had done it all correctly except for the Django syntax which he could have fixed in under a minute, but instead he rewrote the whole thing with significantly altered logic. And of course his code looked like a pair of cats had fought on the keyboard.
I tried asking L why he had made these changes but when he ignored me as usual I asked the managers for a conference call. I showed them what I’ve written above. They tut-tutted and said they would talk to L about it. I don’t think they did, because two weeks later it was still unchanged.
And they paid this guy.
So if they didn’t talk to L then they probably decided I was bringing conflict to the team, though they never told me so. This was my last item in the work, all my stuff worked except this mangled API. I was done. With three new languages under my belt and experience in a really cool cryptographic implementation.
I didn’t bother talking to L again. What would be the point? He had done a bare minimum lousy job and in his work ethic that was just fine. In previous debates on design he had contributed nothing. I could have mentored him but I knew from months of working with him that he would have ignored me and gone on doing things the way he was accustomed: sloppy, shoddy, and illegible.
Managers Who Don’t Know Code
As with so many who say that “people skills” are more important than “coding skills,” the managers on this project were more interested in keeping things nicey-nicey in the team than in doing a solid product. Since this was a very security-centric application it was more vital than usual to do the most rigorous job possible, but they allowed L’s sloppy rewrite to remain.
Their attitude toward my report was probably that there was some “friction” between me and L; I got along fine with everyone and managed to mask my frustration with L and his mysterious context-loss episodes and godawful code, and my part was about done so not much came of this.
This is what comes of regarding software development as a social activity. It sure as hell isn’t engineering yet.
But had I been the development lead, L would have been looking for another job.
There is a continuum in the software development work ethic; the two poles are
- Do it as perfectly as possible and to hell with the deadlines
- Do as little as you can get away with and make clearing your task list your only priority. Take up the slack by writing unit tests (which we didn’t do).
L and I were at opposite poles of this continuum. Stir in his disinterest in communication and we had a mess.