Quick overview of the domain
In the domain of accounting, there are the following distinct but related concepts:
- an account identifies the basic financial "topics" that are to be accounted for;
- a transaction or a posting represents a business event that aggregates several change of values to the accounts;
- a (posting/transaction) line or item is a part of a transaction that documents a change of value that affects exactly one account;
- an account balance summarises the value of an account, taking into account all the relevant items;
- a ledger is a chronological ordered set of transactions. The general ledger is the set of all items, chronologically ordered by account.
Beyond the basic (and here somewhat simplified) concepts, there is some business logic to ensure in all cases:
- the sum of all debits and credits of a transaction must be equal (or if your represent credits with negative numbers, the sum must be 0).
- as a consequence, the sum of all debits in a ledger or in the general ledger will mechanically be equal as well.
- the totals of items for an account in the general ledger must always be equal to the balance of that account
Analysis of your design alternatives
Current approach is very sensitive to the quality of each application. Each application could break the rule and create a mess in the accounts of all the others.
The Linq approach ensures a better consistency between all your applications. But are you sure that you can guarantee the consistent update of all your new domain objects, especially if you'd update one application and forget to recompile/deploy the others ?
The more abstract approach seems to have a cleaner architecture. Furthermore it implements a sound separation of concerns:
- The 10 applications each implement their own specialised application logic (sales, purchasing, stock management, etc..)
- The common domain logic of accounting is guaranteed by your accounting service layer. If you test thoroughly your service layer, you could then be sure that no application could mess up the accounts (event if it would be an older version of the application that someone forgot to recompile). In each application, the developers have only to worry that the right transactions are recorded, and would focus their tests on the application's specialised logic only, without having to understand the details of accounting.
- If you want to improve your accounting logic and for example add some logging features (for example at request of the financial auditors), you'd just have to do it in your service level, and you're sure that all the application will work as expected with the new feature.
So in the end, the applications should not do any accounting calculation anymore: they should just query the service for getting the accounts to be used, send to the service consistent transactions (using some kind of DTO), and query account balances if needed.