-2

Most of financial apps have complex calculations and over time have change in calculation methods. Then you mostly create a new version for your calculator class that extends previous calculator and override some method.

You may extend new calculator from old version because you will avoid repeated code and use typecasting in inheritance advantages in your program.

But there is a big problem, calculation is a complex process and when you use inheritance over that, readability of your calculator will decrease over time and it is very hard for new programers to read and understan that.

Now I will know there is a solution or design pattern for implementation of complex process? I think about a simple workflow or strategy design pattern but I will know your experience in dealing with similar problems.

Thanks.

Update :

My question is not about following sentence :
-- Why I mostly prefer composition over inheritance on inheritance problem on benefit of composition over inheritance.
My question is about your experience on a common problem about code readability in complex domain problems like calculation that inheritance can decrease readability.

Tulains Córdova
  • 39,201
  • 12
  • 97
  • 154
Rasoul Taheri
  • 121
  • 1
  • 4
  • 1
    Possible duplicate of [Why should I prefer composition over inheritance?](http://programmers.stackexchange.com/questions/134097/why-should-i-prefer-composition-over-inheritance) – gnat Aug 11 '16 at 19:59
  • 4
    ^^^ "pattern" is simple: just don't use inheritance. The single most efficient improvement in readability I achieved in one past project with financial application was when I just removed all that senseless inheritance from a large bunch of "calculators". Technically it was easy, I just declared all classes final (it was in Java) and went on fixing all compiler errors that appeared from these brainless subclasses, sub-subclasses etc (for the sake of completeness after rework was over I removed final because there was no compelling reason to keep it) – gnat Aug 11 '16 at 20:04
  • 2
    ...sorry, forgot to mention: don't. use. inheritance. – gnat Aug 11 '16 at 20:07
  • @gnat Why remove the `final` keyword? You should use it unless you have a compelling reason to remove it. Making a class inheritable is the same as giving others permission to inherit from it, and that limits your ability to refactor it. – Doval Aug 11 '16 at 20:09
  • @Doval I heard that some projects have such a policy (and I personally like it, so I felt some... pain when removing these) but in the one I mention, it wasn't so. My finals sprinkled over in not particularly cohesive bunch of classes would confuse other team members – gnat Aug 11 '16 at 20:13
  • @gnat this means you create simple final class for calculate each part of your calculation (for example basic calculation, tax calculation, ...) and in main calculation just calls that simple class sequentially. is my guess correct? – Rasoul Taheri Aug 11 '16 at 20:14
  • if memory serves it was mostly like that. There were some variations I think but I didn't bother to remember because it was really simple: as soon as compiler forces you to do something else instead of stupid inheritance it becomes quite easy to see how to arrange stuff – gnat Aug 11 '16 at 20:24
  • `class Panama extends TaxCalculation2015` what could possibly go wrong? – null Aug 11 '16 at 20:35
  • @null per my recollection even more innocent looking inheritance led to trouble. `class TaxCalculation2016 extends TaxCalculation2015`? no thanks – gnat Aug 11 '16 at 20:50
  • @gnat: of course, I just wanted to get the point across very clearly – null Aug 11 '16 at 20:56
  • Broken english. Question hard to understand. – Tulains Córdova Aug 12 '16 at 12:20

3 Answers3

9

Neither inheritance nor polymorphism decreases readability. Using any OOP concept for the wrong reasons does.

Avoiding repeated code is not a good reason to use inheritance, you can do that by isolating code parts in methods of the same class. You need an "is a" relationship to justify inheritance. A new calculator is not a kind of old calculator. I can imagine though you would have an abstract base class calculator if all thinkable calculators in your problem domain were to offer the same feature set, just with different implementations.

Andy
  • 10,238
  • 4
  • 25
  • 50
Martin Maat
  • 18,218
  • 3
  • 30
  • 57
  • While I technically agree with you that it is up to the programmer to make good use of language features, I would argue that inheritance decreases readability something like 95% of the time, and at that point I deem a language feature dangerous enough to get rid of. – gardenhead Aug 12 '16 at 01:02
  • 5
    While I politically agree with you (from a human rights perspective), I argue readability is only compomised when inheritance is misused. If it is misused 95% of the times, I would not know. I would know getting rid of a feature just because a lot of folks do not know how to use it is not good (the folks that do know how to use it have rights too you know). Educating the people seems the better option to me. – Martin Maat Aug 12 '16 at 04:53
  • Readability isn't the ultimate goal of code though... If something decreases readability 95% of time, but the increases in functionality and efficiency greatly, well, deal with less readable code. – Joe Aug 12 '16 at 12:45
  • @Joe readability *is* usually the primary concern though in most cases; moreover, inheritance doesn't bring anything to the table when it comes to functionality or efficiency either. This is probably a philosophical difference on language design. I've never been a fan of the kitchen sink approach (e.g. C++). I like my languages to have a streamlined, thoughtful design where all the features work in tandem to aid the programmer experience. And of course I just made that number up out of thin air - there is no way to measure such a thing. – gardenhead Aug 12 '16 at 14:29
4

If you are a little myopic and only looking at your computation classes, then yes, perhaps using some inheritance and polymorphism may make your code a little harder to read, because everything isn't in one place. I know it can be challenging for some developers to follow code that isn't completely linear.

On the other hand, if your responsibilities ever increase and you work on the larger program that uses your computation classes, among dozens of other classes and objects in the overall solution, I can guarantee that inheritance and polymorhism make your life much, much easier.

For example, if you are working on a workflow system that needs to be able to call a variety of computation classes, it is very helpful if they all derive from a base class. Then you can write things like

void ExecuteComputation(BaseObject computerObject)
{
    computerObject.Execute();
}

Otherwise you'll have to write some garbage like this:

void ExecuteComputation(object computerObject)
{
    if (computerObject is ComputerType1) { ((ComputerType1)computerObject).ExecuteThis())};
    if (computerObject is ComputerType2) { ((ComputerType2)computerObject).ExecuteThat())};
    if (computerObject is ComputerType3) { ((ComputerType3)computerObject).ExecuteThisOtherThing())};
}

