←back to thread

Please stop the coding challenges

(blackentropy.bearblog.dev)
261 points CrazyEmi | 2 comments | | HN request time: 0.419s | source
Show context
agentultra ◴[] No.42149111[source]
> When was the last time you had to debug an ancient codebase without documentation or help from a team?

All the time. 300-400k SLOC in C++. Legacy in the sense that there were no tests of any kind. Little-to-no documentation. Solo developer at the tiny company. Fix bugs and add features while keeping the system available to the tens of thousands of users.

A more recent example: here’s a patch for a critical feature we need. It was written over a year ago. The original author isn’t available anymore. You can write the code from scratch or try to resurrect the patch against master.

Being able to jump into a project and lead people towards some goal is definitely a skill for senior developer positions. Yes, you generally have a team you can lean on and have the ability to do research and all that. But how do you show that you can do all that in an interview?

Agree with the conclusion that a good thing to test for is for problem-solving.

The tech side depends a lot on what you’re doing. Although it gets ridiculous and organizations get lazy with this part. You don’t need to be white boarding graph algorithms for a junior web developer role. If your application is a social networking role and you’re interviewing a senior developer or architect? Definitely. They’re going to be teaching this stuff and need to understand it at a deep level.

replies(25): >>42149161 #>>42149283 #>>42149381 #>>42149490 #>>42149504 #>>42149546 #>>42149679 #>>42150007 #>>42150216 #>>42150233 #>>42150322 #>>42150383 #>>42150537 #>>42151066 #>>42151233 #>>42151287 #>>42151513 #>>42152496 #>>42153372 #>>42153374 #>>42155334 #>>42155491 #>>42157152 #>>42162104 #>>42194406 #
derefr ◴[] No.42150216[source]
Real. Engineers who don't think they have this problem, are engineers who see their dependencies and the lower layers of their stack as ossified black boxes they "can't" touch, rather than something they can reach into and fix (or even add features to!) when necessary.

IMHO the willingness to "dig your way down" to solve a problem at the correct layer (rather than working around a bug or missing feature in a lower layer by adding post-hoc ameliorations in "your" code) is one of the major "soft skills" that distinguishes more senior engineers. This is one of those things that senior engineers see as "the natural thing to do", without thinking about it; and fixes that take this approach work subtly to ensure that the overall engineered system is robust to both changes up and down the stack, and to unanticipated future use-cases.

And contrariwise, fixes tending not to take this approach even when it'd be a very good idea, is one of the central ways that a codebase starts to "rot" when all the senior engineers quit or are let go/replaced with more-junior talent. When, for example, every input-parsing edge-case is "fixed" by adding one more naive validation regex in front of the "opaque, scary" parser — rather than updating the parser grammar itself to enforce those validation rules — your codebase is actively evolving into a Ball of Mud.

Of course, the tradeoff for solving problems at the "correct" layer, is that you/your company often ends up having to maintain long-lived, trivial, private hotfix-branch forks of various ecosystem software you use in your stack. More often than not, the upstreams of the software you use don't see your problem as a problem, and so don't want to take your fix. So you've just got to keep it to yourself.

(Funny enough, you could probably trivially measure an engineer's seniority through a tool that auths against their github profile and calculates the number of such long-lived trivial private hotfix branches they've ever created or maintained. Much simpler than a coding challenge!)

replies(1): >>42153519 #
1. polishdude20 ◴[] No.42153519[source]
That's I'd the company you're at will let you take the time to "do it right". Usually that's not the case. They want features yesterday. You try and fix something properly by going down to the correct layer? "You shouldn't be doing that."
replies(1): >>42158261 #
2. derefr ◴[] No.42158261[source]
Well, that's what this thread is fundamentally about / the point that the GGP poster was making.

Coding challenges should measure your ability to quickly and efficiently dive into a big unknown codebase to fix something — because that's the prerequisite skill that develops with engineering seniority, that makes the use of this approach practical.

