That coworker who never stops refactoring
critter.blog
critter.blog
Every engineer I know who I respected for this behaviour also delivered boatloads of functionality independent from "improving dev productivity 25%" which kinda makes sense since if you go around refactoring everything you kinda know the whole thing. Also, how do you even know if you've improved dev productivity 25% if you haven't even improved your own functionality-delivering at any rate (which you'd only know if you attempted to deliver functionality)?
In fact, every engineer I know who I respected to deliver boatloads of functionality also had this behaviour.
All of the guys who thought they were this guy but didn't deliver boatloads of functionality were just some wheel spinners who weren't really useful. I'll probably never work with them again if I do my hiring right.
I agree with your general sentiment.
But there are situations and teams where programmers don't tend to have an optimal individual skill-distribution so to speak. Surely there is an opportunity to complement each other to a certain degree.
I guess the analogy here is that Fred who likes to refactor (or write library level code) should also be a user of these APIs.
I guess a well oiled team could rotate positions around but then you tend to lose a coherent vision of what "right" is in any given domain because you don't have domain experts anymore since everyone has to be an omni-tool.
Product people aren't reviewing your code and infrastructure. The manager is responsible for the speed and quality of their team's delivery, so if they have the team devote some time to polishing their tools, they're just using their professional technical expertise to keep things running smoothly for the product folks.
They do need to be good at it - not overseeing a bunch of feel-good but not-actually-that-useful rewriting and cleanup - but that's a question of competence more than responsibility.
It's a very similar thing with rotating people. A manager is going to get into trouble sooner or later if they only ever have the same people work on the same systems. It's the short-term optimization, but not the long-term one. And that doesn't mean nobody can be an expert in an area, but it's bad if only one person is able to work in that area.
A company that wouldn't let a technical manager make the call on that - who works on what, and how much to attention to pay to their tools - may as well have the devs report directly to the product manager. The manager has to stand up for that and not just be steamrolled.
As-if the business side of things has any idea of how long something will take. Refactoring or doing some infrastructure work can just be tagged together with some other bits.
For the business side of things it's more important to know when things will be ready and knowing that timeline.
Further, a manager can explain that e.g. "the car needs maintenance". Business isn't against such things, but if the manager cannot switch from IT-speak to business language then it might seems that the business side won't get it.. but maybe it was the explanation that was lacking.
Especially in sprints I noticed that it's understandable to everyone that not everything is finished in one sprint. Though if it happens to often, maybe just promise less.
To do X feature, you need to clean up tech debt Y.
Tying it to projects means we can intentionally distribute these to different team members.
... It also means that if cleaning up the tech debt is hard, you're project gets delayed for something where you could have found a way around fixing the tech debt.
My own productivity has been horrible lately, so maybe that should be taken with a grain of salt:P
However, working with legacy, you often find techdebt or inadequate architecture/infrastructure mid project...
It really depends on what kind of improvements you are talking about but if someone measurably decreases the time it takes me to land a PR by improving CI/CD systems then its really easy to say that such improvements massively effect developers in a positive way. Also opened ticket to landed code can be looked at more broadly and be measured and optimized, as can downtime.
The other thing I worry about is other team members getting sloppy, because "don't worry, Fred will come clean that up later". For many developers this won't be a problem, but for some it will be, especially when there's time pressure (and there's always time pressure).
"But the customers' needs should prioritize the roadmap!"
Yes, they should, but it should be balanced. Better to have 10x the output, a happy team, and hit a broad surface area of customer value, than a slow, clock-punching team who comes into work being told what to work on by dictum based upon the most high customer demands. A sign you're doing this right is if there is some slight tension between engineers working on what they like, and what management feels is the important thing to be doing. You want that tension, and need to manage it from falling too far to one side or the other.
It often turns out if you have a balance here, you'll see innovation happen as a side effect. Team interests of a smart team often are somewhat far afield and lead to bursts of creativity, and can lead to new forms of thinking that lead to new features. Ensuring the team groks the customers' needs, and their demands, as well as giving them opportunities to pursue their passions, allows them to connect the two together when inspiration hits. Often times to innovate you need to do more than just listen to your customer, you also need someone with an orthogonal interest, knowledge, or talent stack to cross-connect things into something greater than the sum of its parts. Empowering the builders on your team to explore things is a good way to harvest some of this 'innovation space.'
Someone spots the same functionality in two places, applies DRY, then two weeks later a new requirement means they need to work slightly differently from each other and that change has to be unwound again.
I've seen plenty of helpful refactors that broke code in subtle ways (if your tests aren't robust enough this can happen really easily).
I've seen projects take literally months longer because the team hit caught up in "refactoring" code written by previous engineers - not because it needed it, but because the new engineers preferred to write their own code than dig in and understand what was written before them.
Third time? Maybe consider a refactor at that point.
We were looking at a pull I'd created and he asked 'are these things really the same or is it just a coincidence because the features aren't mature enough yet?'. And yes I'd conflated two things with entirely different intents by over-abstracting.
But I do think it falls apart when applied at a more macro level.
The kind of duplication you want to avoid is knowledge duplication. If two pieces of code literally do the same thing but for different reasons/purposes, it may not be a good idea to deduplicate them.
I know that eventually I can move all the identical code out of there to its own service, and replace the 8 services with just 8 simple configuration lists, and that's definitely where we're going at some point in the future, but for now, the 8 times duplication is actually fine. People know these services and what they do, and I know they're conceptually all instances of the same thing, it's just not quite represented that way in the code yet. We'll get there.
It's possible a few still have some exceptions, so that needs to be figured out first, but due to the way the code is put together, there's no rush; people are only changing the parts they're meant to change anyway.
The result made it hard to understand the code, and hard to graft in new functionality. So over time I refactored it to duplicate the code, but each string of code is a lot easier to understand.
I think knuth was the first time I heard of reeditable.
For example I had to recently write some code to center a form shown as a dialog based on the overlying window. Because we use a MDI. I had to take into account local to screenspace coordinates.
Once it was a usercontrol embedded in a form, once just a form and once the top window, etc. All of those needed just tiny adjustments, while rolling it into one function would be MUCH more cumbersome.
Rather you should ask yourself if you want these two functions to be coupled? So that by changing one you are forced to change both. This is very desirable in some cases, but when you don't want components bolted together just copy and paste.
Copying the code - 2 seconds. Copy the unit tests? Another 2 seconds? Refactoring the copy pasted thing that is now in 25 different git repos? Sad face
I'd guess that most devs don't c/p two lines, unless they're particularly slow typers. Or you're one of those fancy vim people that jumps all over the joint with keystrokes instead of having to move to the mouse to select text.
Also, the reason I basically never c/p is because I do it manually. I have a habit of using old code as a reference while I write new code, and the two pieces of code somehow end up being the same. The difference is, I've vetted every single line of what I've written, even if it's a duplicate, so I know it's relevant to the new context I'm working in. If you c/p, there's no requirement for you to mentally check that the new code is all relevent, and correct, for the new context.
Plenty of it is also on managers who simply aren’t competent to manage, of which there is a tragic abundance. If that really bothers you, move up to management and start doing the job better or go find a new job. Otherwise, not your circus, not your monkeys.† Just make sure to keep your papertrail.
--
† Whereas the liabilities for screwing with production code outside your scope of work def should be. Though again, that assumes a management that actually understands what’s going on in its own shop, and isn’t just running around with its hair on fire 24/7.
Even big corporations are open to refactoring when you put it in the context of data integrity and consistency (foreign keys), because data inconsistency causes tickets which cause churn which is a number the CEO reports to the board.
People learn by doing. And after a few such messes, the dev will learn how to do smaller refactors.
I chip away at it in my down time but it's no longer prioritized.
I find in this line of work, you will always seek to find ways to balance business/market needs vs. being a paragon of programming.
In my current project, there are piece of code that I've wanted to remove for months now. I was working on refactoring it out completely, but there's one place that still uses it, and that wasn't so easy to fix as all the other places where it had become unnecessary. It still needs to be done, but there hasn't been any time. Or urgency, really. But it's still there, taking up space in my head.
The code melts and changes for awhile... and then congeals into unchanging rock again.
One project I worked on had almost a half dozen "lava flows" in the JavaScript alone... I had a hard time convincing folks we could rewrite it using ASTs because all the rewrites scared folks away from any further rewrites!
That’s very different to just dicking with the company codebase for one’s personal amusement. That’s the bloke with the dozen rusted automobile shells sitting on bricks in his front yard, while he’s in his shed “busy working” on number thirteen. He’s not productive, he’s just playing with himself. And making the whole place look like trash while he’s at it.
I know this seems pejorative on some level, but I'm trying to paint a contrast here between sensibilities. I think it is worth considering that one person's urgent and long-needed reduction in technical debt is another person's over-engineered. It often comes down to whether the person passing judgement has the awareness of how everything fits together and thus can benefit from a structural tune-up. It could also depend on how many systems and code bases they have had to maintain.
I mean, on balance, we have a really bad track record as an industry of building unmaintainable code bases. Most developers are working on the things they find enjoyable with less regard for making it work well for other developers. I think that the author's remedy of splitting these responsibilities out into separate roles is an indicator of the overall problem. It shouldn't have to be framed in that way to make it palatable to the average developer.
As a developer, you should always want to make the code you work on work well for others, and that includes refactoring on occasion. If you find yourself in a posture where you are always "innovating the new fun stuff" while others are seemingly dragging you down with making it actually manageable, it's time to slow down enough to realize what this means to your team.
By not taking care of your own code so that your other developers find it manageable, you've turned them into your cleanup crew. You need to thank them for being "That coworker" who you find "gold plater, or unproductive, or slow", and perhaps stop building prototypes and calling them done.
Just some food for thought.
In this particular case, it takes like 15 seconds to split those places ... even if you dont remember that they were ever split.
The point is that any engineer who is always refactoring or never refactoring is doing it wrong. All cases require judgement of the specific situation and balancing short-term goals with long-term vision.
That seems to happen when refactorings are infrequent and random, vs. a well-groomed codebase. Of course the well-groomed codebase is a mythical creature.
The problem I see is that if refactoring isn't part of the culture, what tends to be built is a tower of cards that never gets the benefit of hindsight because with each subsequent change, the understanding of interactions decreases, and the fear of breaking something increases, leaving to very narrow cludgy changes that become impossible to maintain.
The added impetus of external schedules just exacerbates the issue until the whole codebase falls over, unless people come along who take on that risk and attempt live brain surgery.
which would take nearly as long yet have more uncertainty.
everytime i see this, which is all the time, it's because engineers are not trained nor managed properly. with everyone doing "agile", and the wrong incentives in place, engineers write code that only lives until the next sprint.
you can't just blame the engineers. you need both sides of the whole to make it work. management has to place importance on quality, and engineers have to learn to write code for someone ELSE to read. (usually themselves, 6-12 months later).
the common, pervasive flaw i always see is the curse of knowledge. engineers write code that they understand, at the time they write it. when i review, i want to see code (rather, comments, for the most part) that don't expect specific and deep internal codebase knowledge. a one-line 10s comment that seems obvious at the time (due to the curse of knowledge), can save 10m later. when poring through the code 6 months later, each of those 10m chunks adds up, very very quickly.
In that case, let Fred focus on improving the unit tests.
That sounds like a board fresh-out-of-school dev. An experienced "refactorist", who knows the risks such as pissing off the other team members who find their memory of the program expired, in addition to pissing off managers with extra latency, isn't going to waste precious political capital on dubious refactors.
Make more your senior devs start the refactor, or better yet, they start them, and junior devs have to finish them. Grueling but useful training exercise.
> I've seen projects take literally months longer because the team hit caught up in "refactoring" code written by previous engineers - not because it needed it, but because the new engineers preferred to write their own code than dig in and understand what was written before them.
I've seen that too.
But a good refactor can also be the antithesis of NIH syndrome: a good refactor means someone took the time to understand the old code enough to safely change it. A slap-on "write only" patch conversely may indicate someone didn't bother to understand what was already there.
It's important to distinguish between refactors that "kneed" the code, mostly moving existing bits around, and partial rewrites that replace one portion of the code with all-new stuff. The former is a lot more trust worthy.
once you dig in and understand what was written before, that's the logical time to refactor. so the next guy doesn't have to spend the time
I have been in teams where we carried out projects, and each project's codebase re-invented a lot of functionality (e.g. converting HTML to plain text, tokenising an English sentence). Of course I proposed a librarian role, which as the article contends is suitable for particular personalities.
In a group of, say, ten or more people there is a room for that kind of specialisation (librarian, sysadmin, statistician, ...).
It’s wonderful. With guaranteed longevity and having internal devs as the customer, things like on boarding are a snap. The documentation is comprehensive and there’s a slack channel monitored 24:7 for questions and onboarding.
Of course there should probably be a toolsmith at the team level, but also at the org or even company level to avoid the re-inventing problem you mention.
Because it implies that Fred is not just doing refactoring, optimization and automation work but also writes new code that others use/interact with (hopefully with sufficient documentation).
Also because I'm often this kind of Fred, sometimes because it is expected of me, sometimes because I just have a natural urge to do so. However with the caveat that I also complete features and projects as is the nature of my work.
In the past I was _too_ Fred-like, but with experience comes pragmatism I guess. KISS and YAGNI are the mantras that keep Fredism at bay.
A simple yet effective technique to fight Fredism when inappropriate is to just write things down in plain $Language and keep going with your feature/ticket/task. It also helps in another way: Sometimes the first instinct is not the right one so you avoid premature optimization etc. by sleeping over it, bouncing it off your collaborators/team and so on.
Maybe historian is a better name though
I try to document (in code) a lot of that "why", so that the answer doesn't need to be passed around as tribal knowledge.
If you need a person around to be able to explain the project architecture, it's probably a sign that you need more/better documentation.
Just my 2 cents.
This has saved countless man-hours for my teams, including myself when refactoring part of the codebase a year or so later, having a nicely written rationale behind some weird-looking code gives me not only peace of mind but a lot of trust in the rest of the team.
Quality doesn't start when a customer comes up with a simple fix/enhancement. Quality comes from people with experience who knows exactly what needs to be done even if it is not stated in a Ticket.
- Security - Maintainability - Usability - Clarity - Performance
You are the expert, NOT your PO. Your PO tells you what he/she needs, you tell them what you HAVE to do.
And personally, i have never heard anyone complaining that someone else did a better job on a ticket than the ticket stated.
And yet they bring so many great ideas to the table that make the product far better than what I wrote up in a story. They make the code better, they ask great questions, they propose changes to designs and features... and we then end up with a much stronger product. The stakeholders love the results we are coming up with, and I'm thrilled with where the product is going, and the devs enjoy contributing at multiple levels and having some autonomy.
I haven't been working for long, but the product manager at my job just tells us the features and the we're free to build it however we decide to.
There are plenty of people writing code in small companies who just never seen or heard it or never experienced the advantage of doing it good/better.
They get a task to do and thats what they gonna do.
There are also Teams in the wild where people get pushed to over a longer time of period because people gave up on them but you don't wanna be the bad guy firing them and there is still an it expert shortage and you might find something new for them to do, you know, people where you are wondering how they earn a paycheck.
And i have seen plenty of experts who just don't have the experience to see certain issues.
Good example are things like: Mandatory Code review (for shared ownership, for quality), taking metrics serious (yes messure what you do), proper CI/CD (no do not skip breaking unit tests...) etc.
I believe, one of my most critical skill for companies is making sure those things are in place or become good. It feels weird to be honest, that those things are so critical and still are not lived as you would assume, or at least i do.
If you have one new feature ticket and one refactoring ticket, don't give the new feature ticket to the developer known for refactoring too often.
> But there needs to be constraints on when to start optimizing and when to stop.
Now that is very true. But feels like a separate issue to me.
I will take this to my team.
I have worked on teams where people don’t know what the code does and the test coverage is spotty. It’s a minefield and only a matter of time before something breaks. It sounds like your refactoring work was a much needed step in the right direction.
There needs to be sufficient testing and monitoring in place to catch problems earlier than production, so that people are not afraid to change code.
Would you be willing to share more details about the specific problem you ran into?
It's like a mountain. The team is dropped half-way up the mountain. The dev that refactors all of the time continues to head up the mountain. It can be slow work. It's a tough climb. Most of the time, devs on the team don't know any better, so they just do the work in front of them, slowly sliding down the mountain. Eventually, they look at the mountain and say "There's no way anybody could conquer that! We're lucky just to get our work done without too many bugs!"
Meanwhile, the refactoring dev reaches the top and slides down the other side. That dev starts looking for bigger mountains. The rest of the team he left behind sink into despair and cynicism.
Eventually, when organizations grow large enough, most everybody lives at the bottom of the first mountain. Devs who leave and try to summit are ridiculed at best, shunned at worst. They're hated if they only go halfway and then fail.
I am of the opinion that most big-organization developers don't actually know how to code. Sure, they know how to type in programs. Hopefully they know enough to test what they're writing. But a real understanding of what programming is? No. Until you've been over a few mountains you don't know what you don't know. Sadly these are many times the folks that get promoted.
But to extend it, consider this. The refactoring dev can’t help but climb every single mountain they see. The product focused dev decides instead they want to climb Everest.
You drop them both in a mountain range in the US. The refactoring dev starts climbing. The product focused dev decides to hop a plane and fly directly to Everest.
Taking a step back from the analogy, not everything is worth refactoring. How much will that code change over time? And what’s the opportunity cost of doing the refactor?
This is only really true in the real world for a subset of brand new startups, where none of the low hanging fruit product ideas have been built yet but the "idea" for the business is very good. Tech-driven work doesn't pay off here because of scale. It's not worth working on perf when your total server bills is in the hundreds or thousands of $. It's not worth working on dev exp when you have < 10 developers. You don't need to refactor yet as it's greenfield code anyway and it's easy enough to glob stuff on to support business ideas ... for now.
If you are working on a sufficiently mature product, there is a fairly high chance that the product-driven feature you are about to spend months on will fail to gain any traction and be totally scrapped. Anyone who has 5+ years experience has probably experienced this multiple times, this happens all the time even at "good companies".
This is because all the obvious low-hanging fruit ideas were already built years ago (which is why the business even has any money to employ YOU as a software engineer).
In more established companies you are less likely to deliver value to users but more likely to deliver value to the business by executing on "tech-driven" initiatives. This is because of scale:
- If you work on perf, cutting 10% of server costs is a big deal when you run thousands of them vs. tens of them - If you work on developer efficiency, improving that for hundreds or thousands of developers is a big deal - If you refactor to support future changes, preventing forced "big bang" rewrites of large established systems you will save the business millions of $ in salary
Found a link to a tweet, which looks like the original source (not sure though): https://twitter.com/KentBeck/status/250733358307500032
so i took some time and consolidated all the sprite geometry code into a bounding box object, and then had every sprite own a bounding box, and have the rest of the code interact with the bounding box where possible. that suddenly made a bunch of other things easier to do, because they came down to "how will this affect the bounding box" and they could be done in a single place.
Don't be Fred. Freds get fired.
Don't be Fred's employer. Set up teams which build tools, maintain developer infrastructure, work across the company to improve code quality standards, and ease the burden of deploying services at scale.
I've been at three different employers on the equivalent of a tools team. It's a pleasure to have fellow developers as my customers, and I understand that my role is integral to not just success, but comfort and peace of mind.
I wonder if Fred accurately estimates his work to include all the quality, longevity and cost reduction work he does but just gets shouted down as pessimistic during their iteration planning?
In my exp re-factor happens when you add a new feature and it does not fit into the existing framework. Sort of a arch version of the rule of 3.
Eventually the "make a ticket for everything" scrum crowd wins out and it's now Fred's fault for refactoring without a ticket. Fred long ago learned that refactoring tickets always mysteriously sink to the bottom of the backlog, so he doesn't make them anymore.
TBH, the Freds I encountered are not really in any danger of getting fired. Because they were the only ones touching all parts of the codebase with their refactorings, they were pretty much walking bus factors.
Exactly this. Maybe Fred understands that if he creates a ticket to do a required refactor then it will never get prioritized and when things blow up in production 2 months from now it's his phone that's going to ring in the middle of the night.
You're spot on, though. I'm currently in a position where I refactor a lot. This is in a team that started with just me cobbling together a prototype, later with two other freelancers. We'd regularly completely reorganise our entire stack, because we were still figuring stuff out. Now it's a team with 7 developers, an actual PO, a separate scrum master and a designer, and I still love to refactor stuff while everybody else is building features. Another freelancer that's still left is our infra guru and he keeps tinkering with that instead of building features, but it's definitely helping the team.
You're right - it's important. But, guess what, most business people have no idea what refactoring means and no amount of explaining seems to get that through. They think it means developers get the equivalent of a paid holiday because of some preconceived notion they had at some other company they worked at.
Unless they wrote code in the last few years - I don't see people ever relating. It's just some abstract problem to them and you never get enough time to thoroughly explain how it all works.
Unfortunately, we're not like a factory. You can't make the retooling argument in the same way and see blatantly obvious results. It's more nebulous.
If someone out there figures it out - I'm sure we'd never have these discussions. They'd say, "Oh, why don't you just use the bradlys argument? He wrote it up on HN some years back and this refactoring discussion has been solved ever since."
"You can go fast when you're rapidly prototyping something that doesn't have to go to production, doesn't have to support thousands of users, is allowed to fall over at any time, and doesn't need to be maintained. You can also go fast when you're working on a well-designed system that is designed to support what you're trying to do. But the moment you start making it do something it wasn't originally designed to do, you slow down, and you risk turning the code into a mess that will slow you down even further in the future. If you want to go fast, let us refactor it now, so it will support the things we want to use it for."
And if they don't get that, maybe they shouldn't be in a position to make decisions about this sort of thing. Though I guess they won't respond well to you telling them that.
As you mention, they don't respond well to telling them that. Their own managers also don't like the implication that they made a mistake in whom to promote. Since everyone wants to protect their own career, nobody will ever step down or revert such a decision, with predictable results for overall product quality.
Be Fred. Get fired.
The art of management is to take that creative energy, skill, and passion and direct it towards generating value for the organization. Top tier teams happen in part because management flips this bit from zero to one for each team member, through leadership, coaching, decision making, and providing 'air cover.' You go to war with the army you have, and the best leaders turn people who would fail under average leaders into superstars.
If this is the person's only flaw, and they're otherwise a great team member, good person, and capable engineer, if they are ultimately fired, that is management's fault, not Fred's.
I hate to admit it, but I'm a Fred. Extrinsic motivation doesn't work well for me.
Yeah, I need to make some money I guess, but I'll make some pretty hefty compromises re: pay and benefits if it means working with an interesting stack or on an interesting problem because intrinsically motivated work is far higher quality for me than extrinsically motivated work.
A common pattern in my career is that my work stands out in some way that causes me to get pulled out of the main grind--and put on some fun special project.
As long as the value you're providing by being a Fred is greater than the value of the job you were hired to do, I find that they'll find ways to keep you around.
I do feel like a Jerk sometimes because I end up getting what feels like a promotion for doing my job poorly, while those doing it well have to stay and keep doing it, but when I buckle down and keep my nose to the grindstone I end up writing shitty code and letting my team down.
If Fred is otherwise hard working, there's probably a place for him nearby.
Don't be in a job that fires Fred. That job is a ticking bomb.
Its not that I'm less productive writing your CRUD application with set of 6 different popular obscure libraries of the week, it's just that when I reach a point where I've spent 40-45 hours doing that, I'm going to report back that it needs more time, because it does. I'm less likely to report back something I love needs more time, because I'm already giving it more time.
So often that efficiency difference you see is me consuming tech debt or cost in the form of personal time. It has little to do with the fact I struggle because I think the work is silly or meaningless and more to do with the fact that I'm not giving 110% if I feel it's meaningless, but you will get 100%. Not slacking on the boring tasks, just giving additional effort on the interesting tasks.
I remember having a coworker ask me for advice on a storage array he was working on. He was banging on the UI, checking out all kinds of irrelevant paths, seemingly exploring all possible ways of accomplishing the task at hand, even the ones that were very unlikely to be correct. I was kind of frustrated that he was spending time exploring unimportant elements as I could clearly see it was one of just two or three options. I tried to brush aside some of the exploratory actions and he said "oh, I know that probably won't work, I just wanted to take a look.."
I didn't have the patience or attention span to wait for this ridiculously slow interface, so I wandered away after giving my best advice.
A couple months later, whose experience did we always rely on when trying to figure out a novel problem? That's when it clicked for me. I won't necessarily have more patience myself with the exploration steps, but I certainly appreciate those who do.
Because the minute Fred leaves, all that work will rot then be discarded. It's better to have Fred work on something that will be maintained beyond his employment.
Automation fails, I turn it off and run the thing by hand. Fred isn't there to turn the automation back on, or yell at me for running it by hand instead of fixing the automation.
We ultimately fired him and got another cofounder up to speed into that role. It was the most frustrating red flag that we should have caught earlier and put a stop to.
The first step in refactoring is writing a test (probably component level at first) such that you can make sure you don't break anything.
Seriously, this is all covered in Fowler's book on refactoring (which is incredibly worth a read).
I really appreciate the author’s attempt here to get into the psyche (developer experience vs user experience) and to find a constructive resolution.
I’m not sure I agree with the conclusion though because I think often the issue is a matter of lacking experience (which takes time) and discipline (which takes practice). Though I’m sure many cases are just as the author described.
1. Adding small features is extremely predictable, in terms of delivery time estimates we give to management. 2. Our bug count is very low, and when we solve a bug it is often small, pervasive, and resolved in exactly one piece of code. 3. The more we factor, the better we get at it, and the easier it is to add new factors rather than new globs that need factoring.
I don't see the promise of "agile" work out every time but factored code delivers like this every time for me.
In my experience so far it is the structuring for maintainability that really shows the skill of the programmer - writing the logic itself is the easy part.
That said people with ADHD tend to have trouble with delayed gratification. Helping your coworkers has immediate benefits when they are grateful for your help, even though long-term it may make things worse. We also tend to have a lot of social anxiety and care a lot what other people think about us (rejection sensitive dysphoria). For these reasons, I believe people with ADHD have learned to be very helpful to those immediately around us, even to a fault.
Fred still has to get his work done though. Have some empathy for him because you don't know what he may be dealing with compared to you, but it's not an excuse.
I've managed to strike a deal with my manager that I get to spend 25% of my time working on reducing tech debt and other smaller fixes, and the rest on primary product development.
It does not show enough details for us to know whether Freds refactorings are needed or making codebase worst. It is sort of Rorschach test where we are supposed to pick a side and then fight among ourselves about following two questions:
Question 1: "is the refactoring you never seen on the codebase you have no idea about by a guy that is despised by his team" good or bad?
Question 2: "A guys is disliked by his team. Is he right and team is wrong or other way round?"
The only correct answer is "who the hell knows but damm start managing that damm team".
Sometimes other people do that too, they just need some guidance that it’s okay to do that and then throw it away. The important artifact you’ve created is a deep understanding of the codebase.
The feature pods outpace the refactor pods. Feature pods can use a bad pattern 50 times in the time it takes refactor pods to fix 10 of them. Not every fix can be scripted. Some bad patterns restrict the ability for the codebase to stay up to date on dependencies, etc. Lots of reasons not to accumulate this stuff faster than you can strip it off.
It also impacted team cohesion, as refactor pods started to resent the poor quality of feature pods' deliverables. Since refactorers are peers, it got weird when they exerted refactor pressure on feature devs who got wedged between their peers and their managers.
Ultimately I think this article is a little too black and white. The "just do the ticket" dev is as undesirable a teammate as the "refactors to excess" dev. It's better if devs are a little of both and the team culture helps everyone keep a healthy balance.
I love the project I'm currently on, and that's probably because for the first time since I've gotten good at this, I actually get the freedom to do it.
Would it be better to just build those features quick and dirty? Maybe. Certainly for the first few weeks or months. And then the code starts turning into a mess, and somebody needs to clean it up, and apparently that's what I love.
The idea that he might be good at the plumbing doesn't mean he wants to do it.
There's also the danger that you end up with endless churn in your plumbing, testing, etc, tools instead.
I get the gist of the article, but sometimes you have to face the hard reality that there's a bad match between a team's needs and a team member's desires.
You end up with everything having dependency injection or one service that has been churned on 15 times. I haven't seen it yet where it's general plumbing fixes.
> That coworker who never stops refactoring
to this:
> Fred is more interested in providing value to other developers than to users.
is not so clear to me, while the article assumes it to be self-evident.
I personally like refactoring even though I work on the codebase alone. I do it because refactoring allows me to ship features faster (in aggregate), and allows me to create a better overall experience for users. I care only about the end result for the users, and this necessitates that I keep the code clean and succinct.
- Keeping his coworkers sane (barely functional codebases that are difficult to work with have a way of killing morale) - Having an intimate knowledge of the code base that can inform future feature work - Paying down tech debt that's generally uninteresting to more feature-oriented coworkers
Having a whole team of Freds is probably not a good idea, but having one in a senior engineer or tech lead role is really useful.
The old way, inspired by bridge building, I guess, was to first thing out a great design for your software, and then implement it.
This turns out to not work because, unlike bridges, software is always changing and needs new features.
So in agile, you just write the simplest thing that can possibly work to solve your next task. Then, when things work, you refactor the code to have a good design.
Designing something after it's built is a mind bending concept, but it's made possible by what we make being just text in files, not set in stone.
My company once decided to use dependency injection, everywhere, everywhere, and for anything. The code became a needlessly orchestrated nightmare.
Now any refactor to make my code solve a generic rather than specific problem — and I’m making the codebase bigger in code and number of files — gives me pause for thought.
The more abstract something is, the further away from specifics it is, and sooner or later specifics change, and those changes break your happy abstraction.
Just using an "abstraction" doesn't mean that your code is abstract, it may just not be a tangle of functions that were stringed together on the fly.
At least for me, there's a clear point where I've coded something and find myself getting overwhelmed when making changes or trying to bridge the final gap to completion. That's when I step back and try to make sense of it and refactor.
It’s underappreciated that developers have different strengths and interests and could be doing different kinds of work rather than being treated as interchangeable workers, even at a relatively small start-up, in my experience.
If you stop repeating yourself, you may make less mistakes because there are simply less chances of it. Good abstractions help.
They also speed up your development speed, accelerating you towards your goal instead of coasting.
I often write something and don't look at it for a long time thereafter; In the intervening period, I forget some important aspect of how this code works. Or I inherit a piece of code from another developer, and I have no idea why it was implemented the way it was.
I would love it if developers wrote a line of comment or two per function, just laying out what's happening and why the code was written that way.
The idea of what is correct (to you and to others) and what needs refactoring changes over time, even the product changes. Sometimes it can be beneficial to wait a while and see if you still feel the same way after a few weeks.
Group 1 year 5 years Gain
5 product 3.3 403.4
1 tools, 4 product 3.2 392.8 -2.6%
6 product 3.5 492.7
1 tools, 5 product 3.3 501.0 +1.7%
Now, obviously the team probably won't stay 5 engineers for 5 years, but my point is: like everything else, this is a cost-benefit analysis. For small teams, it turns out it's not worth it to have happy Fred on your team, and you should let him go work on internal tools for a few dozen engineers where he can have massive impact there.While there's certainly something to be said for assigning people responsibilities that work well with their personal strengths, that won't compensate for misunderstanding the purpose of refactors, how and when to apply them, and how to prevent the need for them in the first place. It's essentially hiding the problem rather than identifying the problem and introducing a relevant solution.
Whether that pressure is provided by regular developers, or partly or wholly by dedicated people, depends on the interests and skills of the people on hand. Carving off a Fred is one successful strategy. So is having core developers actively maintaining the integrity of the overall system as they make changes.
You have to pick, or stumble upon, the right strategy for your situation and staff.
Which isn't to say that the rest of the dev team can't do any of these things, but the tech lead is almost always the most experienced dev, and a lot of the DevOps type points aren't concrete ticket items, and a ticket which basically says "Explore [X] to see if it'll help" is (a) potentially too abstract for a very green dev and (b) the tech lead is probably best positioned to judge whether there'll be any meaningful help in practice.
Background/Goal: With a larger userbase, we would like to add a moderator role. Users with this role would be able to hide posts, but not have any other elevated privileges.
Suggested Implementation:
* Add Moderator to the UserRole enum
* Split the post hide/deletion privilege into two separate privileges
* Associate the post hide privilege with Moderator and Admin roles
* Associate the post deletion privilege with only the Admin role
But a "improve the deploy process" ticket would probably look more like:
Background/Goal: Deploys currently take fifteen minutes on average, from start to finish. We would like to cut this down if feasible.
Potential Lines of Inquiry:
* Can we build things in parallel?
* Can we add more CPU/memory to our build environment?
* What would implementing blue/green deploys look like in terms of cost and benefit?
Comparing the two, you can see that the second is a lot more abstract--and maybe this is just me being bad at ticket writing!
Having one person be the point person for refactoring, tech debt and code review on the other hand seems like a bad idea - these should be every developer's responsibilities. This sounds like a pretty silly team overall - all the team members write quick, messy code and then one person is on "cleanup crew" fixing bugs and improving design?
Talk about a way to brew up some tension and misalignment on a team. "Hey George... I know you are about to open a 2nd pull request to add additional features to your work, but I just refactored your whole initial implementation, and now there are 30 merge conflicts..."
We always talk about the bus rule at work - if someone got hit by a bus tonight, would the team be able to operate tomorrow? If we had "refactor guy" on our team though, I probably would have to resist not giving them a gentle nudge forward every time we wait to cross the street together.
A co-worker initialized the project with CoffeeScript and Flummox, then switched to ES6 and then switched to Redux.
It was a few thousand lines of code, so it was often "Yes we can add that new feature when I did my refactoring" which often took weeks in which I couldn't do anything valuable.
Also, the bugs that grew of those re-writes followed us for months.
Fred may be helping, he may be helping in an inefficient way, he may be doing 'make work', he may be screwing things up.
It depends more on the materiality of the outcome, not the motivation of the effort.
It should go without saying that I think refactoring is super valuable. The way to go about it is to: 1. Recognize what in the codebase you see an opportunity to refactor 2. Discuss with the team (more experienced developers can have some useful suggestions) 3. Write a separate ticket for the changes (you can prioritize this after your required work)
Obviously, #3 won't work if your group doesn't value refactoring. In that case, you should bring up the conversation. You'll probably find many/most of your coworkers will be in agreement.
Another perspective, if I am busy building out a feature and I open my source control to several huge PRs containing trivial changes, I groan. Now, not only do I have to respond to these PRs in a timely manner, I have to ensure that the changes are part of a codebase's design roadmap.
Large refactorings should be discussed, agreed upon and expected. Breaking a several thousand line module into a folder containing separate modules is nice and a welcome endeavor. I just don't want to see it as part of a feature PR. Discuss it and create a separate PR.
Also, just because you refactor, doesn't even your refactor is good. You can refactor in a worse off way as well. Your refactor may make the codebase nicer now, but could prevent easy changes later. Your refactor may go against best practices. I have seen this from developers that are on the Dunning–Kruger spectrum. Once again, refactors should be discussed and agreed upon.
As a side note, this seems like a great interview question to determine cultural fit. I do not want to work with a "fred" that doesn't communicate concerns and intentions.
Similarly, "refactoring and managing tech debt" will become "rewrite from scratch", and "automating anything that can possibly be automated" and "streamlining the deploy process" will be inordinately parameterized in order to cover every possible (and hypothetical) edge case.
Architecture design is to me a different beast from simply refactoring, because it is also meant to anticipate future evolutions, in order to provide a solid technical layer upon which feature can be iterated.
Unfortunately i don't think a lot of teams knows when is a good time to seriously think about the time to (re)design / architecture a system. Nor what is truely meant by "architecture" ( hint: no, it's not just about picking the latest MVC variation of day).
Refactoring and tooling work make sense if that work is oriented towards increasing productivity and maintainability, using contrasted personal experience, and skill.
Do you envision being done at some point? Are you getting a actual productivity boost with your meta-work? Are you solving problems proven to be actual problems from previous experiences?
If not, it's better to introspect.
Programming langauges and IDE's have an effect too in my opinion. I've found myself and other team members refactoring much more when using OOP languages. Design is very subjective.
When you're a hammer everything looks like a nail syndrome?
I said fire because it reminds me of a coworker who was very lazy. He complained about code (yes it was messy) but he was extremly slow in delivering. Simple tasks took 5x the time they should take and the refactoring wasn't that good. I mean 2x the time might be ok if you improve stuff. But no way a 5x delay. Especially in a large project, if there are some really messy things, you need to talk with other devs to decide on architecture and so on. It's no way a one man show.
I hate shitty band-aid code. I love perfection.
I'm Michelangelo - but that by definition makes me a loner. I love staring at my code and contemplate on it's beauty just like the result of the code working.
I'm perfect at one-man projects.
I hate processes, standups, scrums and all that team playing bullshit.
I love customers and bosses who are trusting and freedom giving.
I love beers, steaks, good food and team gatherings - and i love people whom i am "working" with - but everyone knows i am working on something that is NOT "let get this shit done quickly and push this out of the door by next friday". That's not me.
Although I'm the one my boss comes to with "i don't know how but can you do something about it tomorrow"? I'm good and super sharp focusing and delivering on my own. If i need help - I'll ask.
I'm all for skunkworks.
I debug my code myself, using techniques i polished myself over the years and I'll end up with lightbulb that will last 100 yrs. Not the one that cost $3 and requires full replacement after 3.5 weeks of light usage.
I try not to buy stuff made in China. I love stuff made in Europe or Japan.
So, don't push guys like me into your "processes" and "change managements" wasting pipeline bullshit.
I won't fit.
I speak at conferences. I do evil harmless things. I violate countless stupid compliance rules. I take risks no one knows about. I don't follow rules, and pretty much skip reading them when i can.
I do my best to deliver masterpieces. One piece at a time.
Downvote me.
true master carry no sword
The worst part about manifestos like this is when they enable people who think they're this good when really they are subject to the Dunning-Kruger effect.
That said, I could only nod along with the first half of your comment - the rest started to get a bit condescending.
I mean, you do you - if this working style works for you, that's great! But I think you can still work on your craft and be a perfectionist while appreciating how others want to work as well.
I do really like that analogy, of artisanship or craftsmanship. I understand the business need to move quickly, but over time I've found myself more intrinsically motivated by building what I think of as well-designed systems. That, to me, is art. That's what I get excited about. I'd also like to think that some of the extra time I spend upfront is saved down the road when things don't break. I think great engineering cultures respect that balance.
Me too.
But art without constraints is boring. What gets me off is building the most perfect well designed system possible within the constraint of shipping things that solve real problems for real people and the business.
We need more artisans in the world.
Also, I would add:
I love clean code and auto-linting via perfectionist code rules that also auto-realign code to my standards of beauty.
I love using vim because it fits my self automation behavior and I've optimized it so much that I cannot use any other IDE without breaking things.
I am a Linux guy and I hate it when coworkers are too stupid for utf8 encoding.
I love tabs, not spaces and I don't understand it when coworkers are not able to setup a simple editorconfig file, hence integrate it in their "IDE".
I love working during the night because nobody is standing in my door while asking me whether I got that email two minutes ago.
You sound like a jerk. Team-mates not understand something is not an excuse to call them stupid. If you truly love something then usually you'd want to share that love with the uninitiated.
Your not sharing it in a way that's understandable?
People learn and think about things in different ways. An explanation for something that's clear to you might be gibberish to me. Continuing to explain it to me in a way you understand doesn't really help me.
In my experience, people develop a better understanding of a particular concept if they take the time to figure it out for themselves rather than relying on someone to explain it to them.
The person might not be able to figure it out on their own. That doesn't mean they're dumb; they just missed a particular intuitive leap that was easier for you.
The person might dive into it and learn it incorrectly. They might find something on the internet that seems to make sense, but isn't a good way of doing it. Then you have to clean up the mess their imperfect understanding caused, plus help them unlearn the wrong thing.
I think the best bit is somewhere in between. When learning something new, everyone should do some of their own research and self-teaching. But having someone knowledgeable to also teach can be essential, and if someone like that is available, I think it's wise for a self-learner to at least check their understanding with that person, early on.
I'm sure the project management guy hates it when his coworkers are too stupid to think of planning and deadlines.
I'm sure the product manager guy hates it when his coworkers are too stupid to think of users and use cases.
Engineering beauty is when form follows function. A hundred year bulb that will only be used for 5 minutes is ugly and imperfect
One that lasts 3.5 weeks is still ugly, but one that last 20m +/- 15 is beautiful, and one that lasts 10min +5/-5 is a masterpiece. An engineer still wants a safety factor, after all
This must be the most incongruous part of this post.
Probably the ideal thing for me is to do a project where I am coordinating with others but they are working independently, like microservices for instance where you can look at the back end and say this looks like crap let me tear it up without blocking anyone else's progress.
So I'm surprised by the assertion that that sort of code perfectionism is good for one-man projects, but to each their own.
I feel like the only thing you are actually good at is working by yourself because participating in a society seems far too difficult for you.
People further up the top of the hierarchy take the economic output of the ever decreasing number of work horses while contributing nothing but talk.
It is a humble observation, even if it was difficult for me to appreciate for such a long time.
It goes both ways: I hate shipping ugly code, which makes me a slow coder. On the other hand I love spending weeks refactoring pieces of code which will have no repercussions on the end user but will make life easier to the rest of the team.
I've also been accumulating home-made scripts for debugging and such for the last 10 years. The fact that I made them makes them more powerful.
It's not usually a choice between, leaving the code as it is (and just adding a bit of functionality), or refactoring to make it better. It's usually a choice between making it worse, or making it better. So the developers who aren't Fred, are making things worse. I try to make refactoring and keeping the code clean part of every team members' job description. It's often hard to get the business to schedule time for this sort of thing, so it should just get built into the time for each task. As for automating tasks which could be automated - seriously, if you have developers who are not doing this, then they are the problem, not Fred.
I humbly submit that you have been exceptionally lucky in that case, unless you're quite new to the industry. We've had problems with dogmatic developers and architecture astronauts for as long as software development has been a thing.
In the 1990s, they were the ones trying to shoehorn as many design patterns as possible into every OO project. There was little evidence that doing so made the code better in any material way, but that didn't matter, because Design Patterns Are Good Things.
In the 2000s, they were the ones adding lots of artificial complexity to otherwise reasonable designs to enable their preferred test automation tool to hook in everywhere. There was little evidence that enforcing these rules universally actually improved quality or saved time, but Everything Must Be Unit Tested.
In the 2010s, they were the ones refactoring anything with more than five lines in a function or more than one level of nesting. There was little evidence that this improved any important code metrics, and even some evidence that it actually made things worse, but the longer or deeper version violated someone's arbitrary list of Code Smells That Are Bad so it had to be fixed.
A recurring theme here is taking the essence of a reasonable idea that might be useful in some circumstances but then applying it with an absurd degree of rigidity and scope without regard for the cost-benefit trade-offs being made. XP advocates even made this the centrepiece of their philosophy, though XP was born out of a project that was hardly a great success...
Good for you, but change management saves my time more often than not.
First observation... This stance only works if you’re so talented that you can succeed without outside help, and you have a boss that respects your value and can take ownership of building bridges for you. Those bosses are rare.
Observation two... Building bridges and helping others makes it easier, not harder, to get things done.
Observation three... Some people who take this stance aren’t worth it. Many folks take this stance to purposefully close their ears to ideas that could be useful.
Observation four... The person referenced in the article is someone who can be a huge net positive in building developer tools.
This contrasts sharply with professional software development, where you are building software for a purpose and often within a specified budget and timescales. In this case, you can't be selfish any more, because the whole reason for what you're doing is to satisfy the need of someone else. Processes and tools that you can happily ignore on your fun projects become relevant. Being unwilling or unable to work effectively with other developers or with people who have different roles on the project team makes you almost worthless. Taking risks that no-one else knows about becomes a danger to the whole project. Your goal isn't to achieve perfection, it's to deliver software that meets the requirements, on time, on budget, to an acceptable standard.