3

According to DDD and the clean architecture, entities should encapsulate data and related logic.

So, how do you design a class to represent a particular real world entity?

Two alternatives among lots of possible strategies:

  1. Firstly, define properties of entity (ask which information should be stored.). Then create required getters/setters. Find associations with other entities. Finally add operations for extra business logic.

  2. Firstly, define which information the entity should provide (design an interface including only getters). Then decide how the class provides required information. (Implement the interface and add some operations with side effects.) You may create properties and setters, you may calculate return values. (Create a public operation calculating desired info), etc.

For example, let's consider Student entity. It has name, id, etc. A student attends some courses. He enrolls courses with some limitations and he takes grades. You want to get his academic transcript. Now, how do you start to write a Student class. What are your considerations? How do you make sure that the class complies requirements?

closed as too broad by Doc Brown, Euphoric, gnat, Daenyth, Andres F. Sep 29 '16 at 23:38

Please edit the question to limit it to a specific problem with enough detail to identify an adequate answer. Avoid asking multiple distinct questions at once. See the How to Ask page for help clarifying this question. If this question can be reworded to fit the rules in the help center, please edit the question.

  • 1
    You will find several different opinions from different experts here what the "best" way might be. One people will prefer a "TDD" approach, the next will cite the Yagni principle, but without writing tests first, and there will surely be people favoring some real up-front design. So IMHO your question is not a good fit for the FAQ format this site, since it invites to an open-ended discussion. – Doc Brown Sep 29 '16 at 11:57
  • @DocBrown I think your comment could be an answer. Because, you give a list of possible approaches. – Q Q Sep 29 '16 at 12:26
  • You use yours skills and experience as software developer to make it. – Euphoric Sep 29 '16 at 12:33
  • 2
    It would be a non-answer. And I have a clear vision in which order I would implement things in some contexts, and in which order in other contexts (others surely have a different opinion about this). But if I would write a length-winded answer about it, it could start a flame war ;-) This site and the community here prefer clear questions with real answers, the SE sites are not a discussion forum. – Doc Brown Sep 29 '16 at 12:37
3

It's foolish to think you can just look at a real world object and just start modeling it. What's important is what you really need of that object in your system.

That said, it doesn't really matter if you design the student class first or everything that talks to the student class first. Realize your going to have to make changes later no matter where you start. So 1 and 2 are just a personal preference. You can write good code either way.

A student is an Entity. A student's transcript shouldn't disappear if the student has their name legally changed. Therefore the transcript is not associated with the students name but with their identity.

  • Why is that foolish...? I think the idea is that if you're accurate in your domain model, your domain will change much less often than the infrastructure that implements it. – RJB Sep 29 '16 at 22:52
  • 2
    @RJB It's foolish because that thinking can attract clutter. Sure a duck has 2 legs and a dog has 4 but if my system doesn't care so long as you can move why the hell does Animal have a numberOfLegs attribute? – candied_orange Sep 29 '16 at 23:48
  • Duck shoe business? – RJB Sep 30 '16 at 0:12
  • Students actually have a head, and a body. But we don't model a student like this in an academic IT system. The question is not about modelling real world objects, it is about class design. – Q Q Sep 30 '16 at 6:19
  • 1
    We don't? – candied_orange Sep 30 '16 at 13:23
1

I would suggest you follow the behavior.

A Student is a real world object. It's also your aggregate root -- a Transcript means nothing unless it belongs to a Student. So first, create the Student class.

Then create required getters/setters.

Kind of/no. I wouldn't discourage you from creating properties for any real-world attributes you're aware of. But the properties should only have private set, otherwise they're "promiscious." You can set an initial value in the constructor, and you can change that value via a special behavior method.

This is kind of arbitrary, but for example....

public string Name { get; private set; }

// usually there's more logic involved than just updating the value...
// in other words, usually there's a special real-world reason it's changing
public void ChangeName(string newValue) { Name = newValue; }

Following the behavior, say the next thing your app needs is to load a student's transcripts. Your aggregate root is a Student, so you might have a StudentRepository to query all the Students. The repository is a list of special-purpose data access operations defined in your domain.

This belongs in your Core/Domain:

public interface IStudentRepository {
    IEnumerable<Transcript> GetTranscriptsForStudent(int studentId);
}

This belongs in whatever project you're using for data (like EF):

public class StudentRepository {
    IEnumerable<Transcript> GetTranscriptsForStudent(int studentId) {
        //...
    }
}

(This separation is maybe subjective, but personally I think that a domain model shouldn't be doing its own data access.)

And then you could argue that Course is its own aggregate root, with its own repository for adding a Student to a Course.

And it goes on as it grows. Your domain behavior shapes the application, tells you which unit tests to write, and should generally be recognizable to any code-illiterate Business Analyst.

0

My advice is to start from the outside by first writing the code that uses the entity. Think of the use cases in your application and write them in the Ubiquitous Language of your domain. Two examples:

class ViewTranscript {

    // TODO populate using dependency injection or a service locator
    StudentRepository studentRepository;

    public StudentTranscript viewTranscript(String studentId) {     
        Student student = studentRepository.getStudent(studentId);
        StudentTranscript transcript = student.getTranscript();
        return transcript;
    }
}

and

class Enroll {

    // TODO populate using dependency injection or a service locator
    StudentRepository studentRepository;

    CourseRepository courseRepository;

    // I like having CourseEnrollment as a separate aggregate root 
    // but you could also have it as a child entity of student.
    CourseEnrollmentRepository courseEnrollmentRepository;

    public void enroll(String studentId, String courseId) {
        Student student = studentRepository.getStudent(studentId);
        Course course = courseRepository.getCourse(courseId);
        CourseEnrollment enrollment = selectedCourse.enroll(student);
        courseEnrollmentRepository.save(enrollment);
    }
}

Now you can start implementing the Course.enroll() and Student.getTranscript() methods since you know that they are actually useful and you now know what parameters and return type they should have.

Some of you may be shouting already about the ViewTranscript and Enroll classes but I assure you, it is perfectly normal DDD and Clean Architecture to have application services that exercise the domain model by calling such high level methods, and now the programmer can start coding the real business logic in the Course.enroll() and Student.getTranscript() methods. Entities should preferably not know about repositories.

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