Ask HN: Working with a monolithic codebase

57 points by throwaway047292 ↗ HN
Junior dev, about 6 months out of college at a smallish (~20 engineers) software company. Monolithic java codebase that all runs on a single cluster of app servers. I've been feeling frustrated lately and wanted some advice.

The most common comment in my code reviews: "You're reinventing the wheel - we already wrote something similar. Take a look at [X], extend it a bit to fit this use case, and toss what you have." Since X is always undocumented this involves sleuthing + picking senior dev's brains. The process slowly repeats until my feature eventually converges onto a configuration of existing components, with as little new code as possible.

That's great for the business but not much fun for me. It means that to do a task that could be completed from scratch in X hours, I must spend X^(size of our codebase) hours grappling with other people's ideas, solutions, and mistakes. It means my thoughts must be bent to fit some pre-existing shape, which eliminates the need for my thoughts, and suggests they should be permanently replaced with those of my predecessors.

Is this actually the sign of a good codebase? Should I be deriving pleasure from this? Is this what software development is?

50 comments

[ 3.1 ms ] story [ 87.6 ms ] thread
In order of your questions: no, no, typically.
Yes If the current abstractions in the code are flexible enough to be extended, I certainly think so. I've worked on so many projects that were so brittle extension/reuse wasn't really an option, with out major refractors

No.

Yes, you're lucky the current code is flexible enough to be extended, if there is good unit test coverage that's one better. For me, it is crucial to study outside of work and have side projects

To tell you the truth it has nothing to do with monolith. You think if you write it in microservices because that's what's "hip" now you're very wrong.
Besides, the microservices architecture doesn't mean you should re-implement features (like the framework / library type of functions). Microservices have the same amount of code, if not more, than the monoliths they're supposed to replace, and likewise should employ code re-use / not re-invent the wheel as much as possible.
Yea, exactly. Company I'm working with now made the mistake of following the hip. Basically management were crazy about node and microservices.

Went from PHP "monolith" with couple of services to Node.js using microservices. Jesus what a mess, our previous stack was 10x cleaner. Not to mention company now spends thousands of dollars every month for all the new/cool AWS stuff.

But hey, they pay me so I'm not complaining. :)

If your co-workers are telling you that you are reinventing the wheel then you are likely not taking the time to understand the framework that has been developed over time.

You are a junior dev. They hired you to invest in you and grow you. They pay you in dollars, not pleasure. Your day 1 contributions are likely meaningless in the grand scheme. What they want to see is that you can read and understand existing code and that you are a team player. Any code monkey can go in and write functions for validation or logging, but if I am paying you to understand HOW you should do it, taking advantage of the (hundreds of) thousands of dollars of my investment, then I would be pretty frustrated with you if you rolled your own. I would be further frustrated if you disregarded my attempts to point you in the right direction.

You are more likely going to have a positive impact by suggesting changes within the framework they are providing you than creating your own. Learn and understand what the code does and WHY it exists and then you will be able to see what can be improved. Coming in and saying that everything is wrong and persisting in doing your own thing, at your employers expense, will probably leave you without a job.

To satisfy your need to learn and be creative, work on a side project of your choosing. You shouldn't expect your day job to give you 100% of your career development. A large part of it is on you and whether you are passionate enough to invest in your own development on your own time.

If the software is undocumented, then document it as you read it. At the very least make sure that you are documenting your own modifications. In any code base, you are going to need to dedicate the time to learning what that code base is.

Before you do X, you should always ask someone if they are aware whether or not X already exists in the code base.

This is true outside of the work setting. If you are making websites for fun in your spare time, you are likely to spend time learning a framework such as node or django. If you are making games you are going to learn some tool like Unity or an engine like unreal or source.

Imagine if you had a project where you defined 20 different functions for requesting the html of a webpage, each doing something slightly different. Think about what kind of a maintenance nightmare that would be. You are suddenly required to implement a proxy on all requests, but doing so breaks half of your functions. You can't just scrap them, because each has a nuanced use (since you were too lazy to update your existing function(s) to fit your needs).

