7

Whenever I write a piece of functionality from scratch, it's a good and robust code.

But often times my assumptions about how the code should work evolve over time. After I reflect those changes in the code, the whole system suddenly loses its quality.

It seems to me that the best approach is to drop the old code and write a new one from scratch with new assumptions in mind. But from obvious constraints in time I wanna learn how to keep the code quality high while heavily changing it.

Question: Are there any techniques or books that could help me develop this skill?

I see how code review is a good tool to uncover issues in code and I agree. But I'm interested in preventing those issues from happening in the first place and developing the skill to do that on my own without involving other team members.

PS: Please don't confuse this with refactoring, which is meant to change the code, while keeping the behavior the same. In my case when the requirements to the code change, it's obviously not refactoring and involves changing the behavior.

8
  • 2
    How do you measure the quality of the code? Commented May 29, 2017 at 19:53
  • Bugs, presence of unnecessary code, that was needed before and isn't need after the change, code reduncancy, bad abstractions, etc. All kinds of bad things. Commented May 29, 2017 at 19:58
  • Are you familiar with tools for static analysis? They could help you to look at the "quality of the code" from a objective point of view Commented May 29, 2017 at 19:59
  • 10
    "Please don't confuse this with refactoring". Well, you wrote after you changed the behaviour of your code to implement changing requirements, your code becomes a mess. Well, at that point in time you are then in a situation where you have to clean up the mess while keeping the (newly added) behaviour the same. And you already know how that process is called, you mentioned it. Commented May 29, 2017 at 20:03
  • Take your time, start over if you need to. Commented May 29, 2017 at 21:13

9 Answers 9

12

What are the techniques for keeping the code quality high when requirements change?

Have you tried Test-Driven Development? It's exactly for this purpose. When you're done with a feature with TDD, you don't just have the feature, but also all the automated tests that cover that feature. As new features or changes come in, you can run these tests and be sure nothing broke. This will aid you in safely improving the structure of the code, before and after implementing changes.

Which leads me to the second point:

PS: Please don't confuse this with refactoring, which is meant to change the code, while keeping the behavior the same. In my case when the requirements to the code change, it's obviously not refactoring and involves changing the behavior.

As you said yourself, the issue you're facing is that code quality degrades after each change, so eventually the codebase will require refactoring, otherwise you may reach a halting point in productivity. There's no escaping it.

However, perhaps you meant simply that you don't want answers such as "Just refactor the code", which is fair. But this is exactly what your question is asking for here.

Also, an answer to this question could not be complete without a Kent Beck quote:

When faced with a hard change, first make it easy (warning, this may be hard), then make the easy change.

To add a bit of context, when Kent Beck says "first make it [the change] easy", he's talking about refactoring the current codebase to make it more welcoming to the new requirements which we now need to implement.

12

Whenever I write a piece of functionality from scratch, it's a good and robust code.

We all think that at this point. We're seldom right.

But often times my assumptions about how the code should work evolve over time. After I reflect those changes in the code, the whole system suddenly loses its quality.

Well no. It never had quality. If it had you'd have been able to change your assumptions easily. Quality is more then satisfying today's requirements.

It seems to me that the best approach is to drop the old code and write a new one from scratch with new assumptions in mind. But from obvious constraints in time I wanna learn how to keep the code quality high while heavily changing it.

If you simply can't write flexible code then a rewrite is the best. Certainly better then half mutated code that is still trying to satisfy requirements that no longer exist.

Question: Are there any techniques or books that could help me develop this skill?

From the development point of view this is agile. Waterfall doesn't react well to lots of unplanned and emergent changes. Right now agile is the best we have for this.

From a coding point of view the best principle for this is single responsibility. Each module should have only one, preferably unique, reason to change. Make your decisions in one place. Don't spread them around. Follow that from the start and change won't be so traumatic.

I see how code review is a good tool to uncover issues in code and I agree. But I'm interested in preventing those issues from happening in the first place and developing the skill to do that on my own without involving other team members.

Code review is mainly a check that your code is readable. Definitely worth while but it won't guaranty everything. Others may check your design and implementation but don't lean on that.

PS: Please don't confuse this with refactoring, which is meant to change the code, while keeping the behavior the same. In my case when the requirements to the code change, it's obviously not refactoring and involves changing the behavior.

True. Refactoring changes design. You need transformations to satisfy new requirements. Guess what? Refactoring allows you to change old designs that didn't anticipate a need to accommodate change into ones that do. Once you have that you're ready to write new unit tests that reflect your new needs and can make them pass.

We don't recommend books here but this answer has enough buzz words in it that you should be able to find some now.

