One of the premises of Strategic Domain Driven Design is that in every non-trivial application there will be multiple models at play. This may sound controversial to some, but since a model is a representation of a portion of the problem domain aimed to serve a specific use, the need of multiple models promptly arises as our application grows in size and/or complexity.
The Ubiquitous Language plays many roles in DDD, among others it may be considered an integrity check for any model in play assuring that every role involved in software development, from domain experts to developers, shares the same language and agrees on the specific meaning of every term which is part of the ubiquitous language.
The Ubiquitous Language plays many roles in DDD, among others it may be considered an integrity check for any model in play assuring that every role involved in software development, from domain experts to developers, shares the same language and agrees on the specific meaning of every term which is part of the ubiquitous language.
The Ubiquitous Language should be the only language used to express a model. Everybody in the team should be able to agree on every specific term without ambiguities.
Code is the primary expression of the model, other artifacts might be necessary along the way to capture requirements or portions of the design, but the only artifact that will be constantly in sync with the application behavior is code itself. Ensuring that every term is precisely defined and that is consistently used in every representation of the model greatly helps ensuring integrity of our application. Model integrity comes at a (reasonable) price: the model cannot be extended indefinitely, but can be shared, coherent and acknowledged only within a given Context.
So, ...what exactly is a context?
In Domain Driven Design, a Context is defined as
“The setting in which a word or a statement appears that determines its meaning”which might sound rather ...vague, at first read. But I’ve learnt that Eric Evans always chooses carefully each word, especially in the key sentences. So the definition above describes exactly what a context is (at least in the Domain Driven Design context). This definition says nothing about the size, shape or other characteristics of a context, so they are likely to be consequences of the link between the word or the statement and the meaning.
But this definition calls for examples, here is a trivial one. The word Account has a very precise meaning in the banking context, and in a typical application, we would probably model it with a balance and an accountNumber attribute, and so on. But in the context of Web Applications, an Account is closely related to credentials, such as username, password, and so on, and we would tend to model it in a very different way.
Trying to force the two definition within a single class might result in awkward code, whose conceptual integrity has been undermined by the attempt to fulfill two distinct models within the same class. Admitting that the same term might be referred to two distinct concepts is crucial for model integrity.
Making the contexts explicit, we are making both models clearer and unambiguous.
Ok, this first example might be too trivial: the term Account refers to two different concepts, and simply calling them BankingAccount and LoginAccount might have solved the problem. A more subtle distinction might arise when the concepts is the same but but used in different ways, thus leading to different models.
Let’s suppose we’re working with an application managing payments. We’ll probably use this application to manage our Banking Accounts, keeping track of current balance and past operations. The model for our Banking Account might be a BankingAccount class like the one below.
Some PFM apps allow us to manage also payments, keeping a Payee Registry. In this scenario, a Payee is normally associated with one or more Banking Account, but in this case we won’t know anything of the internals nor we can issue any operation on those accounts. Does it make sense to model the Payee account with the BankingAccount class we’ve just defined?
Well... it does sound reasonable: it’s the same concept, I mean, in the real world our account and the payee’s one might even be in the same physical bank. Still, it doesn’t feel completely right: we are not supposed to issue any operation on the payee Banking Account, or to track anything on that. Even worse: doing so would probably be a bad mistake within our application.
In this case, we’re using the same concept in different ways, and this will lead us to different models. Even if the class is already defined in the application, a different context calls for a different model.
Making the contexts explicit, we are making both models clearer and unambiguous.
The term Account does not have a single non ambiguous meaning, but in a given context the meaning is well defined.
Ok, this first example might be too trivial: the term Account refers to two different concepts, and simply calling them BankingAccount and LoginAccount might have solved the problem. A more subtle distinction might arise when the concepts is the same but but used in different ways, thus leading to different models.
Let’s suppose we’re working with an application managing payments. We’ll probably use this application to manage our Banking Accounts, keeping track of current balance and past operations. The model for our Banking Account might be a BankingAccount class like the one below.
Some PFM apps allow us to manage also payments, keeping a Payee Registry. In this scenario, a Payee is normally associated with one or more Banking Account, but in this case we won’t know anything of the internals nor we can issue any operation on those accounts. Does it make sense to model the Payee account with the BankingAccount class we’ve just defined?
Well... it does sound reasonable: it’s the same concept, I mean, in the real world our account and the payee’s one might even be in the same physical bank. Still, it doesn’t feel completely right: we are not supposed to issue any operation on the payee Banking Account, or to track anything on that. Even worse: doing so would probably be a bad mistake within our application.
In this case, we’re using the same concept in different ways, and this will lead us to different models. Even if the class is already defined in the application, a different context calls for a different model.
Again, name clashes might be solved in different ways at the code level, you can effectively partition the system by adding meaningful prefixes to the classes, or using packages, or in some other way. What matters now is that there are ambiguities, and a term can be effectively defined only within a given space.
So, a Context is a “space” where a given concept is precisely defined without ambiguities, so that it can be safely used in the Ubiquitous Language. If the same concept appears different times with different meanings within an application, we’re probably heading towards multiple Bounded Contexts within the same application.
In Domain Driven Design, a model is intended to serve a specific use, and nontrivial applications often tend to be used in different ways: trying to accommodate every use within a single model is a meaningless effort. It will end up corrupting your model with ill-defined or ambiguous term making the model you developed within a context less valuable. Contexts cannot be expanded indefinitely: Context Boundaries are needed to define which concepts are in and which ones are out, and to ensure conceptual integrity to the model within the context.
So, a Context is a “space” where a given concept is precisely defined without ambiguities, so that it can be safely used in the Ubiquitous Language. If the same concept appears different times with different meanings within an application, we’re probably heading towards multiple Bounded Contexts within the same application.
In Domain Driven Design, a model is intended to serve a specific use, and nontrivial applications often tend to be used in different ways: trying to accommodate every use within a single model is a meaningless effort. It will end up corrupting your model with ill-defined or ambiguous term making the model you developed within a context less valuable. Contexts cannot be expanded indefinitely: Context Boundaries are needed to define which concepts are in and which ones are out, and to ensure conceptual integrity to the model within the context.
No comments:
Post a Comment