4

It's not my intent to engage in a debate over validation in DDD, where the code belongs, etc. but to focus on one possible approach and how to address localization issues. I have the following behavior (method) on one of my domain objects (entities) which exemplifies the scenario:

public void ClockIn()
{
    if (WasTerminated)
    {
        throw new InvalidOperationException("Cannot clock-in a terminated employee.");
    }

    ClockedInAt = DateTime.Now;
    :
}

As you can see, when the ClockIn method is called, the method checks the state of the object to ensure that the Employee has not been terminated. If the Employee was terminated, we throw an exception consistent with the "don't let your entities enter an invalid state" approach.

My problem is that I need to localize the exception message. This is typically done (in this application) using an application service (ILocalizationService) that is imported using MEF in classes that require access to its methods. However, as with any DI framework, dependencies are only injected/imported if the object was instantiated by the container. This is typically not the case with DDD.

Furthermore, everything I've learned about DDD says that our domain objects should not have dependencies and those concerns should be handled external from the domain object. If that is the case, how can I go about localizing messages such as the one shown above?

This is not a novel requirement as a great many business applications require globalization/localization. I'd appreciate some recommendations how to make this work and still be consistent with the goals of a DDD.

UPDATE

I failed to originally point out that our localization is all database driven, so we do have a Localization Service (via the injectable ILocalizationService interface). Therefore, using the static Resources class Visual Studio provides as part of the project is NOT a viable option.

ANOTHER UPDATE

Perhaps it would move the discussion along to state that the app is a RESTful service app. Therefore, the client could be a simple web browser. As such, I cannot code with any expectation that the caller can perform any kind of localization, code mapping, etc. When an exception occurs (and in this approach, attempting to put the domain object into an invalid state is an exception), an exception is thrown and the appropriate HTTP status code returned along with the exception message which should be localized to the caller's culture (Accept-Language).

SonOfPirate
  • 5,642
  • 3
  • 41
  • 97
  • Related: http://stackoverflow.com/questions/4835046/why-not-use-an-ioc-container-to-resolve-dependencies-for-entities-business-objec. – Steven Apr 11 '12 at 06:46
  • Related, yes, but far from an answer. Thanks for the link! – SonOfPirate Apr 11 '12 at 12:11
  • User mechanism that is provided by you Framework\Platform, for .NET application throw new Exception(Resources["TerminatedEmployeeMessage"]). http://stackoverflow.com/questions/1138934/c-sharp-class-library-localization – Alex Burtsev Apr 13 '12 at 05:20
  • @Alex, thanks for catching my gaff! See my update. – SonOfPirate Apr 13 '12 at 12:18

4 Answers4

2

Not sure how helpful this response is to you, but localization is really a front-end concern. Localizing exceptions messages as per your example is not common practice, as end users shouldn't see technical details such as those described in exception messages (and whoever will be troubleshooting your exceptions probably has a sufficient level English even if it is not their native language).

Of course if necessary you can always handle exceptions and present a localized, user-friendly message to your users in your front-end. But keeping it as a font-end concern should simplify your architecture.