You would never do that in your own project, but that's exactly what you're doing with this company's code base.

"It means my thoughts must be bent to fit some pre-existing shape, which eliminates the need for my thoughts, and suggests they should be permanently replaced with those of my predecessors."

No, it means your thoughts must bend the pre-existing shape, which eliminates the need to create the shape yourself, since that was already handled by your predecessors.

Your point of view is a lie. Do you program on an OS you wrote yourself from assembly code, in your own programming language, on your own custom built hardware, with no libraries or tooling?

Musicians do not reinvent thousands of years of musical discovery, yet they manage to find immense pleasure and creativity in their work.

If you have done very little programming outside of college, you should see other people's code as a treasure trove of information. Just as musicians find inspiration in other people's songs. My last tip is to revert to pencil and paper when you are having difficulty understanding someone else's code.

I also believe this is primarily a communication issue. It is bound to happen a few times when working in an unknown codebase, but if you feel this is systematic, before writing a single line of code, just discuss with the code reviewer what you plan to implement. It should be a matter of seconds for him to tell you if it makes sense or not.
You just need to chat about the solution before you start coding - which is the normal way to do it.

You: I have the task of X and I'm thinking of doing Y to do it

Other dev: Oh, we have W for that, it might help

You: Cool, I'll check W out

My suggestion is:

1. Let go of your frustration for now, a company is an incredibly complex machine and you need to invest more than 6 months learning how it works before people take your criticism seriously (I know this can be hard). Also, some people like to 'grill' the newbie as a right of passage, you may be experiencing this.

2. Acknowledge that code-reuse is awesome. It's great that there's reusable functionality, part of your job is memorizing the handy tools at a company and if they're good enough, rebuilding those tools later at your next job.

3. It sounds like you're frustrated that you don't find out about existing libraries/functions/classes/tools until your code review. That seems like a reasonable concern. Maybe next time you have a project come up with a rough plan and ask a senior developer for architecture-level feedback before you start coding.

4. Don't feel bad. You don't need to be a hero or change the world. If you mimic the senior engineers and try to fit in that'll go further than studying engineering theory, writing perfect code, or documenting the codebase. Once you're accepted into the group they'll be much more receptive to your ideas on how fix things.

> It sounds like you're frustrated that you don't find out about existing libraries/functions/classes/tools until your code review. That seems like a reasonable concern. Maybe next time you have a project come up with a rough plan and ask a senior developer for architecture-level feedback before you start coding.

I couldn't agree with this point more. When I first started, my team lead gave me a rough plan to add new features so that I wouldn't go in blind. Until I could stand without the support of others, I drafted a quick plan of action to get the task accomplish. This let my team lead know how I was planning on accomplishing the task while allowing them to point out existing code that would take care something I would have written.

It seems like unnecessary overhead, but the 5 minute conversation up front saves more time down the road.

Other people have put it very well here. Welcome to the job. Beautiful code from scratch is for your own time. You'll see that you'll learn this "monolithic" code base over time and that eventually you will play it like a violin and it will be somewhat enjoyable.

If you want to write code from scratch and just blaze forward all the time join a startup. Less guaranteed job security but more fun for sure.

Greenfielding when there's already existing code to do what you want adds bloat and allows for regressions. Using previously-developed frameworks for e.g. validation, can help reduce bloat, and can help ensure the codebase is maintainable for the long run.

Think about it: do you want to have 5 separately-implemented code paths that all accomplish essentially the same thing, or one generic codepath that handles all the reasonable cases?

This is all codebases ever, including all open source codebases. You have to learn the codebase before you can contribute effectively to it.
Sometimes it can be helpful to try and fast-forward through time. Imagine you are writing your own new code. You've got it working well. You've spent some time thinking about it, so you've left room for growth and made it extensible so that next time a new feature comes along you don't have to rewrite the whole thing. Then a new dev onboards and starts redoing things you've already done.