which is not only less readable but poses a severe maintainability problem, especially if you were hoping for some sort of separation of concerns between your workflow system and your computation classes.

The problem gets even more severe when working with distributed systems, third parties, and information networks. Having base abstractions and concrete implementations that inherit from those base abstractions makes it possible for messaging that is transport-agnostic, for example, and interfaces and contracts make service oriented architecture and parallel development possible.

In addition, without inheritance and abstraction, there would be no inversion of control, dependency injection, or automated unit testing. Basically you'd throw out all of the engineering innovations of the past ten years. Good luck with that.

John Wu
  • 26,032
  • 10
  • 63
  • 84
0

Your question sounds as if you've just inherited a big legacy system to take care of, and you're looking for a magical design pattern that would make it simple.

Is it all because of inheritance ?

Let's be honest: Any majors system looks complex and difficult to understand at first sight. That's because of the complex matters they are dealing with.

The system has to be decomposed into smaller, understandable parts. But what would be the alternative to inheritance in your case ? Flat calculation sub-routines that write everything down again and again with a lots of parameters to tell the variables and calculation variant to be used ?

Wouldn't this result in even more difficult code where you're never sure that if you change something in one formula you shouldn't also adapt some other formulas elsewhere ? Wouldn't you then end-up posting a question like I've inherited 200K lines of spaghetti code — what now?.

Is it complex or complicated ?

However the code is written, the more classes you have, the more difficult it'll be to understand. That's natural.

Some psychologists even claim that our brain has in average a short term memory capacity of around 7 items, and trying to understand simultaneous interrelation between more items appears difficult. In their opinion the only way to overcome this limitation would be cluster items. And inheritance is just about that: you can handle the derived object as the original object, with just the variations you'd need. So it should be simpler to understand.

What's difficult to master is how all the classes are related. Not only in their static structure, but also how they dynamically interact at run-time.

How is your system designed ?

Reading the code can give you a detailed view, class by class. With a good IDE, it should not be an issue to navigate between related classes and find all the related pieces of code.

But this is not sufficient to get the perspective and the overall understanding of the system:

The worst possible documentation to create for an object-oriented system is a stand-alone description of the semantics of each method on a class-by-class basis. This approach tends to generate a great deal of useless documentation that no one reads or trusts, and fails to document the more important architectural issues that transcend individual classes, namely, the collaborations among classes and objects.

- Grady Booch in Object-Oriented Analysis and Design

For example, it's a common practice to define a high-level relationships between abstract classes, to reduce dependencies in derived concrete classes. But this makes it easy to loose sight of these relations when implementing the concrete classes. And it is sometimes difficult to guess the intent behind the abstraction.

Solution

Unfortunately, there is no general purpose design pattern to overcome complexity. There is no way round: you have to get a high level understanding of your system first:

  • If there is some architectural design document, start with that.
  • If not, make some reverse engineering. Start with a class diagram. There are automated tools that can help.
  • Then if you're familiar with design patterns, try to identify in the structure some existing design patterns. This will accelerate your understanding of dynamic relationship between classes.

Maybe that with a deeper understanding you'll find that the code is better structured than you thought. And maybe not. And in this case you can come back with additional specific questions, for which we can provide some ideas about specific design patterns for improvement.

Christophe
  • 74,672
  • 10
  • 115
  • 187