Programmers Stack Exchange is a question and answer site for professional programmers interested in conceptual questions about software development. Join them; it only takes a minute:

Sign up
Here's how it works:
  1. Anybody can ask a question
  2. Anybody can answer
  3. The best answers are voted up and rise to the top

One of the most basic and widely accepted principles of software development is DRY (don't repeat yourself). It is also clear that most software projects require some kind of management.

Now what are the tasks that are easy to manage (estimate, schedule, control)? Right, repetitive tasks, exactly the tasks that should be avoided according to DRY.

So from a project management perspective, it is great to solve a task by copying some existing code 100 times and make some minor adaptations to each copy, as required. At all times, you know exactly how much work you have done and how much is left. All managers will love you.

If instead, you apply the DRY principle and try to find an abstraction that more or less eliminates the duplicate code, things are different. Usually there are many possibilities, you have to make decisions, do research, be creative. You might come up with a better solution in shorter time, but you might also fail. Most of the time, you cannot really say how much work is left. You are a project manager's worst nightmare.

Of course I am exaggerating, but there is obviously a dilemma. My questions are: What are criteria to decide if a developer is overdoing DRY? How can we find a good compromise? Or is there a way to completely overcome this dilemma, not just by finding a compromise?

Note: This question is based on the same idea as my previous one, Amount of routine work in software development and its effect on estimation, but I think it makes my point clearer, so sorry for repeating myself :).

Another note: The question has been marked as duplicate. As opposed to the referred question, this is not at all about designing for future reuse or about the YAGNI principle. It is about repeating code in the current work package. Also, the referred question and its answers do not cover the project management aspect. However, thanks for adding the 'technical-debt' tag, I was not aware it exists but it fits perfectly.

share|improve this question
54  
Let us know how your project management chops are feeling when it comes time to hunt down, change and test something in all 100 of those copy-and-pasted instances. And don't forget the additional time that's going to be spent figuring out why it ends up broken because only 98 of them actually got changed. – Blrfl 2 days ago
8  
@Blrfl on the other hand, prematurely DRY-ing up code before a good abstraction is clear can really hurt productivity too, as a shared abstraction is a shared dependency. I'm not disagreeing, btw, just pointing out there's definitely a balance to be found. – GoatInTheMachine 2 days ago
9  
The principle which prevents DRY from going out of control is the YAGNI (You ain't gonna need it) principle. – Philipp 2 days ago
55  
There is no dilemma. If the project manager wants you to do a lot of superfluous manual work because it is easy to estimate, then the obvious solution is to fire the project manager. – JacquesB 2 days ago
4  
DRY is to help in future maintenance. That's not something that typically makes it too high on a greenfield PMs priorities. – Matthew Whited 2 days ago

10 Answers 10

You seem to assume the primary objective of project management is to produce exact estimates. This is not the case. The primary objective of project management is the same as for developers: To deliver value for the product owner.

A product using a lot of slow manual processes rather than automation might in theory be easier to estimate (although I doubt it), but it does not provide value-for-money to the customer, so it is simply bad project management. There is no dilemma.

It is well known that estimation of software projects is hard, and numerous books have been written and various processes have been developed to manage it.

If the only objective of the PM was to produce exact estimates, then it would be easy. Just pad the estimates to 10X, and let the developers play games for the rest if they finish early. This would actually be better than your suggestion to use copy-paste busywork to pad the time, since playing games will not reduce the maintainability of the product.

But in reality, the product owner want useful estimates and a quality product delivered as quickly and cheaply as possible. These are the actual constraints a PM will have to navigate.

share|improve this answer
9  
I completely agree with your assertions here but I think it needs to be noted that there are a lot of lousy project managers out there that really do prefer predictability over speed or quality. Most people who have no training in project management learn what they know about it from what they have seen and my experience is that the project managers that can deal with uncertainty in a calm rational way are few and far between. – JimmyJames yesterday
3  
@FrankPuffer I've been there. How long will it take? One option here is to provide a range. Read up on PERT specifically on 3-point estimates because they should know about that already. Percentage complete? This is the most annoying. Try to ignore it but if you can't remember that it's percentage time, not percent of lines coded or whatever. What they really want to know is When will it be completed? Early on, give conservative predictions on each task and refine as you go. Waiting until the last minute to say you more time will make people crazy. – JimmyJames yesterday
6  
How long will it take? I'm 60% certain we can finish it by x, but theres a 10% chance it will take five times as long. – David yesterday
11  
@David: This would probably drive the PM crazy because he knows from experience that this 10% chance actuall happens 80% of the times :) – Frank Puffer yesterday
4  
The reality is many places would love to track a project into the ground then succeed unexpectedly. The PMs are often rewarded for having accurate projections so they have perverse incentives. This is the principal-agent problem. – ArtB yesterday

