0

I have a (php) program, which must change yearly. This program calculates tax for every year and there are sometime changes in requirements. First, the user fills their incomes, expenses, etc. Then clicks the download button, which creates an xml file for him.

The Download class use Calculator classes to calculate the full tax results.
Lest say i have 5 types of calculators. (one calculator per tax report section)
CalcTaxBase, CalcTaxFree, CalcEtc...

In the 1st year i created the classes CalcTaxBase13 ans so on.
The taxBase calculator have methods r1(), r2() and r3().

Next year came, nothing changed in taxBase so i created CalcTaxBase14 extended from previos year class.
(there is a year attribute which i use to load some parameters, of course changing yearly)

Then in 2015 i had to overload r3() and add r4() to CalcTaxBase15

I created this hierarchy because tought this way i can reuse the non changing methods from previous years and implement only the changes or new methods but i have more problem with this.

  1. Now it is a nightmare to quickly find, in which year i have the most recent r3(). With code navigation it is better but i have to jump over every time a need to find something.
  2. I have the same hierarchy of Download classes, because of yearly changes. I had to pass taxBase13.r1() to taxFree13.r1 in 2013 but 2 years later i had to pass the taxBase.r4() to some other calculator, and this is done in the download class. The download class feeds my calculators with inputs and then uses their results to make an xml.
  3. I can't use type definitions in my Download class methods, because the (let's say Download.configureTaxBase($taxBase)) needs TaxBase13 but the Download14.configureTaxBase($taxBase) need this for year 14. (i made it with docblocks now) As i see i can't refer to interfaces because in the new years i will have new methods.

Hope it makes some sense for you. Can someone please suggest me some better design?

1 Answer 1

4

This sounds like a better approach would be to implement a list of business rules with validity date limits, section applicability, ordering key. Then for every section, you execute the applicable rules whose validity range covers the date for which tax is calculated.

The section classes would evolve over time to store newly introduced data, but you'd need only one current version as it would be able to represent everything needed by the rules for earlier years.

I'm not sure I understand the purpose of the download classes - to me it reads like the do too much, and you might want to separate running the calculators from creating XML files,

2
  • Thamk You! the download class ensures, than after instantiating all my calculators for the selected year, i have all the calculation results before i start building the xml.
    – nrob
    Commented Feb 6, 2023 at 17:56
  • It is too much, you're right. I should only return the array of the results and pass it to xml response formatter. Your suggestion is to extract the methods from the calculator to a separate "business rule" class with the attributes you mentioned (validity date,..) ? Then select the applicable rules and use them in the download class to run all the calculations? This way i can delete the taxBase and other classes. Thank you!
    – nrob
    Commented Feb 6, 2023 at 18:11

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.