Philosophy
Think in Features, Not Layers
The design of SliceFlow is guided by a core set of principles aimed at maximizing developer productivity and long-term maintainability. We believe that the best foundation for an application is one that is simple, pragmatic, and helps you move quickly without sacrificing quality.
Traditional software architectures often organize code by technical concern. You’ll have folders for Controllers
, Services
, Repositories
, and Models
. When you want to build a new feature, you have to jump between all these folders, creating a small piece of the feature in each one. This separation scatters the logic for a single use case across the entire project, making it difficult to understand and modify.
SliceFlow champions Vertical Slice Architecture. The idea is simple: organize your code by feature.
Everything required for a single feature—the API endpoint, its request and response models, its validation, and its specific business logic—is located together. This creates a high degree of feature cohesion. When you need to work on the “Assign User Permissions” feature, you know exactly where to look, and all the relevant code is right there. This drastically reduces cognitive overhead and makes the codebase easier to navigate. You stop thinking in technical layers and start thinking in application features.
Pragmatism Over Dogma: Resisting Premature Abstraction
In software development, we’re often taught principles like “Don’t Repeat Yourself” (DRY). While well-intentioned, a dogmatic adherence to DRY can lead to a much bigger problem: high coupling and the wrong abstractions.
Consider managing a user’s subscription. You might have three distinct use cases:
UpgradeSubscription
DowngradeSubscription
CancelSubscription
The initial, “DRY” temptation is to create a single UpdateSubscription
endpoint that takes a new subscription plan. But what happens next?
- Upgrading might require an immediate payment and a call to the Stripe API.
- Downgrading might only take effect at the end of the billing cycle and requires scheduling a background job. The request might also need a
reason_for_downgrade
field. - Canceling needs to send a “sorry to see you go” email and doesn’t require a new plan ID at all.
The single UpdateSubscription
endpoint quickly becomes a tangled mess of if
statements, optional request parameters, and complex logic. The truth is, these three use cases were unrelated, even though they all touched the Subscription
entity. By trying to be DRY, we coupled them together, and now a change to the cancellation flow risks breaking the upgrade flow.
The SliceFlow approach is to create three distinct endpoints: UpgradeSubscriptionEndpoint
, DowngradeSubscriptionEndpoint
, and CancelSubscriptionEndpoint
. Yes, they might share a few lines of code at first. But they can evolve independently as their unique business logic grows. We prefer a little duplication over creating the wrong abstraction that will cause massive headaches down the road.
This pragmatism extends to how we use third-party libraries. SliceFlow encourages you to use tools like Entity Framework Core directly. Hiding powerful, well-documented tools behind your own leaky abstractions (like a generic repository) often limits their power and creates a new, internal API that your team has to learn and maintain. Trust the tools and the experts who built them.
Our Guiding Principles
To summarize, our philosophy can be distilled into the following principles:
We Believe In… | Because… |
---|---|
Simplicity | Complex solutions are harder to debug, maintain, and extend. We prefer the simplest path that solves the problem effectively. |
Feature Cohesion | Keeping all the code for a single feature in one place makes the system easier to understand and reduces the cost of change. |
Pragmatic Duplication | A small amount of code duplication is often a much smaller problem than the high coupling introduced by a premature or incorrect abstraction. |
Serving the Frontend | The backend’s primary job is to empower the frontend. We shape our APIs to provide clients with exactly the data they need, in the format they need it. |
We Avoid… | Because… |
---|---|
Premature Abstraction | It’s nearly impossible to get an abstraction right the first time. It’s better to wait until a clear pattern emerges from real, duplicated code. |
High Coupling | When unrelated features are tied together, a change in one can unexpectedly break another, making the system fragile. |
Needless Philosophizing | Endless debates about whether a piece of logic is a “service” or a “handler” are unproductive. We focus on delivering features. |
This philosophy is a guide, not a set of rigid rules. The goal is to keep you moving fast, iterating with confidence, and building software that is simple, pragmatic, and a pleasure to maintain.