I spent several years working on a large insurance project – developing a portfolio system. Java monolith, organically grown, with decades of expertise behind it.
The assignment I came into the project with: development coaching, improving code quality, increasing testability.
What I found, however, was a system in which the primary problem was not ‘bad code’, but a meta-architecture that systematically slowed down productivity and testability.
Well thought out, yet problematic
The central application generates insurance policies for different lines of business—with complex products, variants, and many special features, as is common in the insurance industry.
The system was a classic Java-based enterprise monolith with a proprietary architecture approach.
On paper, much of it looked reasonable:
- clear architectural principles
- consistent abstraction for clear class signatures
- separation of technical platform and business logic
- business department as a direct part of the team
- close collaboration between different disciplines
- specific initiatives to improve quality
In reality, however, dysfunctional symptoms repeatedly manifested themselves:
- Features took a long time and required numerous revisions.
- Tickets were started and then got stuck.
- More was started than finished.
- Technological updates with new possibilities were available, but were only used hesitantly.
The mycelium of causes
In historically developed systems and teams, it is rarely possible to identify “the one” trigger for the problems. This was also the case here: the apparent problems were symptoms of a deeper network of technical and organizational decisions.
The technical challenge
At first glance, a company's proprietary architectural approach often seems impressive: diagrams, layer models, descriptive building blocks, uniform rules. When I first encountered the architectural documentation, my initial impression was: “Ambitious, but not entirely unreasonable. If you implement it consistently, you can work with it.”
This was precisely the problem: it was not implemented consistently.
During implementation, it was discovered that certain architectural concepts led to performance problems – and so they were not implemented as planned. What appeared to be pragmatism led to a loss of integrity in this case: a vacuum arose in the architectural approach, and the stability of the overall concept began to falter.
The thing about abstraction
The basis for the concrete implementation in the project was the modeling of classes in UML. Abstract Java classes were generated from the model using a generator, which then had to be implemented. If something changed in the signature of a class, the model had to be adapted and regenerated – with implications for the entire team.
At the same time, there was a separate environment for the business logic in a language developed specifically for this purpose – with its own repository, tools, and release logic.
The Java classes were not only abstract, but also very generic, with defined transfer points to the business logic engine.
This had several consequences:
- In practice, any change required all three repositories (code, business logic, UML model) to be branched and later merged again—or risky development directly on the main branch.
- Even minor adjustments had to be made throughout the model, generated code, and DSL – including the respective tooling and approval processes.
Testability quickly fell by the wayside.
There were hardly any natural “cut here” points where methods or technical responsibilities could be meaningfully extracted. Unit tests in the classic sense—small, quick tests for clearly defined responsibilities – were therefore hardly realistic.
The result was a testing strategy that relied primarily on large, heavyweight tests:
- integration scenarios
- end-to-end flows
- extensive setup, comprehensive test data
It was understandable that parts of the team eventually said, “Testing is just too time-consuming for us” – the system was simply not designed to be easily testable.
At the same time, organizational structures exacerbated the technical complexity:
- dedicated database teams that had to approve every change to indexes and structures
- separate UI units with their own priorities, while generic interface components were used in the project at the same time
The result was an architecture that was not only complex, but complex in a way that made every improvement twice as expensive.
Architecture is attitude: where technical and organizational convictions meet
Architecture is never just about technology – it is always an expression of attitudes and priorities. In complex organizations, there are often very different ideas about what “good architecture” means and where the focus should lie.
In this project, one perspective emerged that had a decisive influence:
- Technical quality was considered secondary to technical specifications.
- Long, annotated methods were preferred over small, focused units.
- Consistency and readability were understood as minor issues.
This attitude had direct consequences.
Measures such as SonarQube or code reviews were able to bring about local improvements. However, as long as the fundamental architectural attitude assumed that technical aspects were of secondary importance, structural problems remained:
- overloaded domain objects made it difficult to clearly define responsibilities
- in many cases, testing remained a major project rather than a natural step in the development process
- missing interfaces prevented meaningful unit tests
The limits of coaching
Despite the structural challenges, there were many committed people involved in the project. Part of the task was to harness this energy and translate it into concrete measures.
Visible benchmarks for quality were established:
SonarQube and Quality Dashboard:
Metrics were collected, flaws were made visible, and for the first time, an objective overview of quality development over time was created.
Weekly Quality Sessions:
Every week, there was time for refactoring, code analysis, and the targeted reduction of technical debt. Younger colleagues in particular made active use of this framework.
Coaching on technical innovations:
In long-term projects, updates to the programming languages and libraries used are often required. Making good use of new possibilities was an important focus.
Test procedure and test pyramid:
Modern testing strategies were taught and discussed. In practice, however, they repeatedly came up against architectural limitations—simply because the appropriate interfaces were lacking.
These measures proved effective: positive feedback, noticeable learning curves, initial visible improvements in code areas.
At the same time, it remained clear that
as long as the fundamental architecture and organizational structure remained unchanged, these initiatives would have a natural limit to their effectiveness. Coaching can reinforce micro measures, but it cannot solve macro problems in architecture and organization on its own.
What an architectural review can achieve here
An external architecture review creates a protected framework in which technical and organizational problems can be clearly identified, quality criteria defined, and action measures developed. A good architecture review does not simply provide a “yes” or “no” answer to the architecture, but rather a structured basis for decision-making:
- A risk heat map that shows where productivity, maintainability, and go-live risks are concentrated—and which of these arise at the architecture level rather than the team level.
- A prioritized catalog of measures:
- Short term: specific refactoring zones for better testability.
- Medium term: reduction of proprietary frameworks and simplification of layers.
- Long term: a possible path towards a more modular structure.
- Management scenarios with honest cost-benefit considerations:
- ‘Business as usual’ with predictable effects on speed and costs
- ‘Targeted investment’ in mitigating critical architecture issues
- Optional ‘radical redesign’ of certain parts – including rough cost/benefit estimates
Unfortunately, it was not possible to implement this within the scope of the project. A review would have been ideal once the symptoms had become more pronounced:
- long ticket processing times
- time-consuming bug fixes
- noticeable difficulties with testability and maintainability
At that point, the system was large, but not yet at a point where every change was perceived as an existential threat.
Possible findings
A structured architecture review would have clearly identified the most important problem areas:
Meta-architecture as a productivity killer
The coupling of the UML model, generated code, and external business logic DSL artificially multiplied the effort required for each change.
Recommendation: Reduce the number of mapping layers, define clear responsibilities for each layer, and merge or eliminate redundant strands where possible.
Proprietary framework as a complexity trap
Abstraction layers around established frameworks did not reduce complexity, but rather shifted it—and made debugging, testability, and further development more difficult.
Recommendation: Critical analysis of added value, dismantling in favor of direct use of standard frameworks, transition strategy to empower teams.
Overloaded domain objects and missing interfaces for testing
Central classes bundled data storage, control logic, and technical decisions, making meaningful unit tests practically impossible.
Recommendation: Identify technically coherent responsibilities, separate them into testable units, and define clear interfaces.
Inconsistent architectural principles
A central pattern was removed for performance reasons without adjusting the overall design – documentation and implementation diverged, decisions became situational.
Recommendation: Clearly identify where the target and actual images no longer match, and then force an explicit decision: consistent implementation or adjustment of the target image.
Sociotechnical risks
Architectural decisions were closely tied to roles and individuals whose status depended on “the architecture working.” Critical feedback was filtered politically.
Recommendation: Transparent risk presentation in a form suitable for management, clear separation between technical analysis and political decision-making.
The strength of external perspectives
This step was missing in this project. There were many good building blocks: committed people, metrics, quality rounds. However, without a clearly defined, externally moderated architecture review, the really unpleasant findings either remained stuck within the team or were softened on their way up the ladder.
This is precisely where the strength of a formal architecture review lies:
- It creates a framework in which technical and organizational problems can be clearly identified.
- It translates these findings into a form that management can work with constructively – not as a means of assigning blame, but as a basis for informed decisions.
Clean code, coaching, and quality initiatives are valuable and necessary. However, if the architecture itself systematically works against productivity and maintainability, additional tools are needed—as well as the willingness to speak structural truths.