Logically how can I prevent a client from making changes to a domain model entity if a service is not used? For example:

Let's say I have an Account class that contains Transactions to compute a balance. A service is used to coordinate the interaction of these entities. However, I only want a client to be able to use specific functions (e.g. CurrentBalance, BalanceByDate(), etc.). I do not want to allow them access to AddTransaction without using the service. A DTO seems odd since it's not really transitioning boundaries.


public class Account
    public decimal CurrentBalance()
      // return current balance

    public decimal BalanceByDate(DateTime date)
      // return balance through date

    // Want to restrict usage of this to a service only
    // to coordinate interaction of multiple entities to
    // prevent corruption to the accounting system
    public void AddTransaction(Transaction trans)
      // add transaction to list of transactions


public class AccountingService
    public void AddTransaction(Transaction trans)
        foreach (var account in trans.Accounts)
            account.AddTransaction(trans);      // method in question

    public Account GetAccount(int ID)
        // return account by id


var accountingService = new AccountingService();
// build transaction here
var transaction = TransactionFactory.Create(/*blah*/);

// but this would be harmful to the system...
var account = accountingService.GetAccount(accountID);
account.AddTransaction(new Transaction(/*junk data*/));

// however, still want to get the balance of the account
var balance = account.CurrentBalance();

So how do most people handle this? Expose different interfaces so clients use something different? Have Account implement IAccountable vs ITransactionable? Or just return some type of read-only Account where calling AddTransaction() really only affects that object? Another idea was to inject a list of transactions into the Account constructor and remove the AddTransaction() method.

  • Down-voter care to comment? – keelerjr12 Nov 7 '18 at 0:31

No client should be forced to depend on methods it does not use.

The fancy name for this idea is the Interface Segregation Principle. However, this can seem very annoying to someone who just wants to build a service.

It helps to stop focusing on the service. Just pretend it doesn't exist for a moment. Look at your client and ask what it needs. Build something that promesses the client what it needs. Whatever that thing is let the client define it. Nothing else has any right to cause change in that things interface but the client.

When you think that way, clients OWN the interfaces they use (keyword or otherwise). When a service implements that interface that service isn't publishing it's interface. It's promising that it can do what the clients that use that interface need.

When you think of it that way it's really not that weird to simply leave AddTransaction() off the interface that the client sees, regardless of whether others can see it on other interfaces that it also implements. When the client doesn't know it exists it won't hurt a thing.

  • ideally I’d love for the interface to be something like Account.CurrentBalance(), or Account.BalanceByDate(date), or Account.AddTransaction(). However, there are multiple entities involved (e.g. multiple accounts), so some type of coordinating entity is needed. I hate the idea of a service because I feel that there is always a logical concept to fulfill the role of a service. But I think you’re correct with trying to look at the problem with a top-down view instead of just a bottom-up. – keelerjr12 Nov 7 '18 at 3:16
  • 2
    I don't think of it as top down. I actually think anything can be a client and anything can be a service. Its a simple relationship. One thing needs something done. Another thing knows how to do something. The less the two know about each other the more you can swap out others that do the same things. Doesn't matter who's on top. – candied_orange Nov 7 '18 at 9:18

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.