This is a common interview question for new coders, and the goal in replying is to show the interviewer that you understand the importance of scalability and maintainability in coding, and that you have experience with techniques and best practices that help ensure these qualities in your code.
CodeNewbies: How would you answer - or have you answered - this questions?
Experienced Coders: How do you ensure that your code is scalable and maintainable? And what advice would you give for answering this question?
Follow the CodeNewbie Org and #codenewbie for more discussions and online camaraderie!
Top comments (25)
Maintainability and scalability are the two holy beasts of software engineering. I really don't believe that even large code houses with armies of skilled and talented people have too much to show on this front. Also neither of them has a be all end all solution on that.
Maintainability means that you have a codebase with little to none tech debt where everyone can jump in and contribute. There are a few things that you might do to increase maintainability, like following a specific coding style and convention across the whole codebase, follow the SOLID principles, YAGNI, and other weird acronyms. Keep in mind, though, that these principles can easily lead down the path of a cargo cult. The best advice I can give for maintainability is to "Always write your code as if the next person who will work on it is a violent psychopath who knows where you live" 😁😁😁
As of scalability, things become even more unclear. We go around and say, "We will follow the X architecture because it is more scalable", then after a while we go like "Let's use the shiny new Y architecture it's more scalable". There are actually at least three dimensions you can scale an app, so there isn't a definitive answer. Again, the best thing you could do is to organise your code in components with a single responsibility or context, and keep them as loosely coupled as possible. But again these are too general guidelines and your approach should be dictated by the project at hand.
I love your answer can you break down the three dimensions for me please
According to Michael Fisher's book, The Art of Scalability, we can describe the scale cube.
This model defines three ways to scale an application: X, Y and Z.
X-Axis Scaling or load balancing requests across multiple instances. X-axis scaling is a common way to scale monolithic applications. What we do here is to run multiple instances of the application behind a load balancer, and the load balancer distributes requests among N identical instances.
Y-Axis Scaling or functionaly decomposing an application into services. Y-axis scaling breaks down the monolithic application to a set of services. A service is a mini application that implements a narrow focused functionality.
Z-Axis Scaling or routing requests based on an attribute of the request. Z-axis scaling also runs multiple instances of the monolith, but unlike X-Axis scaling, each instance is responsible for only a subset of the data. So for example you can split the usernames based on their first letter, with one instance handling requests from usernames between A-H, one for usernames I-P and one for usernames R-Z.
That's a really tough question
I don't think many projects can say with confidence "yeah I have figured that out".
And if they do that could be a symptom of the reverse.
Like they over-engineered an infinitely scalable Netflix-like micro-services zoo
... but their backend has currently 1 request per second.
There are practices you can and should put in place:
But you probably want to stay humble.
Your codebase being maintainable is more a constant struggle than a science.
And, I would add to it, the importance of stakeholder/business side's support!
The point inherent in maintainability of code is that of long-term usability. The folks owning the code must view the code as an investment, which carries an RoI. If that support (may be implicit) doesn't exist in principle and in execution, then all the good design practices begin to look like unnecessary overhead.
How do you identify performance problems?
I am just cursious about your point of view, if the question was "How do you deal if unscalable or maintainable repos in your codebase"
First I would buy and read this book
It's a great book. One of my favourites.
Legend
Follow coding standards and conventions: Adhere to established coding standards and conventions for your programming language. This makes your code easier to read, understand, and maintain.
Write modular code: Break your code into smaller, reusable modules or functions. This allows you to manage complexity, isolate issues, and reuse components across your project.
Use version control: Use a version control system like Git to track changes, maintain a history of your code, and collaborate effectively with other developers.
Write unit tests: Create unit tests to validate the functionality of individual code components. Regular testing helps catch bugs early and ensures the stability of your codebase.
Use a consistent naming convention: Use clear and descriptive names for variables, functions, and classes. Consistent naming improves code readability and maintainability.
Enforce prohibition of writing code comments, the code should be self explanatory.
Refactor regularly: Periodically review your code to identify areas for improvement, remove duplication, and simplify complex logic. Refactoring helps keep your codebase clean and maintainable.
Optimize for performance: Analyze your code's performance and identify bottlenecks. Use efficient algorithms and data structures to improve scalability.
Utilize design patterns: Implement proven design patterns to solve common problems. Design patterns provide reusable solutions that can improve the structure and organization of your code.
Plan for future growth: Consider how your code will need to change as your project grows or requirements change. Design your code to be flexible and adaptable to reduce the effort needed for future updates.
When they ask questions like this, they want to hear keywords like: design patterns, loosely coupled, SOLID principles, etc. But honestly no company I ever worked for had achieved truly maintainable and scalable code... Its the holy grail of software engineering. At most what you can achieve is a basic understanding of the code base among all team members that will live on until the last team member with the knowledge is replaced.
Agree! When I hear people say that they have 100% test coverage, I generally just laugh because I'm sure there are "no-cov" or similar comments everywhere. It's like people way I painted this entire wall brown without using the color blue.
This is a very interesting question. In my experience, one needs multiple 5year span projects under it's belt to answer this question with any degree of insight. Books can also help. It is definitely not a noob question.
I am in a constant battle with these 2. It is very relevant for me. I can give some insights.
Maintainability is the ability of the code to change. Scalability is the ability of having a piece of code run more work.
The point where these 2 intersect is coupling. Maintainability:
In the face of scaling, you could just scale the entire service. That usually only raises eyebrows in your financial department and gets rejected. So analogously:
Buzzwords:
Testing: tho' you need a degree of decoupling to comfortably write tests, it is not mandatory. You can test deeply coupled code. It's all just a matter of setting up your test-rig.
Common standards and practices: there is 100% chance you will screw up your projects with it. SPECIAL standards an practices is what you are looking for. And, obviously, the discipline to maintain them, and the creativity to change them.
S of SOLID: the S is REASON for change. The reason for change is completely different from what a code does. Afterall, there are hundreds of ways to achieve the same goal in programming. The S drives you towards domain partitioning. 99% of 'vocal developers on the web are erroneously driven towards functional partitioning. In the context of serviceable decoupling boundaries they are just simply wrong. You are not selling "redis connection" to your customers, you are not selling "css" to your customers, you are not selling "main menu" to your customers. What you sell to your customers have, and should have the highest number of changes to ensure most optimal satisfaction.
Code duplication: a piece should repeat at least 3 times in the EXACT form before it becomes a (for ex.) library entry. The actual repetition dictates repetition, NOT speculation. And, parallel code is a far more dangerous than tens of thousands of lines of repeating code.
Code comments: use them regularly. A comment like "// filter users based on roles" is the first step towards creating filterUsersByRoles(users, roles). Either create it on your refactoring phase, or pair program it with someone who can. All comments are TODOs.
Legacy code: legacy code is not necessarily bad code. Always consider that your code is the bad code. Translation and some minor refactoring is probably all you need, rather going after the broken systems of a 6 months exp. developer-youtuber driven by vanity. The prime concepts of software development have been here since 80's. All we did for the past 40 years is mostly rename them and call them "best practice".
I would start with the following:
1- Break code into smaller reusable components/functions
2- Follow concise naming conventions
3- Write clear and short comments
4- Ask for feedback, if someone else could understand it, then many will do.
5- Build while you're in a tester mindset.
6- CI/CD tool is your best friend to automatically build, test, and deploy
7- Ask if is it efficient, can I write it more efficiently?
I believe it's impossible to build totally maintainable code initially. First focus on your requirement writing the cleanest code you can as you go, but do not over engineer it before it's needed. Chance are either this requirement is never going to be revisited again and thus you have more complexity than useful or is going to be totally changed in unexpected way and the great architecture you built will be in the way of the new requirement.
Most of the time, keeping the code simple is the most maintainable solution.
The same goes with scalability, don't architecture for scalability before you need it, chance are the boundaries you'll create will be at the wrong place and again in your way.
Lots of excellent answers to this question.
In practice, in my experience...
I tell the PMs that we need to do some work to address the technical debt that had been incurred from the previous cycle.
The PMs prioritize that work. Invariably, it gets prioritized behind all the feature work for the current cycle.
Little-to-none of the technical debt work gets addressed from cycle-to-cycle. New feature work is created which is dependent on the behavior of the technical debt, so that behavior becomes ingrained — it's load-bearing behavior, even though it was unintended and expected to have been temporary.
As the intentionally incurred technical debt accrues from cycle-to-cycle, it becomes a drag coefficient that saps productivity. Or the agile crowd would say it saps velocity.
The developers wallow in a mess, productivity suffers, and the total cost of owning a mess is ignored due to the tyranny of the day: getting the next feature out the door.
The code is "scalable and maintainable" only by herculean and sisyphean efforts. And all too frequently, developers have to rise to the challenge again and again to put forth those heroic efforts.
Once the code is in the bad state, some of the policies mentioned in the other answers are imposed on the developers in order to make things better. But those "best practices" policies do nothing to address the underlying problem that the underlying code base is a mess. Dev resources need to be chartered to transform the long neglected bad code into good code.
unit testing and never deliberate create tech debt. "We will refactor later" is the biggest lie ever.