6

This question comes when there are changes during development and some entity of the business changes its name or its purpose. When it comes the time to develop, it can get very confusing during meetings, development, or any process that you mention that entity that has just changed.

Suppose we're in a business of plastic cups, so we create everything over that name. But for some reason, there are not plastic cups anymore, there are glasses, they work different from plastic cups, but not so different. In code, there should be a refactor of names? Or is it better to create a new object? Or better not to do a thing?

Does this code should change like this? :

public class mainClass(){
    private PlasticCup fullCup;

    public PlasticCup createNewCup(){
        fullCup = new PlasticCup();

        return fullCup;
    }
}

To:

public class mainClass(){
    private Glass fullGlass;

    public Glass createNewGlass(){
        fullGlass = new Glass();

        return fullGlass;
    }
}
4
  • 1
    hmm.. I think also a consideration to potentially doing a DDD code refactoring would be in regards to data schema changing efforts.. Sep 23, 2020 at 1:03
  • But what if the code was not made under DDD? I've thought about changing the core Classes and expect the IDE to throw a hell of errors, but it's not only the core Classes, but the names of the variables. I think that having things like Blue red; are mala praxis.
    – user375277
    Sep 23, 2020 at 1:19
  • 1
    well this kind of goes into a semantics conversation defining\depicting what facets domain driven design, I would think you probably don't have business types and variables reflecting products, services or company name if you weren't DDD. but I was really only raising consideration and regards to db schema efforts in this same vein. Sep 23, 2020 at 1:29
  • 1
    I don't have an answer for this question, as I haven't experienced such a scenario or work; but I think a good scenario could be related experiences with azure devops rebranding. Sep 23, 2020 at 1:36

6 Answers 6

7

This depends heavily on the circumstances, and on factors like

  • How many people work with that code, actually come in contact with such internal names, and get potentially confused when the name is changed, or might get confused in the future when the name is not changed?

  • How different are the meanings of the old name and the new one really?

  • How much work will the actual renaming really cause. This depends on further things like how much code exists which relies on that name, how powerful are the available refactoring tools, and necessary changes to documentation, extra testing and debugging efforts.

  • Are there persisted entities with the old name which must correspond to the class name in code because of the used persistence technology? Will you have to support them for backwards compatibility? How costly is a conversion of those persisted entities?

  • Is it really just a name change, or also behavioural change, where the new behaviour does not really fit any more to the old name?

  • What is the expected life time of the code which contains this name? If it is expected to live for decades, a renaming is probably more benefitial than for code which is only expected to be used until next quarter.

  • Is there a more general name, which may cover the meaning of the old as well as the meaning of the new entity in a conclusive way?

In the end, it is a trade-off. One has to make a cost-benefit analysis, taking all those bullet points into account and then make a decision.

2
  • I respectfully disagree with the first bullet point that the size of the codebase (or at least how much code contains the to-be-refactored name) influences whether the refactoring is warranted. It can definitely influence whether you do it now or put it on the backlog, but it doesn't change whether it should be done. (Other than that, I agree, so +1)
    – Flater
    Sep 23, 2020 at 9:30
  • 1
    @Flater: I edited my answer a little bit. I guess you will agree that size of relying codebase can influence the costs of a renaming, so I mention it there to make this more clearer.
    – Doc Brown
    Sep 23, 2020 at 11:11
4

This answer is touching on things mentioned in other answers, but I wanted to explain it in a way I find easier to understand.


There is a huge difference between data and logic. Data is much more easily changeable than logic. Almost by definition, data is something that can change without requiring redevelopment, whereas changes to logic always need some kind of development effort.

However, when you have data alongside your logic, you have to integrate your logic to use that data. Developing logic that handles data takes a non-zero amount of effort. If the data in question doesn't change, then there's no real point to abstracting it as data. In such a case, we hardcode the information in the logic. It's the least-effort approach.

And don't get me wrong, that's not inherently bad to do. Some thing simply don't need to be abstracted. If we abstracted literally everything that could be abstracted, we'd have countless more layers of abstractions in any codebase, without really adding value to that codebase.
There should only be as many abstractions as you need; not as many as you can implement.

