Hard to disagree. I can usually tell what type of type of experience devs have by the snarky, dismissive responses I've gotten on various internet forums over the last two decades. e.g. "Oh but you would never have this problem if you performed proper code review" - Random_Rockstar_Dev_254
However not all legacy projects are bad to work on. If they're decently developed, then often you'll find that most of the pain is in setting up your local codebase. e.g. sorting out make files, or header file clashes etc. And if you're lucky, some poor bastard has already done the hard work for you.
As an aside, I know tons of experienced "Senior" developers who just suck at their jobs. The problem is they have tons of experience in delivering terrible products based on terrible code and architectural decisions. They just never had anyone to show them any better. And now that they're "Senior", noone can tell them anything. Many devs who work in corporates understand this pain. Shoutouts to my peers who have to "fix" 3000 line stored procs with a 100 line "change control comment saying stuff like "2009-04-03 JS Added TAX_REF_ID". I live your pain.
EDIT: Also, if you happen to work at company that thrives on terrible legacy products, try to drill it into their heads that BAU Support is not part of the solution. Every time I've raised the issue of the mounting tech debt I've gotten the response "Business does not have the apetite to solve these issues. And why would they? That's why we have support teams".
I see that going through these three kinds of projects let me grow as a developer:
1. green field project
2. other people's legacy project
3. your green field project growing into legacy project.
You can learn so much from each of these, but to me the most eye opening experience was our green field project growing into a project with more and more developers.
You could learn so much about others, some were very arrogant, went on constant refactoring mission only to mess up everything. If for some reason, I couldn't check what they did, usually, I had to come in and fix their stuff, but sometimes the only person knowing about the edge case was me, so I just left it "messed up".
Others tried to understand why the system ended up this way, some accepted it, while the best actually improved the system by looking back and recognizing the simplicity hiding in the mess.
My experience, is that this is usually a defensive shell around personal insecurity.
On the outside, it looks the same, but internally, insecure people can be reached (not easy), whereas truly arrogant folks (a lot more rare than you might think) cannot.
My experience is that most difficult people are actually decent folks, that we can enjoy working with, but we need to adjust to them, and they need to adjust to us.
> The Kindle runs stripped down Linux with a React Native frontend along with Java backend applications.
Honest question: what exactly is wrong with this setup?
There's the OS, there are services and user land apps written in java and misc native code, and from the link there's a single component where Lua was used as bridge code.
The GUI is React Native, which is just a framework to simplify the design and implementation of native GUIs.
Well, I have found that finding things in common with people is usually a great segue into improving relationships. Learning more about them, also helps a lot. Find the things they care about. It can be surprising.
I have learned to make the first move, myself. It doesn’t work, if I insist on them doing it. Also, I need to accept their value system. If they truly have values that I can’t deal with, I usually “compartmentalize” things, so I don’t deal with them, in those areas.
I’ve spent my entire adult life, getting along with people that don’t play well with others. I haven’t always been able to get through, but I’ve had more success than failure.
> Also, I need to accept their value system. If they truly have values that I can’t deal with, I usually “compartmentalize” things, so I don’t deal with them, in those areas.
It feels like working with all sorts of people (and sometimes working around them) is an important skill that’s not usually focused on enough, which is how you get people that might be brilliant but also are really hard to work together with.
Not OP but: destigmatize admitting failure (by doing it yourself), normalize admitting ignorance and asking questions (by doing it yourself), find someone they look up to and demonstrate healthy collaboration dynamics with that person, explicitly labeling things which you value, as they happen (e.g. "thanks for saying you're not sure, or I would have thought that you were and it would have made me value the statement differently", "thank you for not taking the feedback on the code personally, the result is a better codebase for everyone"). And do the same with them whenever they imitate any of that, without dwelling on it any further or treating it any differently.
TL;DR: Normalize healthy dynamics by example.
Obviously just my 2c and every case is different etc.
- Share credit and be generous with sharing
- It is better to error in the direction of over sharing credit than under sharing (taking credit for yourself)
- Slow down, say "I don't know" (good to follow up with "but I'll find out")
- Saying "I don't know" is often a better answer than guessing
- Guesses are fine, but should be prefaced and be clear that you speculate BUT will follow up and verify
- Not knowing is the first step to knowing. You've turned an unknown unknown into a known unknown. That's a big step! And often one of the hardest!
- Encourage juniors to speak up and not be afraid of raising issues, even if those senior to them disagree.
- Either the junior provides valuable feedback that was missed (everyone is fallible) or it is a learning experience for the junior and //we invest in juniors//.
- Seniority does not make the dev, the logic/ideas/thinking does.
- Mentor more. I think we often want to send juniors to their corner so we can concentrate on our work, but you have to train those who will later on become your peers.
- There are no graybeards without noobs
- Encourage more collaboration
- Especially when there are complementary skill sets
- Drive culture that recognizes that ones ideas are not a reflection of their value. What I mean is that it is okay to be wrong. The idea is distinct from you, and you are more than just one idea
- We're all wrong, it is just a matter of "how" wrong
- Having a "bad idea" or "wrong solution" doesn't mean /you're/ wrong/bad.
- Recognize that we're all on the same team. Criticism is constructive
- A critique is not a dismissal, it is because we are all on the same team trying to make the best thing. An outside view is often helpful to finding issues. We work as a team, so criticism is debugging as a team, just as you criticize your own work when initially formulating ideas (you reject some ideas, find limits, and formulate plans. Criticism is the collaborative version).
- This means also be careful how you hand out criticism. Ensure it is always constructive. It always contains an explanation and a path forward (as much as possible).
- Competition can be beneficial, but it can easily create tribalism. Fight the natural tribalism because we're all on the same team (helps to have team mixing)
- Make time for learning
- The job always involves learning, no matter how senior you are. If there is only time for "doing" and no "learning" then you will only gain debt and you especially are teaching juniors the wrong lesson.
I would state that the first point can be a bit tricky. I've worked in some environments where one or two people follow the point and no one else does, so this ends up with those people being seen as "non-productive." This is more representative of poor management though and I'd push back against the toxicity to the extent possible.
For managers: the last point is really important. Your coders shouldn't always be sitting in front of their IDE or terminal typing code. They should be spending a fair amount of time reading docs, writing docs, and googling. Writing docs is actually important as it helps communicate ideas, which also serve as reports to YOU. This communication also helps de-abstract the ideas and often leads to finding issues. It is an important step to debugging. (It is often a good idea to have juniors build or append docs when they are onboarding. Dual serves as the intro to the codebase)
One of the best ways for me to learn, is to explain.
That's a very old pattern.
That's one of the reasons I write stuff that no one reads[0]. Writing up a technique forces me to research it, and break it down into its simplest components.
> One of the best ways for me to learn, is to explain.
Kinda The Feynman Method[0] or even Rubber Ducky Debugging[1]. I found that teaching in grad school has immensely helped. Not only do you have to solidify concepts to a much higher degree but you revisit stuff too. I think there is a big difference between the level of expertise needed to be comfortable working with some knowledge vs what is needed to teach that knowledge. The former is much more personal. But when learning any topic there's always things you had to table, that you didn't answer, because you had to make general progress. But if you don't revisit these, then they always remain unknown. Revisiting often brings new insights and thinking that you probably didn't expect. Any time I've revisited a topic, even ones I know quite well and have revisited many times, I often find that there's still more for me to learn. There's infinite depth, so always keep your eye out.
One of the places I feel like I grew the most, and I was lucky to have that early in my career, was freelancing. Every month I'd be ushered into a totally new project/codebase, with virtually no time/budget allocated to "understand" the codebase properly but still needing to deliver value (which was a stark contrast to my previous hobby dev time).
"3. your green field project growing into legacy project."
You do all this upfront design about how it's going to work and then "Oh god there's so many splinters and sharp corners, it's only getting worse and every new team onboarded to the framework needs to have their hands held, and management won't allocate time to address the tech debt."
Wow this is a great formulation. I’ve started becoming senior more recently, for most code I’ve become pretty good now at making the tradeoff of how much refactoring to do versus a quick hack based on risk. Sometimes adding in an if statement makes more sense than a full upfront refactor.
The exception… is for any feature I added myself. If I spent a lot of energy releasing v1 with the “perfect” (to me) abstractions, etc. I get paranoid about more junior developers messing it up for new features. Re-reviewing code changes, insisting on all the upfront refactors and rare edge cases handled, etc. Something I need to overcome.
Ugh, too right. Going through that made me appreciate working on a legacy project later on, because I could improve things rather than watching things get worse.
> I can usually tell what type of type of experience devs have by the snarky, dismissive responses I've gotten on various internet forums over the last two decades.
I see this constantly on HN and have had to learn to not engage with those conversations. It is like some people have never had to run a project under any sort of external constraints like head count restrictions, layoffs, inheriting a system which you didn’t write, or awkward organizational structures.
Some will scream until their ears bleed that there is only one optimal way to do things and if you aren’t doing things that way you are a incompetent chump — totally disregarding the reality that people have to work with.
The real miracle is when you see a teammate who can still perform well under these insane constraints. I have seen it a couple of times in my career. They still find a way to write "good enough" code or write "good enough" docs. It was inspiring.
I would say the same about a sales person who can still manage to have a great year even when the (their) market is cratering. Again, I have seen it a few times, and it always impresses me... watching them pull a rabbit out of the hat!
It feels like you're just finding other ways to describe people who are senior in title only which is far too common. Any senior that uses their title to justify a 'you can't tell me way to do attitude, is a senior in title only.
I think the term is the issue. Senior development means something more intrinsic than it does in other title, like a senior manager. I think what we're attempting to define is something closer to seasoned developer.
> I think what we're attempting to define is something closer to seasoned developer.
I'm fully aware of that, which is why "Senior" is in double-quotes, but experienced (aka "seasoned") is not. My point is that you can be seasoned at delivering bad products. The point about seniority just speaks to tenure at a company. Sure, you can join a company as a "Senior dev", but that's not quite what I'm referring to here. One would think that they would be exposed during the interview process, but alas, we all know that's often not the case.
The title is more or less meaningless these days. That said the other problem is people can't always appreciate the perspective of a more seasoned developer. Some people who are very junior or intermediate think they know better since they don't have the experience. Lots of things in software come down to judgement/intuition and are not black and white. A lot of software development is about working with people and culture, not code.
The unseasoned developers are sometimes very keen on some idea, philosophy or method and are very intolerant of skepticism from someone who knows there is no such thing as perfection and no one way of solving all problems.
But this will never be an issue in the real world
- Also Random_Rockstar_Dev_254
I see this a lot too. Which I think I have a good analogy: judging a program by its output is like judging a math proof by its last line. But math proofs are really hard and annoying because you can divide by x somewhere and then have to contend with the fact that x cannot be 0 or else you have to divide by 0, making your proof invalid. The proof is only valid in its entirety. I see programs in the same way. But this is exactly why Test Driven Development is so naive. You can't just write tests to check your correctness, it only works under the assumption that you can predict all possible classes of data that will be processed and in which way. Currently and in the future. The experience of a senior should certainly make TDD far more effective, but I'd say a graybeard is one who knows the limitations and is able to write code that is efficient, can per-emptively address future tests, and writes in such a way that the code can be easily modified and adapted for the future changes.
If I've learned anything in my history of coding it is that where the program ends up is never where I expect it to. My experience makes me better at predicting that differential, but to be honest, given a big enough project you are never really going to be able to predict the end state. Things change that are out of your control.
I'd also argue that this is why it is so important to write documentation and comments while coding. It'll help you later on and anyone that is onboarding (small cost to document, but many people reap the benefits). I don't want a junior coming in and completing a task fast, but I want them to come in and learn the codebase and how to adapt it for the task. Sure, it isn't as fast, but juniors are an investment anyways. I think we have to be honest that no matter what we do we are either investing or taking debt, both of which compound. But I think the problem is that interest is hard to observe and debt is less observable than the direct cost seen in an investment. Maybe a real Sr Dev is the one who is more aware of these trade-offs?
> As an aside, I know tons of experienced "Senior" developers who just suck at their jobs. The problem is they have tons of experience in delivering terrible products based on terrible code and architectural decisions.
It's a classic tragedy of engineering; you can actually ship with almost anything, and just successfully delivering a product reinforces a feeling that your choices were good, no matter how arbitrary they were in practice.
People can get really confident that what they're doing is tried and true, while it's simply the only approach they've had for all of their career.
> I can usually tell what type of type of experience devs have by the snarky, dismissive responses I've gotten on various internet forums over the last two decades. e.g. "Oh but you would never have this problem if you performed proper code review" - Random_Rockstar_Dev_254
Yes, and the flip side to this is the other kind of senior that you mention in your comment: the one that refuses to believe that things can be done better.
It's hard to find the right balance between wanting to write better code and pragmatically dealing with the realities of a huge, messy legacy codebase with tons of bad decision - you can't fix everything (and certainly not at once), so you have to choose your battles wisely.
The windows kernel is old. The Linux kernel is old. These are both old code bases, but they're not "legacy" at least in terms of how many would phrase the term. A codebase let to rot is legacy. A codebase that is constantly improving itself to be in the best state so that it can adjust to modern programming standards is just a good piece of software.
That all said, it's all subjective, blah blah the end.
Maturity and humility are key factors in being a senior developer. Those who lack humility will often cry about how its not their code that's messed up, delaying actual bugfixes and wasting developer hours, or worse producing a toxic work culture.
You can learn from anything. A "legacy" product is one that works, but is generally hard to maintain.
"Why is it hard to maintain?" is a question every architecture person should be able to answer...especially after digging into some large, old piece of software.
However not all legacy projects are bad to work on. If they're decently developed, then often you'll find that most of the pain is in setting up your local codebase. e.g. sorting out make files, or header file clashes etc. And if you're lucky, some poor bastard has already done the hard work for you.
As an aside, I know tons of experienced "Senior" developers who just suck at their jobs. The problem is they have tons of experience in delivering terrible products based on terrible code and architectural decisions. They just never had anyone to show them any better. And now that they're "Senior", noone can tell them anything. Many devs who work in corporates understand this pain. Shoutouts to my peers who have to "fix" 3000 line stored procs with a 100 line "change control comment saying stuff like "2009-04-03 JS Added TAX_REF_ID". I live your pain.
EDIT: Also, if you happen to work at company that thrives on terrible legacy products, try to drill it into their heads that BAU Support is not part of the solution. Every time I've raised the issue of the mounting tech debt I've gotten the response "Business does not have the apetite to solve these issues. And why would they? That's why we have support teams".