The most famous software architectures nowadays are Hexagonal, 3 Layers and MVC. The TT architecture is very similar to 3 layers but combined with the hexagonal one.

Nowadays we can assume that most companies follow a good architecture when designing their services. But that’s not true, you would be surprised to see how lots of companies are still struggling to get a good architecture in place that allows them to scale and grow rapidly.

In this post we’ll go through the most common architectures, their strengths and weaknesses, and then introduce the TT architecture — a simple and practical way to keep your codebase clean and maintainable.

MVC

MVC is a typical architecture inspired by the Web. It has a separation between Model (data), View (presentation, HTML and so) and Controller (code).

MVC Architecture Pattern

The problem with this architecture is that you end up having big fat controllers that mix all kind of different models and contains a mix of presentation logic with business logic. It can easily become out of control making your application a mess hard to extend and grow. This architecture fails in separating the front end concerns from the backend ones.

You can find more info about MVC architecture from this freecodecamp.org post.

3 Tier

The 3-Tier architecture improves on MVC by introducing a clearer separation of responsibilities across three horizontal layers:

  • Presentation Tier — the user interface. This is where controllers, REST endpoints, or web pages live. It handles HTTP requests and responses but contains no business logic.
  • Business Logic Tier — the core of your application. Services, use cases, and domain rules live here. This layer doesn’t know how data is stored or how it’s presented.
  • Data Management Tier — databases, file systems, and external APIs. Repositories and data access objects handle persistence and retrieval.
3 Tier Architecture

The strength of 3-Tier is that each layer only talks to the one directly below it. The presentation layer never touches the database directly. This makes the system easier to understand, test, and modify.

The weakness is that dependencies still flow downward — your business logic depends on your data layer. If you want to swap out a database or an external API, the ripple effect can spread further than you’d like.

Hexagonal

Hexagonal architecture (also known as Ports and Adapters) takes a different approach. Instead of horizontal layers, it puts your domain logic at the center and everything else around it.

Hexagonal Architecture

The core (entities and business rules) defines ports — interfaces that describe what it needs from the outside world. The outer layer provides adapters — concrete implementations that connect those ports to real infrastructure like HTTP, databases, message queues, or external APIs.

The key insight is that dependencies point inward. Your domain never depends on infrastructure. It doesn’t care if data comes from a PostgreSQL database, a REST API, or an SQS queue. This makes the core extremely portable and testable.

The downside? Hexagonal can feel like over-engineering for smaller services. The extra abstractions (ports, adapters, interactors) add ceremony that doesn’t always pay off.

More info about Hexagonal architecture in the Netflix Tech Blog post.

TT Architecture – Where 3-Tier and Hexagonal Meet

So what if we could get the simplicity of 3-Tier with the clean dependency direction of Hexagonal? That’s the idea behind the TT architecture.

The name comes from a visual trick: picture the letters TT side by side. You’ll see three vertical spaces — to the left of the first T, between the two Ts, and to the right of the second T. Each space represents a layer:

Left Middle Right
Controllers, UI, REST endpoints Models, Services, Business Logic Repositories, API Clients, Data Access
Input Core Output

The rules are simple:

  1. The left column handles input. Controllers receive requests, validate input, and translate it into calls to the business layer. They never access repositories or external services directly.
  1. The middle column is pure business logic. Services and domain models live here. This layer defines interfaces (ports) for what it needs — but it never imports anything from the left or the right. It doesn’t know if it’s being called from a REST controller or a CLI command, and it doesn’t know if data comes from a database or an API.
  1. The right column handles output. Repositories, API clients, and data access implementations live here. They implement the interfaces defined by the middle column.

Why It Works

The TT architecture borrows from both of its parents:

  • From 3-Tier, it keeps the intuitive left-to-right flow. Input comes in from the left, gets processed in the middle, and data flows out to the right. It’s easy to explain to new team members.
  • From Hexagonal, it borrows the dependency rule: the middle column has zero dependencies on the outer columns. The left and right columns depend on the middle, never the other way around. This is the key to keeping your business logic clean and testable.

In Practice

In a typical Spring Boot or backend project, the package structure would look like this:

com.example.myservice/
  input/          # Left: Controllers, DTOs, request/response mappers
  domain/         # Middle: Services, models, port interfaces
  output/         # Right: Repository implementations, API clients

Or if you prefer more descriptive names:

com.example.myservice/
  api/            # REST controllers, WebSocket handlers
  core/           # Business logic, domain models, service interfaces
  data/           # JPA repositories, HTTP clients, message publishers

The middle package defines interfaces like OrderRepository or PaymentGateway. The right package provides implementations like JpaOrderRepository or StripePaymentGateway. The left package calls the service interfaces from the middle — never the implementations from the right.

Testing Becomes Trivial

One of the biggest wins is testability. Since the middle column has no dependencies on infrastructure, you can unit test your entire business logic with simple mocks or fakes — no databases, no HTTP servers, no containers needed.

Integration tests can then focus on the left column (does the controller correctly parse requests?) and the right column (does the repository correctly persist data?) independently.

Conclusion

The TT architecture is not a revolution — it’s a practical simplification. It takes the best ideas from 3-Tier and Hexagonal and packages them into a mental model that’s easy to remember and apply.

Next time you start a new service or refactor an existing one, picture those two Ts. Ask yourself: is my business logic truly independent from my controllers and my data layer? If the answer is yes, you’re on the right track.

If you want to keep learning about engineering topics, check out other posts like the Juice Shop hacker sandbox or publishing artifacts with Gradle.