Mindsets to Avoid as a Senior Software Developer
betterprogramming.pub
betterprogramming.pub
Rather, let everyone (juniors, QA, non-developers) in the team perform reviews of everyones code, even your senior code. Not only is it a great way to spread/communicate knowledge and understanding in the team. But everyone looks at your code with a different eye and background.
You may have written the greatest opus magnum of your programming career. But if the junior or medior can't make sense of it, they will not be able to maintain it when you're gone. So effectively you have failed.
Overall I agree with you, yeah. But also no. Of course the code should be as simple to understand as possible, but if the junior or medior doesn't understand matrices, nothing I do will make them understand them.
So I mean, yes, but also no. Sometimes it's OK to expect people to have some domain knowledge. Doesn't mean your code should be spaghetti of course.
Oh but there are things we can do. We can add comments that link to resources, we can write long prose (both inline in comments and in out-of-band documents such as RFCs and documentation) explaining why we're using something that nobody else in the team understands vs the alternatives, and we can level people up via informal sessions like lunch-and-learns, info sharing sessions, etc.
It's true that many juniors aren't capable of following concepts above a certain level of difficulty, but it's also not rare for people to really flourish if given a gentle push.
There's definitely a paretto balance when it comes to knowledge sharing. Don't be that person that writes zero docs and hogs all the knowledge when you could spend 20% effort to level up 80% of people to the point where they can start helping each other.
There is a difference between code that is complex because it needs to be (ex: matrix mathematics) and code that is complex because you wanted it to be (ex: microservices and kafka and obscure functional languages for what could have been a Rails CRUD webapp).
Teaching them will.
Sometimes refactoring is the cheapest of the three, but you won't know until you try to explain/teach it.
I also spend a lot of time explaining and teaching, as it is necessary, but it's really a stopgap measure. Give it a few years and there's mostly new people.
It is an opportunity to go through the code and concepts at least.
Having most of your team not be able to understand the code they support sounds dangerous
I think the OP is just saying that juniors should be allowed to participate in the reviews of senior engineer code (not that a junior review alone is sufficient for merging a PR).
I think this is a great way for juniors to get exposure to the complex topics they might not yet understand, but should learn more about.
What if you took a hour or a day to help educate an eager junior developer about what you did in that PR?
I, personally, don't know matrices. I can damn well learn them if it becomes relevant to me.
If we were on the same team, and I said "what's this stuff?" and you said "nothing I can do will make you understand this" I'd be pissed, and that attitude would _permanently sour_ the relationship.
I imagine there was a point in time that _you_ did not understand matrices. I've no doubt that matrices can be tricky, difficult to understand, etc.
So, lets work together on sharing that knowledge! Once you've helped me learn it (pointing me to resources, pairing with me on an example problem solving session involving matrices) I will be able to maintain the code, understand it, and apply the pattern to novel problems.
But not just that, because I am a compulsive documenter of what I've learned, as you teach me, you help me teach _everyone who comes behind me_
TL;DR the attitude of "if jr/med devs don't already understand matrices, nothing I do will make them understand them." is _extremely_ self-limiting, locking you out of tons of potential value, and causing your entire team to be worse off.
It's not your fault, per se. I know this attitude is common in the industry. It just really pisses me off, because so many teams are deeply damaged by it.
(I know, I know. Maybe you'd love to slow down and teach early-career devs, but the feature death-slog required by management precludes you taking that time... in that case this isn't directly your fault, etc.)
Sometimes the right and fair substitute for "nothing I can do will help you" is "get yourself a proper education on this subject, somehow, and then we can talk about the code."
I often mis-apply slack/markdown formatting.
Instead, now I will less often mis-apply markdown formatting to hacker news.
Thank you!
And this isn't "wildly off-topic", by the way. This is "extremely germane to what I said, but addresses something other than the specific point I was trying to say."
Doesn't make it not helpful. In fact, I bet there are many situations where this kind of feedback is more (I almost wrongly-formatted that!) helpful than addressing the comment directly.
You, dear internet stranger, have taught me something. Thank you!
And not to what some one did mumble years ago when I was taking over the map part of a map reduce product built in PL1/G and say after 3 days "haven't you learnt it all yet"
I've become less positive toward code reviews over the years as well - the low-hanging fruit of style checking, linting, and related stuff has been automated away. Moreover, people are busy and when they do code reviews, they are mostly looking for easy stuff to pick at. What ends up getting avoided is the far more important algorithm, design and architecture reviews that really require a much bigger cognitive load.
Code review might be good for a subset of code, like retrofitting bugfixes to release branches or babysitting a team of beginners.
BUT: I just joined a team with domain experts who do not have a software engineering background. As I go through the code, there's lots of copy & paste, incorrect error handling, inconsistent (and confusing) variable names...
These developers really can benefit from coaching in a review. The team then benefits because the code is easier to read, robust, and maintainable.
(The codebase is impressive for people who have minimal software background. I've seen much worse from people who should know better.)
That’s a real problem. Almost nobody has the time to really understand the code they are reading and how it fits in.
Everything has become dislocated from reality. "Issues" and "tickets" does not capture actual work to do. Unit tests and CI do not capture whether something is truly functional. Peer-reviews do not mean a given commit is stronger than otherwise... At the end of the day there's just no replacement for good judgment and experience, despite all the fancy tools that want to try to "gamify" it.
But if you are giving veto power over code and designs to your most inexperienced developers, you will not have a good time.
I suppose I technically did have "veto power" as my approval was required in order to merge the PR, but nobody ever thought of it in such adversarial terms. We'd comment with questions or things that were unclear, occasionally asking "why are we doing it this way instead of that way?" and more often than not the solution was simply adding/updating comments to make things more clear.
For our team at least, it was a casual and collaborative effort where everyone learned from each other. I wouldn't hesitate to give inexperienced devs veto power over my PRs again unless it was for a time-sensitive hot-fix.
Especially your senior code, by the time you get to being an experienced engineer you really should appreciate the value of lots of eyes on your work.
You may indeed have written the greatest opus magnum of your programming career, but I bet there are a few little bugs or edge cases or something you've overlooked. There's always something.
Similarly - junior might look at your PR and see that it's ok. Senior might look at it, see that you've forgot about a thing that junior didn't know about, you omitted to test a certain condition, etc.
Again, juniors are more than welcome to look at PRs and be a part of discussion, but if you're merging, you should be wary. I'd personally be against allowing a merge if you get only a junior approval.
If you allow everybody to review every PR, it doesn't imply that you'll allow everybody to approve every PR.
This is a strange concern to try to address with code-review. I don't think most folks actually expect to catch a lot of bugs by staring at diffs. Testing is the right tool for that job.
> I'm way more interested in that than I am whether variable names use camel case or snake case or whatever.
Style concerns definitely shouldn't be the primary focus of a code review. Ensuring some stylistic consistency through the code base is a benefit they can provide, but certainly not the the most major.
> In fact if your tests are complete
How do you know if the tests are complete on someone's work before they merge it? Don't you need to get in there, and well, review their code to see what tests they wrote? Evaluation of test coverage by a peer is one of the more important parts of a good code review. What other process would you use to ensure incoming patches have the test coverage you want them to have?
> we can always refactor the code later if we need to.
Isn't it better to catch code structure issues when they are fresh in everyone's mind rather than taking on technical debt and addressing it down the road when it will require more effort? We've all written code in somewhat silly ways. My experience is that when a peer calls that out before I merge it, it's way easier to fix up-front than a year down the road when I'm in there trying to fix some bug and am wondering if I should just refactor the mess while I'm at it.
Correct. I expect those tests to be developed alongside the code. Part of my 'definition of done' is you have passing tests to prove the implementation is complete.
> Style concerns definitely shouldn't be the primary focus of a code review. Ensuring some stylistic consistency through the code base is a benefit they can provide, but certainly not the the most major.
Agreed. However, I've seen too many toxic scenarios where this is what actually happens.
> How do you know if the tests are complete on someone's work before they merge it?
Everything at the branch point can be tested. Also, since we have tests, we have the ability to regression test and ensure everything is still working properly after the merge.
> Isn't it better to catch code structure issues when they are fresh in everyone's mind rather than taking on technical debt and addressing it down the road when it will require more effort?
Yes. My counterargument though is having a complete set of tests that all pass is far more important than concerning yourself with the structure of the code. I understand that's a radical departure from the state of the art but it stems from years and years and years, nay decades, of enduring counterproductive code reviews. I've sat in on several sessions where there have been long, drawn-out discussions on flexibility and extensibility when 9 times out of 10 it simply didn't matter. I've seen so much time wasted on stuff that ultimately didn't matter.
My take away: make sure your tests are reasonably complete and they pass. If so then you're good. Maybe take a quick look at the code, especially if being submitted by a junior, to make sure nothing outrageous is present, otherwise don't worry too much about it.
Also reviewers shouldn't squabble about syntax or formatting, that what we got computers for to do for us using auto formatting tools. Though it does help if a team converges on a similar style for which reviews are great as you quickly learn each others style and cross contaminate them with your own.
PR's become more of a gate to see if you understand the problem and test for the solution opposed to HOW you went about it. Maybe I've had bad experiences but focusing on HOW is really prone to toxicity. I try to avoid that in PRs at all cost and foster a culture of collaboration, shared understanding of the PROBLEM and Respect for the Constraints. I've left places because of extremely toxic PR culture, so I'm probably pretty jaded :p (The culture was so bad I dreaded asking for reviews.)
How did you prove that your solution works and respects the constraints?? How do you protect yourself and others from future changes? Everything else is an implementation detail.
I've worked in a place where code reviews where treated to just a box to have checked off. There was no shared responsibility for the codebase. And most people had a mentality of "if you approve mine, I'll approve yours". Still it was kept as a "safeguard" by management because for them it was also a checkbox they could mark on their process checklist. I'm happy I left, there is only so much culture a single person can change in a team/company.
They're still working through the maladies of youth, like absolute opinions, rabbit-holing, perfectionism, zealotry, and over-identifying with their work. A young person might need 10 years or more to develop a balance of caring and DGAF skills. And some people stay insufferable forever!
What are my blind-spots? Actively seek and solicit contrarian viewpoints, contradictory to ingrained paradigms. Look for unquestioned self-beliefs, with dedicated time plan and check-lists.
As a personal example, the Lisp legacy has made me reconsider not just memory management, but default behavior when a program crashes, system design and, ultimately, the interplay between mathematics, CS and UX.As a follow-up, the legacy of Douglas Engelbart. He demonstrated the computer mouse, hypertext, networked computers and face-to face conferencing, including shared workflow, in 1968 ![ https://en.wikipedia.org/wiki/Douglas_Engelbart ]. This was not mentioned in popular resources nor courses I took. I have learned a lot from this case, such as what being a true visionary vs marketer means and entails. I would have missed this entirely had I not allocated time and dedicated schedule towards a mindset of actively seeking contrarian view-points and historical perspectives.
Dedicate time to self-review, including value alignment and career goals, according to 1 year, 3 year, and 5 year plan(s).
The bigger picture, such as taking the time to review if the software one is producing aligns with own ethical values, and whether it meets own standards of engineering excellence, can often be muted by the mundane, the daily, and the profane/corporate.In my younger years I worked on a project with a much older guy and he was extremely meticulous to the point where it was really really difficult to stay patient. However, I learned that he did that out of several decades of experience, and that getting the stuff right from the beginning saved us tons of hours of work later.
As a (motivated) beginner, you're expect to fail, and fail repeatedly, and such setbacks do not affect you emotionally. Of course things won't work the first time—the key is to stick with it until it works.
However with experience and "seniority" people develop expectations of themselves: about speed, about best practices, about performance, or any number of other methodologies. Basically, you expect a lot of yourself. These expectations often have the effect of slowing down exploration (i.e. I'm going to do it right the first time) and can lead to negative-valence feelings when things don't work out (e.g. you have an unproductive day, run into lots of bugs, or can't figure something out).
A beginner will be fine with such setbacks because they don't have a big ego, but a "senior" developer will be—literally—hurt by such setbacks, and they shouldn't be. It's all good. Failure is normal. Just get up and try again.
Without quoting the entire paragraph, I'm not sure "C" has ever been the mainstream choice. At nearly every point in the history of C, there has been a "better" or more popular language. Be that jcl, cobol, fortran, visual basic, java, python, php, C#, etc.
C/C++ are systems programming languages, they are the underlying technology supporting all the business and application development. Even when I did less pure system programming, our applications were frequently split into a lower level/server/etc portion and the higher level user facing code. The former was written in a high perf compiled language, the user facing code was generally written in a higher level language.
And that is still true today, it takes very little google foo, to find project after project which decided they needed higher perf/more efficiency and rewrote the core data handling in C. Even in cases where C/C++ weren't the obvious choices (https://github.com/sass/libsass).
And yes, sometimes one ends up picking a chain of subpar languages and rotating them du-jour. But in that direction you get trapped on both some language everyone hates (facebook/php anyone? although to be fair facebook has made php one of the better choices these days) So much so, that if I were to start another mobile application, I would probably use one of the C++ based toolkits. Because those are the only choices that provide good cross platform UI's that are performant. For everything else I would probably just write a web application with decent local storage caching/etc.
So, its probably an unpopular opinion, but as a senior developer, I think the ability to make unpopular choices, particularly when it comes to language and toolkits is one of my strongest attributes. Rarely will you find me picking something like react-native (or electron) for mobile apps because i've yet to see a case were the benefits actually outweighed the negatives. Similarly for native toolkits tied to a particular platform because i've yet to work anywhere that could legitimately afford to double (or worse) their engineering efforts by writing the same application multiple times.
I'm back at implementing web design the same way I used to do them back in 2007. Sure, instead of tables I'm using div + flex and instead of inline styles I'm using utility first CSS. For all intents and purposes it's exactly the same process, with just another coat of paint.
The major difference is that back then in order to write terse CSS I memorized all the short forms, whereas nowadays I'd have to look those up.
I learned a lot with Forth, which is older than me. While that is true, I can't also deny that Rust improves a lot on embedded development and is newer.
While I can argue that using Forth or C is possible and simpler/easier, the lesson seems to be that ignoring Rust isnt a good idea.
IMO its like you can keep using raw CSS instead of the latest hype, but the key is not to ignore and always evaluate new things with the same care as you did to old ones. :) (at least that is how I understood it)
I feel like the basic problems we're solving are always the same but the ways we are solving them are always changing and I'm loving the way we're doing things now as much or more as we used to. I think a lot of people in my age group are more resentful or just resisting change.
I don't buy this, or at best it's only very superficially true.
The Hypertext Transfer Protocol is the same as it ever was. Computer science is all fundamentally the same. The languages, paradigms, editors, and operating systems we all use are decades old.
> Python, what is it? No {} and, it’s optional to use ;? Using indentation is a must??
I think this somewhat proves my point.
Quality typically needs a few years of real world experience, but quality is honestly often an after thought in most companies.
The real value of good senior developers is their ability to make haste slowly. Especially in enterprise organisations.
This myth comes up surprisingly often. I've never met a junior developer that could match my productivity as a senior developer. Not to say they're bad in any way, but I've got literally decades more experience in the tools and technologies they're just learning. Maybe they're willing to work longer hours, but they aren't being nearly as productive in those hours as a senior dev.
Which from a management perspective can be explained as the following: In non tech you buy software and development time, and projects almost always fail to deliver on time or within budget regardless of which company you go with. At the same time, the biggest note on your budget is the upfront cost. Even if you end up spending more by going with these junior exploitative companies in the long run, it’s still easier to justify picking them when you’re talking up the latter, because they charge 3-40% less an hour.
On top of that there are different kinds of productivity. There’s the senior developer who does things right, but non-tech clients don’t give a shit about that, they just want something that works most of the time. Which again is more expensive in the long run, but nobody in management is around for long enough to realise, and or, learn from past experiences based on real data. No, in management you learn with how much praise your project gets, and it doesn’t really have to be sound technically to get that.
Having a healthy mixture is key to building a really strong engineering team. You need an efficient pipeline to ingest junior engineers and staff low-complexity projects, but you also need a solid set of senior and staff engineers to guide projects, drive cross-team coordination, staff high-complexity projects, and (very important!) mentor and grow your junior engineers. Without this, your junior talent will remain junior -- you'll end up with a large group of folks with 1 year of experience repeated N times.
I wonder why?
Do you need to pay 20 programmers rather than 10?
Do you have a higher customer turnover rate because they encounter too many bugs and lose trust in the system?
Do you lose out on sales because you can't close the feature gaps with your competitors?
Are you unable to respond to customer support requests in a timely fashion because there are too many, or fixing the problems is really hard?
Code quality can't make a business succeed. But sufficiently bad code can cause a business to fail.
I recall fixing a major problem where we could not collect any direct debits for 6-7 months and we put one of the most high profile UK tech journalist's bank account intro the red - that made the Guardian.
Neither I or the company secretary ever got a thank you for recovering in todays terms several million pounds.
When you sell software to non-tech companies, they’re used to failures. We have 1 supplier out of more than 1200, who hasn’t screwed up majorly at one point or the other.
In a world where that’s a fact, and people have just sort of learned to live with shitty software and IT that doesn’t always works. The key selling point for any major product is cost, and upfront cost weighs so much more than cost-down-the-line. Especially in management where managers won’t be around 4-8 years later when the contract is up for renewal.
We don't have the same definition of "productive". Extra free hours is not "productive", it's "profitable". More productive means do more in less time.
This is not supposed to be taken as something to be defensive about. Some subset of juniors don't have a clue about the things they don't have a clue and learn as they go, making mistakes along the way that they then need to maintain. Some juniors also compensate by working long hours.
But the thing is that these things are also true for some seniors, just as the opposite observations are true of both some juniors and some seniors. The point is precisely that things are more equal than they are different when you are looking at age demographics and you actually consider that any demographic group has a wide spread in terms of competence, willingness to put long hours, and even experience.
A new scientific truth does not triumph by convincing its opponents and making them see the light, but rather because its opponents eventually die and a new generation grows up that is familiar with it. . . . An important scientific innovation rarely makes its way by gradually winning over and converting its opponents: it rarely happens that Saul becomes Paul. What does happen is that its opponents gradually die out, and that the growing generation is familiarized with the ideas from the beginning: another instance of the fact that the future lies with the youth.
— Max Planck, Scientific autobiography, 1950, p. 33, 97
Informally, this is often paraphrased as "Science progresses one funeral at a time".
It's seeing every tiny bit of progress accompanied by ten steps backward as a new language community re-solves and then re-breaks things that were already figured out by other ecosystems. Most "progress" is just going in circles with NIH syndrome, plus a bit of counterproductive cargo culting whatever some famous company does.
New science is only accepted if it does a better job of explaining old problems and anticipating new ones. Every new tech should have to justify itself in the same way. If it's not giving you a clear superpower over what already exists, it's not worth using. If it does, then adopt it ASAP.
I agree with you here. On my own time I'm just now reimplementing a bunch of audio algorithms in nearly pure Ruby with a DSL just for fun and learning.
But I'm not going to go give speeches about how much better the new way is than the old way, how anyone fighting my code is just a luddite who resists progress and is afraid to learn, and how all the doubters are on the wrong side of history.
What's happening at insurance companies has very little to do with your day-to-day.