Right now you're the new dev. Yes, you are going to have a lot to learn about code that's already in place. Totally greenfield development is fairly rare. You don't have to learn the whole codebase (almost no-one does in large projects), but it would be wise to solicit input about where you should start looking before writing brand new code for a new feature.

> That's great for the business but not much fun for me.

That's why we call it "work" and not "play." :)

Are you talking to senior devs before writing code? "Hey, I'm going to implement such-and-such feature, I think this involves building such-and-such classes/services/etc., is that a reasonable way to go about it?"

Even with the best documentation, there aren't very many functional projects (either companies or open-source projects) where the expected way of contributing is not to talk to anyone until you open a PR.

I like this. I've been developing for a while and still spitball ideas with my coworkers to see if it already hasn't been done before. Or if my ideas are just plain crazy.
In addition to what everyone has already said about asking before coding and learning the codebase before writing from scratch, you could step up and document these things as you learn them. Not only might it help in the learning process, it will make it easier on the next guy who gets hired.
This is what I was thinking. When I started on my first project, there was already some documentation of the core classes in our codebase, what they do, how they interact, etc, and it was incredibly useful to me as a new college grad. It gave me a direction to look in and provided structure to the questions that I still inevitably had to take to the more senior developers.
> The process slowly repeats until my feature eventually converges onto a configuration of existing components, with as little new code as possible.

Adding less code as possible is good. It means that things are well structured. The speed that you want seems like you want to hack your way through and just increase maintenance time. That is what software development is.

If you feel some piece of code should be refactored and re-written / extracted, then that is another completely different case. Check what is the value and impact on doing it, both short and long term, and expose your rational to your team.

For me the biggest signs of a good codebase is having a clean build system and proper testing.

Well, probably the codebase doesnt have a lot of documentation, and thats why the 'top' engineers always tell you after-the-fact howto do it.

Next time when they point you to it.. Tell them: where was this documented. How can i prevent reinventing the wheel later?

Also ensure that the code that they wrote, is located in a logic location. Often it is not, and thats why its difficult to write in that codebase.

So it can mean two things: bad structured code, bad documentation, or you lack knowledge in the codebase.

One of the important lessons you need to learn is that code is a liability not an asset! All else being equal, from a balance sheet perspective having more code puts the company in a worse situation.

Your job as a software developer is, roughly, to deliver maximum business value with minimum cost, and that includes writing minimum code to accomplish the task. That is what the senior developers are talking about when they're saying you've written too much code.

It does sound to me like they've got a well designed system if you can add new features simply by making a small modification and some configuration to the existing code. As long as it's also well tested and well documented (that may be lacking...), you've got the ideal codebase: one in which you can add large amounts of business value with only incremental changes.

You mention that this is "great for the business but not much fun for me". I think this is a sign of inexperience. Part of what makes something fun is how difficult it is. If something is too easy it's boring; if something is too hard it's frustrating. In the middle we find things fun. The reason writing lots of greenfield code is fun for you is because it's easy. Understanding and modifying existing code is harder, and that's currently too hard so you find it frustrating. You need to push past this stage to improve as a developer. As you get better, it will become easier to work in existing code and will stop being so frustrating.

A junior dev I worked alongside a few years back got quite angry with me when we were facing an "interesting" problem - he was well into thinking how he would write code to solve the problem meanwhile I had googled and found an existing utility downloaded it and demonstrated that it worked - 0 lines of code required....

[NB To be fair I had the same sense of disappointment myself years before when I was quite proud of a package to do CLOS object persistence and a more experienced chap told me there already was something to do that...]

The first paragraph is just plain wrong. Code is an asset.

Edit: Nice to have a comment downvoted, even though what I said is true.

It's kind of like conventional depreciating capital assets like buildings. A building requires maintenance, utilities, taxes, repairs and so on. If your building is too large for your needs, the costs can become a debilitating albatross round the neck of the business. There have been plenty of European aristocracy bankrupted by having a house that was too big.

In programming terms, it's very tempting to say, "this room is untidy, I'm going to build a new one." It's certainly more fun than tidying your room. But this is how you get sprawl and bloat.