2
  • +10 for your first statement Commented May 30, 2017 at 8:59
  • "Code review is simply a check that your code is readable." I personally believe it's a bit more than that. You should take the time to understand the architecture changes and if what was implemented is actually the best way to do it. Code reviewing is just the process to manually ensure that contributions making their way to the main branch are up to the quality standards of the project, and IMO this includes reviewing the architecture. Commented May 30, 2017 at 13:08
3

Bugs, presence of unnecessary code, that was needed before and isn't need after the change, code reduncancy, bad abstractions, etc. All kinds of bad things.

Adhering to your description of quality of the code, seems reasonable to me to introduce static program analysis in the project's lifecycle. No need to mention that tests are a must (unitary, Integration, functional, end-to-end,...).

The metrics supplied by the static analysis are fairly good at describing objectively the quality of the code in the terms you have expressed.

Sometimes, the analysis can teach you about doubtful practices you didn't know.

What the static analysis can not say is: how good/bad is the design, how bad/good is the model or how efficient or inefficient is the system. At least not the tools I know.

The process can be enhanced introducing programming techniques like peer review or pair programming.

Getting involved one more developer (or two...) makes a big deal better the learning process. The contrast of point of views, skills and knowledge may help to improve those points the static analysis could not.

But I'm interested in preventing those issues from happening in the first place and developing the skill to do that on my own without involving other team members

Regarding to your skills, preventing is a matter of being aware. Developing skills is a matter of time and practice.

It seems to me that the best approach is to drop the old code and write a new one from scratch with new assumptions in mind. But from obvious constraints in time I wanna learn how to keep the code quality high while heavily changing it.

I don't know if It's best or just desirable but I tend to think alike. The time is a relative constraint. In some cases the goal worthwhile an extra effort, overall when the goal is practice and self-improvement.

1

Question: Are there any techniques or books that could help me develop this skill?

Absolutely. The number one, go to book for maintaining code quality while changing the design is Refactoring. It describes a process for taking what you have and changing it to what you need while all of the time keeping an operational system. By combining the refactoring methodologies with test driven design and a functioning version control system, you gain great power over the code.

Rewriting from scratch is something I used to do a lot. While very tempting, there are a lot of reasons for not doing it. If you start with the code you have, you already have a working system, a testing structure, and a suite of tests that allow you to know the health of your code at all times. By refactoring your existing code, using small and large refactoring steps, you find that you are never more than one or two commits from going back to a working state. This give you great freedom to explore the solution space.

1

Yes, perhaps the majority of writing about software architecture is really about writing code which is adaptable in the face of requirements change.

If you think about it, most design principles are pretty irrelevant if the code is never going to change. Why even have readable code if you are never going to look at it again? Following principles like SOLID only really pays off when you have to change the code.

Some important principles to that end are "separation of concerns" and "single responsibility". The objective is to separate the code into units such that a single requirements change will ideally require changing a single class or module. The flip side is the YAGNI principle, which says you should not try to predict and prepare for specific requirements changes which you are not sure will happen.

0

You should ask yourself why your requirements are changing so heavily so often. Is it that maybe you did not understand the requirements properly in the first place and write code to build up this understanding? In that case it makes sense to build one to throw away and then build it right the second time. But even more sensible is understanding the requirements before writing code. Think about the business problem being solved, and then model it at a conceptual level. Who are the users, what are the flows that they will take through the software, what are the types of objects they will manipulate, which actions exist on those objects, what are the data flows in the system, etc... You want to pass your ideas by users, or people who understand the users, with mockups and prototypes.

With a proper understanding of the real world problem being solved I find it is rarely the case that you need to make massive changes to the requirements. You may need to extend them, or tweak smaller points, but big changes won't happen as long as the problem itself remains unchanged.

3
  • 1
    In the real world, requirements change over time. It is inevitable. Commented May 30, 2017 at 15:04
  • 1
    In some domains, but not in those that have to comply with standards or standard practice. For example, I have spent a decade working on and off on a room reservation system. The business of booking meeting rooms is almost exactly the same as it was 10 years ago. The rules are mostly unchanged. What has changed and caused rework is the UI, but the UI is decoupled from the business logic and in fact is rewritten every time (windows app, web app, mobile app, chatbot, etc...). Commented May 30, 2017 at 20:16
  • 1
    @JaquesB, it may be more accurate to say that the understanding of the requirements frequently changes over time, or that small changes in requirements may require a total reworking of an existing brittle implementation, but I'm with JoeriSebrechts in saying that the vast majority of business problems are solved, and either do not change much, or there are standard trajectories of business evolution which should be foreseen and accommodated. The vast majority of developer time is spent simply reinventing the wheel. Commented Aug 23, 2019 at 9:59
