Ask HN: Strategies for working with engineers that are too smart?
- They're brilliant, I mean very smart people (in an almost academic way?)
- They have a big appetite for adding complexity to systems
- They also have a big appetite for adding work to their own plates
- Their code has no consistent style
I work in embedded systems, so I'm generally writing C for resource-constrained systems. This sort of environment is rife with footguns, and I spend most of my time just trying to avoid those. A big part of that is keeping the things that my team controls as simple as possible, and while we are resource constrained, it's a balance. The tension comes when someone's more than happy to, for example, implement a complex caching scheme from scratch to save a few hundred bytes here, a handful of microwatts there. To me, adding that type of complexity for those sorts of performance improvements is missing the forest for the trees.
When an engineer like this proposes something that adds unnecessary complexity, it's usually hard to argue with. The proposed change typically does indeed make the system objectively better, and they're the one taking responsibility for doing the work and ensuring its correctness. But the overall system becomes a little more brittle, and a little harder to reason about, two things that are much more difficult to measure than memory and power.
Here's an example: an engineer on my current team recently proposed adding a significant feature to a module I wrote to make something dynamic that's currently statically defined at compile time. I pointed out that we could just change a couple entries in a static table to accomplish his goals, and we were able to avoid the extra work. What was notable, though, was his immediate willingness to write that feature. Maybe I'm lazy, but I'd sit there and think of half a dozen other ways to do it before settling on changing the module itself. But because he's smart enough to easily reason about a complicated solution, and he's willing to take on the extra work, he stopped there without weighing it against the larger system.
Have you worked with engineers like this? Do you have any thoughts on how to work with them in a productive and friendly way?
--
One more example if you feel like reading more:
In a past role, I got into a debate about code style with the smartest person I've ever worked with. It boiled down to me advocating for more whitespace in his code and him arguing that adding whitespace made the code harder to read. It took a bit, but eventually I came to understand that he is so good at reading code that he just wants it all laid out in front of him as densely as possible. He can effectively run it in his head, as long as he can see it.
That was baffling to me, I walked away thinking that I must be pretty bad at reading code. I use a very consistent style with long variable and function names, I keep my solutions as simple as I can, and I use whitespace generously to provide visual cues about the code's structure. All of this is to minimize the amount of brainpower I needed to understand my code, so I can put that energy toward thinking about the problem itself.
486 comments
[ 4.0 ms ] story [ 122 ms ] threadIn my experience, this happens quite often with people coming from academia because they're used to write throwaway code that doesn't get read by others and doesn't need to be maintained. It's only used temporarily to publish papers. However, most of the people I have worked with were aware of the fact that their code didn't follow software engineering best principles, they just didn't know how to do it better.
Another factor may be ownership. Sometimes people are excited to implement something because they like the idea of owning part of the stack, e.g. the caching implementation, instead of constantly implementing minor improvements in other people's code. Perhaps these people are looking for ownership of something more so than a specific complex solution?
I don't think you (and they) can be sure that the changes make the system objectively better. You may have a hard time measuring the downsides, but they're still here. And that may be the root of the problem. You can argue with an engineer about rate of bugs, power consumption, average time to deliver a feature. But it's hard to argue about "the system being more brittle".
One way out would be to try to have metrics on the downsides of the changes that they propose. Another would be to try to make them understand that even if something is very difficult to measure, it's their job as engineer to take it into account.
I will say this without any malice: the way you describe them, they don't appear to me as "too smart" but simply as focusing on the part of the job where the results are easily measurable.
Sometimes things need to be more complex than they first appear. Think all that pesky error checking that you totally don't need as long as everything is working perfectly for an extreme case.
If the engineers are experienced think strongly about letting the do the work as long as they are ones who will also take the pain of the complexity. Also having them explain why something is needed to the rest of the team is a good way to have everyone on board with a decision and it helps bring the rest of the team up to speed.
https://news.ycombinator.com/item?id=31840331
Edit: When I wrote this I just saw a comment with the text "* * *".
I think it may be a side effect of that delay feature or a change in the HN site that renders these comments in a way it shouldn't?
From your descriptions, it seems less about "adding complexity = good", and more about "solving things in a neat way = good" (for some definition of 'neat').
> Do you have any thoughts on how to work with them in a productive and friendly way?
I'm not sure you've articulated the problem very well?
It sounds like if they left & the code was handed to you, you'd be concerned about hard-to-spot bugs in the sophisticated code. -- But if the code & its correctness is your colleagues responsibility (& not yours), what's the problem?
> It boiled down to me advocating for more whitespace in his code and him arguing that adding whitespace made the code harder to read.
I think you came to the right conclusion about the differences. But, you might enjoy this blogpost from Steve Yegge:
http://steve-yegge.blogspot.com/2008/02/portrait-of-n00b.htm...
I’d also argue productivity is an issue: “neat” solutions may take much longer to develop, while the effort is not really justified. E.g. starting out with a system based on CQRS which is just a simple CRUD app.
tl;dr, young programmers, ignore that schmuck. Please keep writing nice long comments to your heart's delight. You will thank yourself one day.
I don't Yegge is trying to make this point.
Instead, he's making a similar observation to the discussion OP had about whitespace/code:
Yegge reckoned that someone who's very familiar with the program/domain will want to have very dense code, so then they can make as much use of screenspace as possible.
Whereas, for someone who's unfamiliar with a domain will benefit from seeing less code on the screen at once. It will be easier to digest.
I don't really see that as a value judgement where "comments = bad".
" I would rather puzzle through a small, dense, complex piece of code than a massive system with thousands of files containing mostly comments and whitespace" <-- This, a thousand times. _I_ simply don't have the capacity to load giant nonsense class hierarchies into my head and actually execute such a program.. A small machine that I can actually see on on the screen, that I can manage..
[edit] as I wrote that, I just realized that younger devs might actually look in horror on the idea of directly editing libraries like that for particular deployments because the tooling or shop mentality so forces automated upgrades that could overwrite custom changes... and institutional memory being so short, no one might remember the change some dev made to a bootstrap file. heh. But that's like someone calling themselves a mechanic without ever modifying an engine. You write a note, commit it with a custom marker like #weModifiedThis, and don't upgrade the library for 15 years or until you're dead or retired or the company goes out of business. Done.
I'm arguing for a balance.
The underlying problem is that you don't need that smart of an engineer and he's being underutilised.
You should move him to another team where he can do meaningful work without having to come up with complications of the existing codebase.
You can also put more on his plate in the form of people work / leadership; it's a different skill to master and if you constrain the time he has available to do work, he'll be forced to keep it simple.
I definitely had an "overcomplicating" phase (whether to play with something new or just because the job is boring). Right now I just constrain my time for tasks, by doing a lot of different things and I need to keep things as simple as possible.
I still write a few 2000 characters throwaway one-liners every once and then when I get something done quickly, though.
A long time ago I was like the engineer that is described by OP. Basically what drove me was the search for engineering /coding challenges.
Any codebase that is simple to understand and modify is a second party's canvas to add complexity in record time, for the purpose of telling a third party they added complexity in record time.
Imagine you get permits, rip out a bathroom, choose tiles and spend a long time cutting them. Someone comes in overnight and superglues them to the floor, and not even the pattern that was intended, but they did the main work and in only a few hours.
Same with lints, set up a company-wide lint configuration, apply it automatically, auto fix if possible.
People often have a need to be heard, to expose to the world what's going on inside their mind, to be appreciated for their ideas. You can serve that need in a friendly way by listening attentively and being genuinely curious. You can also suppress that need inside yourself and avoid responding with your own critique and argumentation.
You just listen, ask some questions, show that you are interested, thank them for their idea, and then decide for yourself if you want to act on it, and if you don't, then don't.
In most cases the topic will never come up again. If they nag, just be very positive, remind them that you really liked their idea, that you identify what's valuable about it, but don't make any commitment to acting on it.
I suspect you need some balance in the time it takes to debate these ideas, so it might be better to ask them to put their proposals on paper with a word limit and a time limit to debate the ideas; they are heard, and not only that but the ideas are debated. If you time limit not only the time available to debate ideas for each individual idea but also limit the time for debate overall it will require your reports to think selectively about what ideas are really good and which ones are worth the time to pursue.
You will have ideas about what these standards should be and you should feel free to propose some yourself during the process, but the aim is not to impose them on the group but to come up with something cooperatively upon which you get consensus. Then write down what you have agreed, stick it in a prominent place and make sure people stick to it. The process should only take about 10 minutes.
Then whenever one of your engineers comes to you with something that goes against the mutually agreed contract you can just flat out say - no, you agreed we wouldn't do that and move on. If something isn't covered by it then have a discussion.
I've dealt with the whitespace issue by 1) moving to clang format with Google style, and 2) getting people who want less whitespace etc to mentor more junior members of the team who can't read code that dense or quickly
Perhaps they are not too smart but instead "too generative". I.e there are people who generate a lot of code but then don't do any weeding in what they did. If they continue to be responsible for that corner of the code base then everything might be fine, but if other developers pop in and out of it as well, then it will get increasingly difficult to manage.
I'd say mark out the area they are allowed to do this and keep them within those limits :). They probably will enjoy this as well as they'll have something they have autonomy and responsibility over.
Obligatory mention https://xkcd.com/974/
I think one thing that's helped teams I've lead/helped lead in the past, and helps with a huge host of team working issues too, is by setting norms, and documenting them.
For example, in your team's "norms and values" or "way of working" doc, you could include simple things like coding style (in JS land most people just say "use AirBNB style" here).
But it can absolutely also have things like "don't add unnecessary complexity".
Reading your post, I think you can even quantify it too. You mention being able to count the number of bytes or microwatts any given approach will save or cost, that it's objectively measurable? This is great - you could decide (as a team, or let the team lead or whoever else decide) what the approximate limits should be. Complexity itself can also be measured (e.g. cyclomatic complexity). So you could actually be "real engineers" and decide what the trade offs are for your team, or for your target hardware.
All of that aside, it's also good to try and keep an open mind to other peoples' solutions and communicate with each other when deciding what the best approach is. Open, transparent and prompt communication is worth so much, so make sure your team keeps working on that too. (I've worked with some embedded teams that were distributed and almost never spoke to each other. It made things... interesting!)
Linux could be considered simple given the problem it's trying to solve and yaml complex.
For example they might think that in a mixed-paradigmatic language the "pure functional approach" is more simple even if it introduces more indirection and requires a deep understanding of various more advanced language constructs(*).
Or that the simplest explanation of monad is the one based on PL-theory instead of an explanation based on terms people without an scientific-PL background are more familiar with.
Or people which think that writing down things in predicate logic is just way simpler then writing them down in English (well, I guess thats somewhat me).
None of the "I find this is simpler" points I mentioned are bad, but not realizing/accepting that what is simpler for you isn't simpler for others is the problem.
Sometimes the simplest overall solution isn't so simple in isolation.
It's really hit or miss when it comes to having any impact.
It has a value in making businesses aware that production code has an operational cost just to keep it "alive". And it's useful for tempering junior developers who haven't yet absorbed principles like KISS and YAGNI.
But it fails to factor in the relation between code and an organisations ability to make (or save) money from that code. For example the capabilities of your code may be a competitive edge for your business. 10 lines of code which uses CPU and memory inefficiently may end up being more expensive than 1000 lines of code which uses CPU and memory _efficiently_ and leads to lower infrastructure costs as usage grows.
As far as I'm aware the term goes back to 2007 - https://web.archive.org/web/20070420113817/http://blog.objec... - a time where businesses hadn't really understood how to manage software based businesses, so it was a useful concept to help management become more mature about how they think about software.
But these days knowledge of how to run software based businesses is far more widespread - we don't need to simplify our thinking to "code is a liability".
There is a difference between code and a liability. If a business could wave a magic wand and instantly remove all liabilities from the balance sheet, it would do so without question. They would not, however, do that for code (or the business would collapse).
Part of your job as a commercial software engineer is to maximize the balance sheet of the projects you work on.
This focuses discussions about when it is worth it to spend time micro-optimizing certain aspects of the system. If there's a requirement that you must consume less than X μW while in standby - then it may make sense to accept the increased complexity.
Without requirements, people will always leave a trail of chaos in their wake as they do whatever is fun or good for their career and resume. The only advice I have for OP is to not be the sucker who acts as janitor for the messes they leave behind.
My response would be to ask them to support some other code for a while, turn the tables somewhat and argue against any whacky changes in the name of maintainability.
That's good, though sometimes the "academic way" can be a problem when the aim is to build a commercial product: the engineering vs research dichotomy.
> - They have a big appetite for adding complexity to systems
That's not good. One way to influence is to promote simplicity on the grounds of testing and maintenance.
If you mandate unit tests and a minimum level of code coverage, for instance, which is useful but which developers tend to hate doing, it may nudge people into thinking about simplicity.
There's also the good practice of not doing more than currently necessary.
At some point it's down the the person of authority to accept or reject change proposals and to promote/enforce good practices.
> - They also have a big appetite for adding work to their own plates
That's good as long as they can consistently deliver and they don't overwhelm themselves .
> - Their code has no consistent style
That's usually sorted by having a formally described (in a document) coding style and conducting code reviews. People will quickly closely follow the prescribed style in only just to avoid having their code rejected in code review on style grounds.