I ran into many videos and resources for DDD and have been reading quite a bit. Also doing hands on. I am writing this blog series because I believe we have been incepted. There is chaos, scattered, scant sometimes, and misinformation about DDD and nobody has stepped down to a newbie level yet to explain in a practical way what is going on with the architectures that had been in the works for other languages since the golden era. I am realizing that the PHP world is experiencing this renaissance because the level of many developers have matured in such a way that techniques from the Java world are making renaissance inroads with them in order to cope with PHP enterprise application and smaller applications designed smarter and cleaner.
Let’s begin using a popular tool to illustrate this, then explain what is this, just bear with me:
title DDD Exam Process Interactor participant client participant http participant interactor participant factory participant repository participant domain-services client->http: Http Request\n (answer question) http->interactor: AnswerView activate interactor interactor->factory: createFromView(AnswerView) factory->interactor: Answer interactor->repository: Answer(s) repository->interactor: Question(s)\ncreateFromData() interactor->domain-services: othersMethods() domain-services->interactor: results interactor->http: QuestionResponse deactivate interactor http->client: Http Response
Let’s suppose I am solving an exam questionary problem. My domain is the dealing with exams. From the student point of view is the taking of the exams. From the professor is the creation of those exams. Maybe from the university point of view is grading and administering who to ban or choose for given exams, etc.
Thanks to several resources and friends I am walking through the learning curve of DDD + BDD now. For me this is a renaissance of the design culture in the PHP world. To describe then what the procedure I am employing is let me focus on the graphic above.
I have grabbed the itent of the student, he or she take an exam and the first thing they know is they are presented with question after question. The question prompts them for an answer and after they have responded then they are given the next question. I writing a behat feature, create a default context from where I use helper class trying to reach a DSL-like helper. Then as I am trying to make pass the feature I create collateral objects thinking always in terms of intent and not in terms of doctrine entities. I don’t want to know anything about doctrine, about a component library or even a framework. Yes I said it right, I hate, I can’t see doctrine and Symfony2 at this point in time. With this pristine mindset then we make the behat feature pass and iterate of course with phpspec on the inner circle to make the phpspec specs pass as well. This is in the spirit of outside-in approach of BDD acceptance and specification. After this is done, things are not there yet. This was a spike and we should relax. Now we need to organize our ideas and rename folders and files and start making sense on the actual model we are creating by giving thought and digging in DDD theory and practice.
What happens here in the diagram above, it explains how the feature goes in terms of transaction like and domain like ideas. Student issues with his or her browser an HTTP request, this is translated to a boundary acceptable request that plugs into the ports/boundary of our domain model. Because it is an answer, the proper DTO/port is an object of type AnswerPort. I have changed the naming here from view to port because I think it makes more sense. All this inputs land on an interactor that bears as collaborators the services, factories and repositories needed to manipulate the domain model and give an application response corresponding to another port. This port gets translated back into an HTTP response and this is sent back to the student, that is another question and some collateral information.
Here is the feature:
Feature: student can take an exam Scenario: student takes an exam # features/user_stories.feature:3 Given student starts an exam # FeatureContext::student_starts_an_exam() And student is presented with a question # FeatureContext::student_is_presented_with_a_question() When student answers to question # FeatureContext::student_answers_to_question() Then student is presented with a question # FeatureContext::student_is_presented_with_a_question() When student answers to question # FeatureContext::student_answers_to_question() Then student is presented with a question # FeatureContext::student_is_presented_with_a_question() When student answers to question # FeatureContext::student_answers_to_question() Then student ends exam and gets graded # FeatureContext::student_ends_exam_and_gets_graded()
And this is how I have arranged the project files:
~ tree . └── Domain ├── Model │ └── Exam │ ├── ExamSpec.php │ ├── OptionSpec.php │ └── QuestionSpec.php ├── Port │ ├── ExamSpec.php │ └── ExamsSpec.php ├── Services │ ├── ExamRepositorySpec.php │ ├── ExamsConverterSpec.php │ └── PrototypeManagerSpec.php └── UseCase ├── ShowsAllExamsSpec.php └── ShowsNextQuestionSpec.php
Notice the ports or boundaries (in this case, if we use commands then things change a bit), the domain services (sometimes get confused by application services but should not), and the model entities and value objects. The interactors are also renamed as UseCase’s. I credit here my mentors @igorw, @davedevelopment, and @beau for all the ideas, correction and advice given so far on my first steps.
So I will stop here and leave you a bit hungry for the next series. I appreciate ya’lls support getting the book, donating and just mentoring me along this road. I hope I can give all that I know at the talk in Argentina. If you are interested please contribute with new ideas below in the comments and on the repo I have on github.
I say until next for now. Graciously undeserving all of this.
your friend @cordoval.