Dealing with confusing business logic
Posted by achyxhu@reddit | ExperiencedDevs | View on Reddit | 51 comments
In the span of two years, our team has dealt with three different product managers who lack domain knowledge of the product they’re working on. Whenever they come in, they’ll add more business logic - typically ones that contradict an older behaviour (unfortunately support is required for backwards compatibility). The lack of thought behind the business logic shows up as spaghetti code in our code base. Basically a bunch of if-else statements (sometimes nested) and rollout checks. How do you guys deal with complex, messy and sometimes contradicting business logic?
No_Taste_7757@reddit
Applying domain driven design can be helpful here, though it can be a tall order in a legacy codebase. It preaches strict separation of business logic from "application"/"infrastructural" (read: database) concerns. This can help you coalesce the business logic and disentangle it from the incidentally complex machinery of the app.
This also has the side benefit of making it easier for the devs themselves to understand and discover the business logic, which means they can give accurate and timely answers to new product managers when they have questions
CatolicQuotes@reddit
I always recommend people reading this series https://herbertograca.com/2017/07/03/the-software-architecture-chronicles/
No_Taste_7757@reddit
Did I miss the mark a bit?
CatolicQuotes@reddit
I am not sure what do you mean. I am only expanding on what you said with some reading material.
No_Taste_7757@reddit
Makes sense. I was curious if you thought my interpretation was wrong, and that's why you recommend the reading 😅
CatolicQuotes@reddit
I see, no, I agree with what you said 👍
chengannur@reddit
I am not quite sure on whether you will be able to do that halfway through the project.
And what makes you think that another abstraction over frameworks abstraction is going to make things better, if it's a revolving door of developers (add a clueless management) all they really care will be to implement feature somehow within the timeframe client expects and move on
nutrecht@reddit
If all people care about is getting a ticket to "done" as soon as possible, you're fucked anyway. Nothing is gong to fix that.
chengannur@reddit
Apparently, that's the metric being used now a days on a wide range of companies.
No_Taste_7757@reddit
In my exp. DDD isn't really an "abstraction". It's an alternative to mixing DB calls in with all ur domain-logic if/else's. Instead you do the operations in your model, then u write that model to the DB.
The intermixed approach are called "transaction scripts" in the DDD world, which are fine until your domain complexity starts to get out of hand. A smell that it's getting out of hand is when you start wanting to compose transaction scripts. This often isnt possible because of all the DB shit going on -- what you really want to do is share the domain logic.
I'm currently working on a project where we are refactoring transaction scripts into a domain model, and it can definitely be done incrementally
pnfb0y@reddit
Do you know of any FOSS project that follows DDD ?
achyxhu@reddit (OP)
TIL. Never heard of this design pattern before. Will look into it!
LiamTheHuman@reddit
Coding in tests that check specific business logic and reference when it was added and why can help too. It doesn't have to be anything crazy just small tests like "Application does x when Y so that Z". This way when you build in a contradiction its super clear what you will need to remove since the tests will break and what it's old purpose was for
nutrecht@reddit
There are design patterns like a Rule Engine, Command, Factories etc. you can apply here to cleanly separate rules from the rest of the code. So from an implementation standpoint, this does not have to lead to code that's hard to maintain.
Regarding the product managers: if this stuff gets implemented and users are actually happy with it, are they really wrong?
Dro-Darsha@reddit
Is your problem with the business logic or the PMs? It sounds like the latter. In this case the answer is: push back. It depends a bit on your standing in the company what you can do here, but try sentences like "I dont see how the business value justifies the long term maintenance effort" remember that the PM is not your boss
Ill-Ad2009@reddit
I say try that, and if it doesn't work or causes conflicts, then forget it. Businesses let experience walk out the door because they don't want to pay what it's worth, and then new PMs/devs come in mess things up. Why should the people at the bottom care more about the future of the company than the owners and managers who let that shit happen?
achyxhu@reddit (OP)
There’s documentation and flow charts for all our business logic. It’s a huge decision tree with multiple entry points and is failure prone. Whenever, a new nonsensical business logic is proposed, I point out the issues and push back but don’t get heard. My manager is a bit of a pushover so he doesn’t back me up. I’m asking more from a software POV to see what I can do to improve the code base
LiamTheHuman@reddit
Ya I think this is the answer and any other solution just supports this. Like they can even just say:
from what I can tell the system does 'this' and what you want is opposing it. I'm uncomfortable changing it without understanding why it was down that way originally. If we want to make that change we should spend more time to understand if there will be long term consequences of increased complexity or removal of old functionality.
Then the Product owner can decide and they have informed them and given a reasonable engineering opinion.
Ill-Ad2009@reddit
Been there. All code becomes spaghetti at some point if they keep adding to it, so you really just have to accept it if that has started to happen. Good design and developers who actually understand and follow that design can make it work for longer, but eventually people move on and new people come in and it gets messed up.
I don't understand blaming the PMs here. If they want a feature, you do an investigation to determine what that will take to implement, and then you go from there. Build whatever they want, but be sure they understand the consequences of it. And do your best to try to make it less of a disaster wherever possible.
Downtown_Football680@reddit
That's why rule engines exist (since many decades ago). Don't blame clueless "product people", fix the platform.
achyxhu@reddit (OP)
I’m seriously considering this. Business rules get to be abstracted away from our code base. My peeve with rule engines (having worked with it in another product) is this
Downtown_Football680@reddit
I'm going to say that the linked comment is just chickening out on natural challenges of the approach, while diminishing the benefits. I can't believe someone is straight up suggesting to monkey business rules in app logic using dev time rather than actually spend time in guard-railed lo-code platform and build the missing tooling for less technical users.
p1971@reddit
came here to say exactly this ...
So with a rules engine you may have multiple named policies corresponding to the business logic they represent.
Each policy consists of one or more rules, these should be simple assertions based on some input dto, no complex coding or api lookups for example.
This allows the dev team and business users to work out the requirements in a fairly simple fashion (eg the InitialLoanCheck policy consists of the following rules MinLoanAmount, MaxLoanAmount, MinApplicantAge), It also allows for testing of the policies/rules - both unit testing and perhaps via a test harness so users can see how a given input gets processed.
A really simple implementation of this would be to use something like the FluentValidation library, create a dto for each policy and create rules around that.
You can get much more sophisticated and use dsl like languages for rules engines, graphical things the business can drag and drop around - avoid these they're a pain in the arse to debug etc.
cach-v@reddit
Open a tech debt ticket describing the problem and its impact (e.g. cost, risk of bugs, overhead of maintenance etc) and negotiate with the product owner to be given time to work on it.
Break the problem down into smaller discrete steps, so you don't have to ask for 6 weeks to fix it..
achyxhu@reddit (OP)
Tried this but the ROI is never justified (in leadership’s POV). Pushing new features is always greener than fixing old logic
cach-v@reddit
Happens all too often unfortunately
opentowork
Inside_Dimension5308@reddit
DDD might be helping you to design the system. But why even agree to conflicting business logic.
If such a thing happens to our team, PM will be taken for spin bashed from top to bottom.
The first thing to do is get the requirements reviewed from higher management. Once the review starts, you put in your points of concern about conflicting logic.
If the business logic still needs to be implemented as agreed by the review committee, put a strong feet against backward compatibility. You will have to back it up with evidence, how the backward compatibility can introduce a lot of maintainability issues.
If the management is still adamant on backward compatibility, you might want to isolate the business logic based on versioning. Keep the abstractions separate even if it causes duplications.
It will be easier to remove one or the other in future and the control flow is clean.
Dry_Author8849@reddit
In general we transform business logic into configurable features.
Like discounts, pricing, loyalty, in different types/flavors and then relate that to products/customers/sellers/divisions and whatever is needed. Then apply those rules where needed.
I just named a few, but we do this with accounting, resource allocation and you name it. You can then turn on/of the rule in general or disconnect it to products/customers/etc.
That doesn't stop this to become a mess, but we can trace what was applied and each feature has a history to look who, when and why that logic was developed. It brings some order in the chaos, and when implementing something similar we usually found the contradiction first.
So PMs define business rules, but we design the implementation like said.
Cheers!
achyxhu@reddit (OP)
Unfortunately, this is the problem of our product. It is too configurable so the business logic has too many conditions and results. Each time we add a new flow, the number of nodes increases
DuckMySick_008@reddit
I have been there. And sometimes you could make changes, sometimes not. The key here is with the prioritization. If you have the right leaders, convince them on the architectural deficiencies, and if only they listen, and prioritize, it will work in your favor.
As a practical example, the 10yr old codebase I was working with was full of business and spaghetti if-else. Everyone simply focused on rolling out features and never cared for cleaning it up: DDD, Design patterns etc were thrown out of the window and used only while interviewing people.
It was painful to work with. I came up with a doc on what all we are missing with this setup:
* Time to delivery is slow due to lack of abstractions
* Code is bug prone due to lack of tests or even feasibility of adding tests
* Developer onboarding/ on-call ticket resolutions are slow due to...
* Lack of documentation resulting in contradicting and conflicting flows
* Flows dont have clear owners .. etc etc
Put some hypothetical numbers in there and added some proposals on deprecations, clean ups.. and thankfully the persons up the food chain listened and we could make some changes.
wvenable@reddit
A lot of push back, arguments, education, meetings, diagrams, etc.
Over time, I have the respect of lot of managers and we work through things to come to a consensus. I think it's my job to educate, point out the issues, and bring them around to a good design. I'm not always right either so sometimes it works the other way. But, either way, we have to agree on the best solution; I will not just implement whatever they ask blindly.
And yes, whenever we get someone new I have re-live this pain.
RiverRoll@reddit
Sounds like a poor excuse, the development team doesn't just tick requirements from a list, you've been two years in a project it's time to own the business logic and build things together.
el_tophero@reddit
Section 3.3 of the Tao Of Programming:
There was once a programmer who was attached to the court of the warlord of Wu. The warlord asked the programmer: "Which is easier to design: an accounting package or an operating system?"
"An operating system," replied the programmer.
The warlord uttered an exclamation of disbelief. "Surely an accounting package is trivial next to the complexity of an operating system," he said.
"Not so," said the programmer, "When designing an accounting package, the programmer operates as a mediator between people having different ideas: how it must operate, how its reports must appear, and how it must conform to the tax laws. By contrast, an operating system is not limited by outside appearances. When designing an operating system, the programmer seeks the simplest harmony between machine and ideas. This is why an operating system is easier to design."
The warlord of Wu nodded and smiled. "That is all good and well, but which is easier to debug?"
The programmer made no reply.
pauseless@reddit
Put yourself in their shoes. You have dealt with 3+ product managers who are coming in new to the domain you are much more familiar with.
How do you possibly expect them to have the historical knowledge you have?
How can they do anything in their first few months when they’ve not yet reached the point of fully understanding the features and functionality of the system?
Imagine getting a new job and being put in charge of a product that you don’t know anything but the surface details about, and then you’re expected to deal with internal and external people requesting new features, all of which seem fine in isolation (with your limited knowledge), but might conflict with existing code or with the other proposed changes. At the same time, management is telling you they need a roadmap yesterday, even though you don’t even know which of ten options makes sense as step 1, because you don’t have the context or experience on the project.
My solution: guide them, be friends with them, walk them through the various ideas. It takes up time, but it’ll help them, you and the product in the long run. You wouldn’t expect a new dev (no matter how senior) to know all the ins and outs either.
Also… if you don’t feel you can (in a collegial manner) challenge your product manager colleague on decisions for ingrained cultural reasons or whatever, run. As fast as you can. I have done that.
Informal_Chicken3563@reddit
Services catalogue is the way out of messy business logic.
I like this example that shows how a large process is broken down into smaller services:
https://en.wikipedia.org/wiki/Service_(systems_architecture)
Don’t stop the show on features, just migrate the messy business logic into services while you’re in the neighborhood. Over time you’ll slowly untangle the mess
Creativator@reddit
Have an opposite yang to the business ying: a QA analyst to argue with them and show them the mess.
bentreflection@reddit
this is a complex and controversial topic and the answer will very much depend on the specific issue at hand especially when the business logic is contradictory.
If the logic is ACTUALLY contradictory then that means one logic path is wrong and needs to be deleted and that needs to be communicated up the chain so management can decide the correct path. If the logic is just different depending on different flows (e.g. different users have different conditions) then one answer is to use feature switches. Basically you can set up environment variables / settings so the app knows which code path it should take.
At a higher level, dealing with new business logic and how it fits into old business logic is our responsibility as engineers. No product manager is going to come in and be like "hmm let me look at all this existing code and spend time and money removing things that aren't applicable anymore". That would require a huge amount of specific knowledge about the domain and application that i would not expect a product manager to have. Instead, we can bring the contradictions to the product managers / stakeholders attention and figure out if both paths are valid or if one should be removed.
djnattyp@reddit
Don't worry you are The Expert.
ashultz@reddit
I make them sign off on it, and I explain all of it in full detail and don't let them escape with an "I didn't know that".
So if the thing you added has an unpleasant interaction, I will find that, and I will tell you, and you will say it's OK in a very permanent way.
And if your new interactions result in undefined behavior, you will define it before it gets done, and you will sign off on that.
I do it with relentless "let's work together and get this right" attitude and either we work together and get it right or the idea dies and those are both fine by me.
PuzzleheadedReach797@reddit
Adding unit tests and refactor code for more clear and domain driven, yes its long journey but imo its the only way
daredeviloper@reddit
I try to pull things out into methods and add comments.
Icecoldkilluh@reddit
It’s not your product manager’s fault that your code is a mess. Take responsibility for your own shit heap.
Your code is spaghetti because you failed to follow any established good practice of our profession.
Read and learn -> https://refactoring.com/
chengannur@reddit
If the code is something, that we care about (contributions to oss) , then it's good code for the most part.
For work, nope..
Icecoldkilluh@reddit
Cool. You have no professionalism or respect for your own craft. Good luck with that 👍
chengannur@reddit
Thanks, always aim to give others what they truly deserve.
abandonplanetearth@reddit
You can write unit tests to make sure the logic works correctly.
chengannur@reddit
Well, assuming if tests are not present it would be good to add those, so that atleast you will have an idea on whether adding something breaks some other previous expectation
LiquidHelium@reddit
This sounds like a communication and documentation issue more than a code issue. Work with the PM to get a document together with an detailed spec of what the logic is that both product people and developers can understand. Go back and forth until everyone is happy and only then you start coding and use the doc as the source of truth. In my experience you'll find that a lot of stuff doesn't work the way the product people think it does and needs fixing this way which is really valuable to the business, and you can feel comfortable refactoring knowing 100% what the expected behaviour is. The next time they change requirements again you can go to them and show them exactly what they are contradicting and what would need to change.
chengannur@reddit
You dont. You just try to complete your ticket and after a while jump to another company.
Stop thinking someone else's problem as your own. You get paid to write feature, you write those, if existing code is hindering your progress, you estimate based on that and move on.
zero400@reddit
First time? Sometimes you have to educate and lead your leadership. Sometimes you have to do the right thing even if it doesn’t get you the recognition and incentive you think it should. Help your future project maintainers first. Keep doing your job second. Start practicing leet code and interviews third. You don’t have to move but it gives you leverage and makes you ready.
SweetStrawberry4U@reddit
"Anybody and everybody is Replaceable" is the root-cause of legacy spaghetti code practices.
You have inherited, and now you "own" that "Shit".
Obviously, "Coasting" is a lot safer, unless immediate Management is supportive, and then "minimizing tech-debt" ( generally, "tech-debt" is regarded derogatory ), also known as "Product Enablement", may be planned and introduced in phases.