Hexagonal Architecture with Spring Boot, Flyway, and Dual Database Support
There is an addictiveness and joy that comes with visibly getting something done. Our work as software engineers is sometimes not visible to the end user for a long time. Delayed gratification. We press on anyway, trusting the architectural and design principles that enable us to adapt to changing requirements, whether a new feature or a non-functional requirement like a database change.
AI-assisted coding shifts this paradigm. The reward comes faster. Its tempting to ignore everything you've learned to get the rush found in a completed feature. Building "shiny" new features feels great, but if they are built without a solid architecture, changing or extending them becomes difficult. A disciplined engineer needs to recognize this temptation and stick to the plan of developing quality software using a repeatable methodology. If working with a coding assistant, it's still your job to tell Claude to use a specific architecture or pattern.
This post shows how to restructure the basic starter Spring Boot application into a hexagonal architecture. We want an architecture that makes it easier to be flexible later. For example, this helps when changing databases from Postgres to MySQL or swapping Spring Boot for Quarkus.
I've shared the prompts below along with two screenshots of how I work with IntelliJ and Maven. Questions or feedback? You'll have to wait a few posts until my database is ready to save your comment.
Screenshots
Prompts Used
- "we are starting on post 4. this post will take our services application to the next level. Convert this project to a multi-module hexagonal architecture with five modules: domain, application, adapter-rest, adapter-persistence, and bootstrap. Domain should have zero Spring dependencies. Application depends on domain with minimal Spring for Service annotation. Adapter-rest depends on application and domain. Adapter-persistence depends on application and domain. Bootstrap depends on all four, contains the SpringBootApplication class, application.properties, and spring-boot-maven-plugin. Add spring-boot-devtools as runtime optional in bootstrap for hot reload. Configure spring-boot-maven-plugin in bootstrap with jvmArguments for JDWP debug on port 5005. The application must start successfully with mvn clean install && mvn -pl bootstrap spring-boot:run."
- "these changes should break the github action to deploy the services application. review the Dockerfile and api-deploy.yml to verify that the application will deploy given its new architecture."
- "commit this and push this to test the github action again."
- "Configure dual database support. Keep H2 for integration tests using a test profile. Add a local profile for PostgreSQL that reads JAVABLOG_DB_USER, JAVABLOG_DB_PASS, and JAVABLOG_DB_NAME from environment variables, defaulting host to localhost:5432. Add the PostgreSQL driver dependency. Add a docker-compose.yml that spins up PostgreSQL with those environment variables. Update the README with instructions for running locally using either an existing PostgreSQL instance, docker-compose, or a podman run command."
- "There appears to be a missing configuration for production - it appears its your intention to start with a 'local' profile in production - this means the api-deploy.yml has to receive this configurative step as well. I don't like this. the application.properties should contain the production settings, the api-deploy.yml should not be modified."
- "final step, we are going to introduce jpa and flyaway in our adapter-persistence. Do not add entities yet. Create an adapter-persistence/claude.md to use the following persistence guidelines: My preference is to never use vendor specific annotations or query languages - whatever we use to implement the JPA spec. Follow these database naming standards: Use snake_case for all table and column names. Table names should be plural. Primary key columns should be spelled out as tablename_id not just id. Foreign key columns should match the primary key column name they reference. Avoid ambiguous column names. Apply these conventions to all JPA entities and any database migrations."
- "ok, that is enough for this post. create another blog post. This one will include a screenshot or two. The post should be structured Title: Post 4, Body: Post: 4 Screenshots: Sample Image I will delete Prompts: everything from this session including this one. I will commit and push after I test locally and update the content."
Comments
No comments yet. Be the first to share your thoughts!