Ubiquitous Language

Domain-driven design (DDD) nie jest nowym tematem (Eric Evans sformalizował tę koncepcję ponad dekadę temu). Ciekawe jest jednak to, jak do dziś podstawowe pojęcia na ten temat wzbudzają zainteresowanie, szczególnie w społecznościach .NET. Jeszcze dziwniejsze jest to, jak te same pojęcia są błędnie interpretowane.

Podstawa DDD leży w koncepcji wszechobecnego języka. Nie jest nim określanie, czym jest encja, obiekt wartości, agregat, usługa czy repozytorium.

Odnosimy wrażenie, że każdy, kto zaczyna studiować DDD, czyta kilka pierwszych stron książki Evansa lub Vernona i szybko przeskakuje od razu do stron opisujących wzorce.

Często rozmawiamy z informatykami, którzy myślą, że posiadanie zdefiniowanego wszechobecnego języka oznacza, że nazwy klas i właściwości, pisane przez programistów, są zgodne ze słownictwem ekspertów dziedzinowych. Jest to jednak grube uproszczenie.

Aby zrozumieć znaczenie wszechobecnego języka, zacznijmy od „podmiotu” wymienionego poniżej:

public class Employee{ public string Id { get; set; } public string Name { get; set; } public string Cpf { get; set; } public decimal Salary { get; set; }}

Oto doskonały przykład anemicznej implementacji! Ale zanim przeczytasz dalej, spróbuj dowiedzieć się dlaczego.

W naszej codziennej pracy, kiedy używamy tego przykładu, słyszymy sugestie, że tej klasie brakuje zachowań (Co jest słuszne!). Kiedy jednak pytamy, jakie to miałyby być „zachowania”, okazuje się, że ludzie powtarzają ogólne argumenty (od osób, które też nie „załapały” o co chodzi) i nie potrafią wskazać, co jest nie tak!

Jednym z najczęstszych argumentów jest to, że ustawiacze właściwości powinny być prywatne. W ich miejsce powinniśmy mieć metody „DefineXXX”, które implementowałyby walidacje. Ten pomysł nie ma sensu, ponieważ celem setterów jest właśnie ustawianie wartości dla właściwości, i nie byłoby problemu z zaimplementowaniem w nich logiki walidacji.

Metody encji powinny określać motywacje dla zmian jej stanu. Ponadto, musi istnieć przynajmniej jeden konstruktor zdolny do zainicjowania encji od początku, w poprawnym stanie.

Nie jest rzadkością znalezienie implementacji klas z właściwościami, które sprawdzają, na przykład, czy wartość, którą próbujesz ustawić jest non-null, nawet jeśli te same właściwości mają null jako wartość domyślną. Jaka jest tu logika?

Zobacz inny przykład anemicznej klasy:

public class Customer { public string Name { get; private set; } public string Email { get; private set; } public DateTime BirthDate { get; private set; } public Customer(Guid id, string name, string email, DateTime birthDate) { Id = id; Name = name; Email = email; BirthDate = birthDate; } }

W powyższej klasie mamy typowy „zapis” dla implementacji funkcjonalnej. Ale w języku obiektowym nie jest to encja.

Pomysł ten miałby nawet sens w języku czysto funkcjonalnym, gdzie „encja” jest koncepcyjnie rozłożona w różnych funkcjach definiujących zachowanie, ale w C# nie ma to żadnego sensu.

Spróbujmy drugą wersję dla klasy Employee:

public class Employee{ public string Id { get; private set; } public string Name { get; private set; } public string Cpf { get; private set; } public decimal Salary { get; private set; } public Employee(string name, string cpf) { //.. } public void RaiseSalary(decimal amount) { //.. }}

Tym razem encja jest mniej anemiczna. W końcu motywacje, które napędzają zmianę wartości właściwości, są oczywiste. Zauważ, jak nawet wartość pisania testów staje się bardziej wyraźna.

Anyway, wciąż mamy problemy. Nazwaliśmy metodę „RaiseSalary”, jednak nie jest to sposób, w jaki eksperci domeny opisują tę operację. Jedynym sposobem na określenie rzeczywistych powodów zmiany wartości właściwości jest rozmowa z tymi ekspertami.

Do przemyślenia…

Identyfikacja i implementacja wszechobecnego języka nie służy tylko do definiowania nazw klas lub właściwości. Wszechobecny język musi ujawniać się przede wszystkim w motywacjach zmian stanu naszych encji explicite.

Zrozumienie wszechobecnego języka jest znacznie ważniejsze niż nauka standardów. Bez prawdziwej znajomości domeny, wartość wzorców projektowych jest zerowa.

Nie martw się najpierw o naukę tego, co najważniejsze. Poświęć czas i wysiłek, aby dobrze zrozumieć domenę i przeliterować jej wszechobecny język. Wtedy może nawet będzie miało sens myślenie o kojarzeniu DDD z bardziej zaawansowanymi koncepcjami technicznymi.

Dodaj komentarz

Twój adres e-mail nie zostanie opublikowany.