{"id":18369147,"url":"https://github.com/angusgmorrison/hexagonal","last_synced_at":"2025-04-06T17:31:58.102Z","repository":{"id":40363770,"uuid":"476831473","full_name":"AngusGMorrison/hexagonal","owner":"AngusGMorrison","description":"A complete app demonstrating the hexagonal architecture pattern in Go","archived":false,"fork":false,"pushed_at":"2023-04-19T08:51:34.000Z","size":325,"stargazers_count":7,"open_issues_count":0,"forks_count":2,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-03-22T04:03:24.441Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/AngusGMorrison.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2022-04-01T18:36:51.000Z","updated_at":"2023-03-23T15:41:29.000Z","dependencies_parsed_at":"2024-11-05T23:30:34.746Z","dependency_job_id":"aa3c4bd7-5e77-4e19-976d-e64296eb25cc","html_url":"https://github.com/AngusGMorrison/hexagonal","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/AngusGMorrison%2Fhexagonal","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/AngusGMorrison%2Fhexagonal/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/AngusGMorrison%2Fhexagonal/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/AngusGMorrison%2Fhexagonal/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/AngusGMorrison","download_url":"https://codeload.github.com/AngusGMorrison/hexagonal/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247522448,"owners_count":20952553,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-11-05T23:28:35.664Z","updated_at":"2025-04-06T17:31:56.742Z","avatar_url":"https://github.com/AngusGMorrison.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Advanced Hexagonal Architecture Demo\n\n\u003e ### Looking for a more recent and realistic example of Hexagonal Architecture in Go? Check out [my implementation of the RealWorld spec](https://github.com/AngusGMorrison/realworld-go).\n\n## What is this?\n\nAn experiment in \"extreme decoupling\" that satisifies the following criteria:\n* Business logic is fully and rigorously decoupled from transport and persistence layers;\n* Business logic can perform atomic operations without directly manipulating a database or transaction object;\n* Within the persistence layer, database tables are not only independent of domain models, but of the database itself. Tables have no concept of transactions or drivers\u003csup\u003e1\u003c/sup\u003e.\n\nThis work was inspired by a series of training workshops I created for Qonto, Europe's leading finance solution for freelancers and SMEs. It addresses the problem of how to cleanly separate domains in a mono- or macrolithic project where the database tables required by different domains may overlap and atomicity is essential.\n\nThis demo provides an HTTP server with one endpoint: `/enroll`, which receives requests to enroll students in a course identified by a unique code. The request must only succeed if the following criteria are met:\n* The course exists in the database;\n* At least one student is being enrolled;\n* All of the students attempting to enroll in the course exist in the database;\n* None of the students are already enrolled in the course;\n* The course has sufficient capacity for all of the enrolling students.\n\nIf any of these conditions are violated, the server responds 422 Unprocessable Entity.\n\nIf the request is syntactically invalid, the server responds 400 Bad Request.\n\nOtherwise, the students are enrolled in the course and the server responds 201 Created.\n\n## Running the demo\n\nThis project uses docker-compose to run both the `hexagonal` application and a PostgreSQL server.\n\nBefore running the application, create the databases `hexagonal_development` and `hexagonal_test` using `psql`:\n```bash\ndocker-compose up -d postgres\ndocker-compose exec postgres psql -U postgres\n```\n```sql\nCREATE DATABASE hexagonal_development;\nCREATE DATABASE hexagonal_test;\n```\n\nRun the migrations and seed the development database:\n```bash\ndocker-compose run --rm hexagonal bash\nmake migrate\nmake migate_test\nmake seed\n```\n\nRun the server:\n```bash\ndocker-compose up hexagonal\n```\n\nRequests can then be made to\n```bash\nPOST localhost:3000/enroll\n```\n\nA Postman collection containing sample requests is provided in `Hexagonal.postman_collection.json`.\n\n## Database\n\nThis demo uses the `hexagonal_development` database running locally on the PostgreSQL instance specified by docker-compose.yml.\n\nThe effect of bulk transfer requests on the database can be monitored using `psql`:\n```bash\ndocker-compose exec postgres psql -U postgres hexagonal_development\n```\n\n### Migrations\n\nAfter building the application, run migrations with `make migrate`. Use `make migrate_test` to migrate the test database.\n\nAlternatively, the database to be migrated is given by the `DB_NAME` environment variable, which defaults to `hexagonal_development`. To migrate the test database using this method, run `DB_NAME=hexagonal_test make migrate`.\n\nTo seed the database, run `make seed`. The seeds to be loaded are found under `internal/storage/sql/seeds`.\n\n### Schema\n`courses` and `students` are joined in a many-to-many relationship by the `enrollments` table.\n\n**courses**\n* id BIGSERIAL PRIMARY KEY\n* title VARCHAR\n* code VARCHAR\n* description TEXT\n* capacity INT\n\n**students**\n* id BIGSERIAL PRIMARY KEY\n* name VARCHAR\n* birthdate DATE\n* email VARCHAR\n\n**enrollments**\n* id INTEGER\n* course_id BIGINT REFERENCES courses\n* student_id BIGINT REFERENCES students\n\n## Domain\n\nCourses and students are aggregated under the `class` domain, which represents an association of one course with zero or more students.\n\nNote that this business domain is entirely independent of its representation in the database. The business logic has no understanding of join tables or even of relational databases.\n\n## Tests\nBefore running tests, create and migrate the test database:\n```bash\ndocker-compose exec postgres psql -U postgres\n```\n```sql\nCREATE DATABASE hexagonal_test;\n```\n```bash\nmake migrate_test\n```\n\nA full integration test suite can be found under `integration_test`. Run integration tests with `make integration_test`.\n\nExample unit tests can be found for the `handler` package in `internal/handler/rest/enrollments_test.go`, and for the `classservice` package in `internal/service/classservice/enroll_test.go`. Run these using `make unit_test`.\n\n## Notes\n1. Although table code has no explicit dependency on any database or driver package, in practice I take advantage of PostgreSQL's ability to return the rows modified by a query without making a second query. This could be made truly driver-agnostic, but in typical business scenarios there is little need to. The key advantage of the proposed architecture is the separation of the table representation from the manner in which transactions are executed, i.e. with or without a transaction.","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fangusgmorrison%2Fhexagonal","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fangusgmorrison%2Fhexagonal","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fangusgmorrison%2Fhexagonal/lists"}