When you're a fluent speaker of the language of "arbitrary huge foreign codebases", it's usually actually much faster to fix the problem on the "correct" layer. Outside-the-encapsulation-boundary "compensating" solutions have an inherent overhead to their design and implementation, that just solving the problem at the correct layer doesn't.

To reuse the same example from earlier: the parser library is already a parser, while your own business-layer code is not already a parser. (If it was, why would it need to be invoking a parsing library?)

The parsing library is the "correct place" to fix parsing edge-cases, not only because that keeps all the parsing logic in one place, but because, as a parser, it already has all the relevant "tools" available to rapidly express the concept that your bugfix represents.

Whereas, when you attempt to fix the same bug outside the parser, you don't have all those tools. You might have some analogous primitives available to you (like regexes); but usually just the stateless ones. You almost certainly are missing any kind of "where am I in the larger state machine of what's going on, and what is the intermediate analysis state derived from the other checks that have been done so far?" information that would be available to you in e.g. a transform-callback function in a .yacc file.

In other words, a wrong-layer fix is one that requires you to derive non-exposed internal information through heuristics from external side-channel signals. You're essentially doing Signals Intelligence to the library you're wrapping the behavior of — and SIGINT is expensive! And not something a pure SWEng is likely to be very good at!

Approaching things on the wrong layer, inevitably leads to one of three outcomes — either:

1. you end up not really fixing the bug (if you run an overly-weak pre-validation regex that can't hit every case);

2. or you introduce new bugs by making some valid inputs invalid (if you run an overly-strong pre-validation regex that hits cases it shouldn't);

3. or you Greenspun half the implementation of a parser (usually a much-less-efficient recursive-descent parser, which now gives you perf problems) so that you can "do SIGINT" — i.e. copy what the state-transitions the parser would be doing, to derive "just enough mirror state" necessary so that your validation check can be invoked only on the parser-states + lexemes it should actually apply for.

---

Here is, then, a flowchart of what will end up happening in practice, depending on the team dynamics in play:

1. In a "blind leading the blind" situation with only junior programmers, you might see options 1 or 2, where nobody realizes the bug isn't actually fixed, and the system is actually getting less robust with every change.

2. When a junior programmer is working for senior programmers, and the senior programmers aren't doing a very good job of guiding the junior, but are pointing out in code review that the junior hasn't truly solved the problem, then you almost always eventually get option 3 (after much iteration and wasted time.)

3. When a junior programmer is working for senior programmers, and the senior programmers do guide the junior, then what happens likely depends on time pressure and concurrent workload.

3.a. If there's enough capacity, then they'll likely nudge the junior into trying to fix the problem on the "correct" layer — even though the junior doesn't have this skill yet, and so will take longer to do this than they'd take even for option 3 above. The senior programmers want to give the junior the opportunity to learn this skill!

3.b. If there isn't enough capacity among the junior programmers, but one of the senior programmers has strong principles about code quality and at least a few off-hours to dedicate, then the senior programmer will likely steal the bug from the junior and fix the problem themselves, quickly, on the correct layer. (This might only happen after the junior has already flailed around for quite a while; the fact that this looks like "wasted time" to PMs is something senior programmers are very conscious of, and so will often actively defend the competence of the juniors they steal these bugs from — usually explaining that they couldn't have been expected to solve this problem, and it should have been assigned to someone more senior in the first place.)

3.c. If there isn't enough capacity — and that includes overworked senior programmers or senior programmers all pulling double-duty as PMs or such, leaving them no mindspace for implementation-level problems — then they'll probably just tell the junior to solve things through option 3 (because they know it'll be faster) and make a mental note of this as an intentional temporary introduction of technical debt to be repaid later (by moving the solution to the correct place) when they have more time.

4. And if a senior programmer gets directly assigned the problem... then they'll just go directly to fixing the problem at the correct layer.

(These are all from my personal experiences over my career as a junior engineer, senior engineer, and now CTO.)