- 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.
This requires some luck, but there definitely are things you can do to help the process along. In particular, I recommend allowing some probably-unnecessary complexity -- I'd expect your engineers to innovate less and learn at a slower rate if you try too hard to stamp this out -- but be strategic in where you allow it. Software that is already load-bearing for your business should be subject to higher standards. Set an expectation that stable functionality becomes easier rather than harder to work with over time. When the backend has to become more complex to achieve performance goals, ask your engineers to do their best to encapsulate that complexity, and keep the higher-level interfaces simple.
My thoughts are that they need strong management to exert a lot of control and to come up with various ways of slowing them down and automated systems to gate check their code as much as possible (style guides, linting, static code analysis, tests and test coverage, auto-formatters, etc.). Otherwise, I think most people like this are just not worth having on a team because they aren’t interested in being part of a team and just want to solve problems they think are important. They will go off inventing all sorts of stuff, leaving a massive wake for the rest of the team. I also call them “wake makers”.
One of the things the blog post does really well is explain how a volatile can be valuable (even essential) in the lifecycle of a company. I personally tend to lean more toward volatile, so I can appreciate the tensions your colleagues are facing.
I have a few recommendations…
1. It’s very likely they don’t see the value of collaborative team work. You will all benefit from them coming to see the team as important. There’s no magic bullet here, but they’re still human and hopefully reasonable. Questions and conversation can help.
2. It’s possible they’re actually just insecure assholes. If so, work to remove them from the team ASAP. There’s no room for assholes.
3. If they are a volatile and they’re in a team which mostly benefits from stability, try to find a problem which is substantially challenging and useful to the team which you can hand them.
4. If there is no opportunity for that kind of challenging work, they might not be a good fit for the team long-term, and management owes them honesty about their fit.
Overall, I hope it works out for your team. Personality and work-style dynamics are tough but I have seen big changes on teams happen, and it’s possible for yours too!
[0] https://randsinrepose.com/archives/stables-and-volatiles/
Their solutions tend to be obvious in hindsight and simple.
They work within the constraints they're given. They don't merely find one solution and push it through. They get satisfaction finding which fits best. If there's conflict, it's probably because they don't know how else to solve something.
It's true that sometimes there's only one solution, but that's rare and implies you're hitting bedrock fundamental stuff or have an over-constrained codebase that needs some refactoring. In those cases it would be apparent in other places too, not just when dealing with their code or opinions.
You're a manager. Your job is to focus their priorities on business outcomes. If you're not providing focus they will run with whatever pet problems they have with the existing system. That's called doing their job.
I would not worry about style or complexity. Style is irrelevant and complexity is driven by the business case. Don't try to write software that will last 100 years. Its going to be put on maintenance mode and never touched again the second your highest performing engineers leave or are re-orged.
- Worse is better: https://en.wikipedia.org/wiki/Worse_is_better
- Intelligence is compression (at least in one perspective) https://youtu.be/izqSvm-YAww?t=376
- Many smart developers try to reduce code, not multiply it: https://github.com/geohot/tinygrad https://github.com/karpathy/nanoGPT
- Satisficing https://en.wikipedia.org/wiki/Satisficing
- Perfect is the enemy of good https://en.wikipedia.org/wiki/Perfect_is_the_enemy_of_good
A perfectionist engineer optimizes their code to represent reality perfectly and wastes a lot of time along the way. Their objective function is the discrepancy between the code and reality, and they try to minimize that.
You can offer alternative objective functions:
- Minimize time to implement a requested feature
- Maximize survivability of the company
A good engineer is one that finds the right trade-off between "the right thing" which might be deadly for the company and "the worse thing" which enables the company to develop features fast and remain competitive.
At least, these are the arguments I use on myself to prevent myself from overengineering.
Recalibrate your idea of "smart". They may be off-the-scale smart in some context, but are below average smart in other facets. If they weren't, they wouldn't be causing you a headache. It's just that we don't tend to use the word "smart" when talking about the ability to compromise, value effort, work together.
The fault is in your statement "weighing it against the larger system". You need to make it clear to him that it's your job to ensure ideas are weighed against the larger system, if he is unable/unwilling to do so. And that this isn't you calling seniority over him, it's about the skill and responsibility of weighing up priorities. Do that in a way that shows his idea is warranted and excellent inside his frame of context. Explain your objective reasoning and it should be apparent why your decision is correct - "what would you do in my position?". Some of these types want recognition.
Unfortunately, a significant proportion of such people can't cope with this. They'll lobby your peers and seniors to sponsor their idea and eventually one of those will back him. Or they'll just go ahead and do it anyway, if they can. It's why "ignore it" is not an option. This is toxic behaviour that has no part in your organization.
You can move the resource sideways to a new task. Then keep an eye to see if they impose their last bright idea on this task, too.
You can give the resource a task that's more challenging. Or a task that's more in the R&D space.
Sadly, there is prevelance in this type of resource wanting to make his daily job better or more interesting, or engineers in general, and sometime CV embellishment with a new experience. Not enrich the life of the user or the worth of the company.
Tell them there's no free lunch. If they're making efficiency gains they're borrowing from the future in the form of technical debt, they're increasing complexity and therefore increasing difficulty in maintaining and using the code in the future. Remind them that when they take that aspect into account they're not being efficient, and ask them if there is a more efficient way to accomplish the same thing without increasing complexity.
Tell them to take a moment, become disattached from their proposed solution, and try to reason on ways that it might make things harder for other people in the future. That's a key point, because it might feel easy as pie to them. And if they can come up with a way to do what they want without a continued maintenance commitment and another thing to store in their heads forever then you will reconsider it.
Your goal here is to make them better engineers by teaching them to think about the implications of added complexity. Right now their solutions seem so simple to them. They've got talent and potential, but they're not great engineers yet.
Convincing them to switch values may take a long time (or never), but in my experience you need to repeatedly stress the values you want the system built on, and give concrete examples of why whenever possible. Give practical reasons why simplicity is better (system stability, debugging, maintenance, etc).
But recognize that for some “smart” people this will be “boring”, and they will never do well. It reminds me of a manager I had ages ago who preferred C++ to Java because his C++ solutions required huge amounts of brain power for anyone to understand, where as the Java solutions could be understood even by dullards like me.
The most effective way to handle this type of person is usually to make it clear you respect their intelligence/are impressed by them, and then to ask them if they can try to apply that same intelligence to a different problem: as near universal legibility as possible.
Trying to minimize context required for understanding code and think about how to put that map in their head in the code explicitly and to get as close as they can to universal language is a really really fascinating and difficult problem to try to solve, and even more impressive to see done.
If they listen to that and get it that type of engineer can transform and start to write fantastic, very legible code.
It think it depends on the type of intelligence they have, as well. In my experience there’s also a large percentage of people like you’re describing that are much better mathematically and visually/spatially than verbally. Sometimes this type of programmer is just better suited to writing the parts of a system that need to be very complicated. Some code is not really possible to write legibly without a bunch of prerequisite internal knowledge, like the deep guts of a game engine, some very complicated computer vision algorithm, etc. Having them stick to that stuff and make overview documents/general comments about whats going on can also be a good way to utilize their skill without as many downsides and illegibility problems.
I got the impression that one of the developers on the team was particularly smart because he would lock himself away for a few hours at a time and build something amazingly complex that nobody else really understood.
Ultimately, he only worked well when the application was still in development. When it came to shipping it, a lot of the areas of the application that he had worked on had shortcomings or just didn't work. Fixing them was also difficult because of the complexity, which was always made worse by the frustrating thought of "why the heck didn't he just implement this the simple way?".
The work got hard, and the team crunched to fix the problems. He just resigned and left and found another "greenfield" project to work on somewhere else.
In a way, him leaving ultimately helped the remaining developers - we didn't have to keep his unintelligible, not fit for purpose code.
Now, all of these years later and I'm the lead developer elsewhere. I now often have to politely brush off efforts to introduce needless complexity that developers propose infecting our codebase with.
Writing code is fun, and building a caching system might be fun, but in a working environment you need to deliver what the customer wants and is happy to pay for. If the work being done isn't on that path, it shouldn't be done.
I guess I'm sharing this to say, perhaps those brilliant developers aren't that brilliant.
1) With respect to not having whitespace: "Not everyone is as smart as you, and you need to ask yourself, do you want junior engineers working on your code to keep bothering you asking how things work, or would you rather your code by easy to read (and commented) so that they can pick things up on their own?"
2) With respect to complexity: "We are expected to build products that align with business objectives. New and experimental code belongs in your home lab and on your GitHub, not in a production environment."
Depending on how things go with #2, maybe offer to let the engineers spend 20% of their time working on lab projects to improve their product, with the understanding being that the rest of the time they are expected to build products with a minimum of complexity.
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.
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...
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.
This is a program that you run which will deterministically re-format your whole codebase. The CI checks on a PR should not pass until the PR diff matches what the formatting program says is the correct formatting.
In 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?
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.
After a few years maintaining systems, I do not use the word "simple" for anything software or computer related anymore. I'm glad if something works as advertised - and I'm delighted if I see people putting in effort to make someone else's life easier.
People, who appear smart may well indeed be just a little frustrated. Not the person who makes things more complicated or ask complex questions is smart - that difference seems to escape some of the even smartest people.
As for working with these people, I don't know. You have to endure them, make them aware of the tradeoffs that are made, in the best case show them something simpler, that accomplishes the goal.
There is a hierarchy of code quality by difficulty, and it takes increasing smarts to ascend the ladder here:
1. Simple but bad code. - the developer doesn't understand the problem and just writes simple straightforward and wrong code
2. Complex bad code - the developer understands the problem and tries to solve it, but is just making everything worse.
3. Complex good code[0] - the developer solves the problem convincingly, but in a complicated way that perhaps only they understand.
4. Simple good code - the developer realizes a simpler way they could solve the same problem and writes it in a way that allows others on the team to understand and maintain it.
Your developers are currently at a 3, and you need to push them to ascend to 4. If you get your smart devs using their brains to remove complexity from your system with stunningly clever simplifications, everyone will be better off. And it can't be faked, it's truly difficult to solve hard problems with simple code.
[0] "I object! Complex good code is an oxymoron!" Listen, for the sake of this comment, "good code" means all other measures of quality other than complexity. Efficiency, solving all problem constraints, well commented, etc.
This is actually in part a management issue, and process issue.
Whoever is managing the team's work shouldn't allow developers to go rogue and start doing whatever they want. Everything is a card. Everything is prioritised. If the work isn't going through a sanity check and being thought about in the context of everything else then the developer has gone rogue.
Once you have everything being carded up properly (requirements, acceptance criteria etc) then quality control happens during card show-casing / pull-request review. If someone has gone beyond the requirements, don't let it fly during pull-request review. Separate pull-requests for separate cards - no combining them all into one, no working on multiple cards at a time.
Stick to the process and be an anal card and process nazi about it. Don't let things slip.
> - Their code has no consistent style
This is a team standards issue. You need to get together as a team and together agree on a consistent style. People's code who breaks the standard shouldn't make it past pull-request review. You can also introduce linting tools to help enforce the standard.
Assuming you have them, get the team lead and PM in a room together to discuss how to put all of this together. You might find that one of the bigger issues here aren't the team members themselves but whoever is leading the team.
Me: Hey, I got a question I was hoping you could answer. What do you think is harder, writing code or reading code?
Them: That depends who are we talking about?
Me: Idk, I mean it sort of generally. Let’s start with which you think is easier/ harder for other people.
Them: Probably reading code.
Me: like how much harder?
Them: Maybe 2-3x harder ———————-
Then, next time you have a one on one, or you do like a team meeting bring up this point and say that if reading code is 2-3x harder than writing code, then we should strive for our code style to be within an understandability budget. If we write code at our max intelligence, let’s say one of your team mates has a super 10/10 intelligence, then it requires a 15/10 to understand it and it’s therefore out of budget.
I’m an engineer and I’ve used different versions of this argument to great success in convincing people as to the merits of why it’s good to write code that’s intentionally “dumber”.
Roadblocks that I’ve had in the past have come down to communication issues, where in one situation in particular a fellow engineer didn’t want to give answers to the question or be pinned down to even rough easier/harder for reading/writing code. In general, engineers like this don’t understand how they’re perceived by others and they can’t understand how their work affects others, and what can you do? I’m not sure, nothing works 100% when it comes to people.
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 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!)
> 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
> 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.
Complexity is your enemy. Complexity is something you need to have a strong motivation for, and if the system becomes more difficult to maintain moving forward it is not, in fact, objectively better. In the long run, you're going to spend more time maintaining code.
In many cases these engineers are good at optimizing for something, and they enjoy doing that. Optimizing for something like memory or power is, as you said, easy to measure and easy to "gamify" by improving metrics. What you need to do is encourage these engineers to find other metrics to focus on, even if they're a little softer. For all their faults, getting engineers to consider things like total LoC, complexity metrics, etc as something to work toward improving may get them to redirect their focus in more productive areas. It's not that their existing focus areas are bad, they're just an incomplete view of the overall priorities.
A few things I think - one is stress that they might be clever enough to understand and manage that kind of complexity, but you personally aren't, and would prefer styles, solutions and techniques that are comprehend able by mere mortals such as yourself. This is hard if not impossible to argue with. After all, you need to be able to understand it, because if they leave or are unavailable the maintenance burden will be on you / the rest of the team.
But the flip side is these people are usually very good problem solvers and prolific, so the more you can harness that, the happier everyone will be.
Some of my regrets include stalling a PR for being overly complex, resulting in it not getting merged and deployed for months, when the code would have saved 10k/month in server costs. When I tried to re-write it myself to be simpler I failed, so it was arguably necessary complexity. With that said the team that took the code after us, removed the feature entirely as it was a complicated mess - that was probably the sensible but outside the box solution.
Another one was early in my career working with a senior who liked short/scope relative names. I thought it was bad naming at the time, but now I realise that if you do it properly, the shortness itself can be semantic.
The biggie for me is tests, many people dislike writing them, and occasionally the smarter guys can get away without them, more so than the average. But long term, this creates a nightmare because the team will lose confidence when making changes. Convincing people to write more tests is difficult and I haven't worked out a great way to emphasise why it's necessary.
I'm all for keeping things DRY - but sometimes it can go too far. Too many abstractions leads to abstraction-hell.
On my current team, everyone likes to keep things a bit simple, which is a nice change in pace. I don't have to go through a chain of 7-8 files to build a basic CRUD feature. I don't have to wonder what some weirdly written but compact code does. I don't have to think as hard and can focus on what matters
- focus on very specific examples. "We did this (here's the code from the git repo N years ago) and that's how it went wrong".
- if examples don't present themselves, sometimes it's worth letting people do "over complexity mistakes" and let themselves get burned, if you can afford it.
- in such cases lay out simple criteria for success and failure, like "it's going to take too long" or "it's going to be too complex to modify". Write them down, in private, then pull out when it blows up (not necessarily to be an A-hole, just being able to quote the discussion gives you much more credibility in a post mortem).
- Sometimes a bit of "it's too clever for me" works, depending on how humble you're feeling...
But ultimately KISS works because it works, which is hard to see without reference to practical code.
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.
If you are REALLY serious about fixing this, I recommend a book called "Non Violent Communication" https://www.amazon.ca/Nonviolent-Communication-Language-Life... Satya Nadella claims it was one of the reasons he was able to turn around Microsoft.
The way you express your needs may resonate better if you adopt
The software industry often values this–myopically, since their opaque code and misunderstanding of DRY are sure to cause bugs. Some junior engineer five years later will misunderstand how coupled some 300-line function is with unrelated components and introduce a bug while implementing a feature. It happens all the time.
I've seen managers who encourage this and I've seen managers who see the big picture and value simplicity and maintainability. Beyond being in the right environment, it's hard to mitigate the problem. These programmers don't think they need to learn anything from you and are unlikely to ask, and unsolicited advice is not likely to be well received. I've sometimes found that leading by example can help, if they notice that the code you contribute is more pleasant to work with. Perhaps pushing for more pair programming on your team so that members can learn from each other.
Ultimately these people are more interested in solving puzzles than producing software that will stand several years from now. If you can present that challenge as a puzzle they may start to find satisfaction in it, but if not then this will weigh on more than just you and is bad for your product and company.
I would focus on the end impact instead of the implementation. If someone wants to save a few bytes of memory, why? You state it doesn’t seem worth it to you. Is it a value your team actually measures? If not, try starting there. Having conversations about what’s worth optimizing and why will leave everyone feeling heard.
I believe most people want to do a good job and want to have an impact. If they see that there’s little gain in minor optimizations then maybe they might stop code golfing.
Another (likely) theory is that they just don’t see the complexity in their code. To them it’s not complicated. If that’s the case what heuristic could we use? It’s my experience that tested code is easier to modify, so maybe let them write complicated things, but also make it a requirement to do the leg work to make it more maintainable.
Last option that comes to mind: pair with them with the explicit goal of making the code easier to reason about. They’re stuffing the curse of knowledge, you’ve got beginners eyes. Together you might choose to rewrite parts, add tests or lints or docs.
Go into the process expecting change from them, but also from yourself. Oh and also if you’re struggling to bring this up without yelling at people I recommend using the non violent communication (NVC) framework it will help you to be heard. Good luck.
What happens when they leave it for a few months and come back and forget how everything works?
When a client encounters an issue in the field and they have to debug it with "It doesn't work, yo." as a problem description?
When a coworker tries to modify it and breaks everything because they can't figure out how it works and there are no decent tests?
Eventually, they'll come around :) Or maybe there is no saving some people and they should stick to R&D...
Impressive people but not necessarily brilliant people can execute on either many worthwhile relatively simple and perhaps demanding tasks OR something like a really long-running, really complex, and totally worthless idea that provides nobody any tangible value.
I have a friend who's an electrician for example. It's not an incredibly intellectually out-of-reach discipline, but somewhat so. He seems to regularly take on manly projects like redoing his kitchen or his motorbike, and finishing them. Again, he's not building camera sensors from scratch or developing a new machine learning framework in his spare time, but he gets it done. I suck at that. He's smart. But he's probably not a genius.
Meanwhile, a former colleague and I would regularly chat about type theory and datalog and Coq. It was quite a challenge to understand what he was talking about without a lot of background knowledge on that subject, and the value it could possibly create beyond curiosity. He was quite intelligent, made a series of weird academic choices that favoured deep information theory subjects, but looked like you'd expect and had almost non-existent social skills. Maybe smart, mostly intelligent.
But that's not the case. They're taking responsibility for _initially_ doing the work and ensuring the correctness _for the cases they've thought of_. Past that, they're adding mental load to every developer on the team. And to the person that needs to maintain it.
If it's a caching system, what happens when some other person is working on something that doesn't play nice with caching? What if they don't realize there's caching and they waste a lot of time trying to figure out why their code isn't working? What if they need to bypass caching to get the correct results; so they need to understand the caching system enough to do this? Does it even support it? Is their code now coupled to the caching system?
What happens when things about the system need to change? Who is in charge of that change?
Adding complexity to a system doesn't just impact "the person that wrote that complexity at the time it was written". It's an ongoing cost, forever, until it's removed. It needs to be worth that cost, or it shouldn't be done at all.
"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..." - This example puts both you and the engineer and the company in a bad spot as it's a complete waste of time to discuss something like this (if it's discussions over discussions). The tech lead should should decide once and then everyone should comply with whatever way they decided (potentially after one short discussion).
If smart engineers consistently propose un-necessary complexity then Im sorry to bring it, they are not smart engineers and you have nothing to do but run. It wont help to discuss it and try to convey your message (unless you are the CEO but even that wont help as you can't monitor everyone so honestly if you are not the CEO just run and if you are the CEO just replace the team).
So really hard to tell without being in the place who's the smart engineer but if you are the smart engineer then run :) if they are the smart engineers then stay and learn.
”Any fool can write code that a computer can understand. Good programmers write code that humans can understand.” – Martin Fowler
Anyway, I think there has to be a decision/ranking on the importance of having
1. happy programmers & excellent code 2. code that any(?) developer could jump in and maintain
To me it often boils down to not making simple shortcuts due to laziness unless it buys time to market or has some other significant upsides.
Making a system flexible can often be done in a non-complex way so I would challenge then need to make software complex. There is often a trade-off between efficiency and maintainability. If the efficiency route is always preferred there could come a day when the developers quit and others have to maintain what they feel is a mess of code and want to rewrite it. So my vote would be to keep the complexity low (and flexibility high!) unless there's a concrete benefit of allowing the complexity to grow.
You could look into various design patterns to keep code flexible while keeping complexity low.
- Document everything, and have a system for keeping documentation up-to-date (stale documentation is often worse than no documentation at all). Often it's possible to include a README.md in the same folder as the code it is talking about. You can link to it from a parent directory to keep things discoverable.
- Have a test suite for anything you need to be able to reason about. Also, design your test suite so that it defines your application's behavior with positive assertions (i.e. when - Focus on solving a "class" of problem and document over-arching solutions. E.g. littering your codebase with a bunch of one-off optimizations may improve your application's performance, but the goal should be to have a consistent way of building the application so that these improvements are essentially a free by-product. For instance, in a data-heavy environment you may want to write some abstractions around bulk insertion and paging that can be applied universally. This way of problem-solving leads to good consistency and less cognitive load, because rather than a giant block that I look at and think, "What is this thing? oh, that's a paging implementation, gross!" I can instead recognize almost immediately what this thing is ("Oh, this is paged using PagedQuery, cool!") and also have other examples of its use around the codebase I can pull from to do whatever it is I'm actually trying to get done.
- It could be that you misunderstood the argument. Maybe the engineer wanted to avoid the old 'static global global' structures, which are still omnipresent in embedded C code, and which is followed by especially bad engineers. It's not about memory at runtime here; it's more about encapsulation, state and testability
- If that is the case then let the engineer do it. Code quality can be measured by how easy it is to remove a feature
- I've went into numerous turf wars about code style. I lost all of them, even if I won some battles. At one company, they were paying one full time engineer to manually reformat the team's code.
Don't play this game. Slap on astyle or clang-format. Enforce it. End all discussions with "Then you change the style guide and check with other projects". You win in either case.
- Don't ever argue with people who organise their code in neat tables with tabs and spaces
- Don't you have a product to ship? Make that clear to everybody, break it top down, and let the engineers fix that stuff.
- Remember, they are doing the work, you are just organising. Why should the code be easy for you to read?
- Maybe that complexity just exists for you, not for them. An isolated system may be as complex as it wants to be
- I'm not always right. And other people as well. We need room for mistakes. That lets people grow. I did a lot of mistakes, and I will do more.
So even if I know for a 100% that my colleague has chosen a bad path with bad complexity and a lot of work further down the road, I still let him walk that path. He needs freedom. All I can do is support him and protect the rest against the fallout. Other people offer me that freedom as well.
I worked with a guy like this on the last contract I worked, ended up resenting him, really poor social skills and would just obsessively code all day. Another older guy would get lost on a refactoring project for months and then the manager asked me to review it, he's spent so long just refactoring and moving stuff around but it added no functional benefit, that's a lot of time and money to the business lost.
You can set engineering guidelines, PEP8, or enforce code rules via CI pipelines, at least then if they become pedantic you can just refer to the rules.
Ultimately I think it's a combination of introversion, obsessiveness, lack of experience in coding for others, being pedantic and social skills.
There's a lot of fine points made here already by other commenters. I will say that long-term maintenance of software is a non-trivial concern. If you can identify that a change is good in terms of, say, power consumption but bad, say, in terms of making the system more brittle you now have an optimization decision. Do you _need_ better power consumption enough to sacrifice developer time long-term, potentially introducing bugs in the future?
- 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"
These statements contradict each other, or at the very least these people are not good engineers, even if they're smart in the sense of being able to deal with complex ideas. Good engineers do not code with an inconsistent style, nor do they add unnecessary complexity when it was avoidable, just to satisfy intellectual curiosity.
The real smarts are to be found in simple, clean, clear code with obvious lines of control. Great code can look almost 'dumb' to the 'fresh off a CS course' grad. This is the difference between cleverness and the wisdom and the good taste to know the right balance to strike in code.
To me the whitespace/code style issue is separate. Personally I think there are more benefits to letting people make these choices according to their own preferences rather than trying to come up with some consensus and then enforce it.
Usual acronyms of Asbergers, ADHD, ADD, PDA etc. "difficult engineers" is not something that exits in this world. There are difficult people, sometimes highly ordered jobs (like programming) attract people who like order -> many of which are on "the spectrum".
Be human, Be Kind and understand how to communicate effectively with several types of people.
As Henry David Thoreau (?) wrote, if I had more time I'd write a shorter letter.
Smart in the workplace is not just about technical brilliance and complexity.
It is at least as much about:
1. Being able to work well with others 2. Being able to take into account all constraints (which includes simplicity)
My recommendation would be to help these engineers get some coaching.
Let me suggest more provocatively that what we often are witnessing is power dynamics. And these people being smart know how to let this play out using code. This is probably less applicable to OPs case than let’s say a large engineering organization in a large corp.
My pragmatic suggestion in such cases is to push back where it would affect your work or growth directly and let go of the rest. Smart people are scary good at lawyering their way out of situations or tying you down in endless litigation.
There’s no “solution” to this. Power dynamics are a part of life and code isn’t immune.
Next to the other main suggestions, perhaps these people need some sort of outlet where they can scratch this itch.
> ... overly complex ...
To you, it might be overly complex. Who is to say that your assessment of "overly" is accurate? You provide a specific example that seems to prove your point, at least in on particular case.
Be careful of this, as you may be the problem here.
> Their code has no consistent style
Uh, there are tools to resolve this, so, quit the complaint. Use a lint/style app, tie it to commits, or better to the IDE, and insure everyone uses the same formatter. Get consensus from the team, don't just leave it to each individual. Who is in charger here anyway?? This is a solved problem..
> They have a big appetite for adding complexity to systems
Another "subjective" assessment. Each item should be judged by it's own merits, and your "assessment that it is complex is not the final answer.
Setup a code review system, and for any 'large scale' changes, have a code review with co-workers, peers, anyone relevant. You can even discuss a proposed code change before starting the work, or, part-way through an implementation. Challenge the team to look at the proposed change and, perhaps find alternatives (if they exist), and, in that way, get some team consensus before spending the time to build a "complex" feature.
Don't judge a feature by it's complexity "per se". Some things are complex, and for one person, a "level of complexity of say "8" on a universal scale (that does not really exist), might be a 10 for them, and a 6 for someone else.. complexity is not the same to everyone, so, don't take the "least clever" person in the room as the 'standard' for what is too-complex, that will limit your system. For "complex" systems, require a bit of extra documentation. A complex system, well described and documented, can become simpler for that "less clever" person.
A bit of management here can resolve all of the issues you describe. Don't get all judgmental, use the team, and apply some leadership.
Good luck
I see architects as the people to go to under such circumstances. They were not always interested in small things like whitespace, but I think they should take it seriously if it's brought up.
Wise engineers don't add complexity or try to be too clever. Simple and small is elegant. Secure engineers don't have anything to prove and create maintainable code. OTOH, paycheck-driven engineers are incurious to try new things or promote software craftsmanship.
Lack of consistency can be enforced by code style linters. Let the linters be the Bad Guy(tm). Get agreement and buy-in on these beforehand.
Separate the people from the problems: give immediate, actionable, constructive feedback privately. Use frame taking to show how their actions come across and the concerns you have... for example, who supports this code when there's an P0?
Mentors are also needed. If possible, hire or advance an "old timer" in the space who can teach some new dogs new tricks.
Whitespace... I come from Ruby land where visual alignment, proper spacing, and terseness are valued. Too many comments and too much whitespace are a distraction, just like condensing too much. In general, very small functions, good semantic naming, DRY, and few levels of indentation make code more pleasurable to read than giant god functions with duplication or excessive line length. Code that runs together without functional visual separation doesn't make it clear what's prologue assertions and setup, main work, and epilogue return.
Now the real question is do you believe you are right? Do you really(and I mean really deep down) think these people are smart. Do you think you have a better way? Do you wish they'd realize that what you are doing is best path forward?
I have seen this sort of conversation pattern in the past. In my case it was a younger programmer that wanted the team to take a different approach, but at the same time were struggling with the "what if I'm wrong?" dilemma. They didn't want to throw their weight behind a proposed change in direction because of insecurities and fear of rejection. What it came across as to the rest of the team was a person that didn't want to lead but at the same time was always finding fault. When confronted they would say things like "I'm not one of the smart ones ..."
If you really are not smart as they are then trust them and learn from them. If you think you have a better path and are committed then stand up and say "This is wrong and here is a better way". If you are right and they reject you then maybe its not the place. If they are able to demonstrate that you are wrong you should accept it and move on. If you are right and they agree then you are in the promised land.
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.
In some ways, I also benefit from this. If I am working on the same code every day, I typically have it all loaded in my head anyway. If I am coming to a codebase for the first time, or coming back to it after working on something else for a long time, it is very helpful to have as much of the code as possible fit in one screen.
That said, there are tradeoffs for sure. Whitespace is not much help for me, but clearly named variables (e.g. `area` instead of `a`) are essential. Then again, there are some short variables that are very common and clear to me in specific patterns, for example in `for i, length in enumerate(boards)` I have no problem realizing immediately that `i` is short for `index` where ever I see it in the for loop body.
Three specific pieces of advice here:
1. Use an autoformatter when you need to read code to convert it to your preferred style. Don't enforce that on the team without consensus though.
2. Everyone who can afford it should buy larger monitors. 4k 32" will fit a lot of lines of code, even if it's not quite as dense.
3. Don't stress about style consistency too hard, but do attempt to match the existing style in any given project.
You should consider whether or not the solution is actually more complex, as in the simplest implementation is larger. Or if it's just particular in a way that you find confusing. If these engineers are significantly smarter than you, which you allude to, but I'm not presuming, then there is a chance that what they are doing isn't more complex, just confusing to you.
You can try to get at this by asking them about estimated LOC for each implementation, time estimates for each implementation, or number of concepts in each implementation. A good design process usually enumerates a few more complicated solutions, then pares back to a solution optimized for the time and resource constraints. They may not understand that, and so you should explain that complexity vs functionality is an important tradeoff. They excel at producing highly functional designs, but are bad at correctly ranking those designs when complexity is a factor.
Separately, code style discussions are usually just manifestations of OCD. That comes with the territory for certain types of engineer. Those discussions are rarely important, and that energy should be directed towards finding real flaws in the code's structure or the system's design.
Now, it worked fine, easy to work with, though not straight line c code, high quality unit tests in automation, sounds good. But really, if I was solving that problem for my own project I would have used like one interrupt, taken half the time, been much more straight forward to modify, and I can’t imagine it would have worked any worse. But I was giving management the option of good or perfect, without saying hey, when I leave, which I did, other developers are going to need to carefully read my docs and spend some time to get up to speed on the “perfect” option, and I have no reason to think the results of the good option will be measurably worse…
It sounds like these guys are really good technically, but they lack software engineering skills (using the above definition). Defining the problem in terms of brains or selfishness or empathy makes it sound like personal qualities when it's probably just the skills. If you frame the discussion around Russ Cox's definition of software engineering, you can a) get them to see the soft skills defined concretely, b) get them to see serious people (russ is a serious engineer) take it seriously and define it in a helpful way and c) talk about under the umbrella of "software engineering" and doing "good software engineering" (again, using Russ's definition of it) rather than personal qualities or technical skills.
It isn't clear the hierarchy or size of your team or the longterm strategy/goals of the product development. Someone on the team should be pushing back on these changes as they are being planned out or before they are getting merged in.
Ideally, you have a respected senior/staff/cto engineer that can mentor these "clever" programmers. This person needs to be able to grok all the code and see at a macro level how the whole codebase is evolving.
Re: reading code - I am the same way. I spent years writing objective-c when xcode had the best code completion out there so long names weren't an issue. Long function and variable names and tons of whitespace - it is how all of Apple's libraries were written and how the projects templates were setup ¯\_(ツ)_/¯.
Best recommendation is to adopt a strict style for your codebase and ruthlessly apply it to all new code. Linting should happen automatically. There are tools that will run the linter on just the edited files so you can adopt coding styles 1 file at a time.
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.
Add a mentorship role to their responsibilities where they oversee the operational maintenance of the code they write, with one iron rule: to promote the mentees' advancement, the clever coder is not ever able to further git commit to code they wrote until the mentee commits N number of changes to a chunk of code/documentation/tests they're trying to understand. The more operational the setting, even up to and including live production support at a call center, the better.
Clever code stops delivering benefits when the overall group/organization cannot support it in live operations under contracted SLA's. Clever, immature coders invariably go through a phase where they learn there is a giant step function change between coding for themselves or a tight knit peer group of clever coders and coding for an audience. Clever, mature coders expand their tooling way beyond coding to deliver for an audience. There are ways to effectively, operationally support clever code, but those solutions aren't just implemented in code.
It didn't use to be this way when our industry was orders of magnitude smaller, but the economics of the software industry nowadays has changed the dynamic. Our industrialization phase currently favors and rewards solutions at scale maintained by organizations larger than most tight-knit clever coder teams can sustain. Such clever teams are still critical for startups or insulated projects within larger organizations, but the price tag of monetization is this type of maturation.
And business requires things to be sustainable. Profit and costs are ever present things we must all be thinking of. There is definitely a tradeoff between business and user experience many times. And the business requires code be maintainable by average developers.
One argument I found effective for the kinds of people that you are talking about is to get past the “academic” correctness of the argument and move it towards the business side. They are technically correct, after all. But they may not correct be from a business perspective.
It is important to frame it in a way that spares their egos. Most (but not all) very smart people know they are smart and it is a large part of their identity. If you challenge that in any way, they will push back aggressively.
How I have learned to frame it is that, from a business perspective, we must make the software both performative AND maintainable. And by maintainable I mean, maintainable by the average human, which they clearly are not. They are smarter than most, but for the business to live beyond them, they need to write the software in a way that an “average” person can maintain it. It can become a new challenge. How to squeak out the best performance while also writing it in a way that someone dumber than them can understand and maintain it. Another way to put it is, there are quite a few brilliant people that can write brilliant code, but only the best of the best can write brilliant code that is also understandable by normal people.
Good luck!
Likely the best people to determine the time allocation for small optimizations would be people who understand the context; but then again, ALL INPUT is food for writing better code, as long as you're not obligated to follow every idea they toss out off the arm. Sometimes you are too focused on accomplishing a task, and you miss easy things you could do.
Also, keep in mind that what may seem brittle from your perspective may work if their goal is to develop a more domain specific, specialized system, and they don't care so much about interoperability.
And that..
> 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.
Yeah, one aatribute of good engineers is that they are lazy in the right way ;)
Their code has no consistent style? Sounds like you need a coding standard. Everybody should be using the same style, and should be using it consistently. Use tools to enforce your coding standard if you can (auto-formatters and code analysis to enforce naming standards and check spelling(one of my favorite analysis features!)).
Paragraph spacing in code? Your coding standard needs to specify that code is written for the person that follows (i.e. readability and maintainability is a primary goal). Pretty much a boilerplate clause in a coding standard. With that in hand, you have ammunition to back up an discussion about whether paragraph spacing in code improves readability. (I'm inclined to think that it very much does).
As for the rest... I worry that you may be micro-managing. The discussion about dynamic or static initialization is a totally normal and expected sort of conversation to have (without regard to whether you were right or wrong). A discussion happened. You pointed out an easier way to do it. Great. But it doesn't seem productive to me to agonize for hours over a coding decision that probably took under a minute to implement. (If you were able to initialize statically, surely it couldn't have been difficult to write equivalent dynamic initialization, and to reason about it's correctness).
A decision to cache an initialized data structure. Not really that difficult to implement; and not really that difficult to reason about. I think you just need to trust your team members to make reasoned decisions about that sort of implementation detail.
I used to have an appetite for adding needless complexity, and what really helped me was finding better work/life balance. For example, personal projects in the evenings/weekends are a much better output to make something super complicated and brittle and just see how it falls apart or becomes impossible to make directional changes in. Also exploring other hobbies helped satisfy curiosity in a way that I would try to in my work code. Photography is a good one with a good amount of book knowledge, ability to get deeper into the subject matter, explore historical approaches (film and antique bodies) and a lot of space for creativity.
Adopting prettier really helped me with code consistency too. I used to spend time making code nest nicely or having a hard time reading others code when it didn't adhere to a familiar syntax. Prettier just undoes all my formatting on save/commit and unifies all our repos to a common syntax so in my head I just lost perfectionist impulses to put spaces or newlines in perfectly working code files.
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.
That's about it. Unfortunately, they can't just play their toys and get payed for that. Or can they? Well, at least not where they're currently employed.
Also how old are they? For how long they think they'll be able to retain such mental abilities and motivation?
What about other aspects of their lives? Friends? Children? Sports? Travel?
You may say these are none of your business, but I think you see what I mean. It's a matter of 'personal growth' and you as their lead can't force it. Wisdom is sometimes really painful to acquire. In this case they fall into a cognitive bias by not being aware of what others are able or unable to do. And even just recognizing that on a daily basis already has great hack value. But on the other hand that would be an achievement someone would only recognize after the fact and therefore it won't look attractive at all before the fact.
And also what does the manager you report to says about all that?
Cause: This is a symptom of micromanagement. Smart people will always come up with ways to improve anything you give them.
Solution: Lay out the entire problem and let them work on whatever part they think is the most important to the solution. Avoid confusion between solution design and problem specification.
The goal of writing code is so other people can maintain it because you won't be there forever and you can't do it yourself.
I've seen this in C++ engineers in particular. There's a certain kind of person who comes to believe that complexity is a virtue. In a way they're bored and they alleviate that boredom by finding the dark corners of the standard and insist on using those features. It's also a way of demonstrating how smart and knowledgeable they are.
It's also a defensive measure as it makes it really hard to replace such people.
If such people are already running the aslyum (so to speak), you're probably going to have a bad time because (IME) they're just not receptive to the people argument or they dismiss it with a quip about anyone should be able to recite the C++ standard by heart.
The best yo ucan do is constantly ask questions like "do we need this?" and "is this the quickest way to do this?"
I've seen this a lot in people with huge working memories. Pointing out that I (and most others) simply can not pile in all of that information at once typically leads to a solution.
> minimize the amount of brainpower I needed to understand my code
> weighing it against the larger system.
If you haven't try converting these items into something more measurable, and put these problems in front of the smart engineer and let these be their problem?
Sort of delegating these stuffs as their problem too instead of taking it all your own.
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.
As other said, maybe these guys aren't as smart as you think they are and they may be difficult to work with. It's hard to say with a couple of anecdotes. Also, they could be good at some things, and yet take bad decisions for other things.
If I were you, I'd try to make my point in a non-conflictual way with rationale arguments and listen to their point of view. Eventually, follow what they say if they're strongly opinionated and have more seniority than you, for the sake of moving forward and avoiding conflict over minor things.
If you really think the issue is important, you can also try to open up the discussion to more people in the company. Like write a proposal to enforce better coding style through the use of code formater (or give a short talk), gather feedback and try to reach a consensus.
But I think I'd let it go. Eventually, you will switch team or company, work with different people, and also be better a determining who you want to work with or not.
It also takes courage to ask this kind of a question and it's clear that you are a rare engineering leader who cares deeply about your coworkers and your output. You probably don't hear thank you enough, so I'll say it again: Thank you for caring.
To your question:
My answer is, always go back to the holistic goal of the system and make sure that the team is aligned - otherwise you fall victim to micromanagement. At the end of the day your job is to expertly balance long and short term goals of the business against long and short term goals of the team. If there are fundamental misalignment between these then nothing you can do will solve the problem it will just come up in different ways and you'll play whack-a-mole forever.
What strikes me about your situation is that your coworker seems to have developed a "knock the task out as quickly as possible" routine, and is really good at delivering quality features quickly. Of course, the industry has done literally everything it can do force engineers into this myopic approach (I won't rant as to why but suffice to say I think it's based on greed) and doesn't make your life any easier.
I don't know what your situation is, but I think finding a way to slow down so that nobody feels rushed and have been actively provided dedicated time for higher abstraction design and architecture. People joke about "Architects" - but this example is precisely why those jobs are critical in many cases. It's your job as the engineering leader to do that architecture work.
Best of luck and keep up the great work!
Give them a library or tool to build that the team can use, something with a clear boundary from the rest of the code base, and that has a fairly limited domain/scope so it won't need constant maintenance.
Taking the caching scheme as an example, even if it's difficult to reject caching in general, I think you could successfully push for the scheme to be simpler and code complexity forced on users of the cache to be smaller (the latter you can probably get down to 0).
> 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.
Denser code favors people who cultivate expertise. Less dense and more regular code favors people who receive a single ticket to edit a feature they have never seen before. Almost all orgs enforce the latter style. It's worth considering what sort of thing the thing is, and what sort of people will work on it.
First of all, don’t ever argue about solutions with your peers (e.g. whitespaces), and dive deep (Can you imagine that it is hard for others to read your code? Have you tried reading your own code that you have not touched for 5-10 years? Etc.). From what I hear, you might just ask the question to yourself before you confront your coworkers. And then ask Why at least several more times for every answer.
You also are very close to understanding the core issues: It typically matters to understand the business problem and find the simplest solution, with the least effort to resolve any problems.
You might get good mileage out of studying domain driven design at this point in your path.
Demonstrate the complexity and its cost and why it isn't smart.
Show why a lack of consistency isn't smart.
Show why adding work that doesn't align with goals isn't smart.
Show, don't tell. Be the change you want to see in the world. Educate. Encourage humbleness
All of the tooling, and processes, documentation, and code modularization that it takes us mortals to build complex things - this guy likely does in his sleep without it, until there's a problem he'll face where he can't anymore. He hasn't learned the curse of the gifted. You might have met this guy in high school - didn't need to study for his tests, aced most of his classes, then he specialized in college and ran into trouble because he never bothered to build such rigor into what he set out to achieve, it came naturally - and the longer that problem occurs the harder it becomes to learn the kinds of things that us mere mortals require.
My advice, if you can't manage him in house, manage him out
My suggestion would be to bring this to the attention of your PM. If that fails, then focus on picking up tasks of high value and visibility. Let the “smart” engineers do code rewrites or performance improvements. You’ll have a lot more to show on your resume, feel a greater sense of accomplishment in your work, and will have a greater chance of getting noticed as a star on your team.
As to whitespaces. It does not matter and not worth arguing. Either way works. You need to accept that some people might write code differently from you and that's OK. It does not make that code inherently complex. Of course there should be code style and in my opinion the more strict code style - the better, but it still will not cover everything, there's still some freedom and peers should respect that freedom and not push their own view of beatiful.
https://www.teamten.com/lawrence/writings/norris-numbers.htm...
The main tool is to come up with a neutral system for measuring the complexity of a proposal, and then use benign punitive measures like "whoever broke the build has to bring donuts in the morning" to reinforce that the team favors boring stability over fragile complexity.
1. Code that takes advantage of a constraint in an unexpected way (if you know the input will always be 'a' or 'b', you can write 'if not a:' and do things that assume 'b')
2. Code that allows for reuse in an unexpected way (you know these because the explanation in code review is 'in case we switch to system-X, we won't need to re-do this part')
Both of these are really cool in an academic setting because they're bonuses. They're like plot twists, only with code. However, in the real world, these are both pretty bad.
1 is bad because you generally don't know what constraints are 'fixed' and what aren't in your business. 'not a' might mean 'b' today but might not in two months. Your best bet is to make very clear easy-to-understand, easy-to-predict code so when you do learn new constraints you can quickly fix or extend the code.
2 is bad because it's usually premature optimization. Honestly think back to how many times you or someone you know has added code in this way, adding an abstraction layer somewhere or adding complexity because it will allow for extendability later, and think back to how often the code had to be extended in the way predicted. Usually this seemingly clever piece of code ends up being a weird extra step you always have to remember later ("oh, then we convert it into an array of strings and back into ints")
So I would say you should look at the applications you're building and think about what 'smart' code really looks like in your day-to-day and if the people you're talking to are creating such code. I'd argue they aren't, and one of the problems is that part of you believes they are, so you're having trouble articulating why they should stop and why it's harmful.
Code style: mostly an already lost cause debate between two coders. Pick a third party style that you both can agree to use and agree never to add special rules. Just don’t. Use auto formatter. Debate settled, and both (all) parties will adapt to new style. Ex: in python, use ‘black’ formatter, end of story.
Extra features that make code harder to read: don’t make the problem about the coding/technical problems, make it about end user usage, business problems, and business opportunity cost. Will the end user care more about this dynamic hyper optimized code thing, or an extra feature? Can the business charge more for the extra optimization?
No matter how brilliant the code is, it’s useless if the end user doesn’t end up using it - if they don’t know how or if they just won’t really care.
Could be also that your team could take on a lot more work, and would reduce temptation to add unnecessary complexity or argue about small things.
I think the more experience you have the more you appreciate that a clear, maintainable and "pretty good" system always wins in the long run over a solution that's better in some dimension but opaque and unmaintainable, unless that dimension is really business critical.
It also sounds like they're just bored to be honest, and want to implement something because it's interesting or challenging, not because it actually makes sense. Maybe the best thing is to find them an interesting project that's actually useful.
If you have to fire such a person you failed at communicating the relevant metrics to them. They are clearly going out of their way to optimize for something, they are simply working with an incomplete understanding of what to optimize for and what costs that incurs.
edit: Communicate it like you would communicate that the great new improvement in start-up time came at the cost of energy consumption or unit price. Its great but it missed an existential metric.
While there are people that maneuver themself into positions making themselves irreplaceable, quite a few simply have the urge to clean up and make a nicer solution. Their definition of nice is just incomplete.
Look, your soldiers have got to be ready to fight. Your soldiers probably need to like to fight. It may not be an inherently good quality but it is a necessary quality for someone who has it for their job.
It is the generals' job to think lazily and devise ways to avoid fighting when unnecessary and to make each fight as brutish and short as possible; and it is your job to do that with solutioning.
I get paid well to be the type of person who will spend hours investigating a possibly ephemeral, possibly nonexistent bug, and my product manager gets paid well to prevent me from doing that whenever the business has other priorities.
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
Smart engineers reduce complexity.
Smart engineers reduce their own work, unless they're looking to make an impression.
Smart engineers relate to the team and their code style, and understand the value for maintainability.
What you have are arrogant engineers, who don't yet know enough, but are attempting make you think they're smart (and may have some chops).
The true genius is the underdog who gets stuff done, massively progressing projects, without you noticing or them making waves or more work for the team.
They don't tend to get noticed and will move on if not tended. You'll notice their loss when they leave by brain drain and project velocity drop. They will have documented project's stuff for others, but others won't have the same enthusiasm to bother to learn it.
Do you measure the balance?
I write software for drones. Power use is a very real concern and its performance must be balanced with real-world-clock performance. So I wrote some starter benchmarks and tasked the team to continue writing benchmarks against their code. When the team wants to simplify something, we also measure that against benchmarks.
We use C++ instead of C. You can still footgun yourself with C++ but it provides a lot more safety mechanisms than C.
Sometimes smart people need to be micromanaged and others simply need very clear boundaries. Which they need is highly dependent on their personality.
For example, style guides can be used to keep code consistent and readable. The goal is to code for humans not computers. You immortalize these values into the style guide, and if the "smart" persons code doesn't align with the style guide then it doesn't get accepted.
As for the complexities, stop letting them get that far without checking in first. While it may seem quite grade school, it's time that these people submit design documents outlining their solution before they write any code. This will give you a chance to push back on complexity before it's gone too far.
It's even harder to work with these engineers if, like me, you don't have a lot of experience (or are not that smart).
Are these the type of engineers that will tell you "don't do this" when they review your PRs and then you will find "this" in all of their implementations?
It's not easy to work with them but I was hoping that with more experience I'd be able to challenge their ideas with more confidence... Now I think that will never happen..
Usually reviewing their PRs would take me at least half a day of work... Maybe even more
What they're lacking that the grizzled old vets have is experience.
So is your question about how to give them experience?
Let them experiment and fail in small ways that would hurt everyone else. We learn best through failure. Give them cordoned-off pieces of things to work with. Work with them on how to plan work - what factors matter and why. Do frequent check-ins with them to see how they're approaching things and what problems they're facing. Ask lots of questions, provide advice, but don't offer too much of that advice unsolicited (because failing is a better teacher than you are). Mentor them!
I could then "beautify" his code. Way better than trying to fuck with his mind. I am glad people like this exist. They solve problems many other people can't.
Some greatest hits:
- (what I knew to be rebuild data dog from scratch but they did not as they didn’t have a background in it) in the spirit of engineering first, build on our horrible internal logging/alerting tool as the prod solution. When a license and free seats existed for DD.
- attend no meetings, bake a doc internally or side channel with teams, announce the result of both in a team meeting that’s a superset of the team work they just didn’t participate in. And do it 4 times.
- open gossip on who’s a good engineer or not
Flatter their egos while pointing out that they're optimizing for the wrong goal. Their objective is write something that works and can be understood, managed and extended by someone dumber or less careful than they are. That will rule out some changes entirely, but if they're really smart, that can also spur them to change their designs so they still objectively improve the system while retaining clarity.
There is no one thing called "smart" so all of the people debating whether this guy is smart are missing the point.
People like this are "smart" in the sense that they have a beyond average capacity to keep track of complex systems in their head.
This person appears not to be "smart" in the sense of lacking the wisdom to understand what to do with the large volume of complexity they are able to hold in memory.
In my opinion, the second is much more valuable than the first for the average problem you have to solve on a project although sometimes you need people with the first type of intelligence. But these people are usually much more liability than asset.
Your team either needs to better separate areas of work, so that you don't step on each other's feet all the time and each coder has a bit more freedom of how to solve problems, or you need to sit down and agree on a number of fundamental coding style and 'architecture' rules that everybody needs to follow.
Apart from the organisational and trust issues (which I think are the main problem here), tools like clang tidy, clang format, ASAN, UBSAN, TSAN, a CI pipeline and automated profiling/benchmarking can help to bring in some more 'objectivity' into discussions.
I try to adopt this attitude, I love creating some machinery / abstraction / tool etc to more effectively express the solution to some business problem, but I recognise that my fellow developers must be empowered by any such machinery. I spike, educate if needed, then pair to reimplement. I also try to leave a 'back door' to reversing out of a new design, to let the old way and the new way compete in their minds - which is actually better for them. If the old way wins, I might lick my 'wounds' and try something smaller/simpler.
Every feature has a maintenance cost of about 20% of the initial cost per year. If you have a team that is 100% tasked with maintaining and adding features they will halve productivity (features) in 5 years. So there is the cost of adding the feature plus the cost of maintaining the feature and then the opportunity cost of not being able to add new features.
So how much does it cost to add that feature vs the value? There may be more value in going through the code and removing these low value features than adding them but you will have to weigh that on a project by project basis.
“The best programs are written so that computing machines can perform them quickly and so that human beings can understand them clearly. A programmer is ideally an essayist who works with traditional aesthetic and literary forms as well as mathematical concepts, to communicate the way that an algorithm works and to convince a reader that the results will be correct.” ― Donald E. Knuth, Selected Papers on Computer Science
Notice "human beings", plural; so not just the person who's writing the code.
Any fool can make something complicated. It takes a genius to make it simple.
For what its worth, one of the best engineers that I've ever worked with was incredible about not adding complexity to systems. I remember reading a lot of his code and always thinking "damn, that's really simple I bet I could've thought of that" – even though of course I hadn't. I think that these engineers need coaching from people who've gained a lot of experience building complex systems in complex organizations, not just complex code, and supporting them over many years.
Ask them to handover one of their project to another teammate and let them experience why their decisions suddenly make this task much more challenging.
Smart engineers can be very productive but they also demand good managers that can wield them effectively.
1. Keep praising them for their smarts. Few smart engineers will stay when the praise stops.
2. Delegate responsibilities rather than tasks. Demand results. Set up clear accountability for results that are important to you. (You may want to read Crucial Accountability).
3. Let people make mistakes. This is key. You need to show them their course of action causes problems and you will achieve nothing until they understand they are responsible for the result. If they have a plan and you put your fingers on it, they will have an excuse that their original plan would work if you did not meddle in it. Smart people are extremely good at finding excuses and believing in them.
I am selective where I let people fail. If I have a good occasion, I will present my concerns, but if the engineer presses his solution anyway I will let him. I try not to make it a super critical project or anything that would cause long term detriment. Ideal occasions is just wasted time which I try to balance against gained wisdom. I also try to find things that will have rather quick resolution.
Also, I try HARD to not be smug about it.
4. Demand teamwork. Make smart people work with other people, help other people solve their problems. Make your entire team propose and discuss the solution before it gets implemented. When I managed a team that had a lot of trouble with design quality, I found that forcing people put forward and defend their proposed solutions on the forum of the team helped eliminate worst design offenders without me having to step in. Saved a ton of time on review afterwards, practically eliminated changes that had to be scrapped and improved ability to prioritise changes.
5. I can't recommend it too much. Keep praising people. Make sure it is not empty praises. People need safety to focus on their work and the best way to do it is by praising them for things they did well. Understand is that your ability to get heard when you criticise them comes directly from the amount of praise you gave to them up to this point. But do not get into habit of following praise with criticism, otherwise praise will completely lose its value as people will start expecting to get criticised and will see the praise as just a tactic to soften the blow.
I understand this is very general advice that applies pretty much to all, not just super smart engineers. But remember that everybody thinks about themselves as smart. I find it is better to create an environment where particularly smart individuals can be productive than try to make exceptions for them. I find that smart individuals can be an inspiration to the rest of the team only when they work within the same system. When they work within the system they show to others that it is possible to be successful. When you create exemptions from the rules you show the opposite -- that the only way to be successful is to be treated specially by your manager. There are few things more damaging to the team morale.
I worked with a wizkid fellah with Aspbergers...and for the first 3 months, absolutely hated it. Then I realized there was a method to the managements madness for him, and after that I got on board. To this day I can't believe how fast that guy wrote some of the code he wrote, and how incredibly nice he was.
Being a genius isn't always better than being organized ;o)
You should know what is expected of every employee including how they code, how they interact with others, how productive they are, what quality you expect and you hold them to it firstly in the job description, then in 1-to-1s and maybe, eventually in the exit interview.
A business is about creating benefit to the employees, the shareholders and the customers. Whether somebody is "smart" or not is irrelevant, they are either contributing or they are not.
Calms a lot of smart engineers down but every once in a while, a shiny gem encompassing all the bells and whistle emerges.
Truly brilliant engineers write code and systems that look almost stupid simple, but solve truly complex problems. You want engineers who take a complex and difficult problem and turn it into a solution so stupid simple that everyone else goes “Wait, that’s it?”.
What you got on your hands is a failure of management to feed difficult problems to bored engineers. When problems are easy, engineers will make them hard to stay entertained.
If you can shift the discussion to the _why_ rather than the _what_ I think you will have a better chance of reaching some common ground. A team needs to be pulling in the same direction.
Someone mentioned insecure asshole. I have dealt with them. Unfortunately, lot of managers fail to identify them and eliminate them. These asshole do enough to stay in the org while making the workplace toxic.
I work with a lot of people like this, and the key is to bring them to the realization that making a system objectively more featureful or capable does not necessarily make it objectively better: simplicity has value too. One of the key attributes of an embedded system is its longevity. If they want to make something complicated and they're the only person who will ever need to debug or understand it, that's fine, they can make it as complex as they like. But if you need a bus factor greater than 1, or work with other people, they need to design it with other people using it in mind.
Any engineer can make a complicated thing to solve a complicated problem. But the mark of a great engineer is that they can make a tool to solve that complicated problem that's simple enough for anyone to use and understand. A quote that I've often appreciated is this one from Brian Kernighan (the "K" of "K&R C", as I'm sure you and your engineers recognize):
> "Debugging is twice as hard as writing the code in the first place. Therefore, if you write the code as cleverly as possible, you are, by definition, not smart enough to debug it."
I like to look at this, substituting the "you" who has to debug the problem in the present moment with an unknown engineer 5 years in the future with a non-working thing picking up the scraps of your work from today... How much smarter and more familiar with the problem do they have to be to figure out why your code isn't working anymore? Will such a person exist?
If this is partially an ego/respect problem, as it stereotypically often is, they'll hopefully recognize that someone 2x smarter than them probably will not be available. Another frequent stereotype of these engineers is that their creative appetite prefers building to maintaining, if you force them to maintain their creations because no one else understands or can read what they did, you may be able to encourage them to document, format, and design their code in ways that they will hope will reduce the amount of time spent on support down the road.
A good solution results in fewer net problems. A good engineer delivers good solutions. Therefore a good engineer must balance complexity against the problems they set out to solve.
Explain them that complexity is their worst enemy.
They won't understand.
Explain them again, with more examples, real life situations where complexity wasted time, money, and even, lives.
If they keep not understanding, fire them.
If either of those does matter to the product, it’s a much more difficult call whether to sacrifice product capability for code quality.
I have left companies due to people like this.
I have to assume those engineers are not very experienced, by the way. After a few hard-to-solve bugs introduced by overly smart engineers you really start appreaciating simplicity.
This term came from the Navy Nuclear Power School graduates, who are the best of the best in academic scores, but often lack social graces and suffer from overthinking even simple tasks.
This is not a 'smart' problem.
Teams need Bees, not Spiders.
(Edit: spider not an insect, noted)
The lazy solution is to bring in a consultant or tech advisor with some impressive resume and thoughtful demeanor.
smart people are even more vulnerable to bad ideas, because they can convince themselves that their ideas are good, in extremely rational and rhetorical way
You said "productive and friendly" way though, and I'm afraid Linus will usually fulfill only one of the two :) He makes some very sound arguments though.
it's not such a problem if they over-engineer too-smart tools to help maintain and administer your carefully managed, just-smart-enough system. When they move on, a 'normal' replacement doesn't necessarily have to reason about the complexity: if the tools break, or are too hard to understand, the next dev can revert to simpler tools.
it's great to keep really smart people around, but it's also great to have a business that is insulated from risk by minimising unnecessary complexity and engineering for maintainability.
if they're too smart to realise that, maybe they'd be happier elsewhere.
Basically, they're bored. And they make their job more interesting by making things unnecessarily harder.
I mean, when you think about it embedded is pretty simple; there aren't a lot of new challenges. You bring up a new board, it's like an old board but different. Port a new package over, big whoop.
What you need to do is give them a real challenge...then all the other stuff will become super simplified because they want to spend their brainpower on meat. What about a way to retarget your code? Or do some super cool thing, like a HAL (you said you were embedded, and a HAL is something that usually would benefit any embedded team)? What about porting WASM to your platform(s) and retargeting your stuff at it? Or doing an LLVM-based runtime for your embedded stuff?
TL;DR: Your company hired a bunch of smart guys, and they want to do smart things. Code maintenance isn't a smart thing, it's boring. Give them something smart to do that'll help your company long term, something really hard.
I think there is a spectrum with two opposite poles: The ones that think that a complex problem requires a complex solution and those who try to solve complex problems with elegant solutions.
The first group transfers all the complexity directly to the solution, the latter tries to eradicate complexity by dumbing down the problem first.
I found that engineers tend to be in the first group. Designers (especially UX's) tend to form the second group. The fact that there is a "Complexity Reduction"[0] trend in UX may be both a cause or an effect of this (I'm not really sure).
Another UI example.
This is a popular software made by the first group: https://www.bulkrenameutility.co.uk/assets/img-bru/mainscr.p...
This is the same problem solved by the second group: https://cdn.osxdaily.com/wp-content/uploads/2015/05/choose-b...
This may be also explicative: https://xkcd.com/538/
[0]: https://medium.com/slate-teams/complexion-reduction-a-new-tr...
Phrasing as "too smart" is curious. Do you mean too smart for their own (or product/company's) good or for you to manage? I think it really means that they're not productively directed. Including them in some longer term problems/discussions might give them context on how to weigh things better.
I think the idea of "unnecessary complexity" can be avoided two ways: 1. in terms of opportunity cost, if they don't have anything better to work on then it's hard to refute this way, and 2. in terms of maintainability or added risk--they won't see it as a problem but it would be for other team members.
I don't know what your development/shipping process is like but one good way to level your team is to adopt pair programming and rotate pairings e.g. weekly/biweekly depending on the nature of the work. This settles the dev culture/conventions better than anything else I've experienced. It also means that knowledge gets shared and generally more confident that you have 2x coverage.
I agree with comment about allowing some "probably-unnecessary complexity" as your assessment may not always be correct and even if it were allowing it sometimes adds meaning to the times you don't. It also avoids demoralizing their enthusiasm.
Another good idea proposed is about side-projects. But I would say have one for them at the company rather than a personal project. Something that could benefit the product and team to improve a process or validate correctness, completeness, etc. The great thing about this is that it's out-of-band--it runs outside of the shipped product. I've often written complex generators or validators where the results end up in the product but not the complex thing itself.
As for the whitespace thing, I advocate for the amount of space to be proportional to how important a piece is to the overall processing. Making each thing as easy to read as possible by adding whitespace detracts from understanding the whole. Any common idioms can be written as densely as possible with no loss of comprehension. I find jr devs putting one argument per line far too often "for readability"--beware consistency for its own sake. Length of a var name should be roughly proportional to how distantly it's used.
Ask the engineers if they want the company to grow. If they do, that will necessitate hiring new people. Write code with those completely new people in mind.
They're willing to do those things because it's fun, rather than because it solves a problem
I am though a big fan of frequent checkpoints, and checking in with the 'big engineering' / 'refactor everything' people before they get too carried away with code only tangentially related to the business case. Agile provides a really good 'excuse' to do the check in, demo code, and a time to reflect if what the developer has is good enough to hit the aforementioned customer requirements.
This is a bad thing and will lead to it being unmaintainable. Good engineers make simple systems.
> - Their code has no consistent style
Weird. They should have consistent style if possible.
Most of these issues stem of from a lack of understanding in the importance of designing a system that is simple consistent, where the least possible context is required to work with it, that is robust to refactoring and debugging, that other can work with as well, etc.
Unless they're actively trying to improve themselves with the criteria you dictate, it'll be an endless battle to get good output from them -- the management equivalent of the relationship cliché "They're damaged but I can change them".
My only approach now is to isolate them in discardable islands of code or firing them to improve team unity. Only keep if young and really willing to change and stick around.
That's it.
When smart people have a challenging goal to reach for, they reach for it together.
When they don't, they turn inward and muddle around in complexity for the sake of the challenge.
Only thing you can do is accept it, they are not going to change. Nobody does, people get lazy with age and experience:)
Simple thing which worked in my companies is saying:
The key problem here is the lack of empathy — to users, to fellow developers, to the company goals, to the business. They basically don't care about anyone and tend to look down on others.
Those are the kind of people who would kill anyone who points out their "smart" solution is just an overengineered piece of crap in real life.
In my perspective those are not smart at all, they'd better focus on some academic research and not come close to any user facing products.
And I don't see any simple way to change this attitude, it's something deeply rooted in personality.
Of course there are other types of smart engineers who just didn't have a good example or haven't thought about caring for other factors in software engineering beyond pure CS, then it may help just being straightforward with them and find a "good" smarter developer as a role model.
Come work with us. I think you'll be more happy. julien _at_ serpapi.com.
Inconsistent style suggests they did not learn that most of the coding is about reading the code after it was written. Possibly they quickly write and copy&paste code, and do not need to debug it since it "worked once".
If they tell something others can hardly understand, and they are unable to explain it, then your engineers need to learn proper writing and explaining skills.
All in all, you probably need smarter engineers to manage the team.
Treat them as potential saboteurs. Their main job is to hinder your progress to the benefit of a competitor.
As for code style, don't most SCCS systems now give you the option to normalize the style upon checkin?
Write them up and put them on PIP. If they do not improve, part the ways.
Aret hey competitive? Can you maybe set out daily, weekly and/or monthly goals for them to reach (on tasks you need them to do). If they are that good and they do it all in an houre, cool, let them be free and watch Netflix or something xD
As long as the work is done (which is your goal) all is well...
It's hard to give advice since it is probably one of those "you have to be there to understand it completely", but hopefully some of this jibber-jabber helps.
But at the end of day if they're not a good fit for the work you need them to do, maybe they need to go. Maybe they'll find something their suites them better and maybe you can find people that suit you better.
Long term, everyone is happier.
If you are actively trying to find solutions to improve productivity and nothing works, maybe it's not you, it's them.
If there are still things you haven't tried, try and see what happens.
those too smart folks are actually dumb in how to navigate corporate and deal with middle managers.
clueless middle managers only understand feature delivery. they have zero understanding of maintainability, stability and security.
those engineers probably fixed tons of code smells that would completely halt business either by breaking or allowing malicious actors to take over.
but they are not smart on how to communicate that work. now the middle manager only see them when they start to work on small refactors which are actually their way to wind down all the extra work they already contributed and was not accounted by anyone.
Obligatory mention https://xkcd.com/974/
Don't argue for something, ask questions that point to the pros and cons. Eg, "do you think we might be over complicating this? I wouldn't want to add complexity unnecessarily - or do you think `x` is necessary?"
You might need to ask a few questions like this, but if you're right and ask the right questions people will tend to see the error in their thinking themselves and argue your case for you. And if not, well, maybe you are wrong. Or maybe it's just nuanced and there is no clear right or wrong answer.
I find intelligent engineers have an ability to write much more elegant solutions, but also have a larger capacity for complexity. So while they can build great solutions they're often more comfortable with complexity and will sometimes simplify things less.
I think my strength as a developer is that working memory is absolutely terrible, but otherwise I think I'm fairly intelligent. So while I can write and understand complex code, I find I'm naturally inclined to find simple ways to design and structure my code otherwise I can get quickly overwhelmed if too much is going on at once.
Something I try to do is package pieces of logic into lots of very simple services or modules - this way I'm either dealing with multiple parts at a high level or a single part at a low level. I guess some would argue this is just how to write good code, but for me I literally have to do this or my brain stops functioning. I guess my point is that there are ways that complexity can be abstracted away, so unless the extra functionality is truly unnecessary, then perhaps the solution here is just to spend some time on improving the structure of the code?
> 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.
I think this is a you problem personally. I actually struggle to understand why someone would even get into a debate about something like this. As a developer you need to have some level of flexibility in how you work. Every place I work has different coding standards, tooling and ways of working. And while these things are worth discussing as team from time, you have to be understanding that you're just one person on a team with your own personal preferences. If you can't adopt other ways of working then you're never going to work well in a team.
And to be clear, I'm not saying you have to like code with less whitespace, I'm saying it shouldn't be such a big deal that you're getting into debates with individual developers about it. If you're that bothered about it this would be something I'd probably raise in a group chat - "hey guys, just wanted to get your thoughts on whitespace - do you think we should be adding more or are you happy with how things are?"
Whatever the answer is though I don't think it's being combative or argumentative. I think you need to find a better way to resolve differences of opinion (ask questions, listen more, seek to understand) or find a way to manage the complexity you're facing - either independently, or preferably as a team.
The Japanese have a system called Shuhari describing three stages of learning; Shu 'obey' for beginner where you follow recipes, Ha 'detach, break' where you mix recipes to mind new approaches, and Ri 'leave, separate' where you forge new paths.
I view developer growth through the lens of Shuhari as:
* Shu - Dev is using known steps from online articles, StackOverflow, etc. to accomplish tasks of limited complexity. Dev is not designing complex systems.
* Ha - Dev has learned much. They are able to design complex systems integrating multiple technologies, but those systems are overly complex. That comes from the subsystems not integrating seamlessly, APIs that could be better, and a tendency for over-engineering at this stage.
* Ri - Dev has learned not just the technologies and how to design complex systems. They have also learned how to design simple systems that work together to handle even more complexity than could be handled by what they designed in Ha stage, without being over-engineered and while still being much easier to understand by less experienced devs.
Based on what you describe, the extremely smart engineers are in the early stages of Ha; some of their practices are still in Shu (e.g., lack of code consistency).
Someone should have a frank conversation with them. Ask them 'At the end of the day, how do we provide value as devs?'. Make it clear you are not asking them to justify themselves, but lead them to the realization that we provide product from timely shipped working and usable product. Your value delivered increases as you increase how timely you ship, how well your code works, and how usable your product is.
But, to quote Admiral Akbar, 'It's a trap'. Because the conversation shouldn't end there. Then ask them, 'Which one is better to increase?'. They will likely jump on how well your code works. Lead them to the understanding that the importance of each is a balance.
* Well working code that is easily usable is useless if it ships a year after your competitors, unless your competitor's code works so badly and is so hard to use that it makes up the difference (in practice, it usually doesn't - people prefer with a 60-80% solution to their pain points now, than a 90% solution in a year).
* Timely shipped code that works well, but is unusable by anyone outside the dev team is useless to your customers (you did hallway tests right?).
* Timely shipped code that is very usable when it works, which is not most of the time, will frustrate your users, tarnish your brand, and provide a massive opportunity to your competitors.
It sounds like you have mismatched expectations and poor communication on the team.
> 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
Okay, how? If they're writing a proof or a model and using a model checker to validate their model, they are able to communicate their reasoning and teach others how to read the proof or understand the model, and it's sufficient to convince an educated person that it's correct: what's the problem?
You only have to understand the reasoning.
It sounds to me that you have differing opinions on how things should be done. Take a dozen programmers, give them a specification for a problem, and you will get a dozen different solutions. Let's assume we can verify they all implement the specification faithfully: which one is the one we should use? Which one is better?
Endless debate. It's like asking a room full of programmers which programming language should be used for a given problem.
What matters is that the code works for the intended use. It's best not to bother too much with the details unless the details matter. If you have two implementations of a specification but you prefer one because it has the right performance characteristics -- those characteristics probably matter and should be in the specification. If the performance characteristics don't matter then either solution is fine...
Another way to help solve differences in expectations and start communicating on the same level: make sure everyone knows what your shared values are. Write down your list of values (readability, performance, terseness, etc) and get everyone to do the same. Make sure to clarify what you mean by each word. The set intersection of everyone's values are likely the teams' shared values: what makes the team stronger together than any individual can achieve working alone. Use those values to set preferences for things that are "debatable" like code style or when you have implementations that are equal in terms of meeting the specification and you have a stalemate on which implementation to prefer.
> 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.
This is an immense waste of time. You don't have to be "smart" to have this argument. I've seen lots of programmers of all stripes over the years debate endlessly about syntactic and stylistic things like this. Pick a style, put it in a guideline or auto-formatter, and be done with it. There are more pernicious goblins hiding in your code.