Take the example of a bible salesman. They only sell bibles, no other books, and therefore the "bible" concept can be hardcoded in this bible salesman's codebase:

public void SellBibleTo(Customer c) { ... }

This is perfectly fine as long as they only sell bibles.

But just like in your situation, that rigidity has ceased to exist when this salesman begins selling other books as well. At this point, the code needs to be re-evaluated to account for a much more abstract approach: the ability to sell any kind of book.

It is at this point that the hardcoded needs to disappear, and we need to introduce actual data (including handling) that allows for different values to be used, in this case books.

The codebase will end up with another layer of abstraction:

public class Book { ... }

public void SellTo(Customer c, Book b) { ... }

This is more than just a rename. That's the most important thing to take away from this.

Now, your code can no longer assume that it innately knows which book is being sold, and thus the choice of book becomes an input parameter to your book-handling (previously bible-handling) logic.


Moving back to your example, the issue with your approach is that you are merely attempting to rename your logic rather than expand the logic itself.

If your client has decided to also handle glasses instead of just cups, it becomes clear to see that products can change. It's highly likely that your client is going to handle a third, fourth, fifth, ... kind of product down the line.

When things need to be able to change, they are data that can no longer be hardcoded. Therefore, just like how we needed to expand our example logic to handle any kind of book, now we need to rewrite the logic to handle any kind of product. I'm calling it a "product" for lack of a better name, I don't know your company's market focus.

I was going to refactor your code example but it's not a particularly meaningful one to rewrite since you're only using a hardcoded parameterless constructor in a factory whose name doesn't describe its purpose.

So I'm going to create my own example here. If your old code was this:

public void ShipCupToCustomer(Customer customer)
{
    var cup = new Cup();

    washer.Rinse(cup);
    
    var box = packer.Package(cup);
    
    labeler.Label(box, customer.Address);

    shipper.Ship(box);
}

Then your new code would be something along the lines of:

public abstract class Product { }

public class Cup : Product { }

public class Glass : Product { }

public void ShipProductToCustomer(Product product, Customer customer)
{
    washer.Rinse(product);
    
    var box = packer.Package(product);
    
    labeler.Label(box, customer.Address);

    shipper.Ship(box);
}

It's not a huge change, but it is an extra level of abstraction.

Note that this will also cause you to have to change the washer and packer objects' interfaces to account for all Product types, but this example is meant to be short and simple.


Being able to spot this trend early is going to enable you to be prepared when it does eventually happen. It's okay that you didn't spot it during the first version, but now that you have direct experience with this kind of thing happening, you should respond to it accordingly.

1
  • Your answer is very interesting, it gives me a new approach that I think it's completely fair. The bad news that this is not the case... Being specific, I have 2 cases: 1) A company that just changed the name of DB class because business changes. It's only name, functionality still growing the same way as it would be with other name. 2) An early-staged project that requirements are constantly changing, so something that was the main entity, it is not anymore, and it has a new purpose, adding a new level up from it.
    – user375277
    Sep 23, 2020 at 17:16
2

I think you should not avoid the renaming because - as you already experienced - this can lead to a lot of confusion. Your example is of course very significant so based on the real situation a simple renaming might not be enough. A glass will have different characteristics as opposed to a plastic cup.

But in case it is only the name of some business entity which is changing due to changing business terms I would invest in rename refactorings which can be very simple if you have a good IDE (option A).

If there is more to change as I would assume of the plastic cup to glass evolution I would first grab a whiteboard and find all similarities of the two entities. Then I would refactor in several steps by first trying to refactor common stuff into maybe some new value objects (if that has not happened already) or even some new entities which are common to both plastic cup and glass.

This makes it easier to do both either refactor the existing plastic cup (option B) entity which also includes renaming of the entity. Or introduce a new glass entity (option C) which will use the same common stuff. And later on you could sunset the old plastic cup entity altogether.

Option B makes sense if plastic cup and glass do not differentiate from each other that much. Option C makes more sense if they only share some stuff but still have significant logic differences which need to be added as new code anyways.