You are right - copy-paste works great, and DRY has no point when your task is to produce a program for which either the copied template or the copy will not have to be maintained or evolved in the future. When those two software components have a completely different life cycle, then coupling them together by refactoring common code into a common lib which is itself under heavy development can indeed have unpredictable effects for the effort. On the other hand, when copying code sections inside one program or program system, all these parts will typically have the same life cycle. I will illustrate below what this means to DRY and project management.

Seriously, there are lot of such programs out there: for example, the computer game industry produces lots of programs which have to be maintained over a short period of some months or a year at maximum, and when that time is over, copy-pasting old code from a previous game where the maintenance period is exceeeded, into a new game's code base is perfectly fine and might speed things up.

Unfortunately, the life cycle of the most programs I had to deal with over the last years is very different from that. 98% of the requirements or bug fix requests which arrived me were change requests for existing programs. And whenever you need to change something in an existing piece of software, "project management" or planning works best when your testing and debugging efforts are quite low - which will not be the case if you change something in one place, but due to copy-pasted business logic you easily forget you need to change a dozen other places in the code base as well. And even if you manage to find all those places, the time to change them all (and test the changes) is probably much higher as if you have only one place to change. So even you could make an accurate estimation for the change, having the costs a dozen times higher than it needs to be can easily collide with the project's budget.

TLDR - whenever you develop a program where is no necessity or responsibility for bugfixing and maintenance of the original or the copy, feel free to copy. But if you, your team or your company is or might become responsible, apply DRY whenever you can.

Example

As an addendum, let my explain what "bugfixing and maintenance" means, and how this leads to unpredictability in planning, especially inside one product, by a real-world example. I have indeed seen these kinds of things happen in reality, probably not with 100 instances, but the problems can even start when you have just one duplicate instance.

The task: create 100 different reports for an application, each report looking very similar, some requirement differences between the reports, some different logic, but all in all, not many differences.

The dev who gets this task creates the first one (lets say it takes 3 days), after some changes or minor bug fixes due to QA and customer inspection its finished, it seems to run fine. Then he started to create the next report by copy-pasting and modifying the whole thing, then the next, and for each new report he needs ~1 day in average. Very predictable, at a first glance ...

Now, after the 100 reports are "ready", the program goes to real production, and some problems occur which were overlooked during QA. Maybe there are performance problems, maybe the reports crash on a regular basis, maybe other things do not work as intended. Now, when the DRY principle had been applied, 90% of those problems could be solved by changing the code base in one place. But due to the copy-paste approach, the problem has to be solved 100 times instead of once. And due to the changes already applied from one report to another, the dev cannot quickly copy-paste the fix for the first report to the other 99. He has to look into all the 100 reports, read them, translate the change to the modified report, test it, and maybe debug each of it individually. For the PM, this starts getting really hard - he can of course take the time for a "regular" bug fix (lets say, 3 hours) and multiply this by 100, but actually, this is most probably a wrong estimation, some of the fixes might be easier to make than others, others might be harder. And even if this estimation is correct, having the debugging costs 100 times as high as they needed to be will cost you company a lot of money.

The same will happen the next time when the customer asks for changing the color of his company emblem in all those reports, for making the page size configurable, or by some other new requirement which affects all reports in a similar manner. So if that happens, you can make an estimation for the costs and bill the customer 100 times the price he would have to pay when the code had been DRY. However, try this a few times and then the customer will cancel the project because he will probably not be willing to pay your exorbitant evolvement costs. And maybe at that point someone will ask the question why this happened and point with the finger at the person who made the decision for this copy-paste programming.

My point is: when you produce software for others, you have always at least for a short period of time the responsibility of making the thing work, fixing bugs, adapt the program to changing requirements etc. Even in a green-field project, these parts can quickly add up to far more than initially planned development effort. And especially when all your copy-pasted code is inside one product, the period of time of responsibility is for all parts the same, which is quite different from the situation where you copy-pasted some older code from a dead project which is no longer under active maintenance.

share|improve this answer
    
Probably a good answer but way too verbose compared to other good answers. – Vince O'Sullivan 1 hour ago

So from a project management perspective, it is great to solve a task by copying some existing code 100 times and make some minor adaptations to each copy, as required. At all times, you know exactly how much work you have done and how much is left. All managers will love you.

Your base assertion is incorrect.