0

But often times my assumptions about how the code should work evolve over time. After I reflect those changes in the code, the whole system suddenly loses its quality.

Just looking at this old question, I think this idea that a design loses quality when adapted over time in a partial but non-local way, is an outcome familiar to many other professional fields which incorporate either significant amounts of complicated design work and/or complicated building/manufacturing procedures (that require practical experience, and often many rehearsals of doing tasks in a fixed sequencing, for a worker to perform correctly).

In software, the loss of design quality ultimately arises because of a desire to salvage something of what exists, or to keep the software in full operation at all times, which leads to obvious seams or compromises in the design integrity of what is installed new.

Often, there are also signs of transitional arrangements that got things from the old way to the new, or remnants of the existing design (like naming schemes in source code) that were adjudged too troublesome/costly to improve at the same time.

The alternative to accepting partial refits of the design that lead to a loss of quality, is either to review the refitted design in its entirety, or to rewrite everything from scratch.

However, the initial development was often a serious intellectual effort, perhaps taking many years of working time to process all the details. Both a global review of the refitted design, or a total reconception and rewrite, must also be on a similar scale.

The need to cover such a large amount of ground at once means developers risk becoming cognitively exhausted, when the original development was more likely delivered in stages rather than as one big heave, or otherwise punctuated for various reasons.

To avoid exhaustion in a review process, developers may also be tempted to rush through without the serious detailed engagement which the design received the first time around, so that an inferior design is still the outcome anyway.

The amount of return on this review effort, either as perceived internally by the developer, or as perceived by the employer, is also tiny compared to when the original design was being conceived. The prospective benefit of all this effort is not a new design. It is not even the achievement of a working refit. It is merely the restoration of overall design quality that would otherwise be slightly impaired by the refit.

Surprisingly it can also often be very much more complicated and demanding to review an existing design, than to proceed from first principles on a completely clean slate. This is because, with a review, almost all work ends up being a comparative evaluation of an existing facet of the design versus one or more newly proposed approaches, and these decisions cause a significant mental workload.

Whereas when proceeding from a clean slate, the only question is whether the proposed approach seems to solve the problem or not - not whether it solves it better than what exists.

Also, fresh designs are often progressively refined over time in how they solve problems, so that not every design decision is made on the spot up front, whereas when reviewing parts of an existing design and an alternative proposal, the developer is having to conceive not just the general nature of the alternative but also try and imagine and apply immediately all the possible refinements, and then finally decide whether it's better than the existing solution or not.

For these reasons, when dealing with complicated legacy designs, they are at first refitted conservatively in ways that may cause unavoidable loss of quality, and then if a loss of quality accumulates too far, they are simply replaced outright by new designs which seek to proceed afresh from first principles.

Whilst not every change to an existing design may cause a loss of quality, it is not possible for every change to avoid a loss of quality, or for every impending loss of quality to be avoided with a reasonable amount of effort, and that's why loss of quality inexorably creeps in until the design is replaced outright.

0

What is “good code quality”? Correctness is required anyway; so anything helping you to get correct code is very welcome, but doesn’t give “good code quality”.

You have good code quality when your code implements its requirements in an obvious, easy to understand, non convoluted way, does nothing not needed for the purpose, and has documentation that allows the reader to verify this easily.

You achieve this by writing correct code, then consciously making all changes needed to get good code quality instead of leaving the first correct version. And after requirements change the exact same thing should happen: you make all the changes needed to correctly meet the changed requirements, and then you need conscious effort to change the code to be good quality again.

This is best done immediately after making the changes for the changed requirements. Now from a practical point of view, there will be companies and short sighted managers who don’t value quality. If you change requirements, and hand the correct but low quality code to a review, you might be prevented from improving the quality. So best to adapt the new requirements, put the code quality back to scratch, and then have it reviewed.

1
  • 1
    I think the kind of "quality" the OP meant, refers to deep-seated conceptualisations, naming schemes, recurrent patterns, or the choice of where the seams have been drawn for modules or subsystems to interact, the harmony and simplicity of which gets subtly disrupted or undermined by certain kinds of alterations. Commented Jul 21, 2024 at 14:02
-2

...I wanna learn how to keep the code quality high while heavily changing it.

That's easy. There is just a single step: either define the code quality or adhere to a definition of code quality from the available definitions and keep developing software complying to the adhered to definition. The reason is simpler than might think of: code quality is what's making the code easy to grasp and that ease is developed through practice.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.