Well, you can simply give up ownership rights on the code. If code was indeed a liablity, it would be profitable to transfer ownership to (for example) me.
You can give away your castle with a license indicating that nobody can keep you out, too, but that doesn't guarantee that it will be maintained so that you can keep using it, either.
You're being downvoted because while you were technically correct you completely missed the point and your comment adds nothing to the discussion. But at least you got the satisfaction of "correcting" somebody, eh?
I got that he was trying to say something along the lines of "more code = more maintanance"... but code is simply not a liability. (Yeah, I have a natural urge to correct stuff that's incorrect, but that's not an uncommon trait.)
> One of the important lessons you need to learn is that code is a liability not an asset

I cannot upvote this enough.

(comment deleted)
This is simply not true. If code was an liability, it would be profitable to transwer owenership of it to other people. I haven't noticed any software company doing that.
Maybe not what you meant, but I immediately thought of SaaS. Or various companies' policies of open sourcing non-core software.

Both of those are along the lines of "I need code to do this thing, but I don't want to be the (sole) maintainer."

You could write your own language, IDE, OS, build system, source control, networking library, logging library, shopping cart, payment processor, etc.

That's an overly pedantic use of the word "liability." It simply means that all things being equal, it is better to do $THING in 50 lines of code than it is to do it in in 500.
This is easy to explain when you treat third parties as liabilities as well. For many companies this is a bigger liability than maintaining the code in house.

I recently made the decision to have a third party build a component as opposed to doing it in house. The cost and time to build a component in house vs using a third party ended up being a wash, but the third party offered to maintain and support a solution so this presented less risk to us. This major risk we incurred was in vendor lock-in.

These types of trade offs happen all the time. Think about virtually any SAAS offering that could otherwise be built in house.

In software, there's a whole industry around this: we call it SaaS and/or cloud services. And in fact, it's basically what it means to be a 'services' company. Your customers are paying you to move that liability I mentioned onto your balance sheet instead of theirs.
Great comment. It's a bit hazy when you say that code is a liability and also that they've got an ideal codebase because you can add value easily due to the existing code. Maybe something more like: "new code is a liability, and tested, extensible code is an asset."
In this metaphor, all code (new or old) is a liability and the revenue/value stream derived from it is the asset. As a developer, you're trying to maximize assets minus liabilities. It's okay to take on a liability as long as it's balanced by a greater asset.

But buying on margin increases your volatility and risk exposure, so you shouldn't take on more than you need to. Assuming zero transaction costs, it's always a good idea to substitute less code for the same benefit.

6 months is not very long, so it's not surprising that you don't know what's already available in your company's codebase. That's true whether it's monolithic or not, in Java or another language, on a single server or a fleet of raspberry pis flying around on drones. In fact, assigning you tasks that involve tweaking existing components is exactly what most companies will do in order to get you familiar with the codebase (and style, process, etc) while they they get familiar with you.

* Don't worry if you have to replace parts of your code. That's just part of the process, especially if the existing code is undocumented and everyone knows that. The code reviews are working.

* However, if at all possible, get feedback early in order to skip straight to implementing the feature with existing code. You'll finish features faster, get familiar with the codebase sooner, and hopefully move on to more interesting tasks sooner.

* Document existing code as you discover and use it. This is technical debt that your company needs fixed, and you're in a great position to help with that.

In school you get to write a lot of our own code from scratch with our own ideas, and it's fun. Some developers pump out code by the minute, even implementing the same thing over and over again in their own code; it's fun, and there often aren't repercussions for that in school. But code re-use is good practice. I love days when I produce net negative lines of code in an existing codebase, while adding a feature.

Not every company offers the opportunity to implement your own ideas from "scratch". In fact that's somewhat rare. If this is the only coding you enjoy, you may need a new company, but you may just need to wait a bit longer at your current company. A good advisor/boss will be able to have a conversation with you about expectations (going both ways) for the first and second year. You'll want to find out if your company can eventually provide the kind of projects you want, especially as you get a better idea of what those are.

