├── README.md ├── courses-examples └── behavioral-design-patterns-course │ ├── chain-of-responsibility │ ├── command-bus-middleware │ │ ├── README.md │ │ └── java │ │ │ ├── .editorconfig │ │ │ ├── .env │ │ │ ├── .github │ │ │ └── workflows │ │ │ │ └── ci.yml │ │ │ ├── .gitignore │ │ │ ├── Dockerfile │ │ │ ├── Makefile │ │ │ ├── README.md │ │ │ ├── apps │ │ │ ├── main │ │ │ │ ├── resources │ │ │ │ │ ├── .env │ │ │ │ │ ├── backoffice_frontend │ │ │ │ │ │ ├── public │ │ │ │ │ │ │ └── images │ │ │ │ │ │ │ │ └── logo.png │ │ │ │ │ │ └── templates │ │ │ │ │ │ │ ├── master.ftl │ │ │ │ │ │ │ ├── pages │ │ │ │ │ │ │ ├── courses │ │ │ │ │ │ │ │ ├── courses.ftl │ │ │ │ │ │ │ │ └── partials │ │ │ │ │ │ │ │ │ ├── list_courses.ftl │ │ │ │ │ │ │ │ │ └── new_course_form.ftl │ │ │ │ │ │ │ └── home.ftl │ │ │ │ │ │ │ └── partials │ │ │ │ │ │ │ ├── footer.ftl │ │ │ │ │ │ │ └── header.ftl │ │ │ │ │ └── log4j2.properties │ │ │ │ └── tv │ │ │ │ │ └── codely │ │ │ │ │ └── apps │ │ │ │ │ ├── Starter.java │ │ │ │ │ ├── backoffice │ │ │ │ │ ├── backend │ │ │ │ │ │ ├── BackofficeBackendApplication.java │ │ │ │ │ │ ├── command │ │ │ │ │ │ │ └── .gitkeep │ │ │ │ │ │ ├── config │ │ │ │ │ │ │ ├── BackofficeBackendServerConfiguration.java │ │ │ │ │ │ │ └── BackofficeBackendServerPortCustomizer.java │ │ │ │ │ │ ├── controller │ │ │ │ │ │ │ ├── courses │ │ │ │ │ │ │ │ └── CoursesGetController.java │ │ │ │ │ │ │ └── health_check │ │ │ │ │ │ │ │ └── HealthCheckGetController.java │ │ │ │ │ │ └── middleware │ │ │ │ │ │ │ └── BasicHttpAuthMiddleware.java │ │ │ │ │ └── frontend │ │ │ │ │ │ ├── BackofficeFrontendApplication.java │ │ │ │ │ │ ├── config │ │ │ │ │ │ ├── BackofficeFrontendServerPortCustomizer.java │ │ │ │ │ │ └── BackofficeFrontendWebConfig.java │ │ │ │ │ │ └── controller │ │ │ │ │ │ ├── courses │ │ │ │ │ │ ├── CoursesGetWebController.java │ │ │ │ │ │ └── CoursesPostWebController.java │ │ │ │ │ │ ├── health_check │ │ │ │ │ │ └── HealthCheckGetController.java │ │ │ │ │ │ └── home │ │ │ │ │ │ └── HomeGetWebController.java │ │ │ │ │ └── mooc │ │ │ │ │ └── backend │ │ │ │ │ ├── MoocBackendApplication.java │ │ │ │ │ ├── command │ │ │ │ │ ├── ConsumeMySqlDomainEventsCommand.java │ │ │ │ │ └── ConsumeRabbitMqDomainEventsCommand.java │ │ │ │ │ ├── config │ │ │ │ │ ├── MoocBackendServerConfiguration.java │ │ │ │ │ └── MoocBackendServerPortCustomizer.java │ │ │ │ │ └── controller │ │ │ │ │ ├── courses │ │ │ │ │ ├── CourseGetController.java │ │ │ │ │ └── CoursesPutController.java │ │ │ │ │ ├── courses_counter │ │ │ │ │ └── CoursesCounterGetController.java │ │ │ │ │ ├── health_check │ │ │ │ │ └── HealthCheckGetController.java │ │ │ │ │ └── notifications │ │ │ │ │ └── NewsletterNotificationPutController.java │ │ │ └── test │ │ │ │ ├── resources │ │ │ │ └── log4j2.properties │ │ │ │ └── tv │ │ │ │ └── codely │ │ │ │ └── apps │ │ │ │ ├── ApplicationTestCase.java │ │ │ │ ├── backoffice │ │ │ │ ├── BackofficeApplicationTestCase.java │ │ │ │ ├── backend │ │ │ │ │ └── controller │ │ │ │ │ │ └── health_check │ │ │ │ │ │ └── HealthCheckGetControllerShould.java │ │ │ │ └── frontend │ │ │ │ │ └── controller │ │ │ │ │ └── health_check │ │ │ │ │ └── HealthCheckGetControllerShould.java │ │ │ │ └── mooc │ │ │ │ ├── MoocApplicationTestCase.java │ │ │ │ └── backend │ │ │ │ └── controller │ │ │ │ ├── courses │ │ │ │ ├── CourseGetControllerShould.java │ │ │ │ └── CoursesPutControllerShould.java │ │ │ │ ├── courses_counter │ │ │ │ └── CoursesCounterGetControllerShould.java │ │ │ │ ├── health_check │ │ │ │ └── HealthCheckGetControllerShould.java │ │ │ │ └── notifications │ │ │ │ └── NewsletterNotificationPutControllerShould.java │ │ │ ├── build.gradle │ │ │ ├── doc │ │ │ └── endpoints │ │ │ │ └── backoffice_frontend.http │ │ │ ├── docker-compose.yml │ │ │ ├── gradle │ │ │ └── wrapper │ │ │ │ ├── gradle-wrapper.jar │ │ │ │ └── gradle-wrapper.properties │ │ │ ├── gradlew │ │ │ ├── gradlew.bat │ │ │ ├── settings.gradle │ │ │ ├── src │ │ │ ├── analytics │ │ │ │ └── main │ │ │ │ │ └── tv │ │ │ │ │ └── codely │ │ │ │ │ └── analytics │ │ │ │ │ └── domain_events │ │ │ │ │ ├── application │ │ │ │ │ └── store │ │ │ │ │ │ ├── DomainEventStorer.java │ │ │ │ │ │ └── StoreDomainEventOnOccurred.java │ │ │ │ │ └── domain │ │ │ │ │ ├── AnalyticsDomainEvent.java │ │ │ │ │ ├── AnalyticsDomainEventAggregateId.java │ │ │ │ │ ├── AnalyticsDomainEventBody.java │ │ │ │ │ ├── AnalyticsDomainEventId.java │ │ │ │ │ ├── AnalyticsDomainEventName.java │ │ │ │ │ └── DomainEventsRepository.java │ │ │ ├── backoffice │ │ │ │ ├── build.gradle │ │ │ │ ├── main │ │ │ │ │ ├── resources │ │ │ │ │ │ └── database │ │ │ │ │ │ │ ├── backoffice.sql │ │ │ │ │ │ │ └── backoffice │ │ │ │ │ │ │ └── backoffice_courses.json │ │ │ │ │ └── tv │ │ │ │ │ │ └── codely │ │ │ │ │ │ └── backoffice │ │ │ │ │ │ ├── auth │ │ │ │ │ │ ├── application │ │ │ │ │ │ │ └── authenticate │ │ │ │ │ │ │ │ ├── AuthenticateUserCommand.java │ │ │ │ │ │ │ │ ├── AuthenticateUserCommandHandler.java │ │ │ │ │ │ │ │ └── UserAuthenticator.java │ │ │ │ │ │ ├── domain │ │ │ │ │ │ │ ├── AuthPassword.java │ │ │ │ │ │ │ ├── AuthRepository.java │ │ │ │ │ │ │ ├── AuthUser.java │ │ │ │ │ │ │ ├── AuthUsername.java │ │ │ │ │ │ │ ├── InvalidAuthCredentials.java │ │ │ │ │ │ │ └── InvalidAuthUsername.java │ │ │ │ │ │ └── infrastructure │ │ │ │ │ │ │ └── persistence │ │ │ │ │ │ │ └── InMemoryAuthRepository.java │ │ │ │ │ │ ├── courses │ │ │ │ │ │ ├── application │ │ │ │ │ │ │ ├── BackofficeCourseResponse.java │ │ │ │ │ │ │ ├── BackofficeCoursesResponse.java │ │ │ │ │ │ │ ├── create │ │ │ │ │ │ │ │ ├── BackofficeCourseCreator.java │ │ │ │ │ │ │ │ └── CreateBackofficeCourseOnCourseCreated.java │ │ │ │ │ │ │ ├── search_all │ │ │ │ │ │ │ │ ├── AllBackofficeCoursesSearcher.java │ │ │ │ │ │ │ │ ├── SearchAllBackofficeCoursesQuery.java │ │ │ │ │ │ │ │ └── SearchAllBackofficeCoursesQueryHandler.java │ │ │ │ │ │ │ └── search_by_criteria │ │ │ │ │ │ │ │ ├── BackofficeCoursesByCriteriaSearcher.java │ │ │ │ │ │ │ │ ├── SearchBackofficeCoursesByCriteriaQuery.java │ │ │ │ │ │ │ │ └── SearchBackofficeCoursesByCriteriaQueryHandler.java │ │ │ │ │ │ ├── domain │ │ │ │ │ │ │ ├── BackofficeCourse.java │ │ │ │ │ │ │ └── BackofficeCourseRepository.java │ │ │ │ │ │ └── infrastructure │ │ │ │ │ │ │ └── persistence │ │ │ │ │ │ │ ├── ElasticsearchBackofficeCourseRepository.java │ │ │ │ │ │ │ ├── InMemoryCacheBackofficeCourseRepository.java │ │ │ │ │ │ │ ├── MySqlBackofficeCourseRepository.java │ │ │ │ │ │ │ └── hibernate │ │ │ │ │ │ │ └── BackofficeCourse.hbm.xml │ │ │ │ │ │ └── shared │ │ │ │ │ │ └── infrastructure │ │ │ │ │ │ └── persistence │ │ │ │ │ │ ├── BackofficeElasticsearchConfiguration.java │ │ │ │ │ │ ├── BackofficeHibernateConfiguration.java │ │ │ │ │ │ ├── BackofficeMySqlEventBusConfiguration.java │ │ │ │ │ │ └── BackofficeRabbitMqEventBusConfiguration.java │ │ │ │ └── test │ │ │ │ │ └── tv │ │ │ │ │ └── codely │ │ │ │ │ └── backoffice │ │ │ │ │ ├── BackofficeContextInfrastructureTestCase.java │ │ │ │ │ ├── auth │ │ │ │ │ ├── AuthModuleUnitTestCase.java │ │ │ │ │ ├── application │ │ │ │ │ │ └── authenticate │ │ │ │ │ │ │ ├── AuthenticateUserCommandHandlerShould.java │ │ │ │ │ │ │ └── AuthenticateUserCommandMother.java │ │ │ │ │ └── domain │ │ │ │ │ │ ├── AuthPasswordMother.java │ │ │ │ │ │ ├── AuthUserMother.java │ │ │ │ │ │ └── AuthUsernameMother.java │ │ │ │ │ └── courses │ │ │ │ │ ├── ElasticsearchEnvironmentArranger.java │ │ │ │ │ ├── domain │ │ │ │ │ ├── BackofficeCourseCriteriaMother.java │ │ │ │ │ └── BackofficeCourseMother.java │ │ │ │ │ └── infrastructure │ │ │ │ │ └── persistence │ │ │ │ │ ├── ElasticsearchBackofficeCourseRepositoryShould.java │ │ │ │ │ ├── InMemoryCacheBackofficeCourseRepositoryShould.java │ │ │ │ │ └── MySqlBackofficeCourseRepositoryShould.java │ │ │ ├── mooc │ │ │ │ ├── build.gradle │ │ │ │ ├── main │ │ │ │ │ ├── resources │ │ │ │ │ │ └── database │ │ │ │ │ │ │ └── mooc.sql │ │ │ │ │ └── tv │ │ │ │ │ │ └── codely │ │ │ │ │ │ └── mooc │ │ │ │ │ │ ├── courses │ │ │ │ │ │ ├── application │ │ │ │ │ │ │ ├── CourseResponse.java │ │ │ │ │ │ │ ├── CoursesResponse.java │ │ │ │ │ │ │ ├── create │ │ │ │ │ │ │ │ ├── CourseCreator.java │ │ │ │ │ │ │ │ ├── CreateCourseCommand.java │ │ │ │ │ │ │ │ └── CreateCourseCommandHandler.java │ │ │ │ │ │ │ ├── find │ │ │ │ │ │ │ │ ├── CourseFinder.java │ │ │ │ │ │ │ │ ├── FindCourseQuery.java │ │ │ │ │ │ │ │ └── FindCourseQueryHandler.java │ │ │ │ │ │ │ └── search_last │ │ │ │ │ │ │ │ ├── LastCoursesSearcher.java │ │ │ │ │ │ │ │ ├── SearchLastCoursesQuery.java │ │ │ │ │ │ │ │ └── SearchLastCoursesQueryHandler.java │ │ │ │ │ │ ├── domain │ │ │ │ │ │ │ ├── Course.java │ │ │ │ │ │ │ ├── CourseDuration.java │ │ │ │ │ │ │ ├── CourseId.java │ │ │ │ │ │ │ ├── CourseName.java │ │ │ │ │ │ │ ├── CourseNotExist.java │ │ │ │ │ │ │ └── CourseRepository.java │ │ │ │ │ │ └── infrastructure │ │ │ │ │ │ │ └── persistence │ │ │ │ │ │ │ ├── InMemoryCourseRepository.java │ │ │ │ │ │ │ ├── MySqlCourseRepository.java │ │ │ │ │ │ │ └── hibernate │ │ │ │ │ │ │ └── Course.hbm.xml │ │ │ │ │ │ ├── courses_counter │ │ │ │ │ │ ├── application │ │ │ │ │ │ │ ├── find │ │ │ │ │ │ │ │ ├── CoursesCounterFinder.java │ │ │ │ │ │ │ │ ├── CoursesCounterResponse.java │ │ │ │ │ │ │ │ ├── FindCoursesCounterQuery.java │ │ │ │ │ │ │ │ └── FindCoursesCounterQueryHandler.java │ │ │ │ │ │ │ └── increment │ │ │ │ │ │ │ │ ├── CoursesCounterIncrementer.java │ │ │ │ │ │ │ │ └── IncrementCoursesCounterOnCourseCreated.java │ │ │ │ │ │ ├── domain │ │ │ │ │ │ │ ├── CoursesCounter.java │ │ │ │ │ │ │ ├── CoursesCounterId.java │ │ │ │ │ │ │ ├── CoursesCounterNotInitialized.java │ │ │ │ │ │ │ ├── CoursesCounterRepository.java │ │ │ │ │ │ │ └── CoursesCounterTotal.java │ │ │ │ │ │ └── infrastructure │ │ │ │ │ │ │ └── persistence │ │ │ │ │ │ │ ├── MySqlCoursesCounterRepository.java │ │ │ │ │ │ │ └── hibernate │ │ │ │ │ │ │ ├── CoursesCounter.hbm.xml │ │ │ │ │ │ │ └── CustomTypes.hbm.xml │ │ │ │ │ │ ├── notifications │ │ │ │ │ │ ├── application │ │ │ │ │ │ │ └── send_new_courses_newsletter │ │ │ │ │ │ │ │ ├── NewCoursesNewsletterSender.java │ │ │ │ │ │ │ │ ├── SendNewCoursesNewsletterCommand.java │ │ │ │ │ │ │ │ └── SendNewCoursesNewsletterCommandHandler.java │ │ │ │ │ │ ├── domain │ │ │ │ │ │ │ ├── Email.java │ │ │ │ │ │ │ ├── EmailId.java │ │ │ │ │ │ │ ├── EmailSender.java │ │ │ │ │ │ │ ├── NewCoursesNewsletter.java │ │ │ │ │ │ │ └── NewCoursesNewsletterEmailSent.java │ │ │ │ │ │ └── infrastructure │ │ │ │ │ │ │ └── FakeEmailSender.java │ │ │ │ │ │ ├── shared │ │ │ │ │ │ └── infrastructure │ │ │ │ │ │ │ └── persistence │ │ │ │ │ │ │ ├── MoocHibernateConfiguration.java │ │ │ │ │ │ │ ├── MoocMySqlEventBusConfiguration.java │ │ │ │ │ │ │ └── MoocRabbitMqEventBusConfiguration.java │ │ │ │ │ │ ├── steps │ │ │ │ │ │ ├── domain │ │ │ │ │ │ │ ├── Step.java │ │ │ │ │ │ │ ├── StepId.java │ │ │ │ │ │ │ ├── StepRepository.java │ │ │ │ │ │ │ ├── StepTitle.java │ │ │ │ │ │ │ ├── challenge │ │ │ │ │ │ │ │ ├── ChallengeStep.java │ │ │ │ │ │ │ │ └── ChallengeStepStatement.java │ │ │ │ │ │ │ └── video │ │ │ │ │ │ │ │ ├── VideoStep.java │ │ │ │ │ │ │ │ └── VideoStepText.java │ │ │ │ │ │ └── infrastructure │ │ │ │ │ │ │ └── persistence │ │ │ │ │ │ │ ├── MySqlStepRepository.java │ │ │ │ │ │ │ └── hibernate │ │ │ │ │ │ │ └── VideoStep.hbm.xml │ │ │ │ │ │ └── students │ │ │ │ │ │ ├── application │ │ │ │ │ │ ├── StudentResponse.java │ │ │ │ │ │ ├── StudentsResponse.java │ │ │ │ │ │ └── search_all │ │ │ │ │ │ │ ├── AllStudentsSearcher.java │ │ │ │ │ │ │ ├── SearchAllStudentsQuery.java │ │ │ │ │ │ │ └── SearchAllStudentsQueryHandler.java │ │ │ │ │ │ ├── domain │ │ │ │ │ │ ├── Student.java │ │ │ │ │ │ ├── StudentId.java │ │ │ │ │ │ └── StudentRepository.java │ │ │ │ │ │ └── infrastructure │ │ │ │ │ │ └── InMemoryStudentRepository.java │ │ │ │ └── test │ │ │ │ │ └── tv │ │ │ │ │ └── codely │ │ │ │ │ └── mooc │ │ │ │ │ ├── MoocContextInfrastructureTestCase.java │ │ │ │ │ ├── courses │ │ │ │ │ ├── CoursesModuleInfrastructureTestCase.java │ │ │ │ │ ├── CoursesModuleUnitTestCase.java │ │ │ │ │ ├── application │ │ │ │ │ │ ├── CourseResponseMother.java │ │ │ │ │ │ ├── CoursesResponseMother.java │ │ │ │ │ │ ├── create │ │ │ │ │ │ │ ├── CreateCourseCommandHandlerShould.java │ │ │ │ │ │ │ └── CreateCourseCommandMother.java │ │ │ │ │ │ └── search_last │ │ │ │ │ │ │ └── SearchLastCoursesQueryMother.java │ │ │ │ │ ├── domain │ │ │ │ │ │ ├── CourseCreatedDomainEventMother.java │ │ │ │ │ │ ├── CourseDurationMother.java │ │ │ │ │ │ ├── CourseIdMother.java │ │ │ │ │ │ ├── CourseMother.java │ │ │ │ │ │ └── CourseNameMother.java │ │ │ │ │ └── infrastructure │ │ │ │ │ │ └── persistence │ │ │ │ │ │ ├── InMemoryCourseRepositoryShould.java │ │ │ │ │ │ └── MySqlCourseRepositoryShould.java │ │ │ │ │ ├── courses_counter │ │ │ │ │ ├── CoursesCounterModuleInfrastructureTestCase.java │ │ │ │ │ ├── CoursesCounterModuleUnitTestCase.java │ │ │ │ │ ├── application │ │ │ │ │ │ ├── find │ │ │ │ │ │ │ ├── CoursesCounterResponseMother.java │ │ │ │ │ │ │ └── FindCoursesCounterQueryHandlerShould.java │ │ │ │ │ │ └── increment │ │ │ │ │ │ │ └── IncrementCoursesCounterOnCourseCreatedShould.java │ │ │ │ │ ├── domain │ │ │ │ │ │ ├── CoursesCounterIdMother.java │ │ │ │ │ │ ├── CoursesCounterMother.java │ │ │ │ │ │ └── CoursesCounterTotalMother.java │ │ │ │ │ └── infrastructure │ │ │ │ │ │ └── persistence │ │ │ │ │ │ └── MySqlCoursesCounterRepositoryShould.java │ │ │ │ │ ├── notifications │ │ │ │ │ ├── application │ │ │ │ │ │ ├── NotificationsModuleUnitTestCase.java │ │ │ │ │ │ └── send_new_courses_newsletter │ │ │ │ │ │ │ ├── SendNewCoursesNewsletterCommandHandlerShould.java │ │ │ │ │ │ │ └── SendNewCoursesNewsletterCommandMother.java │ │ │ │ │ └── domain │ │ │ │ │ │ ├── EmailIdMother.java │ │ │ │ │ │ ├── NewCoursesNewsletterEmailSentMother.java │ │ │ │ │ │ └── NewCoursesNewsletterMother.java │ │ │ │ │ ├── shared │ │ │ │ │ └── infrastructure │ │ │ │ │ │ └── bus │ │ │ │ │ │ └── event │ │ │ │ │ │ ├── mysql │ │ │ │ │ │ └── MySqlEventBusShould.java │ │ │ │ │ │ └── rabbitmq │ │ │ │ │ │ ├── RabbitMqEventBusShould.java │ │ │ │ │ │ └── TestAllWorksOnRabbitMqEventsPublished.java │ │ │ │ │ ├── steps │ │ │ │ │ ├── StepsModuleInfrastructureTestCase.java │ │ │ │ │ ├── domain │ │ │ │ │ │ ├── StepIdMother.java │ │ │ │ │ │ ├── StepTitleMother.java │ │ │ │ │ │ ├── challenge │ │ │ │ │ │ │ ├── ChallengeStepMother.java │ │ │ │ │ │ │ └── ChallengeStepStatementMother.java │ │ │ │ │ │ └── video │ │ │ │ │ │ │ ├── VideoStepMother.java │ │ │ │ │ │ │ └── VideoStepTextMother.java │ │ │ │ │ └── infrastructure │ │ │ │ │ │ └── persistence │ │ │ │ │ │ └── MySqlStepRepositoryShould.java │ │ │ │ │ └── students │ │ │ │ │ ├── application │ │ │ │ │ ├── StudentResponseMother.java │ │ │ │ │ ├── StudentsResponseMother.java │ │ │ │ │ └── search_all │ │ │ │ │ │ └── SearchAllStudentsQueryMother.java │ │ │ │ │ └── domain │ │ │ │ │ └── StudentIdMother.java │ │ │ └── shared │ │ │ │ ├── build.gradle │ │ │ │ ├── main │ │ │ │ └── tv │ │ │ │ │ └── codely │ │ │ │ │ └── shared │ │ │ │ │ ├── domain │ │ │ │ │ ├── AggregateRoot.java │ │ │ │ │ ├── DomainError.java │ │ │ │ │ ├── Identifier.java │ │ │ │ │ ├── IntValueObject.java │ │ │ │ │ ├── Logger.java │ │ │ │ │ ├── Monitoring.java │ │ │ │ │ ├── Service.java │ │ │ │ │ ├── StringValueObject.java │ │ │ │ │ ├── Utils.java │ │ │ │ │ ├── UuidGenerator.java │ │ │ │ │ ├── VideoUrl.java │ │ │ │ │ ├── bus │ │ │ │ │ │ ├── command │ │ │ │ │ │ │ ├── Command.java │ │ │ │ │ │ │ ├── CommandBus.java │ │ │ │ │ │ │ ├── CommandHandler.java │ │ │ │ │ │ │ ├── CommandHandlerExecutionError.java │ │ │ │ │ │ │ ├── CommandNotRegisteredError.java │ │ │ │ │ │ │ └── Middleware.java │ │ │ │ │ │ ├── event │ │ │ │ │ │ │ ├── DomainEvent.java │ │ │ │ │ │ │ ├── DomainEventSubscriber.java │ │ │ │ │ │ │ └── EventBus.java │ │ │ │ │ │ └── query │ │ │ │ │ │ │ ├── Query.java │ │ │ │ │ │ │ ├── QueryBus.java │ │ │ │ │ │ │ ├── QueryHandler.java │ │ │ │ │ │ │ ├── QueryHandlerExecutionError.java │ │ │ │ │ │ │ ├── QueryNotRegisteredError.java │ │ │ │ │ │ │ └── Response.java │ │ │ │ │ ├── course │ │ │ │ │ │ └── CourseCreatedDomainEvent.java │ │ │ │ │ └── criteria │ │ │ │ │ │ ├── Criteria.java │ │ │ │ │ │ ├── Filter.java │ │ │ │ │ │ ├── FilterField.java │ │ │ │ │ │ ├── FilterOperator.java │ │ │ │ │ │ ├── FilterValue.java │ │ │ │ │ │ ├── Filters.java │ │ │ │ │ │ ├── Order.java │ │ │ │ │ │ ├── OrderBy.java │ │ │ │ │ │ └── OrderType.java │ │ │ │ │ └── infrastructure │ │ │ │ │ ├── ConsoleLogger.java │ │ │ │ │ ├── JavaUuidGenerator.java │ │ │ │ │ ├── bus │ │ │ │ │ ├── command │ │ │ │ │ │ ├── CommandHandlerMiddleware.java │ │ │ │ │ │ ├── CommandHandlersInformation.java │ │ │ │ │ │ ├── InMemoryCommandBus.java │ │ │ │ │ │ ├── LoggerMiddleware.java │ │ │ │ │ │ └── TransactionalMiddleware.java │ │ │ │ │ ├── event │ │ │ │ │ │ ├── DomainEventJsonDeserializer.java │ │ │ │ │ │ ├── DomainEventJsonSerializer.java │ │ │ │ │ │ ├── DomainEventSubscriberInformation.java │ │ │ │ │ │ ├── DomainEventSubscribersInformation.java │ │ │ │ │ │ ├── DomainEventsInformation.java │ │ │ │ │ │ ├── mysql │ │ │ │ │ │ │ ├── MySqlDomainEventsConsumer.java │ │ │ │ │ │ │ └── MySqlEventBus.java │ │ │ │ │ │ ├── rabbitmq │ │ │ │ │ │ │ ├── RabbitMqDomainEventsConsumer.java │ │ │ │ │ │ │ ├── RabbitMqEventBus.java │ │ │ │ │ │ │ ├── RabbitMqEventBusConfiguration.java │ │ │ │ │ │ │ ├── RabbitMqExchangeNameFormatter.java │ │ │ │ │ │ │ ├── RabbitMqPublisher.java │ │ │ │ │ │ │ └── RabbitMqQueueNameFormatter.java │ │ │ │ │ │ └── spring │ │ │ │ │ │ │ └── SpringApplicationEventBus.java │ │ │ │ │ └── query │ │ │ │ │ │ ├── InMemoryQueryBus.java │ │ │ │ │ │ └── QueryHandlersInformation.java │ │ │ │ │ ├── cli │ │ │ │ │ └── ConsoleCommand.java │ │ │ │ │ ├── config │ │ │ │ │ ├── EnvironmentConfig.java │ │ │ │ │ ├── Parameter.java │ │ │ │ │ └── ParameterNotExist.java │ │ │ │ │ ├── elasticsearch │ │ │ │ │ ├── ElasticsearchClient.java │ │ │ │ │ ├── ElasticsearchCriteriaConverter.java │ │ │ │ │ └── ElasticsearchRepository.java │ │ │ │ │ ├── hibernate │ │ │ │ │ ├── HibernateConfigurationFactory.java │ │ │ │ │ ├── HibernateCriteriaConverter.java │ │ │ │ │ ├── HibernateRepository.java │ │ │ │ │ └── JsonListType.java │ │ │ │ │ ├── spring │ │ │ │ │ ├── ApiController.java │ │ │ │ │ └── ApiExceptionMiddleware.java │ │ │ │ │ └── validation │ │ │ │ │ ├── ValidationResponse.java │ │ │ │ │ ├── Validator.java │ │ │ │ │ ├── ValidatorNotExist.java │ │ │ │ │ └── validators │ │ │ │ │ ├── FieldValidator.java │ │ │ │ │ ├── NotEmptyValidator.java │ │ │ │ │ ├── RequiredValidator.java │ │ │ │ │ ├── StringValidator.java │ │ │ │ │ └── UuidValidator.java │ │ │ │ └── test │ │ │ │ └── tv │ │ │ │ └── codely │ │ │ │ └── shared │ │ │ │ ├── domain │ │ │ │ ├── EmailMother.java │ │ │ │ ├── IntegerMother.java │ │ │ │ ├── ListMother.java │ │ │ │ ├── MotherCreator.java │ │ │ │ ├── RandomElementPicker.java │ │ │ │ ├── UuidMother.java │ │ │ │ ├── VideoUrlMother.java │ │ │ │ └── WordMother.java │ │ │ │ └── infrastructure │ │ │ │ ├── InfrastructureTestCase.java │ │ │ │ └── UnitTestCase.java │ │ │ └── var │ │ │ └── log │ │ │ └── .gitkeep │ └── functional │ │ └── ts │ │ ├── .editorconfig │ │ ├── .eslintrc.js │ │ ├── .github │ │ └── workflows │ │ │ └── ci.yml │ │ ├── .gitignore │ │ ├── LICENSE │ │ ├── README.md │ │ ├── jest.config.js │ │ ├── package-lock.json │ │ ├── package.json │ │ ├── src │ │ ├── Command.ts │ │ ├── CommandHandler.ts │ │ ├── InMemoryCommandBus.ts │ │ ├── LoggerMiddleware.ts │ │ ├── Middleware.ts │ │ ├── TransactionalMiddleware.ts │ │ └── index.ts │ │ ├── tests │ │ └── .eslintrc │ │ └── tsconfig.json │ ├── command │ ├── README.md │ └── java │ │ ├── .editorconfig │ │ ├── .github │ │ └── workflows │ │ │ └── workflow.yml │ │ ├── .gitignore │ │ ├── Makefile │ │ ├── README.md │ │ ├── build.gradle │ │ ├── doc │ │ └── endpoints │ │ │ └── mooc_courses.http │ │ ├── gradle │ │ └── wrapper │ │ │ ├── gradle-wrapper.jar │ │ │ └── gradle-wrapper.properties │ │ ├── gradlew │ │ ├── gradlew.bat │ │ ├── src │ │ ├── main │ │ │ ├── java │ │ │ │ └── tv │ │ │ │ │ └── codely │ │ │ │ │ └── mooc │ │ │ │ │ └── api │ │ │ │ │ ├── Application │ │ │ │ │ ├── Command.java │ │ │ │ │ ├── CommandHandler.java │ │ │ │ │ └── Create │ │ │ │ │ │ ├── CourseCreator.java │ │ │ │ │ │ ├── CreateCourseCommand.java │ │ │ │ │ │ └── CreateCourseCommandHandler.java │ │ │ │ │ ├── Domain │ │ │ │ │ ├── Course.java │ │ │ │ │ ├── CourseDuration.java │ │ │ │ │ ├── CourseId.java │ │ │ │ │ ├── CourseName.java │ │ │ │ │ ├── CourseNotExist.java │ │ │ │ │ ├── CourseRepository.java │ │ │ │ │ ├── DomainError.java │ │ │ │ │ ├── Identifier.java │ │ │ │ │ └── StringValueObject.java │ │ │ │ │ ├── Infrastructure │ │ │ │ │ └── Persistence │ │ │ │ │ │ └── InMemoryCourseRepository.java │ │ │ │ │ ├── MoocApplication.java │ │ │ │ │ └── Ui │ │ │ │ │ ├── Api │ │ │ │ │ └── Controller │ │ │ │ │ │ ├── CoursePutControllerRequestBody.java │ │ │ │ │ │ ├── CoursesGetController.java │ │ │ │ │ │ └── CoursesPutController.java │ │ │ │ │ └── Console │ │ │ │ │ └── CreateCourseConsoleCommand.java │ │ │ └── resources │ │ │ │ └── log4j2.properties │ │ └── test │ │ │ ├── java │ │ │ └── tv │ │ │ │ └── codely │ │ │ │ └── mooc │ │ │ │ └── api │ │ │ │ ├── ApiTestCase.java │ │ │ │ └── Ui │ │ │ │ └── Api │ │ │ │ └── Controller │ │ │ │ ├── CoursesGetControllerShould.java │ │ │ │ └── CoursesPutControllerShould.java │ │ │ └── resources │ │ │ ├── application.properties │ │ │ ├── log4j2.properties │ │ │ └── logback-test.xml │ │ └── var │ │ └── log │ │ └── .gitkeep │ ├── iterator │ ├── README.md │ └── typescript │ │ ├── .eslintrc.js │ │ ├── .github │ │ └── workflows │ │ │ └── ci.yml │ │ ├── .gitignore │ │ ├── LICENSE │ │ ├── README.md │ │ ├── jest.config.js │ │ ├── package-lock.json │ │ ├── package.json │ │ ├── src │ │ ├── AggregateRoot.ts │ │ ├── Course.ts │ │ ├── CourseRepository.ts │ │ ├── CourseReview.ts │ │ ├── CourseReviews.ts │ │ ├── CourseReviewsSnapshot.ts │ │ ├── CourseSnapshot.ts │ │ ├── DomainEvent.ts │ │ ├── FileEventSourcedCourseRepository.ts │ │ ├── FileSnapshotCourseRepository.ts │ │ ├── Generator.ts │ │ ├── ReviewAdded.ts │ │ └── Stars.ts │ │ ├── tests │ │ ├── .eslintrc │ │ ├── FileCourseSnapshotRepository.test.ts │ │ ├── FileEventSourcedCourseRepository.test.ts │ │ └── Generator.test.ts │ │ └── tsconfig.json │ ├── mediator │ ├── README.md │ └── typescript │ │ ├── .eslintrc.js │ │ ├── .github │ │ └── workflows │ │ │ ├── lint.yml │ │ │ └── test.yml │ │ ├── .gitignore │ │ ├── jest.config.js │ │ ├── package-lock.json │ │ ├── package.json │ │ ├── public │ │ └── courses │ │ │ ├── bash.jpg │ │ │ ├── ddd-en-php.jpg │ │ │ ├── ddd-java.jpg │ │ │ ├── layouts-css.jpg │ │ │ ├── makefiles.jpg │ │ │ ├── novedades-vue-3.jpg │ │ │ └── terminal-zsh.jpg │ │ ├── readme.md │ │ ├── src │ │ ├── app.ts │ │ ├── controllers │ │ │ └── api.ts │ │ ├── entity │ │ │ ├── Role.ts │ │ │ ├── User.ts │ │ │ ├── UserRepository.ts │ │ │ ├── Workspace.ts │ │ │ └── WorkspaceRepository.ts │ │ ├── server.ts │ │ └── service │ │ │ ├── DomainEvent.ts │ │ │ ├── Email.ts │ │ │ ├── EventBus.ts │ │ │ ├── InMemoryEventBus.ts │ │ │ ├── Mailer.ts │ │ │ ├── Observer.ts │ │ │ ├── SendWelcomeEmailOnUserSignUp.ts │ │ │ ├── UserSignUpDomainEvent.ts │ │ │ └── UserSignUpServiceManagerHandler.ts │ │ ├── test │ │ └── api.spec.ts │ │ └── tsconfig.json │ ├── memento │ ├── README.md │ └── typescript │ │ ├── .eslintrc.js │ │ ├── .github │ │ └── workflows │ │ │ └── ci.yml │ │ ├── .gitignore │ │ ├── LICENSE │ │ ├── README.md │ │ ├── jest.config.js │ │ ├── package-lock.json │ │ ├── package.json │ │ ├── src │ │ ├── AggregateRoot.ts │ │ ├── Course.ts │ │ ├── CourseRepository.ts │ │ ├── CourseReview.ts │ │ ├── CourseReviews.ts │ │ ├── CourseReviewsSnapshot.ts │ │ ├── CourseSnapshot.ts │ │ ├── DomainEvent.ts │ │ ├── FileEventSourcedCourseRepository.ts │ │ ├── FileSnapshotCourseRepository.ts │ │ ├── ReviewAdded.ts │ │ └── Stars.ts │ │ ├── tests │ │ ├── .eslintrc │ │ ├── FileCourseSnapshotRepository.test.ts │ │ └── FileEventSourcedCourseRepository.test.ts │ │ └── tsconfig.json │ ├── observer │ ├── README.md │ └── typescript │ │ ├── .eslintrc.js │ │ ├── .github │ │ └── workflows │ │ │ ├── lint.yml │ │ │ └── test.yml │ │ ├── .gitignore │ │ ├── jest.config.js │ │ ├── package-lock.json │ │ ├── package.json │ │ ├── public │ │ └── courses │ │ │ ├── bash.jpg │ │ │ ├── ddd-en-php.jpg │ │ │ ├── ddd-java.jpg │ │ │ ├── layouts-css.jpg │ │ │ ├── makefiles.jpg │ │ │ ├── novedades-vue-3.jpg │ │ │ └── terminal-zsh.jpg │ │ ├── readme.md │ │ ├── src │ │ ├── app.ts │ │ ├── controllers │ │ │ └── api.ts │ │ ├── entity │ │ │ ├── DefaultWorkspaceCreated.ts │ │ │ ├── Role.ts │ │ │ ├── User.ts │ │ │ ├── UserRegistered.ts │ │ │ ├── UserRepository.ts │ │ │ ├── Workspace.ts │ │ │ └── WorkspaceRepository.ts │ │ ├── server.ts │ │ └── service │ │ │ ├── AssignUserToWorkspace.ts │ │ │ ├── CreateDefaultWorkspace.ts │ │ │ ├── Email.ts │ │ │ ├── Mailer.ts │ │ │ ├── Observable.ts │ │ │ ├── Observer.ts │ │ │ ├── SendWelcomeEmail.ts │ │ │ └── UserSignUpServiceManagerHandler.ts │ │ ├── test │ │ └── api.spec.ts │ │ └── tsconfig.json │ ├── state │ ├── README.md │ └── php │ │ ├── .editorconfig │ │ ├── .github │ │ ├── FUNDING.yml │ │ └── workflows │ │ │ └── ci.yml │ │ ├── .gitignore │ │ ├── .scrutinizer.yml │ │ ├── .semver │ │ ├── LICENSE │ │ ├── README.md │ │ ├── composer.json │ │ ├── composer.lock │ │ ├── phpunit.xml │ │ ├── src │ │ ├── ArchiveCourse.php │ │ ├── Course.php │ │ ├── CourseDuration.php │ │ ├── CourseId.php │ │ ├── CourseName.php │ │ ├── CourseStatus.php │ │ ├── DomainError.php │ │ ├── DraftCourse.php │ │ ├── PublishedCourse.php │ │ └── StringValueObject.php │ │ └── tests │ │ └── CourseTest.php │ ├── strategy │ ├── README.md │ ├── achivements-functional │ │ └── ts │ │ │ ├── .eslintrc.js │ │ │ ├── .github │ │ │ └── workflows │ │ │ │ └── ci.yml │ │ │ ├── .gitignore │ │ │ ├── LICENSE │ │ │ ├── README.md │ │ │ ├── jest.config.js │ │ │ ├── package-lock.json │ │ │ ├── package.json │ │ │ ├── src │ │ │ └── index.ts │ │ │ ├── tests │ │ │ └── .eslintrc │ │ │ └── tsconfig.json │ └── kotlin │ │ ├── .github │ │ └── workflows │ │ │ └── main.yml │ │ ├── .gitignore │ │ ├── README.md │ │ ├── build.gradle.kts │ │ ├── gradle.properties │ │ ├── gradle │ │ └── wrapper │ │ │ ├── gradle-wrapper.jar │ │ │ └── gradle-wrapper.properties │ │ ├── gradlew │ │ ├── gradlew.bat │ │ ├── settings.gradle.kts │ │ └── src │ │ ├── main │ │ └── kotlin │ │ │ └── com │ │ │ └── codely │ │ │ └── achievement │ │ │ ├── AchievementDealer.kt │ │ │ ├── AchievementType.kt │ │ │ ├── Codely.kt │ │ │ ├── ConstantLearnerRepository.kt │ │ │ ├── DummyStepRepository.kt │ │ │ ├── EarnedPoints.kt │ │ │ ├── InMemoryLearnerAchievementRepository.kt │ │ │ ├── Learner.kt │ │ │ ├── LearnerAchievement.kt │ │ │ ├── LearnerAchievementDealer.kt │ │ │ ├── LearnerAchievementRepository.kt │ │ │ ├── LearnerEarnedPoints.kt │ │ │ ├── LearnerRepository.kt │ │ │ ├── LearnerStep.kt │ │ │ ├── LearnerStepRepository.kt │ │ │ ├── Step.kt │ │ │ ├── StepCompleter.kt │ │ │ ├── StepRepository.kt │ │ │ ├── VoidLearnerStepsRepository.kt │ │ │ ├── achievements │ │ │ ├── BackendGuru.kt │ │ │ ├── FrontendGuru.kt │ │ │ ├── FullStackGuru.kt │ │ │ ├── PointsEarned100.kt │ │ │ ├── PointsEarned2500.kt │ │ │ └── PointsEarned500.kt │ │ │ └── factories │ │ │ ├── AchievementDealerFactory.kt │ │ │ └── LearnerAchievementDealerFactory.kt │ │ └── test │ │ └── kotlin │ │ └── com │ │ └── codely │ │ └── achievement │ │ └── LearnerAchievementDealerShould.kt │ └── visitor │ ├── README.md │ └── typescript │ ├── .eslintrc.js │ ├── .github │ └── workflows │ │ └── ci.yml │ ├── .gitignore │ ├── LICENSE │ ├── README.md │ ├── jest.config.js │ ├── package-lock.json │ ├── package.json │ ├── src │ ├── ElementA.ts │ ├── ElementB.ts │ ├── ExportVisitor.ts │ ├── PrintVisitor.ts │ ├── ValidatorVisitor.ts │ ├── VisitingElement.ts │ └── Visitor.ts │ ├── tests │ ├── .eslintrc │ └── Visitor.test.ts │ └── tsconfig.json ├── design-patterns ├── behavioral │ ├── chain-of-responsibility │ │ └── .gitkeep │ ├── command │ │ └── .gitkeep │ ├── iterator │ │ └── .gitkeep │ ├── mediator │ │ └── .gitkeep │ ├── memento │ │ └── .gitkeep │ ├── observer │ │ └── .gitkeep │ ├── state │ │ └── .gitkeep │ ├── strategy │ │ └── .gitkeep │ ├── template-method │ │ └── .gitkeep │ └── visitor │ │ └── .gitkeep ├── creational │ ├── abstract-factory │ │ └── .gitkeep │ ├── builder │ │ └── .gitkeep │ ├── factory-method │ │ └── .gitkeep │ ├── prototype │ │ └── .gitkeep │ └── singleton │ │ └── .gitkeep └── structural │ ├── adapter │ └── .gitkeep │ ├── bridge │ └── .gitkeep │ ├── composite │ └── .gitkeep │ ├── decorator │ └── .gitkeep │ ├── facade │ └── .gitkeep │ ├── flyweight │ └── .gitkeep │ └── proxy │ └── .gitkeep ├── exercises └── .gitkeep ├── node_modules ├── .package-lock.json └── .yarn-integrity ├── package-lock.json └── yarn.lock /courses-examples/behavioral-design-patterns-course/chain-of-responsibility/command-bus-middleware/README.md: -------------------------------------------------------------------------------- 1 | Chain of responsibility applied to CommandBus Middlewares 2 | ========================================================= 3 | 4 | An example of the Chain of responsibility pattern applied 5 | to CommandBus Middlewares. 6 | 7 | ## Description 8 | 9 | In this example we implement a middleware system for a 10 | CommandBus, using the chain of responsibility pattern. 11 | 12 | Each element of the chain decorates the execution of the 13 | command: 14 | - LoggerMiddleware: Logs every command dispatched to the command bus 15 | - TransactionalMiddleware: Create a database transaction for each dispatched command 16 | - CommandHandlerMiddleware: Executes the command handler 17 | 18 | ## Languages 19 | 20 | - [Java](java) 21 | 22 | ## Patterns used in this example 23 | 24 | - [Chain of Responsibility](/design-patterns/behavioral/chain-of-responsibility) 25 | -------------------------------------------------------------------------------- /courses-examples/behavioral-design-patterns-course/chain-of-responsibility/command-bus-middleware/java/.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | charset = utf-8 5 | end_of_line = lf 6 | insert_final_newline = true 7 | trim_trailing_whitespace = true 8 | 9 | [*.java] 10 | indent_size = 4 11 | indent_style = space 12 | -------------------------------------------------------------------------------- /courses-examples/behavioral-design-patterns-course/chain-of-responsibility/command-bus-middleware/java/.env: -------------------------------------------------------------------------------- 1 | # See apps/main/resources/.env 2 | -------------------------------------------------------------------------------- /courses-examples/behavioral-design-patterns-course/chain-of-responsibility/command-bus-middleware/java/.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | 3 | on: [push] 4 | 5 | jobs: 6 | build: 7 | 8 | runs-on: ubuntu-latest 9 | 10 | steps: 11 | - uses: actions/checkout@v1 12 | 13 | - name: Start all the environment 14 | run: docker-compose up -d 15 | 16 | - name: Wait for the environment to get up 17 | run: | 18 | while ! make ping-mysql &>/dev/null; do 19 | echo "Waiting for database connection..." 20 | sleep 2 21 | done 22 | 23 | - name: Run the tests 24 | run: make test 25 | -------------------------------------------------------------------------------- /courses-examples/behavioral-design-patterns-course/chain-of-responsibility/command-bus-middleware/java/.gitignore: -------------------------------------------------------------------------------- 1 | # Gradle 2 | .gradle 3 | build/ 4 | 5 | # Ignore Gradle GUI config 6 | gradle-app.setting 7 | 8 | /var/log/* 9 | !/var/log/.gitkeep 10 | 11 | .env.local 12 | .env.*.local 13 | -------------------------------------------------------------------------------- /courses-examples/behavioral-design-patterns-course/chain-of-responsibility/command-bus-middleware/java/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM openjdk:11-slim-buster 2 | WORKDIR /app 3 | -------------------------------------------------------------------------------- /courses-examples/behavioral-design-patterns-course/chain-of-responsibility/command-bus-middleware/java/Makefile: -------------------------------------------------------------------------------- 1 | .PHONY: all 2 | all: build 3 | 4 | .PHONY: up 5 | up: 6 | @docker-compose up -d 7 | 8 | .PHONY: build 9 | build: 10 | @./gradlew build --warning-mode all 11 | 12 | .PHONY: run-tests 13 | run-tests: 14 | @./gradlew test --warning-mode all 15 | 16 | .PHONY: test 17 | test: 18 | @docker exec codelytv-ddd_skeleton-java ./gradlew test --warning-mode all 19 | 20 | .PHONY: run 21 | run: 22 | @./gradlew :run 23 | 24 | .PHONY: ping-mysql 25 | ping-mysql: 26 | @docker exec codelytv-java_ddd_skeleton-mysql mysqladmin --user=root --password= --host "127.0.0.1" ping --silent 27 | 28 | # Start the app 29 | .PHONY: start-mooc_backend 30 | start-mooc_backend: 31 | @./gradlew :run --args='mooc_backend server' 32 | 33 | .PHONY: start-backoffice_frontend 34 | start-backoffice_frontend: 35 | @./gradlew :run --args='backoffice_frontend server' 36 | -------------------------------------------------------------------------------- /courses-examples/behavioral-design-patterns-course/chain-of-responsibility/command-bus-middleware/java/README.md: -------------------------------------------------------------------------------- 1 | # Chain of responsibility design pattern: Java 2 | 3 | Java implementation of the [Chain of responsibility applied to CommandBus Middlewares example](../README.md). 4 | 5 | ## Steps 6 | 7 | To navigate between steps use `git checkout` command 8 | using the specified commit hash below 👇 9 | 10 | 1. Chain of responsibility applied to CommandBus middlewares 11 | 12 | ```bash 13 | # step 1 14 | git checkout d76d554d 15 | `` 16 | 17 | 18 | -------------------------------------------------------------------------------- /courses-examples/behavioral-design-patterns-course/chain-of-responsibility/command-bus-middleware/java/apps/main/resources/backoffice_frontend/public/images/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodelyTV/design-patterns/45c671d989a8d49dc219eae4b9a820fb704d00cc/courses-examples/behavioral-design-patterns-course/chain-of-responsibility/command-bus-middleware/java/apps/main/resources/backoffice_frontend/public/images/logo.png -------------------------------------------------------------------------------- /courses-examples/behavioral-design-patterns-course/chain-of-responsibility/command-bus-middleware/java/apps/main/resources/backoffice_frontend/templates/pages/courses/courses.ftl: -------------------------------------------------------------------------------- 1 | <#include "../../master.ftl"> 2 | 3 | <#macro page_title>Cursos#macro> 4 | 5 | <#macro main> 6 |
11 | Actualmente CodelyTV Pro cuenta con ${courses_counter} cursos. 12 |
13 |{ 4 | R handle(Q query); 5 | } 6 | -------------------------------------------------------------------------------- /courses-examples/behavioral-design-patterns-course/chain-of-responsibility/command-bus-middleware/java/src/shared/main/tv/codely/shared/domain/bus/query/QueryHandlerExecutionError.java: -------------------------------------------------------------------------------- 1 | package tv.codely.shared.domain.bus.query; 2 | 3 | public final class QueryHandlerExecutionError extends RuntimeException { 4 | public QueryHandlerExecutionError(Throwable cause) { 5 | super(cause); 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /courses-examples/behavioral-design-patterns-course/chain-of-responsibility/command-bus-middleware/java/src/shared/main/tv/codely/shared/domain/bus/query/QueryNotRegisteredError.java: -------------------------------------------------------------------------------- 1 | package tv.codely.shared.domain.bus.query; 2 | 3 | public final class QueryNotRegisteredError extends Exception { 4 | public QueryNotRegisteredError(Class extends Query> query) { 5 | super(String.format("The query <%s> hasn't a query handler associated", query.toString())); 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /courses-examples/behavioral-design-patterns-course/chain-of-responsibility/command-bus-middleware/java/src/shared/main/tv/codely/shared/domain/bus/query/Response.java: -------------------------------------------------------------------------------- 1 | package tv.codely.shared.domain.bus.query; 2 | 3 | public interface Response { 4 | } 5 | -------------------------------------------------------------------------------- /courses-examples/behavioral-design-patterns-course/chain-of-responsibility/command-bus-middleware/java/src/shared/main/tv/codely/shared/domain/criteria/FilterField.java: -------------------------------------------------------------------------------- 1 | package tv.codely.shared.domain.criteria; 2 | 3 | import tv.codely.shared.domain.StringValueObject; 4 | 5 | public final class FilterField extends StringValueObject { 6 | public FilterField(String value) { 7 | super(value); 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /courses-examples/behavioral-design-patterns-course/chain-of-responsibility/command-bus-middleware/java/src/shared/main/tv/codely/shared/domain/criteria/FilterValue.java: -------------------------------------------------------------------------------- 1 | package tv.codely.shared.domain.criteria; 2 | 3 | import tv.codely.shared.domain.StringValueObject; 4 | 5 | public final class FilterValue extends StringValueObject { 6 | public FilterValue(String value) { 7 | super(value); 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /courses-examples/behavioral-design-patterns-course/chain-of-responsibility/command-bus-middleware/java/src/shared/main/tv/codely/shared/domain/criteria/OrderBy.java: -------------------------------------------------------------------------------- 1 | package tv.codely.shared.domain.criteria; 2 | 3 | import tv.codely.shared.domain.StringValueObject; 4 | 5 | public final class OrderBy extends StringValueObject { 6 | public OrderBy(String value) { 7 | super(value); 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /courses-examples/behavioral-design-patterns-course/chain-of-responsibility/command-bus-middleware/java/src/shared/main/tv/codely/shared/domain/criteria/OrderType.java: -------------------------------------------------------------------------------- 1 | package tv.codely.shared.domain.criteria; 2 | 3 | public enum OrderType { 4 | ASC("asc"), 5 | DESC("desc"), 6 | NONE("none"); 7 | private final String type; 8 | 9 | OrderType(String type) { 10 | this.type = type; 11 | } 12 | 13 | public boolean isNone() { 14 | return this == NONE; 15 | } 16 | 17 | public boolean isAsc() { 18 | return this == ASC; 19 | } 20 | 21 | public String value() { 22 | return type; 23 | } 24 | } 25 | 26 | -------------------------------------------------------------------------------- /courses-examples/behavioral-design-patterns-course/chain-of-responsibility/command-bus-middleware/java/src/shared/main/tv/codely/shared/infrastructure/JavaUuidGenerator.java: -------------------------------------------------------------------------------- 1 | package tv.codely.shared.infrastructure; 2 | 3 | import tv.codely.shared.domain.Service; 4 | import tv.codely.shared.domain.UuidGenerator; 5 | 6 | import java.util.UUID; 7 | 8 | @Service 9 | public final class JavaUuidGenerator implements UuidGenerator { 10 | @Override 11 | public String generate() { 12 | return UUID.randomUUID().toString(); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /courses-examples/behavioral-design-patterns-course/chain-of-responsibility/command-bus-middleware/java/src/shared/main/tv/codely/shared/infrastructure/bus/command/CommandHandlerMiddleware.java: -------------------------------------------------------------------------------- 1 | package tv.codely.shared.infrastructure.bus.command; 2 | 3 | import tv.codely.shared.domain.bus.command.Command; 4 | import tv.codely.shared.domain.bus.command.CommandHandler; 5 | import tv.codely.shared.domain.bus.command.Middleware; 6 | 7 | public class CommandHandlerMiddlewareimplements Middleware { 8 | private final CommandHandler commandHandler; 9 | 10 | CommandHandlerMiddleware(CommandHandler commandHandler) { 11 | this.commandHandler = commandHandler; 12 | } 13 | 14 | @Override 15 | public void handle(T command) { 16 | commandHandler.handle(command); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /courses-examples/behavioral-design-patterns-course/chain-of-responsibility/command-bus-middleware/java/src/shared/main/tv/codely/shared/infrastructure/bus/event/rabbitmq/RabbitMqExchangeNameFormatter.java: -------------------------------------------------------------------------------- 1 | package tv.codely.shared.infrastructure.bus.event.rabbitmq; 2 | 3 | public final class RabbitMqExchangeNameFormatter { 4 | public static String retry(String exchangeName) { 5 | return String.format("retry-%s", exchangeName); 6 | } 7 | 8 | public static String deadLetter(String exchangeName) { 9 | return String.format("dead_letter-%s", exchangeName); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /courses-examples/behavioral-design-patterns-course/chain-of-responsibility/command-bus-middleware/java/src/shared/main/tv/codely/shared/infrastructure/bus/event/rabbitmq/RabbitMqQueueNameFormatter.java: -------------------------------------------------------------------------------- 1 | package tv.codely.shared.infrastructure.bus.event.rabbitmq; 2 | 3 | import tv.codely.shared.infrastructure.bus.event.DomainEventSubscriberInformation; 4 | 5 | public final class RabbitMqQueueNameFormatter { 6 | public static String format(DomainEventSubscriberInformation information) { 7 | return information.formatRabbitMqQueueName(); 8 | } 9 | 10 | public static String formatRetry(DomainEventSubscriberInformation information) { 11 | return String.format("retry.%s", format(information)); 12 | } 13 | 14 | public static String formatDeadLetter(DomainEventSubscriberInformation information) { 15 | return String.format("dead_letter.%s", format(information)); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /courses-examples/behavioral-design-patterns-course/chain-of-responsibility/command-bus-middleware/java/src/shared/main/tv/codely/shared/infrastructure/config/Parameter.java: -------------------------------------------------------------------------------- 1 | package tv.codely.shared.infrastructure.config; 2 | 3 | import io.github.cdimascio.dotenv.Dotenv; 4 | import tv.codely.shared.domain.Service; 5 | 6 | @Service 7 | public final class Parameter { 8 | private final Dotenv dotenv; 9 | 10 | public Parameter(Dotenv dotenv) { 11 | this.dotenv = dotenv; 12 | } 13 | 14 | public String get(String key) throws ParameterNotExist { 15 | String value = dotenv.get(key); 16 | 17 | if (null == value) { 18 | throw new ParameterNotExist(key); 19 | } 20 | 21 | return value; 22 | } 23 | 24 | public Integer getInt(String key) throws ParameterNotExist { 25 | String value = get(key); 26 | 27 | return Integer.parseInt(value); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /courses-examples/behavioral-design-patterns-course/chain-of-responsibility/command-bus-middleware/java/src/shared/main/tv/codely/shared/infrastructure/config/ParameterNotExist.java: -------------------------------------------------------------------------------- 1 | package tv.codely.shared.infrastructure.config; 2 | 3 | public final class ParameterNotExist extends Throwable { 4 | public ParameterNotExist(String key) { 5 | super(String.format("The parameter <%s> does not exist in the environment file", key)); 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /courses-examples/behavioral-design-patterns-course/chain-of-responsibility/command-bus-middleware/java/src/shared/main/tv/codely/shared/infrastructure/validation/ValidationResponse.java: -------------------------------------------------------------------------------- 1 | package tv.codely.shared.infrastructure.validation; 2 | 3 | import java.util.HashMap; 4 | import java.util.List; 5 | 6 | public final class ValidationResponse { 7 | private HashMap > validationErrors; 8 | 9 | public ValidationResponse(HashMap > validationErrors) { 10 | this.validationErrors = validationErrors; 11 | } 12 | 13 | public Boolean hasErrors() { 14 | return !validationErrors.isEmpty(); 15 | } 16 | 17 | public HashMap > errors() { 18 | return validationErrors; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /courses-examples/behavioral-design-patterns-course/chain-of-responsibility/command-bus-middleware/java/src/shared/main/tv/codely/shared/infrastructure/validation/ValidatorNotExist.java: -------------------------------------------------------------------------------- 1 | package tv.codely.shared.infrastructure.validation; 2 | 3 | public final class ValidatorNotExist extends Exception { 4 | public ValidatorNotExist(String name) { 5 | super(String.format("The validator <%s> does not exist", name)); 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /courses-examples/behavioral-design-patterns-course/chain-of-responsibility/command-bus-middleware/java/src/shared/main/tv/codely/shared/infrastructure/validation/validators/FieldValidator.java: -------------------------------------------------------------------------------- 1 | package tv.codely.shared.infrastructure.validation.validators; 2 | 3 | import java.io.Serializable; 4 | import java.util.HashMap; 5 | 6 | public interface FieldValidator { 7 | Boolean isValid(String fieldName, HashMap fields); 8 | 9 | String errorMessage(String fieldName); 10 | } 11 | -------------------------------------------------------------------------------- /courses-examples/behavioral-design-patterns-course/chain-of-responsibility/command-bus-middleware/java/src/shared/main/tv/codely/shared/infrastructure/validation/validators/NotEmptyValidator.java: -------------------------------------------------------------------------------- 1 | package tv.codely.shared.infrastructure.validation.validators; 2 | 3 | import java.io.Serializable; 4 | import java.util.HashMap; 5 | 6 | public final class NotEmptyValidator implements FieldValidator { 7 | @Override 8 | public Boolean isValid(String fieldName, HashMap fields) { 9 | return !fields.get(fieldName).toString().isEmpty(); 10 | } 11 | 12 | @Override 13 | public String errorMessage(String fieldName) { 14 | return String.format("The field <%s> should not be empty", fieldName); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /courses-examples/behavioral-design-patterns-course/chain-of-responsibility/command-bus-middleware/java/src/shared/main/tv/codely/shared/infrastructure/validation/validators/RequiredValidator.java: -------------------------------------------------------------------------------- 1 | package tv.codely.shared.infrastructure.validation.validators; 2 | 3 | import java.io.Serializable; 4 | import java.util.HashMap; 5 | 6 | public final class RequiredValidator implements FieldValidator { 7 | @Override 8 | public Boolean isValid(String fieldName, HashMap fields) { 9 | return fields.containsKey(fieldName); 10 | } 11 | 12 | @Override 13 | public String errorMessage(String fieldName) { 14 | return String.format("The field <%s> is required", fieldName); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /courses-examples/behavioral-design-patterns-course/chain-of-responsibility/command-bus-middleware/java/src/shared/main/tv/codely/shared/infrastructure/validation/validators/StringValidator.java: -------------------------------------------------------------------------------- 1 | package tv.codely.shared.infrastructure.validation.validators; 2 | 3 | import java.io.Serializable; 4 | import java.util.HashMap; 5 | 6 | public final class StringValidator implements FieldValidator { 7 | @Override 8 | public Boolean isValid(String fieldName, HashMap fields) { 9 | return true; 10 | } 11 | 12 | @Override 13 | public String errorMessage(String fieldName) { 14 | return String.format("The field <%s> should be of type string", fieldName); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /courses-examples/behavioral-design-patterns-course/chain-of-responsibility/command-bus-middleware/java/src/shared/main/tv/codely/shared/infrastructure/validation/validators/UuidValidator.java: -------------------------------------------------------------------------------- 1 | package tv.codely.shared.infrastructure.validation.validators; 2 | 3 | import java.io.Serializable; 4 | import java.util.HashMap; 5 | import java.util.regex.Pattern; 6 | 7 | public final class UuidValidator implements FieldValidator { 8 | @Override 9 | public Boolean isValid(String fieldName, HashMap fields) { 10 | Pattern uuidPattern = Pattern.compile("[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$"); 11 | 12 | return uuidPattern.matcher((String) fields.get(fieldName)).matches(); 13 | } 14 | 15 | @Override 16 | public String errorMessage(String fieldName) { 17 | return String.format("The field <%s> is not a valid uuid", fieldName); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /courses-examples/behavioral-design-patterns-course/chain-of-responsibility/command-bus-middleware/java/src/shared/test/tv/codely/shared/domain/EmailMother.java: -------------------------------------------------------------------------------- 1 | package tv.codely.shared.domain; 2 | 3 | public final class EmailMother { 4 | public static String random() { 5 | return MotherCreator.random().internet().emailAddress(); 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /courses-examples/behavioral-design-patterns-course/chain-of-responsibility/command-bus-middleware/java/src/shared/test/tv/codely/shared/domain/IntegerMother.java: -------------------------------------------------------------------------------- 1 | package tv.codely.shared.domain; 2 | 3 | public final class IntegerMother { 4 | public static Integer random() { 5 | return MotherCreator.random().number().randomDigit(); 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /courses-examples/behavioral-design-patterns-course/chain-of-responsibility/command-bus-middleware/java/src/shared/test/tv/codely/shared/domain/ListMother.java: -------------------------------------------------------------------------------- 1 | package tv.codely.shared.domain; 2 | 3 | import java.util.ArrayList; 4 | import java.util.Collections; 5 | import java.util.List; 6 | import java.util.function.Supplier; 7 | 8 | public final class ListMother { 9 | public static List create(Integer size, Supplier creator) { 10 | ArrayList list = new ArrayList<>(); 11 | 12 | for (int i = 0; i < size; i++) { 13 | list.add(creator.get()); 14 | } 15 | 16 | return list; 17 | } 18 | 19 | public static List random(Supplier creator) { 20 | return create(IntegerMother.random(), creator); 21 | } 22 | 23 | public static List one(T element) { 24 | return Collections.singletonList(element); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /courses-examples/behavioral-design-patterns-course/chain-of-responsibility/command-bus-middleware/java/src/shared/test/tv/codely/shared/domain/MotherCreator.java: -------------------------------------------------------------------------------- 1 | package tv.codely.shared.domain; 2 | 3 | import com.github.javafaker.Faker; 4 | 5 | public final class MotherCreator { 6 | private final static Faker faker = new Faker(); 7 | 8 | public static Faker random() { 9 | return faker; 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /courses-examples/behavioral-design-patterns-course/chain-of-responsibility/command-bus-middleware/java/src/shared/test/tv/codely/shared/domain/RandomElementPicker.java: -------------------------------------------------------------------------------- 1 | package tv.codely.shared.domain; 2 | 3 | import java.util.Random; 4 | 5 | public final class RandomElementPicker { 6 | @SafeVarargs 7 | public static T from(T... elements) { 8 | Random rand = new Random(); 9 | 10 | return elements[rand.nextInt(elements.length)]; 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /courses-examples/behavioral-design-patterns-course/chain-of-responsibility/command-bus-middleware/java/src/shared/test/tv/codely/shared/domain/UuidMother.java: -------------------------------------------------------------------------------- 1 | package tv.codely.shared.domain; 2 | 3 | import java.util.UUID; 4 | 5 | public final class UuidMother { 6 | public static String random() { 7 | return UUID.randomUUID().toString(); 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /courses-examples/behavioral-design-patterns-course/chain-of-responsibility/command-bus-middleware/java/src/shared/test/tv/codely/shared/domain/VideoUrlMother.java: -------------------------------------------------------------------------------- 1 | package tv.codely.shared.domain; 2 | 3 | public final class VideoUrlMother { 4 | public static VideoUrl create(String value) { 5 | return new VideoUrl(value); 6 | } 7 | 8 | public static VideoUrl random() { 9 | return create(MotherCreator.random().internet().url()); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /courses-examples/behavioral-design-patterns-course/chain-of-responsibility/command-bus-middleware/java/src/shared/test/tv/codely/shared/domain/WordMother.java: -------------------------------------------------------------------------------- 1 | package tv.codely.shared.domain; 2 | 3 | public final class WordMother { 4 | public static String random() { 5 | return MotherCreator.random().lorem().word(); 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /courses-examples/behavioral-design-patterns-course/chain-of-responsibility/command-bus-middleware/java/var/log/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodelyTV/design-patterns/45c671d989a8d49dc219eae4b9a820fb704d00cc/courses-examples/behavioral-design-patterns-course/chain-of-responsibility/command-bus-middleware/java/var/log/.gitkeep -------------------------------------------------------------------------------- /courses-examples/behavioral-design-patterns-course/chain-of-responsibility/functional/ts/.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | max_line_length = 100 5 | indent_style = space 6 | indent_size = 2 7 | -------------------------------------------------------------------------------- /courses-examples/behavioral-design-patterns-course/chain-of-responsibility/functional/ts/.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | parser: "@typescript-eslint/parser", 3 | extends: [ 4 | "plugin:@typescript-eslint/recommended", 5 | "plugin:prettier/recommended", 6 | ], 7 | plugins: ["simple-import-sort", "import"], 8 | parserOptions: { 9 | ecmaVersion: 12, 10 | sourceType: "module", 11 | }, 12 | rules: { 13 | "simple-import-sort/imports": "error", 14 | "simple-import-sort/exports": "error", 15 | "import/first": "error", 16 | "import/newline-after-import": "error", 17 | "import/no-duplicates": "error", 18 | }, 19 | }; 20 | -------------------------------------------------------------------------------- /courses-examples/behavioral-design-patterns-course/chain-of-responsibility/functional/ts/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | -------------------------------------------------------------------------------- /courses-examples/behavioral-design-patterns-course/chain-of-responsibility/functional/ts/jest.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | testMatch: ["**/tests/**/*.test.ts"], 3 | transform: { 4 | "\\.ts$": "@swc/jest", 5 | }, 6 | }; 7 | -------------------------------------------------------------------------------- /courses-examples/behavioral-design-patterns-course/chain-of-responsibility/functional/ts/src/Command.ts: -------------------------------------------------------------------------------- 1 | export interface Command {} 2 | -------------------------------------------------------------------------------- /courses-examples/behavioral-design-patterns-course/chain-of-responsibility/functional/ts/src/CommandHandler.ts: -------------------------------------------------------------------------------- 1 | import { Command } from "./Command"; 2 | 3 | export interface CommandHandler { 4 | handle(command: Command): void; 5 | } 6 | -------------------------------------------------------------------------------- /courses-examples/behavioral-design-patterns-course/chain-of-responsibility/functional/ts/src/InMemoryCommandBus.ts: -------------------------------------------------------------------------------- 1 | import { Command } from "./Command"; 2 | import { CommandHandler } from "./CommandHandler"; 3 | import { functionalLoggerMiddleware } from "./LoggerMiddleware"; 4 | import { functionalTransactionalMiddleware } from "./TransactionalMiddleware"; 5 | 6 | export class InMemoryCommandBus { 7 | constructor(private readonly commandHandler: CommandHandler) {} 8 | 9 | dispatch(command: Command): void { 10 | const transactionalMiddleware = functionalTransactionalMiddleware(this.commandHandler.handle); 11 | const loggerMiddleware = functionalLoggerMiddleware(transactionalMiddleware); 12 | 13 | loggerMiddleware(command); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /courses-examples/behavioral-design-patterns-course/chain-of-responsibility/functional/ts/src/LoggerMiddleware.ts: -------------------------------------------------------------------------------- 1 | import { Command } from "./Command"; 2 | import { Middleware } from "./Middleware"; 3 | 4 | export function functionalLoggerMiddleware(next: Middleware): Middleware { 5 | return function (command: Command): void { 6 | console.log(`Ejecutando ${command.constructor.name}`); 7 | 8 | next(command); 9 | }; 10 | } 11 | -------------------------------------------------------------------------------- /courses-examples/behavioral-design-patterns-course/chain-of-responsibility/functional/ts/src/Middleware.ts: -------------------------------------------------------------------------------- 1 | import { Command } from "./Command"; 2 | 3 | export type Middleware = (command: Command) => void; 4 | -------------------------------------------------------------------------------- /courses-examples/behavioral-design-patterns-course/chain-of-responsibility/functional/ts/src/TransactionalMiddleware.ts: -------------------------------------------------------------------------------- 1 | import { Command } from "./Command"; 2 | import { Middleware } from "./Middleware"; 3 | 4 | export function functionalTransactionalMiddleware(next: Middleware): Middleware { 5 | return function (command: Command): void { 6 | try { 7 | next(command); 8 | } catch (error: unknown) { 9 | // Rollback 10 | throw error; 11 | } 12 | }; 13 | } 14 | -------------------------------------------------------------------------------- /courses-examples/behavioral-design-patterns-course/chain-of-responsibility/functional/ts/src/index.ts: -------------------------------------------------------------------------------- 1 | import { InMemoryCommandBus } from "./InMemoryCommandBus"; 2 | 3 | const commandBus = new InMemoryCommandBus(); 4 | commandBus.dispatch(); 5 | -------------------------------------------------------------------------------- /courses-examples/behavioral-design-patterns-course/chain-of-responsibility/functional/ts/tests/.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "plugins": ["jest"], 3 | "env": { 4 | "jest/globals": true 5 | } 6 | } -------------------------------------------------------------------------------- /courses-examples/behavioral-design-patterns-course/chain-of-responsibility/functional/ts/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es6", 4 | "module": "ESNext", 5 | "moduleResolution": "node", 6 | "strict": true, 7 | "skipLibCheck": true, 8 | "esModuleInterop": true, 9 | "allowSyntheticDefaultImports": true, 10 | "experimentalDecorators": true 11 | }, 12 | "include": ["src/**/*.ts"], 13 | "exclude": ["node_modules"] 14 | } 15 | -------------------------------------------------------------------------------- /courses-examples/behavioral-design-patterns-course/command/java/.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | charset = utf-8 5 | end_of_line = lf 6 | insert_final_newline = true 7 | trim_trailing_whitespace = true 8 | 9 | [*.java] 10 | indent_size = 4 11 | indent_style = space 12 | -------------------------------------------------------------------------------- /courses-examples/behavioral-design-patterns-course/command/java/.github/workflows/workflow.yml: -------------------------------------------------------------------------------- 1 | name: Main Workflow 2 | 3 | on: [push] 4 | 5 | jobs: 6 | build: 7 | 8 | runs-on: ubuntu-latest 9 | 10 | steps: 11 | - uses: actions/checkout@v2 12 | 13 | - uses: actions/setup-java@v1 14 | with: 15 | java-version: 17 16 | 17 | - name: Assemble 18 | run: ./gradlew assemble --warning-mode all 19 | 20 | - name: Check 21 | run: ./gradlew check --warning-mode all 22 | 23 | -------------------------------------------------------------------------------- /courses-examples/behavioral-design-patterns-course/command/java/.gitignore: -------------------------------------------------------------------------------- 1 | # Gradle 2 | .gradle 3 | build/ 4 | 5 | # Ignore Gradle GUI config 6 | gradle-app.setting 7 | 8 | var/log/* 9 | !var/log/.gitkeep 10 | -------------------------------------------------------------------------------- /courses-examples/behavioral-design-patterns-course/command/java/Makefile: -------------------------------------------------------------------------------- 1 | .PHONY: all 2 | all: build 3 | 4 | .PHONY: build 5 | build: 6 | @./gradlew assemble --warning-mode all 7 | 8 | .PHONY: test 9 | test: 10 | @./gradlew check --warning-mode all 11 | -------------------------------------------------------------------------------- /courses-examples/behavioral-design-patterns-course/command/java/README.md: -------------------------------------------------------------------------------- 1 | # Command design pattern: Java 2 | 3 | Java implementation of the [Command pattern applied to HTTP Controllers example](../README.md). 4 | 5 | ## Steps 6 | 7 | To navigate between steps use `git checkout` command 8 | using the specified commit hash below 👇 9 | 10 | 1. Starting point 11 | 2. Apply the Command design pattern 12 | 3. Replace Command with CommandHandler 13 | 4. Command pattern for query actions 14 | 15 | ```bash 16 | # step 1 17 | git checkout 473e7160 18 | 19 | # step 2 20 | git checkout 20f84858 21 | 22 | # step 3 23 | git checkout d37f2bc8 24 | 25 | # step 4 26 | git checkout 11a50aa8 27 | ``` 28 | -------------------------------------------------------------------------------- /courses-examples/behavioral-design-patterns-course/command/java/doc/endpoints/mooc_courses.http: -------------------------------------------------------------------------------- 1 | ### Create a course 2 | PUT localhost:8080/courses/6854aaba-0ded-4837-bf18-cae3caad45ed 3 | Content-Type: application/json 4 | 5 | { 6 | "name": "Patrones de Diseño", 7 | "duration": "2 horas" 8 | } 9 | 10 | ### Find a course 11 | GET localhost:8080/courses/6854aaba-0ded-4837-bf18-cae3caad45ed 12 | 13 | -------------------------------------------------------------------------------- /courses-examples/behavioral-design-patterns-course/command/java/gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodelyTV/design-patterns/45c671d989a8d49dc219eae4b9a820fb704d00cc/courses-examples/behavioral-design-patterns-course/command/java/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /courses-examples/behavioral-design-patterns-course/command/java/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-7.3-bin.zip 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | -------------------------------------------------------------------------------- /courses-examples/behavioral-design-patterns-course/command/java/src/main/java/tv/codely/mooc/api/Application/Command.java: -------------------------------------------------------------------------------- 1 | package tv.codely.mooc.api.Application; 2 | 3 | public interface Command { 4 | } 5 | -------------------------------------------------------------------------------- /courses-examples/behavioral-design-patterns-course/command/java/src/main/java/tv/codely/mooc/api/Application/CommandHandler.java: -------------------------------------------------------------------------------- 1 | package tv.codely.mooc.api.Application; 2 | 3 | public abstract class CommandHandler { 4 | public R execute(T command) { 5 | var result = this.run(command); 6 | this.log(command); 7 | return result; 8 | } 9 | 10 | abstract protected void log(T command); 11 | abstract protected R run(T command); 12 | } 13 | -------------------------------------------------------------------------------- /courses-examples/behavioral-design-patterns-course/command/java/src/main/java/tv/codely/mooc/api/Application/Create/CourseCreator.java: -------------------------------------------------------------------------------- 1 | package tv.codely.mooc.api.Application.Create; 2 | 3 | import org.springframework.stereotype.Service; 4 | import tv.codely.mooc.api.Domain.Course; 5 | import tv.codely.mooc.api.Domain.CourseRepository; 6 | 7 | @Service 8 | public class CourseCreator { 9 | private final CourseRepository repository; 10 | 11 | public CourseCreator(CourseRepository repository) { 12 | this.repository = repository; 13 | } 14 | 15 | public void create(String id, String name, String duration) { 16 | var course = new Course(id, name, duration); 17 | repository.save(course); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /courses-examples/behavioral-design-patterns-course/command/java/src/main/java/tv/codely/mooc/api/Application/Create/CreateCourseCommand.java: -------------------------------------------------------------------------------- 1 | package tv.codely.mooc.api.Application.Create; 2 | 3 | import tv.codely.mooc.api.Application.Command; 4 | 5 | public record CreateCourseCommand(String id, String name, String duration) implements Command { 6 | } 7 | -------------------------------------------------------------------------------- /courses-examples/behavioral-design-patterns-course/command/java/src/main/java/tv/codely/mooc/api/Domain/Course.java: -------------------------------------------------------------------------------- 1 | package tv.codely.mooc.api.Domain; 2 | 3 | public class Course { 4 | private final CourseId id; 5 | private final CourseName name; 6 | private final CourseDuration duration; 7 | 8 | public Course(String id, String name, String duration) { 9 | this.id = new CourseId(id); 10 | this.name = new CourseName(name); 11 | this.duration = new CourseDuration(duration); 12 | } 13 | 14 | public String id() { 15 | return id.value(); 16 | } 17 | 18 | public String name() { 19 | return name.value(); 20 | } 21 | 22 | public String duration() { 23 | return duration.value(); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /courses-examples/behavioral-design-patterns-course/command/java/src/main/java/tv/codely/mooc/api/Domain/CourseDuration.java: -------------------------------------------------------------------------------- 1 | package tv.codely.mooc.api.Domain; 2 | 3 | public final class CourseDuration extends StringValueObject { 4 | public CourseDuration(String value) { 5 | super(value); 6 | } 7 | 8 | private CourseDuration() { 9 | super(""); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /courses-examples/behavioral-design-patterns-course/command/java/src/main/java/tv/codely/mooc/api/Domain/CourseId.java: -------------------------------------------------------------------------------- 1 | package tv.codely.mooc.api.Domain; 2 | 3 | public final class CourseId extends Identifier { 4 | public CourseId(String value) { 5 | super(value); 6 | } 7 | 8 | public CourseId() { 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /courses-examples/behavioral-design-patterns-course/command/java/src/main/java/tv/codely/mooc/api/Domain/CourseName.java: -------------------------------------------------------------------------------- 1 | package tv.codely.mooc.api.Domain; 2 | 3 | public final class CourseName extends StringValueObject { 4 | public CourseName(String value) { 5 | super(value); 6 | } 7 | 8 | public CourseName() { 9 | super(""); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /courses-examples/behavioral-design-patterns-course/command/java/src/main/java/tv/codely/mooc/api/Domain/CourseNotExist.java: -------------------------------------------------------------------------------- 1 | package tv.codely.mooc.api.Domain; 2 | 3 | public final class CourseNotExist extends DomainError { 4 | public CourseNotExist(CourseId id) { 5 | super("course_not_exist", String.format("The course <%s> doesn't exist", id.value())); 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /courses-examples/behavioral-design-patterns-course/command/java/src/main/java/tv/codely/mooc/api/Domain/CourseRepository.java: -------------------------------------------------------------------------------- 1 | package tv.codely.mooc.api.Domain; 2 | 3 | import java.util.Optional; 4 | 5 | public interface CourseRepository { 6 | void save(Course course); 7 | 8 | Optional search(CourseId id); 9 | } 10 | -------------------------------------------------------------------------------- /courses-examples/behavioral-design-patterns-course/command/java/src/main/java/tv/codely/mooc/api/Domain/DomainError.java: -------------------------------------------------------------------------------- 1 | package tv.codely.mooc.api.Domain; 2 | 3 | public abstract class DomainError extends RuntimeException { 4 | private final String errorCode; 5 | private final String errorMessage; 6 | 7 | public DomainError(String errorCode, String errorMessage) { 8 | super(errorMessage); 9 | 10 | this.errorCode = errorCode; 11 | this.errorMessage = errorMessage; 12 | } 13 | 14 | public String errorCode() { 15 | return errorCode; 16 | } 17 | 18 | public String errorMessage() { 19 | return errorMessage; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /courses-examples/behavioral-design-patterns-course/command/java/src/main/java/tv/codely/mooc/api/Infrastructure/Persistence/InMemoryCourseRepository.java: -------------------------------------------------------------------------------- 1 | package tv.codely.mooc.api.Infrastructure.Persistence; 2 | 3 | import org.springframework.stereotype.Service; 4 | import tv.codely.mooc.api.Domain.Course; 5 | import tv.codely.mooc.api.Domain.CourseId; 6 | import tv.codely.mooc.api.Domain.CourseRepository; 7 | 8 | import java.util.HashMap; 9 | import java.util.Optional; 10 | 11 | @Service 12 | public class InMemoryCourseRepository implements CourseRepository { 13 | private final HashMap courses = new HashMap<>(); 14 | 15 | public void save(Course course) { 16 | courses.put(course.id(), course); 17 | } 18 | 19 | public Optional search(CourseId id) { 20 | return Optional.ofNullable(courses.get(id.value())); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /courses-examples/behavioral-design-patterns-course/command/java/src/main/java/tv/codely/mooc/api/MoocApplication.java: -------------------------------------------------------------------------------- 1 | package tv.codely.mooc.api; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | @SpringBootApplication 7 | public class MoocApplication { 8 | public static void main(String[] args) { 9 | SpringApplication.run(MoocApplication.class, args); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /courses-examples/behavioral-design-patterns-course/command/java/src/main/java/tv/codely/mooc/api/Ui/Api/Controller/CoursePutControllerRequestBody.java: -------------------------------------------------------------------------------- 1 | package tv.codely.mooc.api.Ui.Api.Controller; 2 | 3 | record CoursePutControllerRequestBody(String name, String duration) {} 4 | -------------------------------------------------------------------------------- /courses-examples/behavioral-design-patterns-course/command/java/src/test/java/tv/codely/mooc/api/Ui/Api/Controller/CoursesPutControllerShould.java: -------------------------------------------------------------------------------- 1 | package tv.codely.mooc.api.Ui.Api.Controller; 2 | 3 | import org.json.JSONObject; 4 | import org.junit.jupiter.api.Test; 5 | import tv.codely.mooc.api.ApiTestCase; 6 | 7 | public class CoursesPutControllerShould extends ApiTestCase { 8 | @Test 9 | public void create_a_valid_non_existing_course() throws Exception { 10 | var newCourseJsonBody = new JSONObject() 11 | .put("name", "The best course") 12 | .put("duration", "5 hours") 13 | .toString(); 14 | 15 | whenPutRequestSentTo("/courses/0def00e9-b7b0-4d2b-ba98-721a1f6acf8a", newCourseJsonBody); 16 | 17 | assertEmptyJsonResponse(201); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /courses-examples/behavioral-design-patterns-course/command/java/src/test/resources/application.properties: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodelyTV/design-patterns/45c671d989a8d49dc219eae4b9a820fb704d00cc/courses-examples/behavioral-design-patterns-course/command/java/src/test/resources/application.properties -------------------------------------------------------------------------------- /courses-examples/behavioral-design-patterns-course/command/java/src/test/resources/logback-test.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | -------------------------------------------------------------------------------- /courses-examples/behavioral-design-patterns-course/command/java/var/log/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodelyTV/design-patterns/45c671d989a8d49dc219eae4b9a820fb704d00cc/courses-examples/behavioral-design-patterns-course/command/java/var/log/.gitkeep -------------------------------------------------------------------------------- /courses-examples/behavioral-design-patterns-course/iterator/README.md: -------------------------------------------------------------------------------- 1 | Iterator pattern applied to Data Access 2 | ======================================= 3 | 4 | An example using Generators using the Iterator pattern 5 | to access database data in an efficient way. 6 | 7 | ## Languages 8 | 9 | - [TypeScript](typescript) 10 | 11 | ## Patterns used in this example 12 | 13 | - [Visitor](/design-patterns/behavioral/memento) 14 | -------------------------------------------------------------------------------- /courses-examples/behavioral-design-patterns-course/iterator/typescript/.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | parser: "@typescript-eslint/parser", 3 | extends: [ 4 | "plugin:@typescript-eslint/recommended", 5 | "plugin:prettier/recommended", 6 | ], 7 | plugins: ["simple-import-sort", "import"], 8 | parserOptions: { 9 | ecmaVersion: 12, 10 | sourceType: "module", 11 | }, 12 | rules: { 13 | "simple-import-sort/imports": "error", 14 | "simple-import-sort/exports": "error", 15 | "import/first": "error", 16 | "import/newline-after-import": "error", 17 | "import/no-duplicates": "error", 18 | }, 19 | }; 20 | -------------------------------------------------------------------------------- /courses-examples/behavioral-design-patterns-course/iterator/typescript/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | -------------------------------------------------------------------------------- /courses-examples/behavioral-design-patterns-course/iterator/typescript/jest.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | testMatch: ["**/tests/**/*.test.ts"], 3 | transform: { 4 | "\\.ts$": "@swc/jest", 5 | }, 6 | }; 7 | -------------------------------------------------------------------------------- /courses-examples/behavioral-design-patterns-course/iterator/typescript/src/AggregateRoot.ts: -------------------------------------------------------------------------------- 1 | import { DomainEvent } from "./DomainEvent"; 2 | 3 | export class AggregateRoot { 4 | private recordedEvents: DomainEvent[] = []; 5 | 6 | record(domainEvent: DomainEvent): void { 7 | this.recordedEvents.push(domainEvent); 8 | } 9 | 10 | pullDomainEvents(): DomainEvent[] { 11 | const events = this.recordedEvents; 12 | this.recordedEvents = []; 13 | return events; 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /courses-examples/behavioral-design-patterns-course/iterator/typescript/src/CourseRepository.ts: -------------------------------------------------------------------------------- 1 | import { Course } from "./Course"; 2 | 3 | export interface CourseRepository { 4 | save(course: Course): void; 5 | 6 | find(id: string): Course; 7 | } 8 | -------------------------------------------------------------------------------- /courses-examples/behavioral-design-patterns-course/iterator/typescript/src/CourseReview.ts: -------------------------------------------------------------------------------- 1 | import { Stars } from "./Stars"; 2 | 3 | export class CourseReview { 4 | constructor(public readonly stars: Stars) {} 5 | } 6 | -------------------------------------------------------------------------------- /courses-examples/behavioral-design-patterns-course/iterator/typescript/src/CourseReviews.ts: -------------------------------------------------------------------------------- 1 | import { CourseReview } from "./CourseReview"; 2 | import { CourseReviewsSnapshot } from "./CourseReviewsSnapshot"; 3 | import { Stars } from "./Stars"; 4 | 5 | export class CourseReviews { 6 | constructor(private reviews: CourseReview[]) {} 7 | 8 | meanStars(): number { 9 | const totalStars = this.reviews 10 | .map((review) => review.stars.value) 11 | .reduce((stars: number, total: number) => stars + total, 0); 12 | 13 | const totalReviews = this.reviews.length; 14 | return totalStars / totalReviews; 15 | } 16 | 17 | add(stars: Stars) { 18 | this.reviews.push(new CourseReview(stars)); 19 | } 20 | 21 | createSnapshot(): CourseReviewsSnapshot { 22 | return { 23 | reviews: this.reviews.map((review) => { 24 | return { stars: review.stars.value }; 25 | }), 26 | }; 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /courses-examples/behavioral-design-patterns-course/iterator/typescript/src/CourseReviewsSnapshot.ts: -------------------------------------------------------------------------------- 1 | export type CourseReviewSnapshot = { stars: number }; 2 | 3 | export type CourseReviewsSnapshot = { 4 | reviews: Array4 | 5 | ; 5 | }; 6 | -------------------------------------------------------------------------------- /courses-examples/behavioral-design-patterns-course/iterator/typescript/src/CourseSnapshot.ts: -------------------------------------------------------------------------------- 1 | import { CourseReviewsSnapshot } from "./CourseReviewsSnapshot"; 2 | 3 | export type CourseSnapshot = { 4 | id: string; 5 | reviews: CourseReviewsSnapshot; 6 | date: Date; 7 | }; 8 | -------------------------------------------------------------------------------- /courses-examples/behavioral-design-patterns-course/iterator/typescript/src/DomainEvent.ts: -------------------------------------------------------------------------------- 1 | export interface DomainEvent {} 2 | -------------------------------------------------------------------------------- /courses-examples/behavioral-design-patterns-course/iterator/typescript/src/Generator.ts: -------------------------------------------------------------------------------- 1 | export function* generator(...values: number[]): Generator { 2 | for (const value of values) { 3 | yield value; 4 | console.log("continue!"); 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /courses-examples/behavioral-design-patterns-course/iterator/typescript/src/ReviewAdded.ts: -------------------------------------------------------------------------------- 1 | export class ReviewAdded { 2 | constructor(public readonly id: string, public readonly stars: number) {} 3 | } 4 | -------------------------------------------------------------------------------- /courses-examples/behavioral-design-patterns-course/iterator/typescript/src/Stars.ts: -------------------------------------------------------------------------------- 1 | export class Stars { 2 | constructor(public readonly value: number) { 3 | if (value < 1 || value > 5) { 4 | throw new Error("Invalid stars value"); 5 | } 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /courses-examples/behavioral-design-patterns-course/iterator/typescript/tests/.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "plugins": ["jest"], 3 | "env": { 4 | "jest/globals": true 5 | } 6 | } -------------------------------------------------------------------------------- /courses-examples/behavioral-design-patterns-course/iterator/typescript/tests/Generator.test.ts: -------------------------------------------------------------------------------- 1 | import { generator } from "../src/Generator"; 2 | 3 | describe("Iterator should", () => { 4 | it("saves and restores a Course", () => { 5 | for (const value of generator(1, 2, 3, 4, 5)) { 6 | console.log(value); 7 | } 8 | }); 9 | }); 10 | -------------------------------------------------------------------------------- /courses-examples/behavioral-design-patterns-course/iterator/typescript/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es6", 4 | "module": "ESNext", 5 | "moduleResolution": "node", 6 | "strict": true, 7 | "skipLibCheck": true, 8 | "esModuleInterop": true, 9 | "allowSyntheticDefaultImports": true, 10 | "experimentalDecorators": true 11 | }, 12 | "include": ["src/**/*.ts"], 13 | "exclude": ["node_modules"] 14 | } 15 | -------------------------------------------------------------------------------- /courses-examples/behavioral-design-patterns-course/mediator/README.md: -------------------------------------------------------------------------------- 1 | Mediator pattern applied to a Backend use case 2 | ============================================== 3 | 4 | An example of the Mediator pattern applied 5 | to a Backend use case, to decouple SignUp main 6 | use case from the derived use cases like SendWelcomeEmail. 7 | 8 | ## Description 9 | 10 | In this example we start with a single use case, in which all 11 | the application logic is executed. 12 | 13 | In this example we apply the Mediator design pattern as an 14 | abstraction to split the SignUp main use case from the derived 15 | use cases: 16 | - CreateDefaultWorkspace 17 | - AssignUserToWorkspace 18 | - SendWelcomeEmail 19 | 20 | ## Languages 21 | 22 | - [typeScript](typescript) 23 | 24 | ## Patterns used in this example 25 | 26 | - [Mediator](/design-patterns/behavioral/mediator) 27 | -------------------------------------------------------------------------------- /courses-examples/behavioral-design-patterns-course/mediator/typescript/.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | parser: "@typescript-eslint/parser", 3 | extends: [ 4 | "plugin:@typescript-eslint/recommended", 5 | "plugin:prettier/recommended", 6 | ], 7 | plugins: ["simple-import-sort", "import"], 8 | parserOptions: { 9 | ecmaVersion: 12, 10 | sourceType: "module", 11 | }, 12 | rules: { 13 | "simple-import-sort/imports": "error", 14 | "simple-import-sort/exports": "error", 15 | "import/first": "error", 16 | "import/newline-after-import": "error", 17 | "import/no-duplicates": "error", 18 | }, 19 | }; 20 | -------------------------------------------------------------------------------- /courses-examples/behavioral-design-patterns-course/mediator/typescript/.github/workflows/lint.yml: -------------------------------------------------------------------------------- 1 | name: lint 2 | 3 | on: push 4 | 5 | jobs: 6 | lint: 7 | runs-on: ubuntu-latest 8 | 9 | steps: 10 | - uses: actions/checkout@v2 11 | 12 | - name: Cache node modules 13 | uses: actions/cache@v2 14 | env: 15 | cache-name: cache-node-modules 16 | with: 17 | path: ~/.npm 18 | key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ hashFiles('**/package-lock.json') }} 19 | restore-keys: | 20 | ${{ runner.os }}-build-${{ env.cache-name }}- 21 | ${{ runner.os }}-build- 22 | ${{ runner.os }}- 23 | 24 | - name: Install Dependencies 25 | run: npm install 26 | 27 | - name: Lint 28 | run: npm run lint -------------------------------------------------------------------------------- /courses-examples/behavioral-design-patterns-course/mediator/typescript/.github/workflows/test.yml: -------------------------------------------------------------------------------- 1 | name: test 2 | 3 | on: push 4 | 5 | jobs: 6 | test: 7 | runs-on: ubuntu-latest 8 | 9 | steps: 10 | - uses: actions/checkout@v2 11 | 12 | - name: Cache node modules 13 | uses: actions/cache@v2 14 | env: 15 | cache-name: cache-node-modules 16 | with: 17 | path: ~/.npm 18 | key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ hashFiles('**/package-lock.json') }} 19 | restore-keys: | 20 | ${{ runner.os }}-build-${{ env.cache-name }}- 21 | ${{ runner.os }}-build- 22 | ${{ runner.os }}- 23 | 24 | - name: Install Dependencies 25 | run: npm install 26 | 27 | - name: Test 28 | run: npm run test -------------------------------------------------------------------------------- /courses-examples/behavioral-design-patterns-course/mediator/typescript/.gitignore: -------------------------------------------------------------------------------- 1 | # API keys and secrets 2 | .env 3 | 4 | # Dependency directory 5 | node_modules 6 | 7 | # Ignore built ts files 8 | dist 9 | -------------------------------------------------------------------------------- /courses-examples/behavioral-design-patterns-course/mediator/typescript/jest.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | globals: { 3 | "ts-jest": { 4 | tsconfig: "tsconfig.json", 5 | }, 6 | }, 7 | moduleFileExtensions: ["ts", "js"], 8 | transform: { 9 | "^.+\\.(ts|tsx)$": "ts-jest", 10 | }, 11 | testMatch: ["**/test/**/*.spec.(ts|js)"], 12 | testEnvironment: "node", 13 | }; 14 | -------------------------------------------------------------------------------- /courses-examples/behavioral-design-patterns-course/mediator/typescript/public/courses/bash.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodelyTV/design-patterns/45c671d989a8d49dc219eae4b9a820fb704d00cc/courses-examples/behavioral-design-patterns-course/mediator/typescript/public/courses/bash.jpg -------------------------------------------------------------------------------- /courses-examples/behavioral-design-patterns-course/mediator/typescript/public/courses/ddd-en-php.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodelyTV/design-patterns/45c671d989a8d49dc219eae4b9a820fb704d00cc/courses-examples/behavioral-design-patterns-course/mediator/typescript/public/courses/ddd-en-php.jpg -------------------------------------------------------------------------------- /courses-examples/behavioral-design-patterns-course/mediator/typescript/public/courses/ddd-java.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodelyTV/design-patterns/45c671d989a8d49dc219eae4b9a820fb704d00cc/courses-examples/behavioral-design-patterns-course/mediator/typescript/public/courses/ddd-java.jpg -------------------------------------------------------------------------------- /courses-examples/behavioral-design-patterns-course/mediator/typescript/public/courses/layouts-css.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodelyTV/design-patterns/45c671d989a8d49dc219eae4b9a820fb704d00cc/courses-examples/behavioral-design-patterns-course/mediator/typescript/public/courses/layouts-css.jpg -------------------------------------------------------------------------------- /courses-examples/behavioral-design-patterns-course/mediator/typescript/public/courses/makefiles.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodelyTV/design-patterns/45c671d989a8d49dc219eae4b9a820fb704d00cc/courses-examples/behavioral-design-patterns-course/mediator/typescript/public/courses/makefiles.jpg -------------------------------------------------------------------------------- /courses-examples/behavioral-design-patterns-course/mediator/typescript/public/courses/novedades-vue-3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodelyTV/design-patterns/45c671d989a8d49dc219eae4b9a820fb704d00cc/courses-examples/behavioral-design-patterns-course/mediator/typescript/public/courses/novedades-vue-3.jpg -------------------------------------------------------------------------------- /courses-examples/behavioral-design-patterns-course/mediator/typescript/public/courses/terminal-zsh.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodelyTV/design-patterns/45c671d989a8d49dc219eae4b9a820fb704d00cc/courses-examples/behavioral-design-patterns-course/mediator/typescript/public/courses/terminal-zsh.jpg -------------------------------------------------------------------------------- /courses-examples/behavioral-design-patterns-course/mediator/typescript/src/app.ts: -------------------------------------------------------------------------------- 1 | import express from "express"; 2 | import path from "path"; 3 | 4 | import { loadApiEndpoints } from "./controllers/api"; 5 | 6 | // Create Express server 7 | const app = express(); 8 | 9 | // Express configuration 10 | app.set("port", process.env.PORT || 3000); 11 | app.use(express.json()); 12 | app.use(express.urlencoded({ extended: true })); 13 | 14 | app.use( 15 | express.static(path.join(__dirname, "../public"), { maxAge: 31557600000 }) 16 | ); 17 | 18 | loadApiEndpoints(app); 19 | 20 | export default app; 21 | -------------------------------------------------------------------------------- /courses-examples/behavioral-design-patterns-course/mediator/typescript/src/entity/Role.ts: -------------------------------------------------------------------------------- 1 | export enum Role { 2 | admin, 3 | editor, 4 | } 5 | -------------------------------------------------------------------------------- /courses-examples/behavioral-design-patterns-course/mediator/typescript/src/entity/User.ts: -------------------------------------------------------------------------------- 1 | export class User { 2 | constructor( 3 | public readonly id: string, 4 | public readonly name: string, 5 | public readonly emailAddress: string, 6 | public readonly password: string 7 | ) {} 8 | } 9 | -------------------------------------------------------------------------------- /courses-examples/behavioral-design-patterns-course/mediator/typescript/src/entity/UserRepository.ts: -------------------------------------------------------------------------------- 1 | import { User } from "./User"; 2 | 3 | export class UserRepository { 4 | save(user: User) { 5 | console.log(user); 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /courses-examples/behavioral-design-patterns-course/mediator/typescript/src/entity/Workspace.ts: -------------------------------------------------------------------------------- 1 | import { Role } from "./Role"; 2 | 3 | export class Workspace { 4 | static default(): Workspace { 5 | return new Workspace(); 6 | } 7 | 8 | assignUser(user: string, role: Role): void { 9 | console.log(`User ${user} assigned to default workspace with role ${role}`); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /courses-examples/behavioral-design-patterns-course/mediator/typescript/src/entity/WorkspaceRepository.ts: -------------------------------------------------------------------------------- 1 | import { Workspace } from "./Workspace"; 2 | 3 | export class WorkspaceRepository { 4 | save(workspace: Workspace) { 5 | console.log(workspace); 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /courses-examples/behavioral-design-patterns-course/mediator/typescript/src/server.ts: -------------------------------------------------------------------------------- 1 | import app from "./app"; 2 | 3 | /** 4 | * Start Express server. 5 | */ 6 | const server = app.listen(app.get("port"), () => { 7 | console.log( 8 | " App is running at http://localhost:%d in %s mode", 9 | app.get("port"), 10 | app.get("env") 11 | ); 12 | console.log(" Press CTRL-C to stop\n"); 13 | }); 14 | 15 | export default server; 16 | -------------------------------------------------------------------------------- /courses-examples/behavioral-design-patterns-course/mediator/typescript/src/service/DomainEvent.ts: -------------------------------------------------------------------------------- 1 | export abstract class DomainEvent { 2 | static EVENT_NAME: string; 3 | 4 | abstract eventName(): string; 5 | } 6 | -------------------------------------------------------------------------------- /courses-examples/behavioral-design-patterns-course/mediator/typescript/src/service/Email.ts: -------------------------------------------------------------------------------- 1 | export class Email { 2 | constructor( 3 | private readonly to: string, 4 | private readonly subject: string, 5 | private readonly body: string 6 | ) {} 7 | } 8 | -------------------------------------------------------------------------------- /courses-examples/behavioral-design-patterns-course/mediator/typescript/src/service/EventBus.ts: -------------------------------------------------------------------------------- 1 | import { DomainEvent } from "./DomainEvent"; 2 | 3 | export interface EventBus { 4 | notify (event: T): void; 5 | } 6 | -------------------------------------------------------------------------------- /courses-examples/behavioral-design-patterns-course/mediator/typescript/src/service/InMemoryEventBus.ts: -------------------------------------------------------------------------------- 1 | import { DomainEvent } from "./DomainEvent"; 2 | import { EventBus } from "./EventBus"; 3 | import { Observer } from "./Observer"; 4 | 5 | export class InMemoryEventBus implements EventBus { 6 | constructor( 7 | private readonly observers: Map []> 8 | ) {} 9 | 10 | notify (event: T): void { 11 | const observers = this.observers.get(event.eventName()); 12 | 13 | if (observers) { 14 | observers.forEach((observer) => observer.update(event)); 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /courses-examples/behavioral-design-patterns-course/mediator/typescript/src/service/Mailer.ts: -------------------------------------------------------------------------------- 1 | import { Email } from "./Email"; 2 | 3 | export class Mailer { 4 | send = (email: Email) => { 5 | console.log(email); 6 | }; 7 | } 8 | -------------------------------------------------------------------------------- /courses-examples/behavioral-design-patterns-course/mediator/typescript/src/service/Observer.ts: -------------------------------------------------------------------------------- 1 | import { DomainEvent } from "./DomainEvent"; 2 | 3 | export interface Observer { 4 | update(event: T): void; 5 | } 6 | -------------------------------------------------------------------------------- /courses-examples/behavioral-design-patterns-course/mediator/typescript/src/service/SendWelcomeEmailOnUserSignUp.ts: -------------------------------------------------------------------------------- 1 | import { Email } from "./Email"; 2 | import { Mailer } from "./Mailer"; 3 | import { Observer } from "./Observer"; 4 | import { UserSignUpDomainEvent } from "./UserSignUpDomainEvent"; 5 | 6 | export class SendWelcomeEmailOnUserSignUp 7 | implements Observer 8 | { 9 | constructor(private mailer: Mailer) {} 10 | 11 | update(event: UserSignUpDomainEvent): void { 12 | console.log("2 - Send welcome email"); 13 | const subject = "Welcome to ..."; 14 | const body = "Welcome email body"; 15 | this.mailer.send(new Email(event.emailAddress, subject, body)); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /courses-examples/behavioral-design-patterns-course/mediator/typescript/src/service/UserSignUpDomainEvent.ts: -------------------------------------------------------------------------------- 1 | import { DomainEvent } from "./DomainEvent"; 2 | 3 | export class UserSignUpDomainEvent extends DomainEvent { 4 | static EVENT_NAME = "user_sign_up"; 5 | 6 | constructor(public readonly emailAddress: string) { 7 | super(); 8 | } 9 | 10 | eventName(): string { 11 | return UserSignUpDomainEvent.EVENT_NAME; 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /courses-examples/behavioral-design-patterns-course/mediator/typescript/test/api.spec.ts: -------------------------------------------------------------------------------- 1 | import request from "supertest"; 2 | 3 | import app from "../src/app"; 4 | 5 | describe("GET /api/signup", () => { 6 | it("should return 201", () => { 7 | return request(app).get("/api/signup").expect(201); 8 | }); 9 | }); 10 | -------------------------------------------------------------------------------- /courses-examples/behavioral-design-patterns-course/mediator/typescript/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "module": "commonjs", 4 | "esModuleInterop": true, 5 | "allowSyntheticDefaultImports": true, 6 | "target": "es6", 7 | "strict": true, 8 | "moduleResolution": "node", 9 | "sourceMap": true, 10 | "outDir": "dist", 11 | "resolveJsonModule": true 12 | }, 13 | "include": [ 14 | "src/**/*" 15 | ] 16 | } -------------------------------------------------------------------------------- /courses-examples/behavioral-design-patterns-course/memento/README.md: -------------------------------------------------------------------------------- 1 | Memento pattern applied to EventSourced system 2 | =============================================== 3 | 4 | An example using Memento pattern applied to EventSourced 5 | system. 6 | 7 | ## Languages 8 | 9 | - [TypeScript](typescript) 10 | 11 | ## Patterns used in this example 12 | 13 | - [Visitor](/design-patterns/behavioral/memento) 14 | -------------------------------------------------------------------------------- /courses-examples/behavioral-design-patterns-course/memento/typescript/.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | parser: "@typescript-eslint/parser", 3 | extends: [ 4 | "plugin:@typescript-eslint/recommended", 5 | "plugin:prettier/recommended", 6 | ], 7 | plugins: ["simple-import-sort", "import"], 8 | parserOptions: { 9 | ecmaVersion: 12, 10 | sourceType: "module", 11 | }, 12 | rules: { 13 | "simple-import-sort/imports": "error", 14 | "simple-import-sort/exports": "error", 15 | "import/first": "error", 16 | "import/newline-after-import": "error", 17 | "import/no-duplicates": "error", 18 | }, 19 | }; 20 | -------------------------------------------------------------------------------- /courses-examples/behavioral-design-patterns-course/memento/typescript/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | -------------------------------------------------------------------------------- /courses-examples/behavioral-design-patterns-course/memento/typescript/jest.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | testMatch: ["**/tests/**/*.test.ts"], 3 | transform: { 4 | "\\.ts$": "@swc/jest", 5 | }, 6 | }; 7 | -------------------------------------------------------------------------------- /courses-examples/behavioral-design-patterns-course/memento/typescript/src/AggregateRoot.ts: -------------------------------------------------------------------------------- 1 | import { DomainEvent } from "./DomainEvent"; 2 | 3 | export class AggregateRoot { 4 | private recordedEvents: DomainEvent[] = []; 5 | 6 | record(domainEvent: DomainEvent): void { 7 | this.recordedEvents.push(domainEvent); 8 | } 9 | 10 | pullDomainEvents(): DomainEvent[] { 11 | const events = this.recordedEvents; 12 | this.recordedEvents = []; 13 | return events; 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /courses-examples/behavioral-design-patterns-course/memento/typescript/src/CourseRepository.ts: -------------------------------------------------------------------------------- 1 | import { Course } from "./Course"; 2 | 3 | export interface CourseRepository { 4 | save(course: Course): void; 5 | 6 | find(id: string): Course; 7 | } 8 | -------------------------------------------------------------------------------- /courses-examples/behavioral-design-patterns-course/memento/typescript/src/CourseReview.ts: -------------------------------------------------------------------------------- 1 | import { Stars } from "./Stars"; 2 | 3 | export class CourseReview { 4 | constructor(public readonly stars: Stars) {} 5 | } 6 | -------------------------------------------------------------------------------- /courses-examples/behavioral-design-patterns-course/memento/typescript/src/CourseReviews.ts: -------------------------------------------------------------------------------- 1 | import { CourseReview } from "./CourseReview"; 2 | import { CourseReviewsSnapshot } from "./CourseReviewsSnapshot"; 3 | import { Stars } from "./Stars"; 4 | 5 | export class CourseReviews { 6 | constructor(private reviews: CourseReview[]) {} 7 | 8 | meanStars(): number { 9 | const totalStars = this.reviews 10 | .map((review) => review.stars.value) 11 | .reduce((stars: number, total: number) => stars + total, 0); 12 | 13 | const totalReviews = this.reviews.length; 14 | return totalStars / totalReviews; 15 | } 16 | 17 | add(stars: Stars) { 18 | this.reviews.push(new CourseReview(stars)); 19 | } 20 | 21 | createSnapshot(): CourseReviewsSnapshot { 22 | return { 23 | reviews: this.reviews.map((review) => { 24 | return { stars: review.stars.value }; 25 | }), 26 | }; 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /courses-examples/behavioral-design-patterns-course/memento/typescript/src/CourseReviewsSnapshot.ts: -------------------------------------------------------------------------------- 1 | export type CourseReviewSnapshot = { stars: number }; 2 | 3 | export type CourseReviewsSnapshot = { 4 | reviews: Array ; 5 | }; 6 | -------------------------------------------------------------------------------- /courses-examples/behavioral-design-patterns-course/memento/typescript/src/CourseSnapshot.ts: -------------------------------------------------------------------------------- 1 | import { CourseReviewsSnapshot } from "./CourseReviewsSnapshot"; 2 | 3 | export type CourseSnapshot = { 4 | id: string; 5 | reviews: CourseReviewsSnapshot; 6 | date: Date; 7 | }; 8 | -------------------------------------------------------------------------------- /courses-examples/behavioral-design-patterns-course/memento/typescript/src/DomainEvent.ts: -------------------------------------------------------------------------------- 1 | export interface DomainEvent {} 2 | -------------------------------------------------------------------------------- /courses-examples/behavioral-design-patterns-course/memento/typescript/src/ReviewAdded.ts: -------------------------------------------------------------------------------- 1 | export class ReviewAdded { 2 | constructor(public readonly id: string, public readonly stars: number) {} 3 | } 4 | -------------------------------------------------------------------------------- /courses-examples/behavioral-design-patterns-course/memento/typescript/src/Stars.ts: -------------------------------------------------------------------------------- 1 | export class Stars { 2 | constructor(public readonly value: number) { 3 | if (value < 1 || value > 5) { 4 | throw new Error("Invalid stars value"); 5 | } 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /courses-examples/behavioral-design-patterns-course/memento/typescript/tests/.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "plugins": ["jest"], 3 | "env": { 4 | "jest/globals": true 5 | } 6 | } -------------------------------------------------------------------------------- /courses-examples/behavioral-design-patterns-course/memento/typescript/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es6", 4 | "module": "ESNext", 5 | "moduleResolution": "node", 6 | "strict": true, 7 | "skipLibCheck": true, 8 | "esModuleInterop": true, 9 | "allowSyntheticDefaultImports": true, 10 | "experimentalDecorators": true 11 | }, 12 | "include": ["src/**/*.ts"], 13 | "exclude": ["node_modules"] 14 | } 15 | -------------------------------------------------------------------------------- /courses-examples/behavioral-design-patterns-course/observer/README.md: -------------------------------------------------------------------------------- 1 | Observer pattern applied to a Backend use case 2 | ============================================== 3 | 4 | An example of the Observer pattern applied 5 | to a Backend use case, to decouple SignUp main 6 | use case from the derived use cases like SendWelcomeEmail. 7 | 8 | ## Description 9 | 10 | In this example we start with a single use case, in which all 11 | the application logic is executed. 12 | 13 | In this example we apply the Observer design pattern as an 14 | abstraction to split the SignUp main use case from the derived 15 | use cases: 16 | - CreateDefaultWorkspace 17 | - AssignUserToWorkspace 18 | - SendWelcomeEmail 19 | 20 | ## Languages 21 | 22 | - [typeScript](typescript) 23 | 24 | ## Patterns used in this example 25 | 26 | - [Observer](/design-patterns/behavioral/observer) 27 | -------------------------------------------------------------------------------- /courses-examples/behavioral-design-patterns-course/observer/typescript/.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | parser: "@typescript-eslint/parser", 3 | extends: [ 4 | "plugin:@typescript-eslint/recommended", 5 | "plugin:prettier/recommended", 6 | ], 7 | plugins: ["simple-import-sort", "import"], 8 | parserOptions: { 9 | ecmaVersion: 12, 10 | sourceType: "module", 11 | }, 12 | rules: { 13 | "simple-import-sort/imports": "error", 14 | "simple-import-sort/exports": "error", 15 | "import/first": "error", 16 | "import/newline-after-import": "error", 17 | "import/no-duplicates": "error", 18 | }, 19 | }; 20 | -------------------------------------------------------------------------------- /courses-examples/behavioral-design-patterns-course/observer/typescript/.github/workflows/lint.yml: -------------------------------------------------------------------------------- 1 | name: lint 2 | 3 | on: push 4 | 5 | jobs: 6 | lint: 7 | runs-on: ubuntu-latest 8 | 9 | steps: 10 | - uses: actions/checkout@v2 11 | 12 | - name: Cache node modules 13 | uses: actions/cache@v2 14 | env: 15 | cache-name: cache-node-modules 16 | with: 17 | path: ~/.npm 18 | key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ hashFiles('**/package-lock.json') }} 19 | restore-keys: | 20 | ${{ runner.os }}-build-${{ env.cache-name }}- 21 | ${{ runner.os }}-build- 22 | ${{ runner.os }}- 23 | 24 | - name: Install Dependencies 25 | run: npm install 26 | 27 | - name: Lint 28 | run: npm run lint -------------------------------------------------------------------------------- /courses-examples/behavioral-design-patterns-course/observer/typescript/.github/workflows/test.yml: -------------------------------------------------------------------------------- 1 | name: test 2 | 3 | on: push 4 | 5 | jobs: 6 | test: 7 | runs-on: ubuntu-latest 8 | 9 | steps: 10 | - uses: actions/checkout@v2 11 | 12 | - name: Cache node modules 13 | uses: actions/cache@v2 14 | env: 15 | cache-name: cache-node-modules 16 | with: 17 | path: ~/.npm 18 | key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ hashFiles('**/package-lock.json') }} 19 | restore-keys: | 20 | ${{ runner.os }}-build-${{ env.cache-name }}- 21 | ${{ runner.os }}-build- 22 | ${{ runner.os }}- 23 | 24 | - name: Install Dependencies 25 | run: npm install 26 | 27 | - name: Test 28 | run: npm run test -------------------------------------------------------------------------------- /courses-examples/behavioral-design-patterns-course/observer/typescript/.gitignore: -------------------------------------------------------------------------------- 1 | # API keys and secrets 2 | .env 3 | 4 | # Dependency directory 5 | node_modules 6 | 7 | # Ignore built ts files 8 | dist 9 | -------------------------------------------------------------------------------- /courses-examples/behavioral-design-patterns-course/observer/typescript/jest.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | globals: { 3 | "ts-jest": { 4 | tsconfig: "tsconfig.json", 5 | }, 6 | }, 7 | moduleFileExtensions: ["ts", "js"], 8 | transform: { 9 | "^.+\\.(ts|tsx)$": "ts-jest", 10 | }, 11 | testMatch: ["**/test/**/*.spec.(ts|js)"], 12 | testEnvironment: "node", 13 | }; 14 | -------------------------------------------------------------------------------- /courses-examples/behavioral-design-patterns-course/observer/typescript/public/courses/bash.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodelyTV/design-patterns/45c671d989a8d49dc219eae4b9a820fb704d00cc/courses-examples/behavioral-design-patterns-course/observer/typescript/public/courses/bash.jpg -------------------------------------------------------------------------------- /courses-examples/behavioral-design-patterns-course/observer/typescript/public/courses/ddd-en-php.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodelyTV/design-patterns/45c671d989a8d49dc219eae4b9a820fb704d00cc/courses-examples/behavioral-design-patterns-course/observer/typescript/public/courses/ddd-en-php.jpg -------------------------------------------------------------------------------- /courses-examples/behavioral-design-patterns-course/observer/typescript/public/courses/ddd-java.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodelyTV/design-patterns/45c671d989a8d49dc219eae4b9a820fb704d00cc/courses-examples/behavioral-design-patterns-course/observer/typescript/public/courses/ddd-java.jpg -------------------------------------------------------------------------------- /courses-examples/behavioral-design-patterns-course/observer/typescript/public/courses/layouts-css.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodelyTV/design-patterns/45c671d989a8d49dc219eae4b9a820fb704d00cc/courses-examples/behavioral-design-patterns-course/observer/typescript/public/courses/layouts-css.jpg -------------------------------------------------------------------------------- /courses-examples/behavioral-design-patterns-course/observer/typescript/public/courses/makefiles.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodelyTV/design-patterns/45c671d989a8d49dc219eae4b9a820fb704d00cc/courses-examples/behavioral-design-patterns-course/observer/typescript/public/courses/makefiles.jpg -------------------------------------------------------------------------------- /courses-examples/behavioral-design-patterns-course/observer/typescript/public/courses/novedades-vue-3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodelyTV/design-patterns/45c671d989a8d49dc219eae4b9a820fb704d00cc/courses-examples/behavioral-design-patterns-course/observer/typescript/public/courses/novedades-vue-3.jpg -------------------------------------------------------------------------------- /courses-examples/behavioral-design-patterns-course/observer/typescript/public/courses/terminal-zsh.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodelyTV/design-patterns/45c671d989a8d49dc219eae4b9a820fb704d00cc/courses-examples/behavioral-design-patterns-course/observer/typescript/public/courses/terminal-zsh.jpg -------------------------------------------------------------------------------- /courses-examples/behavioral-design-patterns-course/observer/typescript/src/app.ts: -------------------------------------------------------------------------------- 1 | import express from "express"; 2 | import path from "path"; 3 | 4 | import { loadApiEndpoints } from "./controllers/api"; 5 | 6 | // Create Express server 7 | const app = express(); 8 | 9 | // Express configuration 10 | app.set("port", process.env.PORT || 3000); 11 | app.use(express.json()); 12 | app.use(express.urlencoded({ extended: true })); 13 | 14 | app.use( 15 | express.static(path.join(__dirname, "../public"), { maxAge: 31557600000 }) 16 | ); 17 | 18 | loadApiEndpoints(app); 19 | 20 | export default app; 21 | -------------------------------------------------------------------------------- /courses-examples/behavioral-design-patterns-course/observer/typescript/src/entity/DefaultWorkspaceCreated.ts: -------------------------------------------------------------------------------- 1 | export class DefaultWorkspaceCreated { 2 | constructor( 3 | public readonly workspaceId: string, 4 | public readonly userId: string 5 | ) {} 6 | } 7 | -------------------------------------------------------------------------------- /courses-examples/behavioral-design-patterns-course/observer/typescript/src/entity/Role.ts: -------------------------------------------------------------------------------- 1 | export enum Role { 2 | admin, 3 | editor, 4 | } 5 | -------------------------------------------------------------------------------- /courses-examples/behavioral-design-patterns-course/observer/typescript/src/entity/User.ts: -------------------------------------------------------------------------------- 1 | export class User { 2 | constructor( 3 | public readonly id: string, 4 | public readonly name: string, 5 | public readonly emailAddress: string, 6 | public readonly password: string 7 | ) {} 8 | } 9 | -------------------------------------------------------------------------------- /courses-examples/behavioral-design-patterns-course/observer/typescript/src/entity/UserRegistered.ts: -------------------------------------------------------------------------------- 1 | export class UserRegistered { 2 | constructor( 3 | public readonly id: string, 4 | public readonly name: string, 5 | public readonly emailAddress: string, 6 | public readonly password: string 7 | ) {} 8 | } 9 | -------------------------------------------------------------------------------- /courses-examples/behavioral-design-patterns-course/observer/typescript/src/entity/UserRepository.ts: -------------------------------------------------------------------------------- 1 | import { User } from "./User"; 2 | 3 | export class UserRepository { 4 | save(user: User) { 5 | console.log(user); 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /courses-examples/behavioral-design-patterns-course/observer/typescript/src/entity/Workspace.ts: -------------------------------------------------------------------------------- 1 | import { Role } from "./Role"; 2 | 3 | export class Workspace { 4 | constructor(public readonly id: string) {} 5 | 6 | static default(): Workspace { 7 | return new Workspace("fake random uuid"); 8 | } 9 | 10 | assignUser(user: string, role: Role): void { 11 | console.log(`User ${user} assigned to default workspace with role ${role}`); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /courses-examples/behavioral-design-patterns-course/observer/typescript/src/entity/WorkspaceRepository.ts: -------------------------------------------------------------------------------- 1 | import { Workspace } from "./Workspace"; 2 | 3 | export class WorkspaceRepository { 4 | save(workspace: Workspace) { 5 | console.log(workspace); 6 | } 7 | 8 | find(id: string) { 9 | return new Workspace(id); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /courses-examples/behavioral-design-patterns-course/observer/typescript/src/server.ts: -------------------------------------------------------------------------------- 1 | import app from "./app"; 2 | 3 | /** 4 | * Start Express server. 5 | */ 6 | const server = app.listen(app.get("port"), () => { 7 | console.log( 8 | " App is running at http://localhost:%d in %s mode", 9 | app.get("port"), 10 | app.get("env") 11 | ); 12 | console.log(" Press CTRL-C to stop\n"); 13 | }); 14 | 15 | export default server; 16 | -------------------------------------------------------------------------------- /courses-examples/behavioral-design-patterns-course/observer/typescript/src/service/AssignUserToWorkspace.ts: -------------------------------------------------------------------------------- 1 | import { DefaultWorkspaceCreated } from "../entity/DefaultWorkspaceCreated"; 2 | import { Role } from "../entity/Role"; 3 | import { WorkspaceRepository } from "../entity/WorkspaceRepository"; 4 | import { Observer } from "./Observer"; 5 | 6 | export class AssignUserToWorkspace 7 | implements Observer 8 | { 9 | constructor(private readonly workspaceRepository: WorkspaceRepository) {} 10 | 11 | update(event: DefaultWorkspaceCreated): void { 12 | console.log("4 - Assign user to workspace"); 13 | const workspace = this.workspaceRepository.find(event.workspaceId); 14 | workspace.assignUser(event.userId, Role.admin); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /courses-examples/behavioral-design-patterns-course/observer/typescript/src/service/Email.ts: -------------------------------------------------------------------------------- 1 | export class Email { 2 | constructor( 3 | private readonly to: string, 4 | private readonly subject: string, 5 | private readonly body: string 6 | ) {} 7 | } 8 | -------------------------------------------------------------------------------- /courses-examples/behavioral-design-patterns-course/observer/typescript/src/service/Mailer.ts: -------------------------------------------------------------------------------- 1 | import { Email } from "./Email"; 2 | 3 | export class Mailer { 4 | send = (email: Email) => { 5 | console.log(email); 6 | }; 7 | } 8 | -------------------------------------------------------------------------------- /courses-examples/behavioral-design-patterns-course/observer/typescript/src/service/Observable.ts: -------------------------------------------------------------------------------- 1 | import { Observer } from "./Observer"; 2 | 3 | export abstract class Observable { 4 | private observers: Observer [] = []; 5 | 6 | addObserver(observer: Observer ): void { 7 | this.observers.push(observer); 8 | } 9 | 10 | async notify(event: T): Promise { 11 | this.observers.forEach((observer) => observer.update(event)); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /courses-examples/behavioral-design-patterns-course/observer/typescript/src/service/Observer.ts: -------------------------------------------------------------------------------- 1 | export interface Observer { 2 | update(event: T): void; 3 | } 4 | -------------------------------------------------------------------------------- /courses-examples/behavioral-design-patterns-course/observer/typescript/src/service/SendWelcomeEmail.ts: -------------------------------------------------------------------------------- 1 | import { UserRegistered } from "../entity/UserRegistered"; 2 | import { Email } from "./Email"; 3 | import { Mailer } from "./Mailer"; 4 | import { Observer } from "./Observer"; 5 | 6 | export class SendWelcomeEmail implements Observer { 7 | constructor(private readonly mailer: Mailer) {} 8 | 9 | async update(event: UserRegistered): Promise { 10 | console.log("2 - Send welcome email"); 11 | const subject = "Welcome to ..."; 12 | const body = "Welcome email body"; 13 | this.mailer.send(new Email(event.emailAddress, subject, body)); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /courses-examples/behavioral-design-patterns-course/observer/typescript/test/api.spec.ts: -------------------------------------------------------------------------------- 1 | import request from "supertest"; 2 | 3 | import app from "../src/app"; 4 | 5 | describe("GET /api/signup", () => { 6 | it("should return 201", () => { 7 | return request(app).get("/api/signup").expect(201); 8 | }); 9 | }); 10 | -------------------------------------------------------------------------------- /courses-examples/behavioral-design-patterns-course/observer/typescript/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "module": "commonjs", 4 | "esModuleInterop": true, 5 | "allowSyntheticDefaultImports": true, 6 | "target": "es6", 7 | "strict": true, 8 | "moduleResolution": "node", 9 | "sourceMap": true, 10 | "outDir": "dist", 11 | "resolveJsonModule": true 12 | }, 13 | "include": [ 14 | "src/**/*" 15 | ] 16 | } -------------------------------------------------------------------------------- /courses-examples/behavioral-design-patterns-course/state/php/.editorconfig: -------------------------------------------------------------------------------- 1 | ; This file is for unifying the coding style for different editors and IDEs. 2 | ; More information at http://editorconfig.org 3 | 4 | root = true 5 | 6 | [*] 7 | charset = utf-8 8 | end_of_line = lf 9 | insert_final_newline = true 10 | trim_trailing_whitespace = true 11 | 12 | [*.php] 13 | indent_size = 4 14 | indent_style = space 15 | 16 | [*.md] 17 | trim_trailing_whitespace = false 18 | -------------------------------------------------------------------------------- /courses-examples/behavioral-design-patterns-course/state/php/.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | custom: https://bit.ly/CodelyTvPro 2 | -------------------------------------------------------------------------------- /courses-examples/behavioral-design-patterns-course/state/php/.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | 3 | on: 4 | push: 5 | branches: 6 | - master 7 | pull_request: 8 | 9 | jobs: 10 | build: 11 | runs-on: ${{ matrix.os }} 12 | strategy: 13 | matrix: 14 | os: [ubuntu-latest, windows-latest, macOS-latest] 15 | php-versions: ['7.4', '8.0'] 16 | 17 | name: Test on ${{ matrix.os }} with PHP ${{ matrix.php-versions }} 18 | steps: 19 | - name: Checkout 20 | uses: actions/checkout@v2 21 | 22 | - name: Setup PHP 23 | uses: shivammathur/setup-php@v1 24 | with: 25 | php-version: ${{ matrix.php-versions }} 26 | coverage: none 27 | 28 | - name: Install dependencies 29 | run: composer install --ignore-platform-reqs 30 | 31 | - name: Run the tests 32 | run: composer phpunit 33 | -------------------------------------------------------------------------------- /courses-examples/behavioral-design-patterns-course/state/php/.gitignore: -------------------------------------------------------------------------------- 1 | vendor/ 2 | .phpunit.result.cache 3 | -------------------------------------------------------------------------------- /courses-examples/behavioral-design-patterns-course/state/php/.scrutinizer.yml: -------------------------------------------------------------------------------- 1 | build: 2 | environment: 3 | php: 4 | version: '7.2' 5 | -------------------------------------------------------------------------------- /courses-examples/behavioral-design-patterns-course/state/php/.semver: -------------------------------------------------------------------------------- 1 | --- 2 | :major: 1 3 | :minor: 2 4 | :patch: 1 5 | :special: '' 6 | -------------------------------------------------------------------------------- /courses-examples/behavioral-design-patterns-course/state/php/phpunit.xml: -------------------------------------------------------------------------------- 1 | 8 | 14 | -------------------------------------------------------------------------------- /courses-examples/behavioral-design-patterns-course/state/php/src/ArchiveCourse.php: -------------------------------------------------------------------------------- 1 | status = CourseStatus::archived(); 19 | } 20 | 21 | /** @throws Exception */ 22 | public function publish(): PublishedCourse 23 | { 24 | throw new Exception('Invalid operation'); 25 | } 26 | 27 | public function archive(): ArchiveCourse 28 | { 29 | return $this; 30 | } 31 | 32 | protected function ensureCanRename(CourseName $newName): void 33 | { 34 | throw new Exception('Invalid operation'); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /courses-examples/behavioral-design-patterns-course/state/php/src/CourseDuration.php: -------------------------------------------------------------------------------- 1 | errorMessage()); 14 | } 15 | 16 | abstract public function errorCode(): string; 17 | 18 | abstract protected function errorMessage(): string; 19 | } 20 | -------------------------------------------------------------------------------- /courses-examples/behavioral-design-patterns-course/state/php/src/StringValueObject.php: -------------------------------------------------------------------------------- 1 | value; 16 | } 17 | 18 | public function __toString(): string 19 | { 20 | return $this->value(); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /courses-examples/behavioral-design-patterns-course/strategy/achivements-functional/ts/.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | parser: "@typescript-eslint/parser", 3 | extends: [ 4 | "plugin:@typescript-eslint/recommended", 5 | "plugin:prettier/recommended", 6 | ], 7 | plugins: ["simple-import-sort", "import"], 8 | parserOptions: { 9 | ecmaVersion: 12, 10 | sourceType: "module", 11 | }, 12 | rules: { 13 | "simple-import-sort/imports": "error", 14 | "simple-import-sort/exports": "error", 15 | "import/first": "error", 16 | "import/newline-after-import": "error", 17 | "import/no-duplicates": "error", 18 | }, 19 | }; 20 | -------------------------------------------------------------------------------- /courses-examples/behavioral-design-patterns-course/strategy/achivements-functional/ts/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | -------------------------------------------------------------------------------- /courses-examples/behavioral-design-patterns-course/strategy/achivements-functional/ts/jest.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | testMatch: ["**/tests/**/*.test.ts"], 3 | transform: { 4 | "\\.ts$": "@swc/jest", 5 | }, 6 | }; 7 | -------------------------------------------------------------------------------- /courses-examples/behavioral-design-patterns-course/strategy/achivements-functional/ts/tests/.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "plugins": ["jest"], 3 | "env": { 4 | "jest/globals": true 5 | } 6 | } -------------------------------------------------------------------------------- /courses-examples/behavioral-design-patterns-course/strategy/achivements-functional/ts/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es6", 4 | "module": "ESNext", 5 | "moduleResolution": "node", 6 | "strict": true, 7 | "skipLibCheck": true, 8 | "esModuleInterop": true, 9 | "allowSyntheticDefaultImports": true, 10 | "experimentalDecorators": true 11 | }, 12 | "include": ["src/**/*.ts"], 13 | "exclude": ["node_modules"] 14 | } 15 | -------------------------------------------------------------------------------- /courses-examples/behavioral-design-patterns-course/strategy/kotlin/.github/workflows/main.yml: -------------------------------------------------------------------------------- 1 | # This workflow will build a Java project with Gradle 2 | # For more information see: https://help.github.com/actions/language-and-framework-guides/building-and-testing-java-with-gradle 3 | 4 | name: Kotlin basic skeleton CI 5 | 6 | on: 7 | push: 8 | branches: [ main ] 9 | pull_request: 10 | branches: [ main ] 11 | 12 | jobs: 13 | build: 14 | 15 | runs-on: ubuntu-latest 16 | 17 | steps: 18 | - uses: actions/checkout@v2 19 | - name: Set up JDK 11 20 | uses: actions/setup-java@v2 21 | with: 22 | java-version: '11' 23 | distribution: 'adopt' 24 | - name: Grant execute permission for gradlew 25 | run: chmod +x gradlew 26 | - name: Build with Gradle 27 | run: ./gradlew build 28 | -------------------------------------------------------------------------------- /courses-examples/behavioral-design-patterns-course/strategy/kotlin/.gitignore: -------------------------------------------------------------------------------- 1 | .gradle 2 | build/ 3 | !gradle/wrapper/gradle-wrapper.jar 4 | !**/src/main/**/build/ 5 | !**/src/test/**/build/ 6 | 7 | 8 | ### IntelliJ IDEA ### 9 | .idea 10 | *.iws 11 | *.iml 12 | *.ipr 13 | out/ 14 | !**/src/main/**/out/ 15 | !**/src/test/**/out/ 16 | -------------------------------------------------------------------------------- /courses-examples/behavioral-design-patterns-course/strategy/kotlin/gradle.properties: -------------------------------------------------------------------------------- 1 | kotlin.code.style=official 2 | org.gradle.parallel=true 3 | org.gradle.caching=true 4 | org.gradle.daemon=true 5 | org.gradle.jvmargs=-Xmx1536M 6 | -------------------------------------------------------------------------------- /courses-examples/behavioral-design-patterns-course/strategy/kotlin/gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodelyTV/design-patterns/45c671d989a8d49dc219eae4b9a820fb704d00cc/courses-examples/behavioral-design-patterns-course/strategy/kotlin/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /courses-examples/behavioral-design-patterns-course/strategy/kotlin/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-6.8-bin.zip 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | -------------------------------------------------------------------------------- /courses-examples/behavioral-design-patterns-course/strategy/kotlin/settings.gradle.kts: -------------------------------------------------------------------------------- 1 | rootProject.name = "kotlin-basic-skeleton" 2 | -------------------------------------------------------------------------------- /courses-examples/behavioral-design-patterns-course/strategy/kotlin/src/main/kotlin/com/codely/achievement/AchievementDealer.kt: -------------------------------------------------------------------------------- 1 | package com.codely.achievement 2 | 3 | import java.util.* 4 | 5 | abstract class AchievementDealer(private val learnerAchievements: LearnerAchievementRepository) { 6 | abstract fun dealAchievements(learnerId: String, earnedPoints: LearnerEarnedPoints) 7 | 8 | protected fun dealAchievement(learnerId: String, type: AchievementType) { 9 | val achievement = LearnerAchievement( 10 | "id", 11 | learnerId, 12 | type, 13 | Date() 14 | ) 15 | learnerAchievements.save(achievement) 16 | println(type.description()) 17 | } 18 | } -------------------------------------------------------------------------------- /courses-examples/behavioral-design-patterns-course/strategy/kotlin/src/main/kotlin/com/codely/achievement/AchievementType.kt: -------------------------------------------------------------------------------- 1 | package com.codely.achievement 2 | 3 | enum class AchievementType { 4 | PointsEarned100 { 5 | override fun description() = "100 Points earned" 6 | }, 7 | PointsEarned500 { 8 | override fun description() = "500 Points earned" 9 | }, 10 | PointsEarned2500 { 11 | override fun description() = "2500 Points earned" 12 | }, 13 | FrontendGuru { 14 | override fun description() = "Front-end guru" 15 | }, 16 | BackendGuru { 17 | override fun description() = "Back-end guru" 18 | }, 19 | FullStackGuru { 20 | override fun description() = "FullStack guru" 21 | }; 22 | 23 | abstract fun description(): String 24 | } -------------------------------------------------------------------------------- /courses-examples/behavioral-design-patterns-course/strategy/kotlin/src/main/kotlin/com/codely/achievement/ConstantLearnerRepository.kt: -------------------------------------------------------------------------------- 1 | package com.codely.achievement 2 | 3 | class ConstantLearnerRepository(private val learner: Learner) : LearnerRepository { 4 | override fun find(learnerId: String): Learner { 5 | return learner 6 | } 7 | } -------------------------------------------------------------------------------- /courses-examples/behavioral-design-patterns-course/strategy/kotlin/src/main/kotlin/com/codely/achievement/DummyStepRepository.kt: -------------------------------------------------------------------------------- 1 | package com.codely.achievement 2 | 3 | class DummyStepRepository : StepRepository { 4 | override fun find(stepId: String): Step { 5 | return Step(stepId, 100) 6 | } 7 | } -------------------------------------------------------------------------------- /courses-examples/behavioral-design-patterns-course/strategy/kotlin/src/main/kotlin/com/codely/achievement/EarnedPoints.kt: -------------------------------------------------------------------------------- 1 | package com.codely.achievement 2 | 3 | data class EarnedPoints(val value: Int) { 4 | operator fun compareTo(other: EarnedPoints): Int { 5 | if (value == other.value) { 6 | return 0 7 | } 8 | 9 | return if (value > other.value) 1 else -1 10 | } 11 | 12 | operator fun plus(other: EarnedPoints): EarnedPoints { 13 | return EarnedPoints(value + other.value) 14 | } 15 | } -------------------------------------------------------------------------------- /courses-examples/behavioral-design-patterns-course/strategy/kotlin/src/main/kotlin/com/codely/achievement/InMemoryLearnerAchievementRepository.kt: -------------------------------------------------------------------------------- 1 | package com.codely.achievement 2 | 3 | class InMemoryLearnerAchievementRepository : LearnerAchievementRepository { 4 | 5 | private val achievements: MutableList9 | 13 |10 | 12 |tests 11 |= mutableListOf() 6 | 7 | override fun save(learnerAchievement: LearnerAchievement) { 8 | achievements.add(learnerAchievement) 9 | } 10 | 11 | fun has(learnerId: String, achievementType: AchievementType): Boolean { 12 | val achievement = achievements.find { achievement -> achievement.learnerId == learnerId && achievement.type == achievementType } 13 | return achievement != null 14 | } 15 | } -------------------------------------------------------------------------------- /courses-examples/behavioral-design-patterns-course/strategy/kotlin/src/main/kotlin/com/codely/achievement/Learner.kt: -------------------------------------------------------------------------------- 1 | package com.codely.achievement 2 | 3 | data class Learner(val learnerId: String, val earnedPoints: LearnerEarnedPoints) 4 | -------------------------------------------------------------------------------- /courses-examples/behavioral-design-patterns-course/strategy/kotlin/src/main/kotlin/com/codely/achievement/LearnerAchievement.kt: -------------------------------------------------------------------------------- 1 | package com.codely.achievement 2 | 3 | import java.util.Date 4 | 5 | data class LearnerAchievement( 6 | val id: String, 7 | val learnerId: String, 8 | val type: AchievementType, 9 | val wonOn: Date 10 | ) -------------------------------------------------------------------------------- /courses-examples/behavioral-design-patterns-course/strategy/kotlin/src/main/kotlin/com/codely/achievement/LearnerAchievementDealer.kt: -------------------------------------------------------------------------------- 1 | package com.codely.achievement 2 | 3 | import com.codely.achievement.factories.AchievementDealerFactory 4 | 5 | class LearnerAchievementDealer ( 6 | learnerAchievements: LearnerAchievementRepository, 7 | private val dealersFactory: AchievementDealerFactory 8 | ) : AchievementDealer(learnerAchievements) { 9 | override fun dealAchievements(learnerId: String, earnedPoints: LearnerEarnedPoints) { 10 | dealersFactory 11 | .build() 12 | .forEach { dealer -> dealer.dealAchievements(learnerId, earnedPoints) } 13 | } 14 | } -------------------------------------------------------------------------------- /courses-examples/behavioral-design-patterns-course/strategy/kotlin/src/main/kotlin/com/codely/achievement/LearnerAchievementRepository.kt: -------------------------------------------------------------------------------- 1 | package com.codely.achievement 2 | 3 | interface LearnerAchievementRepository { 4 | fun save(learnerAchievement: LearnerAchievement) 5 | } -------------------------------------------------------------------------------- /courses-examples/behavioral-design-patterns-course/strategy/kotlin/src/main/kotlin/com/codely/achievement/LearnerEarnedPoints.kt: -------------------------------------------------------------------------------- 1 | package com.codely.achievement 2 | 3 | data class LearnerEarnedPoints( 4 | val frontend: EarnedPoints, 5 | val backend: EarnedPoints 6 | ) { 7 | val total: EarnedPoints = frontend + backend 8 | } 9 | -------------------------------------------------------------------------------- /courses-examples/behavioral-design-patterns-course/strategy/kotlin/src/main/kotlin/com/codely/achievement/LearnerRepository.kt: -------------------------------------------------------------------------------- 1 | package com.codely.achievement 2 | 3 | interface LearnerRepository { 4 | fun find(learnerId: String): Learner 5 | } 6 | -------------------------------------------------------------------------------- /courses-examples/behavioral-design-patterns-course/strategy/kotlin/src/main/kotlin/com/codely/achievement/LearnerStep.kt: -------------------------------------------------------------------------------- 1 | package com.codely.achievement 2 | 3 | import java.util.Date 4 | 5 | data class LearnerStep( 6 | val learnerId: String, 7 | val stepId: String, 8 | val earnedPoints: EarnedPoints, 9 | val completedOn: Date 10 | ) -------------------------------------------------------------------------------- /courses-examples/behavioral-design-patterns-course/strategy/kotlin/src/main/kotlin/com/codely/achievement/LearnerStepRepository.kt: -------------------------------------------------------------------------------- 1 | package com.codely.achievement 2 | 3 | interface LearnerStepRepository { 4 | fun save(learnerStep: LearnerStep) 5 | } -------------------------------------------------------------------------------- /courses-examples/behavioral-design-patterns-course/strategy/kotlin/src/main/kotlin/com/codely/achievement/Step.kt: -------------------------------------------------------------------------------- 1 | package com.codely.achievement 2 | 3 | data class Step(val id: String, val totalPoints: Int) 4 | -------------------------------------------------------------------------------- /courses-examples/behavioral-design-patterns-course/strategy/kotlin/src/main/kotlin/com/codely/achievement/StepCompleter.kt: -------------------------------------------------------------------------------- 1 | package com.codely.achievement 2 | 3 | import java.util.Date 4 | 5 | class StepCompleter( 6 | private val learners: LearnerRepository, 7 | private val steps: StepRepository, 8 | private val learnerSteps: LearnerStepRepository, 9 | private val learnerAchievementDealer: AchievementDealer 10 | ) { 11 | 12 | fun completeStep(stepId: String, learnerId: String) { 13 | val step = steps.find(stepId) 14 | val learner = learners.find(learnerId) 15 | 16 | val learnerStep = LearnerStep( 17 | stepId, 18 | learnerId, 19 | EarnedPoints(step.totalPoints), 20 | Date()) 21 | learnerSteps.save(learnerStep) 22 | 23 | learnerAchievementDealer.dealAchievements(learnerId, learner.earnedPoints) 24 | } 25 | } -------------------------------------------------------------------------------- /courses-examples/behavioral-design-patterns-course/strategy/kotlin/src/main/kotlin/com/codely/achievement/StepRepository.kt: -------------------------------------------------------------------------------- 1 | package com.codely.achievement 2 | 3 | interface StepRepository { 4 | fun find(stepId: String): Step 5 | } -------------------------------------------------------------------------------- /courses-examples/behavioral-design-patterns-course/strategy/kotlin/src/main/kotlin/com/codely/achievement/VoidLearnerStepsRepository.kt: -------------------------------------------------------------------------------- 1 | package com.codely.achievement 2 | 3 | class VoidLearnerStepsRepository : LearnerStepRepository { 4 | override fun save(learnerStep: LearnerStep) { 5 | } 6 | } -------------------------------------------------------------------------------- /courses-examples/behavioral-design-patterns-course/strategy/kotlin/src/main/kotlin/com/codely/achievement/achievements/BackendGuru.kt: -------------------------------------------------------------------------------- 1 | package com.codely.achievement.achievements 2 | 3 | import com.codely.achievement.* 4 | 5 | class BackendGuru(learnerAchievements: LearnerAchievementRepository) : AchievementDealer(learnerAchievements) { 6 | override fun dealAchievements(learnerId: String, earnedPoints: LearnerEarnedPoints) { 7 | if (earnedPoints.backend >= EarnedPoints(2000)) { 8 | dealAchievement(learnerId, AchievementType.BackendGuru) 9 | } 10 | } 11 | } -------------------------------------------------------------------------------- /courses-examples/behavioral-design-patterns-course/strategy/kotlin/src/main/kotlin/com/codely/achievement/achievements/FrontendGuru.kt: -------------------------------------------------------------------------------- 1 | package com.codely.achievement.achievements 2 | 3 | import com.codely.achievement.* 4 | 5 | class FrontendGuru(learnerAchievements: LearnerAchievementRepository) : AchievementDealer(learnerAchievements) { 6 | override fun dealAchievements(learnerId: String, earnedPoints: LearnerEarnedPoints) { 7 | if (earnedPoints.frontend >= EarnedPoints(2000)) { 8 | dealAchievement(learnerId, AchievementType.FrontendGuru) 9 | } 10 | } 11 | } -------------------------------------------------------------------------------- /courses-examples/behavioral-design-patterns-course/strategy/kotlin/src/main/kotlin/com/codely/achievement/achievements/FullStackGuru.kt: -------------------------------------------------------------------------------- 1 | package com.codely.achievement.achievements 2 | 3 | import com.codely.achievement.* 4 | 5 | class FullStackGuru(learnerAchievements: LearnerAchievementRepository) : AchievementDealer(learnerAchievements) { 6 | override fun dealAchievements(learnerId: String, earnedPoints: LearnerEarnedPoints) { 7 | if (earnedPoints.frontend >= EarnedPoints(1500) && 8 | earnedPoints.backend >= EarnedPoints(1750) 9 | ) { 10 | dealAchievement(learnerId, AchievementType.FullStackGuru) 11 | } 12 | } 13 | } -------------------------------------------------------------------------------- /courses-examples/behavioral-design-patterns-course/strategy/kotlin/src/main/kotlin/com/codely/achievement/achievements/PointsEarned100.kt: -------------------------------------------------------------------------------- 1 | package com.codely.achievement.achievements 2 | 3 | import com.codely.achievement.* 4 | 5 | class PointsEarned100(learnerAchievements: LearnerAchievementRepository) : AchievementDealer(learnerAchievements) { 6 | override fun dealAchievements(learnerId: String, earnedPoints: LearnerEarnedPoints) { 7 | if (earnedPoints.total >= EarnedPoints(100)) { 8 | dealAchievement(learnerId, AchievementType.PointsEarned100) 9 | } 10 | } 11 | } -------------------------------------------------------------------------------- /courses-examples/behavioral-design-patterns-course/strategy/kotlin/src/main/kotlin/com/codely/achievement/achievements/PointsEarned2500.kt: -------------------------------------------------------------------------------- 1 | package com.codely.achievement.achievements 2 | 3 | import com.codely.achievement.* 4 | 5 | class PointsEarned2500(learnerAchievements: LearnerAchievementRepository) : AchievementDealer(learnerAchievements) { 6 | override fun dealAchievements(learnerId: String, earnedPoints: LearnerEarnedPoints) { 7 | if (earnedPoints.total >= EarnedPoints(2500)) { 8 | dealAchievement(learnerId, AchievementType.PointsEarned2500) 9 | } 10 | } 11 | } -------------------------------------------------------------------------------- /courses-examples/behavioral-design-patterns-course/strategy/kotlin/src/main/kotlin/com/codely/achievement/achievements/PointsEarned500.kt: -------------------------------------------------------------------------------- 1 | package com.codely.achievement.achievements 2 | 3 | import com.codely.achievement.* 4 | 5 | class PointsEarned500(learnerAchievements: LearnerAchievementRepository) : AchievementDealer(learnerAchievements) { 6 | override fun dealAchievements(learnerId: String, earnedPoints: LearnerEarnedPoints) { 7 | if (earnedPoints.total >= EarnedPoints(500)) { 8 | dealAchievement(learnerId, AchievementType.PointsEarned500) 9 | } 10 | } 11 | } -------------------------------------------------------------------------------- /courses-examples/behavioral-design-patterns-course/strategy/kotlin/src/main/kotlin/com/codely/achievement/factories/AchievementDealerFactory.kt: -------------------------------------------------------------------------------- 1 | package com.codely.achievement.factories 2 | 3 | import com.codely.achievement.AchievementDealer 4 | 5 | interface AchievementDealerFactory { 6 | fun build(): List 7 | } -------------------------------------------------------------------------------- /courses-examples/behavioral-design-patterns-course/strategy/kotlin/src/main/kotlin/com/codely/achievement/factories/LearnerAchievementDealerFactory.kt: -------------------------------------------------------------------------------- 1 | package com.codely.achievement.factories 2 | 3 | import com.codely.achievement.AchievementDealer 4 | import com.codely.achievement.LearnerAchievementRepository 5 | import com.codely.achievement.achievements.* 6 | 7 | class LearnerAchievementDealerFactory( 8 | private val learnerAchievements: LearnerAchievementRepository 9 | ) : AchievementDealerFactory { 10 | override fun build(): List { 11 | return listOf( 12 | PointsEarned100(learnerAchievements), 13 | PointsEarned500(learnerAchievements), 14 | PointsEarned2500(learnerAchievements), 15 | FrontendGuru(learnerAchievements), 16 | BackendGuru(learnerAchievements), 17 | FullStackGuru(learnerAchievements) 18 | ) 19 | } 20 | } -------------------------------------------------------------------------------- /courses-examples/behavioral-design-patterns-course/visitor/README.md: -------------------------------------------------------------------------------- 1 | Visitor pattern example 2 | ======================= 3 | 4 | An example using Visitor design pattern. 5 | 6 | ## Languages 7 | 8 | - [TypeScript](typescript) 9 | 10 | ## Patterns used in this example 11 | 12 | - [Visitor](/design-patterns/behavioral/visitor) 13 | -------------------------------------------------------------------------------- /courses-examples/behavioral-design-patterns-course/visitor/typescript/.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | parser: "@typescript-eslint/parser", 3 | extends: [ 4 | "plugin:@typescript-eslint/recommended", 5 | "plugin:prettier/recommended", 6 | ], 7 | plugins: ["simple-import-sort", "import"], 8 | parserOptions: { 9 | ecmaVersion: 12, 10 | sourceType: "module", 11 | }, 12 | rules: { 13 | "simple-import-sort/imports": "error", 14 | "simple-import-sort/exports": "error", 15 | "import/first": "error", 16 | "import/newline-after-import": "error", 17 | "import/no-duplicates": "error", 18 | }, 19 | }; 20 | -------------------------------------------------------------------------------- /courses-examples/behavioral-design-patterns-course/visitor/typescript/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | -------------------------------------------------------------------------------- /courses-examples/behavioral-design-patterns-course/visitor/typescript/jest.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | testMatch: ["**/tests/**/*.test.ts"], 3 | transform: { 4 | "\\.ts$": "@swc/jest", 5 | }, 6 | }; 7 | -------------------------------------------------------------------------------- /courses-examples/behavioral-design-patterns-course/visitor/typescript/src/ElementA.ts: -------------------------------------------------------------------------------- 1 | import { VisitingElement } from "./VisitingElement"; 2 | import { Visitor } from "./Visitor"; 3 | 4 | export class ElementA implements VisitingElement { 5 | constructor(public readonly name: string) {} 6 | 7 | accept(visitor: Visitor) { 8 | visitor.visitElementA(this); 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /courses-examples/behavioral-design-patterns-course/visitor/typescript/src/ElementB.ts: -------------------------------------------------------------------------------- 1 | import { VisitingElement } from "./VisitingElement"; 2 | import { Visitor } from "./Visitor"; 3 | 4 | export class ElementB implements VisitingElement { 5 | constructor(public readonly title: string) {} 6 | 7 | accept(visitor: Visitor) { 8 | visitor.visitElementB(this); 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /courses-examples/behavioral-design-patterns-course/visitor/typescript/src/ExportVisitor.ts: -------------------------------------------------------------------------------- 1 | import fs from "fs"; 2 | 3 | import { ElementA } from "./ElementA"; 4 | import { ElementB } from "./ElementB"; 5 | import { Visitor } from "./Visitor"; 6 | 7 | export class ExportVisitor implements Visitor { 8 | private readonly _path = "test.txt"; 9 | 10 | visitElementA(element: ElementA): void { 11 | fs.writeFileSync(this._path, element.name, { flag: "a" }); 12 | } 13 | 14 | visitElementB(element: ElementB): void { 15 | fs.writeFileSync(this._path, element.title, { flag: "a" }); 16 | } 17 | 18 | readFile(): string { 19 | return fs.readFileSync(this._path, { flag: "r" }).toString(); 20 | } 21 | 22 | removeFile(): void { 23 | fs.unlinkSync(this._path); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /courses-examples/behavioral-design-patterns-course/visitor/typescript/src/PrintVisitor.ts: -------------------------------------------------------------------------------- 1 | import { ElementA } from "./ElementA"; 2 | import { ElementB } from "./ElementB"; 3 | import { Visitor } from "./Visitor"; 4 | 5 | export class PrintVisitor implements Visitor { 6 | visitElementA(element: ElementA): void { 7 | console.log(element.name); 8 | } 9 | 10 | visitElementB(element: ElementB): void { 11 | console.log(element.title); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /courses-examples/behavioral-design-patterns-course/visitor/typescript/src/ValidatorVisitor.ts: -------------------------------------------------------------------------------- 1 | import { ElementA } from "./ElementA"; 2 | import { ElementB } from "./ElementB"; 3 | import { Visitor } from "./Visitor"; 4 | 5 | export class ValidatorVisitor implements Visitor { 6 | visitElementA(element: ElementA): void { 7 | if (element.name.length === 0) { 8 | throw new Error("ElementA name can't be empty"); 9 | } 10 | } 11 | 12 | visitElementB(element: ElementB): void { 13 | if (element.title.length > 5) { 14 | throw new Error("ElementB title is too long"); 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /courses-examples/behavioral-design-patterns-course/visitor/typescript/src/VisitingElement.ts: -------------------------------------------------------------------------------- 1 | import { Visitor } from "./Visitor"; 2 | 3 | export interface VisitingElement { 4 | accept(visitor: Visitor): void; 5 | } 6 | -------------------------------------------------------------------------------- /courses-examples/behavioral-design-patterns-course/visitor/typescript/src/Visitor.ts: -------------------------------------------------------------------------------- 1 | import { ElementA } from "./ElementA"; 2 | import { ElementB } from "./ElementB"; 3 | 4 | export interface Visitor { 5 | visitElementA(element: ElementA): void; 6 | visitElementB(element: ElementB): void; 7 | } 8 | -------------------------------------------------------------------------------- /courses-examples/behavioral-design-patterns-course/visitor/typescript/tests/.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "plugins": ["jest"], 3 | "env": { 4 | "jest/globals": true 5 | } 6 | } -------------------------------------------------------------------------------- /courses-examples/behavioral-design-patterns-course/visitor/typescript/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es6", 4 | "module": "ESNext", 5 | "moduleResolution": "node", 6 | "strict": true, 7 | "skipLibCheck": true, 8 | "esModuleInterop": true, 9 | "allowSyntheticDefaultImports": true, 10 | "experimentalDecorators": true 11 | }, 12 | "include": ["src/**/*.ts"], 13 | "exclude": ["node_modules"] 14 | } 15 | -------------------------------------------------------------------------------- /design-patterns/behavioral/chain-of-responsibility/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodelyTV/design-patterns/45c671d989a8d49dc219eae4b9a820fb704d00cc/design-patterns/behavioral/chain-of-responsibility/.gitkeep -------------------------------------------------------------------------------- /design-patterns/behavioral/command/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodelyTV/design-patterns/45c671d989a8d49dc219eae4b9a820fb704d00cc/design-patterns/behavioral/command/.gitkeep -------------------------------------------------------------------------------- /design-patterns/behavioral/iterator/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodelyTV/design-patterns/45c671d989a8d49dc219eae4b9a820fb704d00cc/design-patterns/behavioral/iterator/.gitkeep -------------------------------------------------------------------------------- /design-patterns/behavioral/mediator/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodelyTV/design-patterns/45c671d989a8d49dc219eae4b9a820fb704d00cc/design-patterns/behavioral/mediator/.gitkeep -------------------------------------------------------------------------------- /design-patterns/behavioral/memento/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodelyTV/design-patterns/45c671d989a8d49dc219eae4b9a820fb704d00cc/design-patterns/behavioral/memento/.gitkeep -------------------------------------------------------------------------------- /design-patterns/behavioral/observer/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodelyTV/design-patterns/45c671d989a8d49dc219eae4b9a820fb704d00cc/design-patterns/behavioral/observer/.gitkeep -------------------------------------------------------------------------------- /design-patterns/behavioral/state/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodelyTV/design-patterns/45c671d989a8d49dc219eae4b9a820fb704d00cc/design-patterns/behavioral/state/.gitkeep -------------------------------------------------------------------------------- /design-patterns/behavioral/strategy/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodelyTV/design-patterns/45c671d989a8d49dc219eae4b9a820fb704d00cc/design-patterns/behavioral/strategy/.gitkeep -------------------------------------------------------------------------------- /design-patterns/behavioral/template-method/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodelyTV/design-patterns/45c671d989a8d49dc219eae4b9a820fb704d00cc/design-patterns/behavioral/template-method/.gitkeep -------------------------------------------------------------------------------- /design-patterns/behavioral/visitor/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodelyTV/design-patterns/45c671d989a8d49dc219eae4b9a820fb704d00cc/design-patterns/behavioral/visitor/.gitkeep -------------------------------------------------------------------------------- /design-patterns/creational/abstract-factory/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodelyTV/design-patterns/45c671d989a8d49dc219eae4b9a820fb704d00cc/design-patterns/creational/abstract-factory/.gitkeep -------------------------------------------------------------------------------- /design-patterns/creational/builder/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodelyTV/design-patterns/45c671d989a8d49dc219eae4b9a820fb704d00cc/design-patterns/creational/builder/.gitkeep -------------------------------------------------------------------------------- /design-patterns/creational/factory-method/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodelyTV/design-patterns/45c671d989a8d49dc219eae4b9a820fb704d00cc/design-patterns/creational/factory-method/.gitkeep -------------------------------------------------------------------------------- /design-patterns/creational/prototype/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodelyTV/design-patterns/45c671d989a8d49dc219eae4b9a820fb704d00cc/design-patterns/creational/prototype/.gitkeep -------------------------------------------------------------------------------- /design-patterns/creational/singleton/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodelyTV/design-patterns/45c671d989a8d49dc219eae4b9a820fb704d00cc/design-patterns/creational/singleton/.gitkeep -------------------------------------------------------------------------------- /design-patterns/structural/adapter/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodelyTV/design-patterns/45c671d989a8d49dc219eae4b9a820fb704d00cc/design-patterns/structural/adapter/.gitkeep -------------------------------------------------------------------------------- /design-patterns/structural/bridge/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodelyTV/design-patterns/45c671d989a8d49dc219eae4b9a820fb704d00cc/design-patterns/structural/bridge/.gitkeep -------------------------------------------------------------------------------- /design-patterns/structural/composite/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodelyTV/design-patterns/45c671d989a8d49dc219eae4b9a820fb704d00cc/design-patterns/structural/composite/.gitkeep -------------------------------------------------------------------------------- /design-patterns/structural/decorator/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodelyTV/design-patterns/45c671d989a8d49dc219eae4b9a820fb704d00cc/design-patterns/structural/decorator/.gitkeep -------------------------------------------------------------------------------- /design-patterns/structural/facade/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodelyTV/design-patterns/45c671d989a8d49dc219eae4b9a820fb704d00cc/design-patterns/structural/facade/.gitkeep -------------------------------------------------------------------------------- /design-patterns/structural/flyweight/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodelyTV/design-patterns/45c671d989a8d49dc219eae4b9a820fb704d00cc/design-patterns/structural/flyweight/.gitkeep -------------------------------------------------------------------------------- /design-patterns/structural/proxy/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodelyTV/design-patterns/45c671d989a8d49dc219eae4b9a820fb704d00cc/design-patterns/structural/proxy/.gitkeep -------------------------------------------------------------------------------- /exercises/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodelyTV/design-patterns/45c671d989a8d49dc219eae4b9a820fb704d00cc/exercises/.gitkeep -------------------------------------------------------------------------------- /node_modules/.package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "design-patterns", 3 | "lockfileVersion": 2, 4 | "requires": true, 5 | "packages": {} 6 | } 7 | -------------------------------------------------------------------------------- /node_modules/.yarn-integrity: -------------------------------------------------------------------------------- 1 | { 2 | "systemParams": "darwin-arm64-108", 3 | "modulesFolders": [], 4 | "flags": [], 5 | "linkedModules": [], 6 | "topLevelPatterns": [], 7 | "lockfileEntries": {}, 8 | "files": [], 9 | "artifacts": {} 10 | } -------------------------------------------------------------------------------- /package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "design-patterns", 3 | "lockfileVersion": 2, 4 | "requires": true, 5 | "packages": {} 6 | } 7 | -------------------------------------------------------------------------------- /yarn.lock: -------------------------------------------------------------------------------- 1 | # THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. 2 | # yarn lockfile v1 3 | 4 | 5 | --------------------------------------------------------------------------------