Loose coupling, high cohesion for a maintainable application
This is the battle-cry that I hear over and over. There is plenty of advice on how to loosely couple components.
- Base on interfaces and inject all dependencies
- Use events
- Use a service bus
- etc.
However, I feel like I've never really heard any specific suggestions for increasing cohesion. Does anyone have any to offer?
You can start answering there but I have as specific situation in mind that I would like advice on also.
I have a fairly loosely coupled C# Windows Forms MVP application that bases many of its components off of interfaces, injects them through constructors and uses an Inversion of Control container (Castle Windsor) to assemble it all together.
I would say its quite well architected - it has undergone several big change requests already and handled them quite easily. I am overall quite satisfied with it but I just can't let go of a nagging doubt that it's not particularly cohesive. This is not a problem for me as the sole developer but I fear it can get quite confusing for someone that comes into the application for the first time.
Let me give you an example - the application is used by Company A to fill and process outgoing trucks with product. This means that there is an OutgoingTransactionInfo object, an OutgoingTransactionInfoControl (for actually entering said information), OutgoingTransactionValidator, and OutgoingTransactionPersister. With the app in production, we got a request to handle incoming transactions as well - these get different information attached, different validation, and a different way of persisting them. Then Company B wanted to use the application for their transaction processing too, the idea is the similar but again, info, validations, persistence, and maybe a few other components differ.
Because my application has a good testing suite and is loose I've been able to accommodate these requests quite easily. However I recognize that it is all too easy to accidentally configure it in an invalid state. For example, you can wire it to use OutgoingTransactionInfo objects while validating with an IncomingTransactionValidator. If the differences are subtle the error might even go undetected for some time.
Do you have any suggestions for me? What techniques have you use to mitigate such risk?