The problem isn't that you have to use/extend existing code, the problem is that it isn't documented. I'm guessing there is a lack of knowledge sharing between the developers.

Like others have said; instead of writing the functionality from scratch, try to understand the existing code and document it.

> The process slowly repeats until my feature eventually converges onto a configuration of existing components, with as little new code as possible.

In other words: "The process slowly repeats until you know the codebase". Also, less code brings less bugs.

> I must spend X^(size of our codebase) hours grappling with other people's ideas, solutions, and mistakes.

Learning to understanding how other people think is crucial, and its better to learn from the mistakes of others than your own.

> Should I be deriving pleasure from this?

Hopefully, with time. But you are more supposed to derive a salary from it.

NO it isn't a good codebase (can't understand it without talking to senior devs) and NO that doesn't HAVE to be what software development is; but unfortunately, it often IS... try to find work at a startup, or start your own, if you're that unhappy with things; if not, try to learn what you can from the senior devs, and their massive poorly documented codebase. Working with senior devs can be a drag, for sure -- I should know, I am one ;-)
I'm surprised that nobody has mentioned pair programming. You may also try to propose Lunch and Learn sessions where an expert on a particular portion of your project teaches the rest of the team about their area of expertise (how to work in it, architecture, where code is located, etc...). Don't be afraid to ask someone to teach you or a group. Chances are good that multiple other engineers could benefit from the same information.
Pairing helps me figure out large code bases quite a bit.
I'm in the middle of reading "Punished by Rewards" and it's interesting to cast this particular predicament in light of the proposition of that book.

If you're writing code to get the reward of a salary, you're not going to enjoy it nearly as much as if you do it for its own sake! Rather, you'll enjoy less the more you're doing it due to extrinsic motivation.

I'm not sure of the solution, but I suspect you need to cast any of these challenges, whether they are really coding challenges, or rather team communication challenges, as something you're excited (rather than anxious) to overcome and improve your skills at doing. Forget (in those moments) that you're doing it for a salary, but decide that, in order to later improve strictly coding skills, you are wise to currently work on improving your communication skills, your ability to discovering the capabilities of existing code and frameworks, and perhaps your ability to document anything you learn for future reference (for yourself and others.)

> Junior dev

> Monolithic java codebase

> "we already wrote something similar"

Sometimes it's not even them who wrote something. I was working on a Java codebase where decimal numbers always had the separator be a period (e.g. 1.2).

In (most of) continental Europe, the character they use to separate the numbers in a decimal is a comma (e.g. 1,2). So I coded something up to do a location-specific separator.

Woops! Actually java.text.DecimalFormatSymbols().getDecimalSeparator() will do that, and has been a Java core API since Java 1.1.

When I was first learning the ropes as a developer, I found myself in similar situations, and it was equally frustrating (for both myself and my coworkers). What changed was I learned how to separate myself from the code. Programming is a team sport. You're all building a codebase together. And good code should be objectively good so it doesn't matter who writes it. You'll impart maximum value to your team once you learn how to cooperate. That's step 1.

Step 2 is learning how to adopt an engineering mindset. Spend time in analysis and ask your coworkers for feedback on your approach. Critical thought should not change from person to person. If the engineer before you applied critical thought to her/his code, then s/he encountered the same problems and made the same decisions you would, if you also applied critical thought. So spending time reading code and understanding it is a huge time saver.

The critique of re-inventing the wheel isn't "hey you just made a wheel... we already have one of those". It's "hey you spent all your time thinking about wheels and working out all the details... we've already done that thinking and here it is written down. Save yourself some time and catch up to us. We did the heavy lifting for you."

Everyone can write code after 6 months of bootcamp. Not everyone can read code. You're complaining about reading code, which is 90% of what developers do on a daily basis. 10% of what developers do is write code. With of course the rare exception that you're architecting something from the ground up.

If you can write code but you can't read, than I'm sorry to say that you are not a good developer.