Every team has spent hours debating whether to put service files in app/services or lib/services, or whether to use a config file or environment variables for a simple toggle. These arguments are a form of waste — not just time, but mental energy that could go into solving real problems. Convention over configuration (CoC) promises to eliminate that waste by providing sensible defaults. But in practice, many teams either adopt too many conventions too rigidly, or they abandon the idea entirely, falling into a swamp of ad-hoc decisions. For gForce codebases, where the goal is to build sustainable, maintainable systems, we need a middle path: conventions that are zero-waste by design, not just faster to write.
This article is for developers and tech leads who have seen conventions work beautifully on some projects and fail miserably on others. We'll look at CoC through an ethics lens — as a principle that reduces cognitive load, promotes consistency, and respects the future maintainer. By the end, you'll have a framework for choosing and evolving conventions that serve your gForce codebase, not the other way around.
Why Conventions Accumulate Waste in the First Place
Conventions are supposed to reduce decision fatigue, but they can become a source of waste when they are poorly chosen, unenforced, or blindly followed. The waste isn't just in the time spent configuring; it's in the cognitive overhead of remembering arbitrary rules, the friction of onboarding new team members, and the cost of refactoring when a convention no longer fits.
The Hidden Costs of Ad-Hoc Conventions
When a team grows quickly, conventions often emerge organically. Someone puts a file in a certain folder, others follow suit, and soon there's an unwritten rule. But unwritten rules are fragile. They get forgotten, violated, and debated. A study of open-source projects found that inconsistent naming and folder structures accounted for a significant portion of code review comments — not because the code was wrong, but because it didn't follow the expected pattern. In a gForce project, where rapid iteration is common, these small inconsistencies compound into technical debt.
When Conventions Become Dogma
On the other extreme, some teams adopt a framework's conventions wholesale, treating them as immutable law. This can lead to absurd workarounds when the convention doesn't fit the domain. For example, a team building a data-heavy application might force themselves into a strict MVC structure, resulting in bloated controllers and anemic models. The waste here is the effort to fight against the framework's assumptions, plus the confusion for new developers who wonder why the code feels unnatural.
The Sustainability Angle
Sustainability in software isn't just about green computing; it's about building systems that can be maintained over time without exhausting the team. A convention that saves 10 minutes today but causes hours of confusion next year is not sustainable. We need conventions that are easy to learn, easy to enforce, and easy to change when the context shifts. This is the zero-waste principle: every convention should pay for itself in reduced cognitive load and increased predictability.
Core Idea: Convention as a Decision Debt Repayment
Think of every configuration option as a decision that has been deferred to the developer. A framework with no defaults forces you to make dozens of small decisions before you can write any business logic. Each decision is a tiny debt — you have to think, choose, and document. Conventions are pre-paid decisions. They acknowledge that most projects share common patterns, and they offer a default that works for the majority. The zero-waste insight is that this pre-payment only makes sense if the default actually fits your use case. Otherwise, you pay twice: once to override the convention, and again to debug the confusion it caused.
What Makes a Convention Zero-Waste
A convention is zero-waste when it meets three criteria: it is obvious, it is consistent, and it is easy to override. Obvious means that a new team member can guess the convention without reading a wiki. Consistent means that the same pattern applies across the entire codebase. Easy to override means that when the convention doesn't fit, the alternative is straightforward and well-documented. For example, in a gForce project, a convention might be that all database queries go through repository classes. This is obvious (queries are data access), consistent (every entity has a repository), and easy to override (you can write a raw query in a service if needed, but you document why).
Convention vs. Configuration Spectrum
We can think of every design decision as sitting on a spectrum from pure convention to pure configuration. At the convention end, the framework or team makes the choice for you. At the configuration end, you specify everything. The sweet spot for sustainability is not at either extreme, but somewhere in the middle where the most common cases are handled by convention, and the exceptions are handled by explicit configuration. This is the philosophy behind many gForce tools: they provide sensible defaults but allow overrides at key points.
The Role of Documentation
Zero-waste conventions must be documented, but the documentation should be minimal. A good convention is self-documenting: the code structure itself tells you what to do. For example, if all API endpoints follow the pattern app/controllers/api/v1/resource.rb, you don't need a page explaining where to put the controller. Documentation should only cover the edge cases and the rationale behind the convention, so that future teams know why the convention exists and when to break it.
How to Design Conventions for gForce Codebases
Designing conventions that reduce waste requires a systematic approach. It's not enough to declare a convention; you need to validate that it actually reduces cognitive load and doesn't create new problems. Here's a process we've seen work in practice.
Step 1: Identify Recurring Decisions
Start by auditing your codebase for decisions that are made repeatedly. This could be things like error handling patterns, logging strategies, data validation, or API response formats. For each recurring decision, ask: does the team make the same choice 80% of the time? If yes, that's a candidate for a convention. If the choice varies widely, a convention might be too restrictive.
Step 2: Define the Default and the Override Mechanism
For each candidate, define the default behavior. Make it explicit — write it down in a style guide or a linter rule. Then define how to override it. The override should be just as explicit, with a clear signal that the developer is deviating from the norm. For example, if the convention is to use a specific logger, overriding it might require passing a custom logger object and adding a comment explaining why.
Step 3: Automate Enforcement
Conventions that aren't enforced are just suggestions. Use linters, formatters, and static analysis tools to catch violations automatically. In a gForce project, tools like RuboCop, ESLint, or custom checks can be configured to enforce naming, file structure, and pattern usage. Automation reduces the cognitive load of remembering conventions and makes code reviews focus on logic, not style.
Step 4: Review and Evolve
Conventions should be reviewed periodically, just like any other technical decision. As the project grows, some conventions may become obsolete. For example, a convention to use a single database might need to be revisited when the team decides to add a read replica. Schedule a quarterly review of conventions, and be willing to retire or update them. This keeps the codebase sustainable and prevents conventions from becoming dead weight.
Worked Example: Building a gForce API Service
Let's walk through a concrete example to see how zero-waste conventions play out in practice. Imagine we're building a gForce API service for a task management app. We'll define conventions for error handling, response formatting, and data access.
Error Handling Convention
We decide that all errors should be caught and returned as structured JSON with a consistent format: { "error": { "code": "...", "message": "..." } }. The convention is to use a custom error class hierarchy, where each error type knows its own code. This is obvious (errors are always structured), consistent (same format everywhere), and easy to override (if an external API returns a different format, we can catch it and normalize). The override mechanism is a simple adapter pattern. The result: error handling code is predictable, and new team members can add error types without reading documentation.
Response Formatting Convention
We define a convention that all successful responses follow a standard envelope: { "data": { ... }, "meta": { ... } }. Pagination, sorting, and filtering are handled by the same envelope. This eliminates the need to debate response structure for each endpoint. Overrides are allowed for edge cases like file downloads, which skip the envelope. The convention is enforced by a base controller that wraps responses automatically. The waste saved: hours of decision-making and potential inconsistency across dozens of endpoints.
Data Access Convention
We adopt a repository pattern for data access, with a convention that every entity gets a repository class that inherits from a base repository. The base repository provides standard CRUD methods, and custom queries are added to the specific repository. This is obvious (repositories are in app/repositories), consistent (same pattern for every entity), and easy to override (you can write a raw SQL query in a service if performance demands it, but you document the reason). The override is explicit and rare, so it doesn't undermine the convention.
Edge Cases and When to Break the Rules
No convention is universal. There are situations where following the default creates more waste than it saves. Recognizing these edge cases is crucial for a sustainable approach.
Legacy Code Integration
When integrating with a legacy system that has its own conventions, it's often better to adapt to the legacy system rather than force your conventions on it. For example, if the legacy system uses a different error format, trying to convert everything to your standard might introduce bugs and confusion. In this case, the convention should be to isolate the legacy adapter and document its quirks, rather than bending your entire codebase.
Performance-Critical Paths
Conventions often add a layer of abstraction that can impact performance. In a hot path, such as a frequently called API endpoint, it might be worth bypassing the repository pattern and using raw queries. The key is to make the override explicit and to measure the performance gain. If the gain is marginal, stick with the convention for consistency. If it's significant, document the exception and consider whether the convention needs to be updated.
Team Preferences and Domain Differences
Different teams within the same organization may have different preferences. For example, one team might prefer a functional style while another prefers object-oriented. Imposing a single convention across all teams can create friction. In a gForce environment, it's better to have team-level conventions that align with the domain. The zero-waste principle here is to allow team autonomy while maintaining a shared core (e.g., deployment, monitoring, and security conventions).
Limits of the Convention Approach
Even with the best intentions, conventions have limits. Recognizing them helps avoid over-engineering and keeps the focus on sustainability.
Conventions Can Stifle Innovation
If a convention is too rigid, it can discourage experimentation. For example, a team that always uses the same database pattern might miss out on new technologies that could improve performance. The fix is to include a review process that allows for exceptions and to encourage proof-of-concept projects that test new approaches. Conventions should be living documents, not stone tablets.
Overhead of Maintaining Conventions
Maintaining a set of conventions requires effort: updating documentation, adjusting linter rules, and reviewing exceptions. For a small team or a short-lived project, the overhead might outweigh the benefits. In such cases, it's better to rely on a minimal set of conventions (e.g., naming and file structure) and leave the rest to individual judgment.
False Consensus
Sometimes a convention is adopted without real consensus. One senior developer pushes through a convention that the rest of the team doesn't fully understand or agree with. This leads to passive resistance and violations. To avoid this, conventions should be discussed openly and agreed upon by the whole team. If there's strong disagreement, it's better to leave that decision as configuration until the team gains more experience.
In the end, the goal of zero-waste conventions is to free up mental energy for the problems that matter. By treating conventions as a sustainable resource — not a rigid rule set — gForce codebases can remain adaptable, predictable, and a joy to work on. Start small: pick one recurring decision, define a convention, automate it, and see if it reduces friction. Then iterate. That's the sustainable path.
Comments (0)
Please sign in to post a comment.
Don't have an account? Create one
No comments yet. Be the first to comment!