Note: I would only invest the effort (either option A, B, C) if the business has come to a well thought decision and something like this happens very rarely. In addition, the efforts for the change in the code (and potentially other depending modules) with the avoidance of communication problems and confusion betweeen development team and business people have to be weighed out against sparing the effort but changing code but being faced with confusion and inconsistencies between requirements, domain concepts and the actual implementation.

1
  • 1
    I'm between A and B, because if both entities will coexists, I'll just make an abstraction that manage them both. But there's name and functionality changes, and there is not going to be plastic cups anymore. And yeah, these scenario is rare, so the efforts is worth.
    – user375277
    Sep 23, 2020 at 17:21
1

Separate the things that change from the things that stay the same.

Suppose we're in a business of plastic cups, so we create everything over that name. But for some reason, there are not plastic cups anymore, there are glasses,

At this point it's a distinction without a difference. All you've shown is that the name should have been more abstract.

they work different from plastic cups

But here you show a need for a new class with a new name if for no better reason than to avoid destroying old tested proven plastic cup code. Even if you know you'll never make a new plastic cup again, which you don't, having the original code under the original name is less confusing as you convert to the new one.

but not so different

And here you show a need to factor out common behavior in a third class. If you feel that’s too much then just forget OOP and write some procedural if structures.

One of the signs of good code is code that’s easy to change. Do what makes it easy to change.

2
  • 1
    To be fair, OP wrote "they work different from plastic cups, but not so different". So I don't think it is crystal-clear if making a new class or renaming the old one is the more natural option.
    – Doc Brown
    Sep 23, 2020 at 15:23
  • Is 50% renaming and 50% changing logic. Not a completely overhaul of logic but still different from a plastic cup. If they come to coexist together, I just create a new class, but this case plastic cups cease to exist, but great part of the code works like plastic cups.
    – user375277
    Sep 23, 2020 at 17:25
0

This is tricky. Let’s say your company has a “support” department. Everyone knows what you are talking about when you talk about “support”. So the name has entered your code base, like in a method called “sendEmailToSupport”. And now the company changes the department name to “complaints”.

You’ll have to make code changes. Like some code will now send an email to “[email protected]” etc. That’s needed, and it’s not refactoring.

What about that method “sendEmailToSupport”? I’d suggest refactoring it. It’s not urgent. Do it when “complaints” has some foothold in the company. Do not wait two years until nobody remembers what “support” means and why that email method has such a weird name. (Obviously “refactoring” means changing names and comments, nothing else).

-6

Naming conventions are often enforced by the legal department. This usually happens after a company acquisition. Renaming is then done as part of rebranding process (I assume this is related to trademark law).

That decision can't be reasoned about in technical terms. Please consult them, instead of asking the engineering team.

For this reason, as a software engineer, you want to avoid including brands in any names unless absolutely necessary.

From a technical standpoint, rename has a minor advantage of consistent naming down the line, but the damage outweighs the benefit.

8
  • 2
    If a business user or analyst comes to the dev team and tells them about a terminology change in business, it is usually not the job of the devs to question this decision and talk to the legal department, that is job of the forementioned people.
    – Doc Brown
    Sep 23, 2020 at 6:27
  • @DocBrown that is basically what my answer implies. The point is, that is it not a technical question. I'm leaving out of scope, whose job is it to discuss it.
    – Basilevs
    Sep 23, 2020 at 8:03
  • 3
    I have yet to come across one case where the names in code are enshrined in any kind of legislation. This is not a legal issue whatsoever. Nomenclature in a codebase is meaningless post-compilation and has no bearing on anyone but the developers.
    – Flater
    Sep 23, 2020 at 10:01
  • I've worked on three products, which were bought out (and rebranded) from small companies by bigger enterprises. They had to rename Java packages. When queried for main motivation, the response was - "legal issues".
    – Basilevs
    Sep 23, 2020 at 10:34
  • In the case of a company getting bought out, the decision to rename products, namespaces, packages, etc from the old company to the new is largely a legal / marketing move, yes. But what you call your classes, properties, methods, etc is never a consideration for the legal department.
    – mmathis
    Sep 23, 2020 at 12:49

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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