Enable javascript in your browser for better experience. Need to know to enable it? Go here.

Decoupled by design: Building reusable enterprise libraries and services

Disclaimer: AI-generated summaries may contain errors, omissions, or misinterpretations. For the full context please read the content below.

The reusability paradox

 

Enterprise software development is costly. So, it isn’t a surprise that business and technology leaders stay hawkeyed on technology budgets. Those that succeed in keeping their costs in check do so by managing the complexity of their tech stacks and keeping their implementations consistent and domain-aligned. This provides them the opportunity to reuse common shared capabilities economically and efficiently, done through shared libraries and platform capabilities. 

 

There is a method to the madness of being able to reuse software efficiently and economically. The trick is to focus on decoupling capabilities and services to achieve reusability as a consequence. Focusing on reusability instead can lead to upfront or overengineering which has an effect opposite to that of decoupling. Tighter coupling progressively increases the complexity of solutions and makes software development exponentially more expensive.  

 

Enterprise software constructs

 

Engineering teams build and use common libraries, shared services and platforms to optimize reuse. This can reduce the cost of development as well as time to market for features and capabilities. 

 

In reality, building and maintaining these constructs can be a significant challenge.  It seems like a classic tale of attempting to herd cats — where every team has its own priorities, tech stacks, and cultural norms. The holy grail, of course, is to have everyone using a unified approach defined by a common capability. However, in reality, rigid enforcement often backfires, creating friction and spawning a Frankenstein-like monster that nobody loves or wants to maintain. Such an approach eventually leads to these common constructs being neglected or completely abandoned.

 

One of the challenges with these common constructs is code level coupling through shared codebases or binary libraries. The situation is made worse when creators of these constructs focus disproportionately on reuse, making these constructs all encompassing or too generic. This leads to much higher coupling with higher maintenance demands. This is why owners of these libraries and services should focus on decoupling at the domain boundaries and aim to achieve reuse as a consequence. To help increase adoption, we recommend the open - close principle. Libraries are decoupled and closed to change but are open to extension and to be built upon within the consumers context. 

 

The challenge here is not to just create these libraries, services and platforms but to ensure they remain relevant and useful to their consumers, the application development teams.  This involves making these constructs discoverable and consumable in a self-service manner while taking their feedback and monitoring usage and performance statistics to continuously improve and evolve them. Here’s how they do it:

 

  1. Build with at least one customer in mind. Before even starting, successful companies ensure they have at least one team committed to using a common library or service to accelerate their software deliveries. This “early adopter” acts as a real-world test case, providing immediate feedback and validation that guides the development process and the promotion for its reuse in multiple other applications being developed by multiple teams.

  2. Establish a solid foundation. Strong product management principles are essential for the continuous evolution of these libraries and services. This starts with a crystal-clear understanding of the problem the library or service is designed to solve. The focus is on ensuring that the product solves this problem exceptionally well, maintaining a tight feature set with minimal bloat. Just like Unix shell commands, which are designed to do one thing and do it well, a well-founded common library or service avoids feature creep, staying lean and efficient and offering extensibility through composability. This also means that instead of one God library or service that does everything for the business, there is a set of libraries/services each focusing on a specific subdomain.

  3. It should be easy to use. Adoption is driven by making the common capability easy to use, with a focus on discovery and consumption through self-service, seamless migration, and solid documentation (including examples and how-tos as well as an API reference) with strong community support. When teams find that common libraries and services reduce their workload rather than adding to it, they naturally gravitate toward them.

  4. Design for extensibility. The most resilient libraries follow the open-closed principle — open for extension but closed for modification. This ensures that while the core remains stable, teams can still extend the library to meet their specific needs without jeopardizing the overall system’s integrity.

  5. Encourage internal contributions. Borrowing from the open-source model, successful enterprises allow teams to contribute to common libraries, services and platforms. By establishing a core group of committers and moderators, they foster a sense of ownership and community, encouraging teams to both use and improve the shared resource.

  6. Ensure outcome-driven governance with continuous improvement and learning. Finally, effective teams implement governance and guidance using principles, patterns, practices and policies to define library and service development, adoption, maintenance and evolution using monitoring for adoption and variance. Instead of punishing deviations, they study them to glean insights, continuously refining the common capabilities to better serve all teams. 

    1. This includes maintaining different versions catering for different adoption speeds of teams while at the same time helping teams to move to more recent versions so the older ones can be depreciated and retired. Having a versioning convention to help adopters keep track of changes. For example using specifications like Semantic Versioning (Semver.org)

    2. Also continuously reviewing the library or service is providing relevant business outcomes and staying within the technical guardrails

  7. CI/CD: Last but not least, the guidance and governance function also defines the functional and cross functional tests that should be maintained in the delivery pipelines for continuous integration, delivery and deployment through automation to ensure consistency and increase confidence in the process and deliverables.

In essence, building successful common libraries, services, and platforms hinges on prioritizing decoupling and adhering to sound engineering principles like the open-closed principle. When these practices are coupled with a user-centric approach, continuous improvement, and outcome-driven governance, enterprises can achieve a significant competitive advantage by accelerating development, enhancing quality, controlling costs, and most importantly improving adoption.



**Thank you Simon Brunning for your review comment and inputs.

 

Disclaimer: The statements and opinions expressed in this article are those of the author(s) and do not necessarily reflect the positions of Thoughtworks.

Explore more insights