Clafou
  • 15,250
  • 7
  • 58
  • 89
  • The requirement is to present the UI with a descriptive message when an exception occurs. This must be localized along with the rest of the text displayed in the UI. It cannot be simply a UI concern for two reasons: 1. the data is stored in a database, so there has to be a back-end provider for the information; and, 2. it would require a unique exception type for every possible exception so the client could catch it and lookup the localized text. Instead, since the server has the localized text, performing the localization on the server is cleaner. – SonOfPirate Apr 13 '12 at 17:47
  • As an example, a second business rule would be not to clock in an employee that is already clocked in. This would also result in an InvalidOperationException being thrown but will have an error message that is different from the one shown above. So I either localize it here, where I control what message I want, or I have to create two exception classes to represent each case. And that becomes massive when applied to the real-world, enterprise-scale application I am developing with hundreds of business rules to enforce. – SonOfPirate Apr 13 '12 at 17:49
  • 1
    It sounds like you may be overly relying on exceptions. Validation logic doesn't have to be implemented with exceptions. You could return known error codes and have these mapped to resource identifiers so that you can display localized messages in the UI. – Clafou Apr 13 '12 at 19:17
  • We're not overly relying on exceptions. Exceptions are for exceptional cases and trying to clock-in a terminated employee is certainly an exceptional case. Returning errors codes is a well documented bad practice and not something we are going to adopt. – SonOfPirate Apr 14 '12 at 02:47
  • 1
    Throwing exceptions for invalid states/inputs at lower layers is good (asserts, which throw exceptions, are good for this), but the UI and validation logic should prevent invalid usage (and hence exceptions) in the first place. A good UI shouldn't let a terminated employee clock in. – Clafou Apr 14 '12 at 09:56
  • But it you have so many rules that you can't or don't want your front end to validate and you want to convey localized messages in exceptions, perhaps you could create a ExceptionWithDisplayMessage base class for your exceptions and give it a property with an identifier for a message string, for which your front end can then fetch a message in the relevant language and present it in the UI. – Clafou Apr 14 '12 at 09:57
  • All good ideas. See my latest update for more information why I can't rely on the UI doing the right thing or having localization logic. – SonOfPirate Apr 14 '12 at 10:57
  • The problem with creating a specialized exception class is that we use the exception type to indicate the HTTP Status Code that is returned to the caller. For instance, any ArgumentException results in a Bad Request (400) status, NotImplementedException results in a Not Implemented (501) status, etc. Creating subclasses would circumvent this logic, or I'd have to create a subclass for each exception type. – SonOfPirate Apr 14 '12 at 11:01
  • It has taken me a little while to come around to your point-of-view, but with a little help from a friend, I think I see what you were saying. As a result, I have abandoned the need to localize these exception messages as they really are the result of programming errors and should never occur in production. Because the only person ever seeing the exception message is the developer, I really only need to ensure that it is localized to the developer. That can be done with the built-in .resx file support. – SonOfPirate Apr 23 '12 at 12:43
  • As you said, the condition that caused the exception is part of our business rules and anyone making use of our domain layer should be checking these rules prior to the operation. The checks and exceptions still exist to protect the domain, but the messages don't require localization. It is unlikely that the error was the result of user activity but, if so, the UI can localize what is shown. – SonOfPirate Apr 23 '12 at 12:45
1

As Clafou said, you shouldn't use exceptions for passing messages to the UI in any way.

If you still insist in doing this, one option is to throw an error code instead of the message

throw new InvalidOperationException("ERROR_TERMINATED_EMPLOYEE_CLOCKIN");

and then, when it happens, do whatever you need to do with the exception (log, look up localization, whatever).

Luiz Damim
  • 3,803
  • 2
  • 27
  • 31
  • As I said to @Clafou, exceptions are for exceptional cases and that is what I'm describing. I've thought about setting the resource key as the exception message but that seems a little like stuffing a square peg into a round hole. I'd like to find a square hole if possible. – SonOfPirate Apr 14 '12 at 02:48
0

If localisation is important part of the domain/application you should make it a first class citizen and inject wherever it belongs. I am not sure what you mean with "DDD says that our domain objects should not have dependencies" - please explain.

Tomas Dermisek
  • 778
  • 1
  • 8
  • 14
  • Do a web search on "Domain Object Dependencies", "DDD Entity Dependencies" or any variation on the same and you'll find numerous articles, posts and discussions on this topic. And, according the Evans, this is simply not good practice. – SonOfPirate Apr 13 '12 at 12:20
0

You are correct for trying to avoid adding internal dependencies to your domain model objects.

A better solution would be to handle the action inside of a service method such as:

public class EmployeeServiceImpl implements EmployeeService {

   public void ClockEmployeeIn(Employee employee) throws InvalidOperationException {
      if (employee.isTerminated()) {
          // Localize using a resource lookup code..
          throw new InvalidOperationException("Error_Clockin_Employee_Terminated");      
      }       
      employee.setClockedInAt(DateTime.Now);
   }
}

You can then inject the service using your DI framework at the point where you will be making the clockin call and use the service to insulate your domain objects from changes to business logic.

DaCrazyCoder
  • 51
  • 1
  • 5