The thing that makes software different from other professions is that you're making something new every day. After all, no customer is going to pay you to build something that someone else has already made. Project managers might like predictability, but their bosses like value. If you're just copy-pasting code with slight variations, you're not providing much value for the company.

Eventually the company will realize they can do the same work in a fraction of the time by hiring a good programmer. And if they don't, their competitors will.

share|improve this answer
2  
I'd argue most engineering professions are about "making something new every day" – BlueRaja - Danny Pflughoeft yesterday
9  
@BlueRaja-DannyPflughoeft: Not really. Having worked as an electronics/electrical engineer I can testify that most big scale engineering professions (those projects that require commissioning like building ships and powerplants) are about making sure people doing something tried and tested do it properly. That's what business consider "engineering". Making something new is "R&D" – slebetman yesterday
2  
@slebetman Maybe you just didn't notice all the work your management was doing; even when you're doing the same thing again and again, the environment changes every time - you don't have a template of a power plant that you can just deliver to a customer and be done with it, you need to do surveying, figure out how to supply the plant with raw materials and carry the product back out, manage all the raw materials for the construction and deal with supply issues and work shortages and a million other things. It looks like template work (as many software efforts do), but it really isn't. – Luaan yesterday
    
@Luaan: Yes, but none of that is making something new. All of them are "doing something we know how to do". Software development is different. Primarily because in software, unlike physical engineering projects, we tend to encapsulate things we already know how to do in libraries so we don't have to manually "do the surveying" etc. We'd just import a library for that and use it. – slebetman 16 hours ago
    
@slebetman Almost all of software being written is "something we know how to do". Libraries also live in an environment that always changes. And you don't have 100% knowledge and experience with the whole library, and all the dependencies of that library and the other dependencies you have, and there's plenty of weird systems and hardware configurations that simply refuse to work the way a reasonable system should work. Encapsulation is great, but it's still expensive as hell and needs tons of surveying. And engineering has encapsulation too - prefabricated blocks, ICs etc. – Luaan 6 hours ago

Cut-and-paste programming eventually leads to abandoned software. I was a contractor on a system for ordering wireline services from a very large phone company. The system was cut-and-pasted ad nauseum because all the testing was manual and they didn't want to change any working code. The tiniest enhancement could result in a new copy of hundreds of lines of code. Originally the application was written to handle accounts of up to twelve physical lines. Of course this limitation was made in hundreds of locations in the code. After about four years business asked the team what it would take to handle larger accounts. They estimated about $18 million. At that point the project was turned over to an offshore team for minimal maintenance. The existing team was all laid off.

Organizations that think this way are getting crushed by companies with better technology.

share|improve this answer

In your question, you only list three functions of project management - estimate, schedule, and control. Project management is about achieving goals within the constraints of the project. The methods used to achieve goals within the constraints of a project are different for software projects than many other types of projects. For example, you want manufacturing processes to be highly repeatable and well-understood. However, software development is mostly knowledge work - it's non-routine and requires thinking rather than following rigid instructions and procedures. The techniques used to initiate, plan, execute, monitor and control, and close a software project are going to need to account for the type of work that needs to be done on a software project - specifically, non-routine work that cannot be done to specific instructions and procedures.

I think the other problem is that you are taking DRY, a concept that relates to repetition of information, and trying to apply it to managing tasks. DRY simply says that you should only have one authoritative representation of information. Project managers should be embracing this, since it means that everyone will know where to go for the information, communicating changes will be easy, and the changes can be controlled and managed well. DRY, through reusable pieces, helps to keep long-term costs down, helps to maintain long-term schedules, and to improve quality - three pieces to the Project Management Triangle. There needs to be some investment of time and money spent to effectively make things DRY, but the job of the project manager is to make trade-offs of time, cost, schedule, and quality.

share|improve this answer
    
Sure, software development is knowledge work. Actually I wouldn't even consider my 1st example (copy/paste) to be software development in a strict sense. Still, managing this type of work is much tougher, so the PM, even if he has a development background and knows all of this, in his role as a PM he tends to ignore it. (I don't say that this is a good thing, it is just what I have observed many times. I also don't think that those PMs are stupid or incompetent. It's more like the role sometimes forces them into acting like this.) – Frank Puffer yesterday
3  
@FrankPuffer I disagree that the role of project manager forces the person into making particular decisions. It's more likely an educational or organizational force. From what I've seen, most project management education focuses on more traditional project management techniques (probably because they are more commonly applicable to more projects) than software project management techniques. This can bleed into organizations that expect this and don't look at other techniques for managing knowledge work projects like software development. – Thomas Owens yesterday
2  
@FrankPuffer Sure it's tougher, but it provides more value. If your boss' boss is smart enough, he will get rid of the manager that tries to "make things easier for himself" and find someone who can actually do his job. Don't get me wrong, if making things easier provides value, go for it - but in what you describe, this is almost certainly to the detriment of the end value. – Luaan yesterday

