Product Governance - FullstackCodingGuy/Developer-Fundamentals GitHub Wiki
This article focuses on
Product Mindset
The following are key factors from the twelve-factor app pattern methodology that play a role in adopting a product mindset for delivering software:
- Build, release, run – Engineers adopt a devops culture that allows them to optimize all three stages.
- Config – Engineers build better configuration management for software due to their involvement with how that software is used by the customer.
- Dev/prod parity – Software treated as a product can be iteratively developed in smaller pieces that take less time to complete and deploy than long-running projects, which enables development and production to be closer in parity
Adopting a product mindset is driven by culture and process—two factors that drive change. The goal of your organization’s engineering team should be to break down any walls between the engineers who build the code and the engineers who run the code in production. The following concepts are crucial:
- Automated provisioning – Operations should be automated rather than manual. This increases velocity as well as integrates engineering and operations.
- Self-service – Engineers should be able to configure and provision their own dependencies. This is enabled by containerized environments that allow engineers to build their own container that has anything they require.
- Continuous Integration – Engineers should check in code frequently so that incremental improvements are available for review and testing as quickly as possible.
- Continuous Build and Delivery – The process of building code that’s been checked in and delivering it to production should be automated so that engineers can release code without manual intervention.
Containerized microservices help engineering organizations implement these best practice patterns by creating a standardized format for software delivery that allows automation to be built easily and used across a variety of different environments, including local, quality assurance, and production.
Team maturity
DevSecOps
Its an idea of brining Development + Security + Operations together.
Decentralization Governance
Decentralized governance is an approach that works well alongside microservices to enable engineering organizations to tackle this challenge. Traffic lights are a great example of decentralized governance. City traffic lights may be timed individually or in small groups, or they may react to sensors in the pavement. However, for the city as a whole, there is no need for a primary traffic control center in order to keep cars moving. Separately implemented local optimizations work together to provide a city-wide solution. Decentralized governance helps remove potential bottlenecks that would prevent engineers from being able to develop the best code to solve business problems.
Decentralized governance means that each team can use its expertise to choose the best tools to solve their specific problem. Forcing all teams to use the same database, or the same runtime language, isn’t reasonable because the problems they’re solving aren’t uniform. However, decentralized governance is not without boundaries. It is helpful to use standards throughout the organization, such as a standard build and code review process because this helps each team continue to function together.
Decentralized governance helps remove potential bottlenecks that would prevent engineers from being able to develop the best code to solve business problems. When a team kicks off its first greenfield project it is generally just a small team of a few people working together on a common codebase. After the greenfield project has been completed, the business will quickly discover opportunities to expand on their first version. Customer feedback generates ideas for new features to add and ways to expand the functionality of existing features. During this phase, engineers will start growing the codebase and your organization will start dividing the engineering organization into service-focused teams
Evolutionary Design
In modern systems architecture design, you need to assume that you don’t have all the requirements up-front. As a result, having a detailed design phase at the beginning of a project becomes impractical. The services have to evolve through various iterations of the software. As services are consumed there are learnings from real-world usage that help evolve their functionality.
An example of this could be a silent, in-place software update on a device. While the feature is rolled out, an alpha/beta testing strategy can be used to understand the behavior in real-time. The feature can be then rolled out more broadly or rolled back and worked on using the feedback gained. Using deployment techniques such as a canary release, a new feature can be tested in an accelerated fashion against its target audience. This provides early feedback to the development team.
As a result of the evolutionary design principle, a service team can build the minimum viable set of features needed to stand up the stack and roll it out to users. The development team doesn’t need to cover edge cases to roll out features. Instead, the team can focus on the needed pieces and evolve the design as customer feedback comes in. At a later stage, the team can decide to refactor after they feel confident that they have enough feedback. Conducting periodical product workshops also helps in evolution of product design.
The following are the key factors from the twelve-factor app pattern methodology that play a role in evolutionary design:
-
Codebase (one codebase tracked in revision control, many deploys) – Helps evolve features faster since new feedback can be quickly incorporated.
-
Dependencies (explicitly declare and isolate dependencies) – Enables quick iterations of the design since features are tightly coupled with externalities.
-
Configuration (store configurations in the environment) – Everything that is likely to vary between deploys (staging, production, developer environments, etc.). Config varies substantially across deploys, code does not. With configurations stored outside code, the design can evolve irrespective of the environment.
-
Build, release, run (strictly separate build and run stages) – Help roll out new features using various deployment techniques. Each release has a specific ID and can be used to gain design efficiency and user feedback
The following software design patterns can be used to achieve an evolutionary design:
• Sidecar extends and enhances the main service.
• Ambassador creates helper services that send network requests on behalf of a consumer service or application.
• Chain provides a defined order of starting and stopping containers.
• Proxy provides a surrogate or placeholder for another object to control access to it.
• Strategy defines a family of algorithms, encapsulates each one, and makes them interchangeable. Strategy lets the algorithm vary independently from the clients that use it.
• Iterator provides a way to access the elements of an aggregate object sequentially without exposing its underlying representation.
• Service Mesh is a dedicated infrastructure layer for facilitating service-to-service communications between microservices, using a proxy.