An oft forgotten maxim that applies here is the rule of 3. This states, that it is OK to copy code once, but beyond that it should be replaced by generic code.

3 might seem like an arbitrary number but a common scenario is where data and logic are duplicated in an application and database. A example often cited is where there is a lookup table in the database and an enumeration client side. The difference in paradigms don't allow this to be readily stored in a single place and so the information often appears in both places.

Whilst it is nice to have DRY code, there can be times when business logic dictates an exception and so you have to create two or more bits of code from source that was generic before.

So - what to do? Code for the status quo (after all, YAGNI). Whilst code should be written for ease of modification, writing a whole raft of bells and whistles for something that might not be needed is just torching money.

share|improve this answer
4  
Note that this does mean you should comment that you have copied the code (in both places) so that you know if you're about to copy it again, you shouldn't! – Mark Hurd yesterday
    
I've done this in a case where two classes needed the same method but were barely related -- kind of like distant cousins. I would have had to add dependencies to almost a dozen classes to have them actually share the code. So I did like what Mark suggested - copy-pasted the method and also left a big, obvious comment which pointed out the other location for that method. – Jeutnarg 16 hours ago
    
@MarkHurd Yep - great point... – Robbie Dee 4 hours ago

Writing new code is just a small part of the task

Your suggestion would make it easier to estimate the part of initially writing new code. However, for actually bringing anything new (no matter if it's a brand new system, an addition of feature or a change of functionality) doing this is not sufficient and is just a minority of work - the estimates seen in literature tell that in practice this part is something like 20%-40% of the total work.

So the majority of work (which includes adapting your initial development to what was actually needed, integration, testing, rewriting, re-testing) doesn't get easier to estimate; just the other way around, intentionally avoiding DRY just made that part much larger, harder and with more variable estimates - that bug or need-for-change which requires changing all the cloned parts may not happen, but if it does, then your estimates are going to be totally wrong.

You don't get better estimates by improving your estimation quality of a small part of work but making it worse on a large part of work; so it's not really a tradeoff but a lose-lose situation where you get worse productivity but also worse estimates.

share|improve this answer
    
That's a good point. However, DRY or similar principles also apply to other tasks like testing or integration. Most things can be done in a mechanical way, without much thinking or in more intelligent ways. The intelligent solutions are often much faster but they involve a risk of failure. Plus, you have to put a fair amount of work into them before getting any result. – Frank Puffer 5 hours ago

I think you are misunderstanding DRY.

Let's use an example:

public Class A
{
    public int Multiply(int x, int y)
    {
        return x * y;
    }
}

public Class B
{
    public int Multiply(int x, int y)
    {
        return x * y;
    }

    public int Add(int x, int y)
    {
        return x + y;
    }
}

vs.

public Class C : A
{
    public int Add(int x, int y)
    {
        return x + y;
    }
}

By replacing class B with C we have followed the DRY principle and reduced code duplication. But we haven't increased the unknowns or risk to the project (unless you have never done inheritance before).

I think what you mean when you talk about DRY is something more like a design task. I.e.:

public Class A
{
    public int Multiply(int x, int y)
    {
        return x * y;
    }
}

!!!New requirement! Some clients need to be able to multiply doubles!!

// Use class B for new clients!!
public Class B
{
    public int Multiply(double x, double y)
    {
        return x * y;
    }
}

vs.

public Class A // Version 2
{
    public int Multiply(int x, int y)
    {
        return Multiply(x as double, y as double);
    }

    public int Multiply(double x, double y)
    {
        return x * y;
    }
}

Here (assuming it works) we have designed a solution which can deal with both the old AND the new requirement, essentially trying to create a mathematical model of the real life problem or business rules. In real life the system we are modeling will obviously be much more complicated, our model of it won't fit exactly, and the edge cases and unexpected results will take time to find and correct.

So, should we take B or A version 2 in this case?

  • B is going to be more specific to the actual requested change with fewer side effects and be easier to estimate and quicker to do.

  • A version 2 will result in less overall code going forward and will be the more elegant solution

Again I'm going to say it comes down to the quality of the specification and requirements.

If we have very clear specifications which cover the edge cases and backwards compatibility then we can be sure we understand the system well enough to refactor the model without producing bugs.

If we have an emergency request for a single customer where the only requirement is that behaviour changes for that customer without consideration of the overall system; then 'improving' the model by refactoring A carries a substantial risk. Both of breaking other customers or overrunning the deadline because of the extra unknown time needed to design and test the solution.

share|improve this answer
4  
I don't agree. Inheritance is not something you do once and then master it. There are lots of pitfalls. There are reasons why composition should be preferred over inheritance. So we have to make a decision: Inheritance? Composition? Something else? This decision will probably be difficult in the real world. In the second example there are also lots of alternatives. What about generics/templates? Ore maybe some functional approach using lambdas? Again: Lots of possibilities each of which will have specific implications. – Frank Puffer yesterday
4  
The point is in the first example you literaly remove duplicate code through whatever method. but the exact same code executes either way. So there is zero functionality change. In the second example you change the approach to something which you hope is functionaly eqivilant but is actualy different code – Ewan yesterday

Paragraph by paragraph

One of the most basic and widely accepted principles of software development is DRY (don't repeat yourself). It is also clear that most software projects require some kind of management.

Correct.

Now what are the tasks that are easy to manage (estimate, schedule, control)? Right, repetitive tasks, exactly the tasks that should be avoided according to DRY.

Repetitive tasks should be automated, mandatory. They are boring, error prone, when made by hand.

So from a project management perspective, it is great to solve a task by copying some existing code 100 times and make some minor adaptations to each copy, as required. At all times, you know exactly how much work you have done and how much is left. All managers will love you.

I think you can change the word "adaptation" with "configuration". Consider you have a bug in this piece of code that is supposed to be copied. A bug that appears under specific conditions. If it is not fixed in the original source, and it is copied there will be a lot of places to fixed. This may be bad, but then someone has to:

  • first fix the code in the original source;
  • fix the code in every other place;
  • make sure that those were all of the places. When you say this had to be done to the manager, he will probably at least hate someone.

If instead, you apply the DRY principle and try to find an abstraction that more or less eliminates the duplicate code, things are different. Usually there are many possibilities, you have to make decisions, do research, be creative. You might come up with a better solution in shorter time, but you might also fail. Most of the time, you cannot really say how much work is left. You are a project manager's worst nightmare.

Removing duplications leads to single point of failure. If something fails you can be pretty sure where this happens. S.O.L.I.D. and Design Patterns are there to help to fix exactly that problem. Too short deadlines tend to provoke procedural style "coding". More time invested in one project in order to create something reusable means there should be minimal amount of time spent in the next project when the feature will be reused, but it should be configurable in first place.

Of course I am exaggerating, but there is obviously a dilemma. My questions are: What are criteria to decide if a developer is overdoing DRY? How can we find a good compromise? Or is there a way to completely overcome this dilemma, not just by finding a compromise?

A lot of people pointed there is no dilemma here. Yes and no.

If you have something highly experimental that has never before being done - there is no dilemma. Otherwise if you have something that has to be done again, like new booking system you already have abstractions, just depends what you need.

I think the dilemma is - should we implement a something in a feature, if it is unlikely to be requested. Implement something when requested. Nobody needs a huge infrastructure that won't be used.

share|improve this answer

this is not at all about designing for future reuse or about the YAGNI principle. It is about repeating code in the current work package.

It absolutely is about design. Maybe not re-use per se, but design nonetheless.

What are criteria to decide if a developer is overdoing DRY?

Experience and your existing environment/situation. For a given problem you will get a strong sense of the Prado Principle as you attempt greater degrees of DRYness. Then suddenly management considerations come to play. Time, goals, the customer, long term code management (someone said technical debt), etc. will inform your plan of attack.

How can we find a good compromise?

Uh... design? Refactoring is design, well it is supposed to be. The scope of the DRYing can easily expand like a super nova from the loop, to method, to class(es). Been there, done that. But you can't really know until you study the problem - this is design.

How can it not be a design problem? You must consider the problem more widely than the immediate duplicated code at hand. This is a design activity whether it's existing code or a blank sheet; whether it's "extract method" or creating new classes and modules.

Epilogue

... the referred question and its answers do not cover the project management aspect.

Typical management, ignoring design time. We would have, ideally, designed out the superfluously redundant repetitiveness prior to coding. Instead, management thinks development (and bug fixes) is a single Olympic event - coding - when it is in fact a decathlon. And they measure to 1/1000 of a second because they think it's all analog.

To further abuse analogy: there is a wonderful doppler shift with well designed OO code. I had this experience: "I spent two days writing this row (of a GUI form) and two hours writing the rest of the form."

share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.