Showing posts with label architecture. Show all posts
Showing posts with label architecture. Show all posts

Saturday, September 19, 2020

DDD The Lost Discipline

DDD is a modeling method highly focused on business domains and comunication. DDD solves several issues we have with Services/Microservices and Backend Systems in General.  One of the biggest challenges in Services but especially microservices is to find the right boundaries meaning what should belong to one service or what should belong to another service. It's common for engineers, often, just write code right and ignore the design. Modeling is hard for several reasons but one reason is the software might work, even with the wrong design. The right Design starts placing the code in the right place. DDD is key to that. DDD is not only about placing the code in the right place but also about how we communicate with the business to figure out that and other ways(DDD Patterns) to express the solutions.  

DDD is a nutshell 

DDD(Domain Driven Design) is about comunication. Comunication between the business and the business experts(not business proxies) and the engineers(the folks who build the solution). DDD's main interest is in the CORE Domain of the problem you want to solve. In order to explore the comunication between business experts and engineers, we should focus on a common language which for DDD is called "Ubiquitous language". DDD Has many concepts and patterns such as:

 * Domain: Logical area that defines your problem. i.e: Retail, HR, purchase, etc.  

 * Bounded Context: Logical Boundary on the code for the solution domain, can be defined as:

   * Organization

   * Code Base

   * Database Schemas

   * Services and Microservices

 * Layered Architecture: Separated Core Domain from UI, Persistence, DBs. 

 * Entities: Domain Objects defined by unique id (UUID). i.e: User, Customer, Job, Message.

 * Value Objects: Unchangeable Objects, has attributes but not unique ID. i.e: Name, JobTitle, Address. 

 * Aggregates: Cluster Value Objects into aggregates to define a boundary. One entity should be the root of the aggregate. So external objects hold a reference on the root only.     

 * Factories: Use to create complex objects and aggregates. The client does not need to know the internal details.

 * Domain Events: Record Discrete event to model activity within a system. 

 * Services: Significant process or transformation into the domain. When is not the natural responsibility of the Entity or VO(Value Objects) objects.

 * Repository: It's a service, uses a global interface to provide access to all entities and value objects within a particular aggregate collection.          

 * Context Map: Diagram to enforce strategy domain integrity. 

 * Bounded Context Patterns:

     * Anti-Corruption Layer: Wrapper for Legacy API or protect the domain from bad API.

     * Shared-Kernel: N-Bounded contexts depending on shared kernel(core). 

     * Customer/Supplier: Like a client/server has a high dependency.

     * Conformist: UpStream and Downstream teams that ARE NOT ALIGNED (accept as it is).

     * Partner: Mutual Dependency on both contexts and high alignment is needed for proper modeling. 

In order to set the record straight, you dont need to use all patterns to be doing DDD. By the way, if you are using Spring Data and have Repositories that alone does not mean you are doing DDD. DDD is a process, it's not a one-time discrete shot. There is an agile collaborative modeling exercise called Event Storming which can help you a lot. Event Storming can be quite useful to figure out inconsistencies in the breakdown of your services and save lots of refactoring and headaches in the future. 

DDD Benefits

DDD has solid benefits, such as:

  * Better comunication

  * Help Organization to retain knowledge (often a huge issue at scale and as the time pass)

  * More flexibility via strong design and encapsulation 

DDD will not do any magic for you. It's just a tool, at the end of the day it depends on how you use it. 

DDD Challenges

Like anything in software, there are trade-offs. DDD might not work well at all in a very technical project. It's also required to have a domain expert working with the engineering team, which unfortunately is complex nowadays. 

Reality and DDD

In order to organizations scale, they often split Strategy and Execution, Product and Technology. Specific people are often used as proxies to answer questions in sense of priorities and "representation of interests". That representation happens via PM(product Managers), PM(Project Manager), PO(Product Owner), BA(Bussiness analysts). There are good PMs, POs, and BAs out there but wich scale you need more and more, and unfortunately lots of times you have weak and low-performance in those positions. 

When a startup starts by definition and nature the company is super glued with the customers, the problem, and the real needs. As a company succeeds and starts growing end ends ups as an enterprise that connection starts to get weak. DDD might be an important tool to help to promote not only comunication but also sharing an understanding of real business problems. 

The Way forward

Recently, Uber rediscovered DDD and applied for they hyper-scale microservices solution, called DOMA(Domain Oriented Microservices Architecture). DDD has a perfect FIT with SOA and Microservices. It's a great modeling exercise and it's being used for decades in our industry. Analysis and Design are lost disciplines like DDD I hope we can rediscover this techniques and leverage and involve them in the present and the future.

Cheers,

Diego Pacheco 

Sunday, September 13, 2020

Micro Frontends: It's frontend making some mistakes as Backend?

Services are a thing for a long time in the backend. +20 years I would say. Microservices are much newer however they also started the backend. Micro Frontends is a very hot topic in frontend engineering right now. Frontend engineering evolved a lot in the last 5 years. Ui are becoming more and more complex and frontend teams are growing a lot. With complexity and growth, we stumble into classical backend problems such as Teams Organization and Scalability and the need for Isolation as a base for Independence and increase the number of deploys. Frontend technology evolves much faster than backend. With all that comes debit and believe me or not the difficult to find people to work on old tech like AngularJS. 

Micro Frontends Benefits

One benefit from Micro Frontends is Developer Experience. IMHO That's the weakest argument and DX should not be the main reason to do anything in tech. IMHO the real benefits are:

 * Improve Teams Topologies - Reduce the comunication blast radius 

 * Reduce management Overhead (by reducing coordination)

 * Faster Build times by smaller and focused components

 * Technology Diversity (Being able to work with different frameworks)  

The frontend is getting bigger and complex as time pass. We cannot ignore this issue. Technical debt is a big problem at the backend and is becoming a real issue in frontend as frameworks evolve faster and believe me or not is hard to find AngularJS engineers. Micro frontends address a real issue in a sense of scalability and the need to introduce better and newer technology as big companies have issues in refactoring huge code bases. However like any solution, there are drawbacks and issues, so let's take a look into some micro-frontends issues

Micro Frontends issues

There are lots of challenges and potential issues with micro frontends such as:

 * Operational Complexity - Deploys are more complex

 * Performance - Might affect the user experience (slower load time)

 * UX/UI Consistency - Need to implement DS for all different frameworks

 * Tooling / Framework support - IMHO it will be fixed but is a huge issue right now

The idea of Micro Frontends is to have independent teams. This can ship things faster, some teams might be faster than others, and in order to do that, you need a different code base and different deployment pipeline. Performance might be a problem since you might load different frameworks and different versions even I would say(you want to avoid this actually). 

Design Systems often are implemented at the component level, so if you have components in one language like Angular and another team want to use React they might need to re-implement the components which might be a big no go for enterprises trying to adopt micro frontends. 

If you can make the Design System implementation more CSS driven rather than framework driven you can minimize this impact, however is very hard to fix completely. A Design system requires the exact same behavior and duplicating to N technologies(Vue, Angular, React, JQueryy/VanillaJS) is expensive since you have fonts, pixels, error, and lots of small details. It's possible but still hard. 

Tooling is a big issue, there is no problem tooling around. There are some solutions with better tooling but often that means by double down into a specific framework. I believe the tooling problem will be fixed eventually.  Zalando has an interesting solution called Mosaic. There is also OC. However, the stand way to go looks like to be around Web Components. It's also possible to do something reasonable with AWS and Simple Infrastructure.

Runtime issues

One big difference from the backend to the frontend and mobile is that in backend we can run the software on different servers so isolation is totally possible. Frontend/mobile has a common issue wihc would be the phone or the browser. It's possible to use shell-like methods like iFrames, Web-Components, or rely on specific frameworks solutions but at the end of the day, the code runs into the same place, which is the browser. It's possible to load different frameworks and solutions but there are performance and complexity penalties. Lots of companies have already frontends monoliths and one common approach people do is to use the monolith as a shell and they have links to the micro frontends apps. 

It's about granularity or Modularization? 

IMHO we don't want to make the components that micro. One hard lesson we learn at the backend is that things too micro also have lots of issues. IMHO what really matters is the ISOLATION and modularization. So you definitely want to have a modular JS application but not necessarily everything needs to be at the micro-level. Micro not always is the right level of abstraction and that is one of the things who killed microservices

There is a huge difference in a Brownfield and Greenfield project and a shared old monolith application. IMHO React is the best web framework we have it right now, if you have a new project and create proper components I would say you dont need micro-frontends. However, looking to a more complex enterprise where you have all sorts of solutions I would say you definitely need to have some solution for modularization. 

Having a micro frontend solution imply you to have some solution for the following concerns:

 * SSR (Server Side Rendering) VS CSR (Client Side Rendering)

 * Cache

 * Layout assembling or linking 

 * Routing

 * Testing

It's ideal to have the tooling and good solutions around those concerns. It's possible to do Micro Fronentds without tooling for the concerns I mention however keep in mind it might be less productive, more complex, and much harder to test than good old monolith frontend apps. IMHO Micro frontends might be making the same mistakes as Microservices by focusing on the "micro". What matters is some level of isolation(given the browser reality) and modularization. 

Cheers,

Diego Pacheco

Saturday, September 5, 2020

SOA for Internal Shared Libraries

SOA has the right principles for scalability with cohesion and consistency. Microservices are dying nowadays for several reasons like Lack of Isolation, Distributed Monolith & Shared Libs Abuse, and many other reasons such as the wrong boundaries. I deeply believe we need to double down in Services and SOA. Sometimes the Sidecar Pattern also makes sense and is an interesting approach.  However, there are times where we really need to go to Internal Shared Libraries.  When that's the case we can still apply SOA for Internal Shared Libraries and have a better a clean design such as having a clean CORE. Keep in mind there is a lot of shared libs abuse in companies but in the cases where internal shared libs are the right choice, there are some important considerations. SOA can philosophy can help internal shared libs to do better and by doing so we can have better solutions with much fewer headaches. I need to repeat Internal Shared Libs should not be your goto approach. Services should be your number 1 choice to deliver software.  

It's not about being a purist

So should we never ever use any lib and code in Java 1.2? NO. We should use libraries. We should use Frameworks. We should not re-invent the wheel. However, do we mind the dependencies we are imposing in people's classpath? Do we even realize how many jars we are adding there? That's the issue. There is a binary coupling, where upgrading libs is very hard. So the solution is not to go to the other extreme and say no libs any more, No that's not what I'm saying. We need to reach some middle ground where we need to Judge and analyze case by case. However, I need to say that we need to be much more RIGID and DISCIPLINED when come down to using shared libraries.  

Discipline is the key

The discipline is the key. We can copy and paste code from the internet on your CODE, that's 100% fine. We can also use plugging like SHADE and have a single jar with no dependencies. We can introduce dependencies as well as long as we are conscious and paying lots of attention to that. The whole java ecosystem of OSS libs often depend on Guava, People use guava a lot, guava is very hard to upgrade when you have different versions. NetflixOSS stack was very binary, Spring cloud used NetflixOSS and is even more binary. There is this effort to push reactive programming everywhere, meaning to call services you will need to use clients it would be impossible to do REST calls very soon. This is coming.  We should not trade performance for flexibility(never). 

So how can we fix this? Discipline is the answer. We need to Think, case by case, and analyze the options and make sound decisions. Changing one extreme for others is not the answer. We dont need to ban shared libs we need to be much much more disciplined about them. 

Functional Programing is about discipline as well(Discipline state management). DevOps, CI/CD are about discipline too, I should say there is no way you can get internal shared-libs right without discipline.

There is no Silver Bullet

There is no way we could create a single rule and have simple decisions we could just apply to all cases. Things are not that black/white we can't have a clear cut when we talk bout design and this particular libraries issue. In other words, there are no silver bullets. We need to fight complexity and all its forms and hidden costs. We need to stop creating Debt that kills us in the long term. So it's important to Reflect on old dogmas and sometimes the answer is an unpopular opinion

This is hard because it leaves us with no good default choice. If you are looking for a default choice should be serviced, not libraries. We have an obsession with Reuse. We should have an obsession with your consumers and freedom and isolation instead. The IT industry often takes a long time to see it's mistaken so just because few people are talking about(or you think is few people) it does not mean you should not pay attention.  Hopefully, we are just judging and making decisions by popularity.

Design Libs using SOA

SOA has principles. There is the SOA Manifesto. Jeff Bezos wrote in 2002 an SOA Mandate for Amazon. One way to see it is "Talk via Services not via Internal Shared Libs". 

SOA has Services. Services have Contracts and Implementations. The API in your Internal Shared Library should be your Contract. You should decouple you contract from your implementation and hide as many things as possibles. Doing so It's possible to apply SOA to Internal Shared Libraries. Which will give you more flexibility and less Intrusion to your lib consumers.  Proper versioning is also very important you should not break your consumers with MINOR and SECURITY/PATCH versions changes. IF you pay attention to your 3rd party libs you can make this possible. The benefits are countless such as:
  * Reduce the number of Lib Migration Efforts (Time and Money).
  * Increase the TRUST and IMAGE of your Platform team among your consumers.
  * Reduce the blast radius impact in your consumers via(3rd party deps and better contracts).
  * More time to Consumers focus on innovation + Increase the value of your solutions
  * More Freedon to change the Internal Shared Lib under the hood
  * Less coupling and more innovation for both sides (Provider and Consumers).

SOA is key for Better Designs and reducing complexity. SOA can be applied to Internal Shared libs and is not only a Service Thing. 

Cheers,

Diego Pacheco

Saturday, August 29, 2020

BFF Dilemma - GraphQL - part 3


So this is 3rd part of the series of BFF Dilemma. If you did not read part 1 and part 2 I highly recommend read them before continuing with this one. GraphQL is a kind of BFF I would say. BFFs then to be more flexible and allow all sorts of programming models and techniques. GraphQL is Data-Driven and has fewer options in a sense of flexibility. However, GraphQL is an interesting solution that could be used as a BFF solution or in conjunction with a standard BFF solution. Several people wonder if GraphQL is the natural replacement of REST. There are all sorts of comparisons with SOAP vs REST vs GraphQL. IMHO GraphQL is not the REST replacement I would not expose APIs only with GraphQL ONLY for all sorts of reasons. 

A Tale about Joins

Before Microservices monolith applications used to have a single Relational Database for all Storage. That approach had all sorts of issues and problems however there were benefits like much more simple code reuse, dependency management was mich more simple, deployment complexity was much smaller, and in regards to Data access, you could fix almost any problem by doing a query. Right now with lots of microservices However on the classical 90s style monolith architecture, there were lots of abuses in sense of queries. NoSQL raised a strong, scalable, and better design for some uses cases. However besides the abuses was pretty awesome to be able to run a query to answer any question for several reasons like:
 * SQL is known by everybody
 * Tooling around SQL is really good
 * It's possible to share the queries with other analyses, users and also do discovery. 

Often microservices are exposed via REST or gRPC with no common language to query things. That's is one of the many benefits of GraphQL, being able to run queries across all microservices. So Let's talk more about GraphQL.

Before we go down the rabbit hole I just want to say that there are other solutions for "Queries" such as Streaming(Spark, Flink, Sanza) and if we look into the Analytical world there is even the Data Meshes solution. But letś focus on GraphQL and BFFs for now.

Enter The GraphQL

GraphQL is a query language created by Facebook in 2012 but it was only open source in 2015. Later on, the coded moved away from Facebook into a Foundation called GraphQL Foundation.  GraphQL works by Schema definition where you define your data with proper typing. After defining your schema you need to work on your Resolvers in order to fetch the data. Resolvers allow you to talk to any microservice with any data storage behind it. Since Resolvers are done programmatically you literally can integrate with anything. 

Sample of Query and Resul from GraphQL site

GraphQL has clients for many languages such as nodeJs, Java, Rust, and many more. GraphQL also has a UI with autocomplete (similar to a SQL Explorer tool) where you can run your queries. GraphQL also allow mutations(in order to insert/update data). 

GraphQL Benefits

GraphQL has many benefits such as:
 * Reduce latency for the Web or Mobile being fetching several services at once
 * Avoid loading data that the UI or Mobile dont need(get exactly what you want). 
 * Have a common schema across your whole business (DDD Obictus language) 
 * Decouple the Data from the Schema (depending on how you do it) 
 * Fast Reuse and increase time to market

Developer experience using GraphQL us much better. Also, GraphQL is contract first by nature which is something highly desirable when working with REST. GraphQL makes fetching data much more fun and fast. However, like anything in technology, there are drawbacks. Let's explore some of the issues and challenges. 

GraphQL Drawbacks

It's possible to fix some problems by having smart services which you reduce the load and make aggregation easy on the UI / Mobile by:
 * Make your services smart by letting the consumers pick watch fields you will return. 
 * Have Aggregation Services or use classical BFF to reduce the load and do smart aggregation
 * Relly on REST Network transparent caches (huge advantage of REST). 

Graphql has limitations. Like any technology. If you are working with a Tree for instance the query syntax is a bit ugly and you need to say all levels you want to return. It's harder to cache and require your resolvers to be smart and use external caches explicitly.  

There is a limited number of media types you can use. REST is much richer in the sense of media types and also standard BFF can deal with more things(SSR) than just Data. Finally, the biggest issue could be Performance and Scalability. REST is distributed and GraphQL centralizes things by nature. Resolvers can be run in parallel, use external caches and pre-load data, use smart batch calls when needed. So It will all depend on your implementation. 

GraphQL & BFFs

GraphQL is a form of BFF. It's possible to use GraphQL and BFF together if BFF is more towards UI Logic or SSR. However, there is an overlap between both. If your BFFs just call services and dont have any extra logic you might be better off by using GraphQL. However, if your Services are smart services and you can choose the fields you want to return you also might not need GraphQL at all. Your Resolvers implementation could be brilliant or a disaster but for sure it will be more complex and thats fine you just need to understand complexity need to live somewhere. 

IMHO is important to focus on what is your use cases and what exactly you trying to archive. As you might realize by this series of posts, there are so many options and different problems for different IT areas of interest.  IMHO BFFs are here to stay either via NodeJs or Robust languages like Java, Go, and Rust or via Data/Queries using GraphQL we have a rich set of power options that can be explored.  

Cheers,
Diego Pacheco

Friday, August 28, 2020

BFF Dilemma - part 2


Previously I was blogging about the BFF dilemma. I want to continue to explore the subject because I find it very interesting and I believe they're still a lot of things to explore on the subject. BFFs are super popular nowadays, for several reasons, mainly I would because of the nature of modern products.  If you have a digital product is very likely you will need to ship your problem in at Least 3 platforms (Web, Ios, Android) somethings even more platforms and specialized devices like TVs, Tablets, IoT, Arduinos and much more. Also, microservices were a big force pushing for BFFs since the services are "micro" and code need to live somewhere. It's really interesting when we think about them since we have so many options and places where our code can live. 

Latency, Unstable networks and Tradeoffs

Latency is a real issue. If you don't pay attention to Latency for mobile apps means losing money. Apps need to perform as fast as they can to improve user experience and do not affect business transactions.  Mobile carriers often have unreliable and unstable networks which require all sorts of smart architecture at the mobile side such as:

 * Bootstrap cache: When the app loads it's a good time to HIt the cache. 

 * On-Demand cache: Background threads can load and cache data with the battery cost and app size as a tradeoff(Latency vs Complexity). 

 * Offline management: As the network fails for Mobile network carrier issue or because there is an outage on the backend being able to retry in a smart fashion and sync state on demand is complex but yet a powerful feature.  Techniques like Exponential backoff + Jitter with conjunction with CRDTs can be super useful but at the same time complex.   

* What if the data keeps changing? Could you optimize the network calls somehow? Could you change the application workflow to be more push driven rater than pull driven? 

All these problems can get very tricky and very complex at scale. BFFs can help you there since you can aggregate several backend calls in just one shot. 

It's all about Aggregation

So at the end of the day, BFFs are about aggregation. Having a place where you can code stuff allows you to reduce the number of calls and have smarter chances in order to reduce latency and improve user experience. BFFs not necessarily means you need to write them in nodejs. You could build BFFs in any language like Java, Go, or RUST. I would argue that Rust is a super interesting language in a sense of performance and low latency. Also, there is a movement that grows a lot called "Edge Computing" more and more we can run code in POPs(Points of presence). Where you can run code close to your user and reduce the latency and make things more simple. The issue is if you dont have POPs available for you.  

So if you have your frontend in Java(Most companies have in React or Angular). Makes sense to have the BFF written in NodeJS for sake of commodity and the frontend team should maintain that piece of software. However, since this post is about dilemmas :-) What happens to IoS and Android consumers? So we will write the BFF in Java? What about Ios? So clearly one trade-off could be using a different language or provide an efficient engine that could something like GraphQL(If you implement well) or Some centralized middleware(I'm not talking about ESB for God Sake :-) ).  To some degree, BFFs are distributed aggregation(like services or microservices). 

BFFs(when code based) provide the ultimate flexibility and freedom to pick the best strategies and combine techniques for different use cases. I would argue that a Web app with Microfrontends for instance and Mobile-First Apps are very different problems although both could be using BFFs.  

In defense of Drivers and Clients

One interesting thing you can so(considering SOA and Services) is to have a client or driver. Drivers make service consumption more native and more productive for consumers. Having a driver/client allows the services to provide backward compatibility to the client as well. Also, you need to see that when you have a client/driver you have type safety and this is a killer feature. 

You can combine BFFs with clients/drivers although there are some overlaps. Since you have more than one place to Cache things, to provide backward compatibility, to do validations. So you need to be careful to not fall into some traps like:

 * Coupling the driver/client with the BFFs

 * Have lots of delegation layers that dont add value and just add latency and complexity.  

Back to the BFF Dilemma

IMHO BFF is a very wide pattern and can be used for several different use cases such as:

 * Mobile First Apps

 * Microfront ends - Web Apps

 * General aggregation for any "consumer" - IoT, Arduino, TVs, etc... 

When you stop to think about different use cases you might realize overlap with other technologies like GraphQL, API Gateways, Service Meshes, Sidecars, Services/Microservices. Like I said, in the beginning, there are lots of places we can "add code" we need carefully consider the use cases and tradeoffs. 

Cheers,

Diego Pacheco

Tuesday, August 25, 2020

BFF Dilemma

The software industry is always becoming more specialized. We have backend engineers, frontend engineers, edge engineers, cloud/DevOps engineers and I'm sure we will have more specialization in the future. With specialization and growth on systems, we end up having more layers or places that we can put software. Microservices often end up making a huge proliferation of services at the backend(check out Uber case for that).  There are so many places that you can "put" your software but one particular place that is growing a lot is the BFF(Backend for Frontend) place. Often we have different stacks for backend and frontend. Frontend often is on JavaScript or TypeScript. Backend is often in Java, .NET or Go. So the first dilemma is, is BFF a frontend thing or a backend thing? IMHO it's a frontend thing where frontend means consumer. So how different BFF is from a driver or client? Well if you look into drivers and clients they often dont have network logic like routing, discoverability, circuit breaking where BFFs often dont. There is nothing preventing you put that logic on the BFF which really raises the question of how different BFF is from drivers/clients. Definitely, there is an overlap with Drivers/Clients/BFFs and even Services. 

BFFs the Benefits

Let's say you have a big app or multiple apps with multiple platforms like IoS and Android. Let's say you also have multiple sites or web application, it will be common to have a design system where you company want to have a standard view of the brand experience(colors, fonts, tons, etc...). It's important to leverage components, if you are working with React thats even easier and natural. However, another dilemma that often happens is, should I make a design system component, or thats something just for the app? Well, that is a couple of factors that could help you to figure it out. 

* How many apps/sites will have that feature/component? 

* How often that behavior it's likely to change? 

* How complex is to make the component? 

Even if you decide to go one route vs another route you can always refactor. So refactorings are cheap others are not, so as you grow you need to keep asking these questions. But regardless of what kind of component you end up doing or not doing you have benefits on the BFFs like:

* Caching 

* Sever Side Rendering - Which also can be done in a generic way. 

* Centralize and Re-use UI Logic (not business logic)

However, sometimes the UI Logic can easily be seen as business logic, in some sense microservices are making this much worst them it is.

Microservices are making BFFs Fat

I remember first waves of SOA where the default was to write code on the service, the services end up being FAT and with stuff that supposes not to be there. However, I also remember we having Aggregation Services, which were services that call other services and that was like the Gateway Uber is talking about on the re-discover of DDD post on DOMA. 

Right now we have a different default, meaning, do not put stuff on the service, they need to be micro. The consequence is that complexity is pulled upwards. Complexity needs to live somewhere and microservices right now tend to be super simple and small however all the orchestration/choreography is being done by the BFFs which are getting more fat and complex. 

It's a Governance Problem

IMHO we need Services, not Microservices. Services should be a bit more FAT. It's fine if the BFF is also FAT as long as it makes sense. So we are talking about a governance problem, that we need to answer some of the following questions:

 * Where we put our code? (BFF, Aggregator Service / Gateway, Service)? 

 * Are the decisions we made on the past still make sense? 

 * Are we running joint Event-Storming exercises to figure out boundaries? 

 * How do we version APIs? Do we provide forward and backward compatibility? for how long?

 * How we expose APIs? HTTP/2, gRPC? 

 *How own what component? 

 *How we test things properly? Are we having WASTE on our tests? 

 *How we coordinate cross-team efforts? 

 *Do we create a lib instead? Sidecar? 

It's also a management problem

There are lots of options to manage this kind of cross-coordination. Do we have a big team as just have a big kanban to handle it? Do we have a chapters/guild(Spotify) to take care of that? Do we have a small pizza team(amazon) to execute the changes? Amazon's way relies on autonomy as a business construct and lean way it kind of makes a lot of sense because of the dependencies and lack of business autonomy you might end up here. When I say business autonomy I dont mean if you company has a cool culture and people are allowed to experiment and do stuff. I mean autonomy is a business construct, so you need to be able to generate results by ourself otherwise you always will have dependencies and you might be better served by the lean model. 

Guidelines and Reflection Over Rules

Rules should be avoided because like any Design and Architecture matter we need to apply judgment. There is no one size fits all, so thats why rules are complicated. Judgment might be right or wrong or it might be right for a period of time and them things change and it's not valid anymore. For all those reasons we need continuous reflection, via big long retrospectives and working groups. Dilemmas are not bad, they are good actually it forces us to think which is our job. If we are not thinking a lot we might be following things we dont understand and creating debt and problems for the future :-) 

Guidelines are awesome because they are not hard rules, you should have very few hard rules in a sense of design and architecture. Guidelines are educative and teach people how to approach problems. One thing I use a lot with Guidelines is Principles, I love principles they are great and I few the industry needs to use them more. 

Cheers,

Diego Pacheco


Sunday, August 2, 2020

Design 101

Software Design is a super important discipline. However, Design is often made by accident. Software Design is really needed because there is a huge cost associated with some changes further down when you have a scale and lots of software. Lots of engineers dont understand design or understand it on a superficial level. Software design is on the core of everything we do in software and I believe we need to talk bout this super important discipline. So I made a slidecast talking about the subject. Let's get started. 

Video


Slides


Cheers,
Diego Pacheco

Friday, July 24, 2020

Sidecar Pattern

There are several architectural patterns we can follow when we need to distribute a shared piece of software. My favorite and default pattern is Service Pattern. However, there are other patterns for software distribution.  If we think about startups for instance there is a popular tool called Lean business Canvas where you model the business model of your startup and there are many dimensions there but one particular dimension called "Distribution Channels" is highly related to the subject of this blog post. We, as engineers often just think about one dimension with is either a Service or Binary shared library.  However, there are other dimensions we could explore. The other options are Tooling, Internal Services / Self-Service Platforms, Runtime Platforms, and Service Mesh. So for this blog post, I want to cover a little bit more the Sidecar Pattern. 




Old Idea in a new reality

For Linux we always had very small, dedicated programs that run in background waiting to react on specific tasks often called "daemons". For me, the demons might be the very first sidecars. So you might be wondering why dont we all right daemons and be happy? Well, written code in C and follow the Linux patterns won't give you much nowadays because there is a different reality. The reality is that we are running software in specialized space with even specialized hardware. So mostly(who is on the cloud which is 30% of the market) people are running workloads at the cloud run the software with a compute solution, often virtualized like (EC2 or Google Cloud Compute). However, the trend and reality are to run some workloads in Containers(Docker, Kubernetes, RKT, OCI/OCR, etc..) or Even MicroVMs / Serverless. So you have a specialized Kernel / Os for your software or even specialized hardware. So Sidecar means let's run a co-process there saying you will have 2 processes: Your App and the Sidecar. 

Sidecars are not the answer to all kinds of problems. Also, they are not tight to Kubernetes Only. Of course, Kubernetes makes it so much easier to use sidecars since in a POD a sidecar is just another Docker container.  However, you can run sidecars in VMs. Like Netflix is doing for so many years with Priam, Dynomite Manager, Raigad, and lately, now Lyft is doing with Envoy

Sidecar Architecture












In order to have a sidecar, you can have any architecture "inside" your sidecar. You can be RPC, Event-Driven, IPC, or whatever you want as long as you are DECOUPLED from the Application Runtime path. Sidecars can be used with Thin Client pattern as well and thats fine but keep in mind that what defines a sidecar is that running in another process, therefore not embedded in your application. 

Sidecars are not embedded but they also are not remote. Sidecars are not microservices, not Services at all. However, sidecars can have HTTP / REST interfaces and can be called by Application via "sudo remote calls". I mean sudo because for the application will look like a remote call BUT because the sidecar is running on the side machine as the Application the latency is much smaller. 

Sidecar Benefits 

There are several benefits of the Sidecar Architectural Pattern like:
* Isolation: You are not in the same "runtime process space" as your application.
* Decoupling: You are not coupled with application choices and vice-versa. 
* Provide Safe Reuse: Meaning no binary coupling (Issue with shared jars and frameworks).
* Encapsulation: We can have encapsulated generic code that can be shipped to all services/apps. 
* Avoiding Binary Coupling: For me, this is a huge win because at scale binary coupling is painful. 
* Technology Diversity: Fredon to chose any language, stack, lib or framework.
* Updates / Deploys independence: They can happen apart for the application CI/CD lifecycle. 
* NO SPOF: Since you would have 1 sidecar per service/microservice we dont have a SPOF. 
* Avoid Massive Migrations: Since the application code is not coupled with the sidecar, there are no massive code migrations. 
 
Finally, I just want to point out that Sidecars works perfectly with Containers/Kubernetes because in k8s for instance the deployment unit is a POD. PODs are just group of containers that share same resources such as network interface and disk. Which makes creating sidecars so easy, since is just another docker container. 

However like I said before, you can have sidecars without containers. It will require a bit of more deployment effort for you but is not impossible or hard at all.  

Sidecar Drawbacks

Like everything in software architecture, there are tradeoffs. So sidecars have drawbacks for sure. Let's take a look in some of them: 
 * IF you are not in K8s, More deployment complexity(EC2)
 * Great Observability is required or sidecars become black boxes.
 * Hard to Debug for application: Let's say sidecar is written in RUST and app is on Java or Go.  
 * Reliability Path: Sidecars now become part of the reliability path. Meaning Downtime could be a big issue.

Sidecars have a narrow set of use cases, you won't be used to replace the Service in SOA for your business applications for instance.  However, there are some set of problems that make Sidecars great for like Proxy, Routing, Observability, Auditing, Security, etc... However, if you can make a proper shared library being lean and minding dependencies they could be a much more simple and effective solution. 

IMHO having a high technology diversity like Go, Rust, Java, Python, C++ would definitely just using sidecars. But if you are massively in one language lest say Java for instance you need to make sure that is the right use case. Different languages and different libs have different strengths so analyze the tradeoffs carefully because moving away from the default language could be an issue. 

The default language(let's say Java for instance) often means you have people trained to deploy, monitor, tuneup and deal with complex workloads at scale or cloud, so introducing another language might mean you would be alone or would need to build that capability in the house which is beyond pure technology decision IMHO, meaning there is more. 

When to use sidecars

A Good indicator is having a cross-cutting concern that is not your business logic like Observability, Security, Performance, Reliability, Auditing, and Infrastructure/Operations. Another point of consideration is that you might want to avoid binary coupling with the applications. Also, let's say you really would gain performance or you have a tool in other languages that is much more suited for the job or much faster or simple. 

If your use case FITs in sense of requirements and architectural goals on the things I described above them I think you should really consider sidecar as your solution. 

When to Avoid sidecars

If you need extreme performance and super-low latency, definitely making a lib would be faster than a sidecar because you would be running embedded on the application. You need to analyze these tradeoffs carefully since there are other things you could to make your sidecar efficient like Using IPC, Reactive Programing, performant languages like Rust. Another criterion to avoid sidecars could be the fact that the final solution is not that complicated or the infrastructure price of sidecars dont pay off(assuming you're not running on K8s but Ec2).  

If some reason you need to scale the sidecar apart of the application, using a sidecar might not be a great idea. However, you always can use other external components to have scalabilities like Databases and Caches but you still need to think about this. Especially if the workload happens mainly on the sidecar. 

Sidecar is a very interesting architecture pattern we can use in Cloud-native applications. However, we need to resit to make "sidecar all the things" otherwise we won't have benefits. Remember there is no one-size-fits-all. 

Cheers,
Diego Pacheco



Tuesday, July 21, 2020

Core Design: Avoid coupling at the Core

Software Design it's a huge sub-set of Software Architecture. Software design is really about the domain and the designer. Good design takes time to make and it's not a one-size-fits-all solution. In order to have a good design, you need someone who first of all cares about design and study design a lot. In order to improve as a Designer you need to:
 * Write code
 * Read code (a lot)
 * Think about responsibilities
 * Think about bringing things together
 * Think about braking things apart
* Do and participate in Design Sessions 
* Time and Experience 

There are several schools out there like Services, OOP, FP, and many others. IMHO there are some CORE ideas that we can use besides your language, school of thought, and experience.  Knowing what not to do is as much important as knowing what to do. For this blog post, I want to talk more about CORE Design.

The CORE

Every good software has a CORE. Often a CORE could be called by different names like Kernel(i.e Linux Kernel). Other names but not that commons are CORE and KERNEL are (Heart, Base, Parent, framework, or just implementation). What is CORE? Let's look at some definitions:



As you can see in Dictionary.com the CORE means the "Cental part" the "Essential part". Identifying the CORE part of your software means better focus and avoid coupling. Coupling is really the heart of all evil. We often (For commodity) try to couple concepts and solutions(For us or for others).  Coupling is fine if done right and at the right level. 

Why should I care about identifying the CORE of my solution? 

There are several reasons why you dont want to couple your CORE solutions with the other parts. Modular design is a missing discipline nowadays. We often talk about Deployment units like Microservices VS Monolith but we spend little time to improve the whole design of solutions. 

Why we need to Keep the CORE Lean and Clean:
 * Easier to Reason about it. Lots of time complexity means code obscurity. 
 * Easier to USE and Re-use. Even if you dont have re-use I would keep the CORE clean. 
 * Easier to Test. Clean COREs tend to be very easy to be tested. 
 * Easier to Debug. Debuggability is an important matter since we maintain code for a longer time.  
 * Less coupling, meaning more freedom and fast interaction times. 
 
How can I identify my CORE?

That should be fairly easy. he trick is not coupled things you dont need. Your core should be as clean as free of dependencies as possible. As much as possible not remote calls, no database calls, no external IO. That will depend on what you are doing, but most of the cases I would argue that it's true. Let's say you're making a solution to predict when someone should retire. The MATH is your core, not the database schema, not the remote calls, not your access devices like Web, Mobile, AR/VR or Audio Interfaces(like google home/Alexa). But you could argue IF I will make retirement predictions I need to have a MOBILE API or APP otherwise there is no value. True but that should be a different module.  Because you want to re-use that MATH in the WEB or you dont want to change that just because Apple has an IOS bug or new version. 

Could we think about what happens inside of a Service?

We often think about What services should we create. Valid questions, don't get me wrong but what about what happens inside the service? What about internal Design? We need to worry about that too. There are other approaches that tackle this problem as well. 




























Uncle Bob's Clean Architecture is one example of an approach thinking about that. One of the things I like about it is that the External Interfaces are lots of layers away from the CORE entities. However, thinking about the CORE is not a new IDEA. Look Linux Kernel for instance. 




























Linux Kernel is a good example of modules. Separation from the CORE from the REST of the system. You might be wondering if is that really necessary? When we realize that software is not going away the answer is YES. If you have a SHORT term thinking or a PROJECT mindset might think thats not needed. However when you understand that this is part of your digital products and in the long run this will affect your ability to deliver value to the business it becomes critical. Unfortunately, Good Design is like CAR insurance you can't get up after the fact(car crash). 

Cheers,
Diego Pacheco

Friday, July 3, 2020

Double Down on Service Orientation

Service-Oriented Architecture(SOA) is not new. Microservices which are a specific flavor of SOA are the default architecture you will find out in digital products. I'm not sure if Microservices will be here for much longer. However, thanks to the silicon valley, companies can be structured in 2 organizations(Which is a good thing IMHO). Product and Engineering organization. An engineering organization means that you create software for your product engineers to be more productive and focus on the product and improving the user experience. Engineering organizations have different ways they could be distributing software. Software distribution is a fascinating theme for me. There are several ways we can distribute software however we often dont consider other distribution models. As your company grows and depending on your business segment you might have several specializations insider engineering like Data Science, Security, Big Data, Architecture, Storage, Mobile Devices, and so on and on. IMHO it does not matter the kind of software specialization we are not limited to binaries.  

SOA It's all about Services

SOA only talks about Services. Services are 1st class citizens and if you want to reuse you do it via services. Product organizations leverage Services however it's very common to find engineering organizations being too much binary, I saw it so many times. Binaries are not wrong if you are very careful about dependencies(most of the time people are not). However, there are other distribution models beyond binaries. For instance, a model that is growing a lot nowadays is the Side Car pattern. Besides sidecars, you could rely on Services. Services dont need to be a consumer only via APIs or JARs or binaries, services can be consumed via generic UI or even a generic Jenkins Job. 

One important thing that Services provide is abstractions. Meaning you dont need to CODE or you dont need to configure it a good abstraction if done the right way. Within a remote service interface like API/REST, UI or Jenkins job is possible, with binaries is not possible and often results in lots of coupling.

Issues with Binaries

By definition binaries are "EMBEDDED" meaning you need to have them on your side(classpath). Having binaries on your side means you get all side effects like Configuration, Schemas, 3rd party dependencies. By nature, binaries are much more coupled with the remote services.  +10 years ago I remember when I was in a big international SOA Project. Then we had an idea to have EMBEDDED Services. Since all our SOA Services was written in Java we just important the jars in the target/consumer project and thats it you have an embedded service and it works. There was a great performance benefit for killing the remote call however it resulted in several other issues like:
 * Much more difficult to configure since the jars had to have the configs our you would duplicate it.
 * Dependency hell - since 3rd party dependencies were brought put there were jar conflicts. 
 * Potential Coupling - Now there is noting blocking developer to use non-contract classes(contract by accident will happen eventually). 
 * Difficult to upgrade individually:  If you change the service need to change the embedded deployed service as well - which was always hard.  

Services Benefits

Services provide abstractions. Service Abstractions are potentialized by remote interfaces like REST/APIs, Generic UI/Jenkins because:
 * Natural Hiding: Since you are "remote" or at least running the code someplace else. 
 * No contract By Accident:  It's basically impossible for the consumer to use anything beyond the public contract. When we think about the binary model, it's every use to couple beyond the public contract. 
 * Easier to Scale: as you have control over how you operate your solution it's easier to scale and provide a better experience and abstract that from consumers.
 * Easier to Maintain: Since we are exposing less it's much easier to upgrade the underlying operating system, data stores, code, languages, libraries, or whatever aspect of the solution besides the contract.
 * Easier to Reason about it:

Service provides many benefits, they will always be less optimized as a specific solution however they often make more sense and provide a stable way to the company to build products and other services on top of each other which is how the internet works and how companies operate in the real world. 

Operationalizing Services beyond Service Interfaces

SOA is not restricted to APIs(REST). You can do SOA with other interfaces / API, for instance, it does not matter the language or serialization format(XML, Json, Yaml, Protobuf, Flatbuffer, Avro, Parquet, MessagePack, whatever). Having said so, it's also possible to provide generic UI's and Jenkins jobs, which can be useful to consumer stateful services like Databases, Caches, Object Storages, DNS, Pipeline Platforms, Observability platforms, Stress Test / Chaos platform and much more. 

If you take a look at AWS there are managed services like S3, RDS, Kinesis, and many others. These services abstract the operation, scalability, upgrade, patching, and security aspects for you. It's possible to use some ideas and deliver internal services to your company. Netflix pig bank a lot in that idea and has several of internal services(Similar to AWS managed Services). 

You can do the same, therefore you can consider Operacionalizing services as an interesting distribution channel/model for your engineering solutions. Service approach means you have a centralized operation for those services, you can have different teams operationalizing different services. 

Consuming a service does not need to be done always via an API. API(REST) has one big drawback when we compare it with Generic UI / Generic Jenkins job. They require you to CODE. In order to use it, you need to code. Sometimes coding is fine, as much as possible you should not require your consumers to code. For instance, think about a Database Backup Service. It could be a generic UI or Generic Jenkins Job you go there and just click in a button and thats it, you enable automatic backup for your application rather than have a DSL or Java API someone would need to use and run the code against it. 

SDKs are fine, DSLs are fine. API's are great. However, you need to consider whenever is possible to not require your consumers to code will be great and will increase productivity, abstraction and you will be leveraging more service orientation than binaries. 

Double Down on Services

Remote Services with standard interfaces often could have performance drawbacks. For instance, REST Interface + JSON will be always slower than the LOCAL IPC call with a binary format for instance. However, trading performance for flexibility and abstraction is often a bad deal. Being remote often means you can scale beyond a single machine.  Services are great as distribution channels because of the abstraction, easy to upgrade, isolation and it's much easier to organized teams around it. 

Services can be used for non-end-user products. Internal Services are an interesting and yet powerful solution to avoid inertia in software architecture. When you have a binary, if you improve your code, you often need to do a migration, which can be hard, tedious, risky, and expensive. Services provide a great abstraction and reduce lots of migration needs. Migration is a big concern because refactoring / re-testing all your consumers could be expensive and risky as you grow and have a big organization. 

Internal Services make consumer life easier, compare DVD with Stream model for instance. DVD was like a binary JAR and Streaming is like an API(REST) or Generic UI or Generic Jenkins Job. There are several concerns that get abstracted by the service model. All models have tradeoffs, there will be cases were binaries are the right answer. IMHO we should be open to considering using more services whenever is possible. 

Cheers,
Diego Pacheco

Friday, June 19, 2020

Sources of Complexity

Software can get and often does get complex very fast. Many engineers and teams often don't understand the effects of some decisions resulting in extra Complexity. For this blog post, I want to explore more of these sources of Complexity. We can, in fact, only improve what we understand. Lean Thinking often tells us that we need to understand to see waste; otherwise, we cannot avoid it. Complexity can be generated thought of many sources. Nowadays, every single team is aware of technical debt. Technical debt is, in fact, too late, you can only fix it by refactoring. However, if you do teach your team to see and understand the Complexity, you will still be creating debt. It's impossible to have software that is 100% debt-free, however for sure, we can prevent a reasonable degree of debt by understanding software complexity and manage it proactively with proper education and carefully taught. Managing debt is a duty that every software product and project has. We need to act tactically, proactively, reactively on all fronts. Let's get started. 

7 Sources of Complexity

There are many sources of Complexity. I want to focus on non-conventional ones or non-obvious ones. You might not consider then as sources of Complexity at first glance. Hopefully, after some explanation, it will make sense. At the end of the day, there is only one ultimate source of Complexity. Complexity could be quickly boiled down to Ignorance. If you know what you are doing meaning, you understand your problems, you know your tools, you deliberately work on our culture complexity can be minimized. Let's see some other factors that often spark Complexity. 7 Sources of Complexity:

#1 Big Successful Enterprises 
#2 Technical Events
#3 Organizational Culture
#4 Convenience 
#5 Binary Coupling
#6 Contract by Accident
#7 Concept Coupling

#1 Big Successful Enterprises 

Many C-level executives down here in Brazil have the costume to visit other companies. Unfortunately, they dont visit companies like NuBank, iFood, Magazine Luiza. Often they go to old but yet super Succseful traditional, waterfall-based companies. I dont need to name these companies, but for sure you know lots of them. I see it so many times in the past. Believe me, this still happens. OH, I visit my CIO friend from company X, and they are doing the latest vendor O ESB, and we should do it too. Big traditional successful companies go visit other big traditional successful company and guess what? They copy the software development methods and stacks. So this creates lots of complexities and debts. Because if company X is successful, you can just copy they stack + processes, and we will be too. This is not the case, but it still happens a lot. 

#2 Technical Events

This might sound wrong but is also a source of HUGE Complexity. Often Tech events can be significant because we can learn what other companies are doing. However, usually, it couple be a source of Envy where you go there and just say: OH my company is not doing Docker, I should be doing Docker now. You might think this is crazy, but this is very true. Many engineers just want to do things because if what other people are doing and really dont understand what problem they are trying to solve and what pros/cons each choice generates. I love tech events, but I have a conscience about what I should do and not do for each project/customer. For better or worst, it creates a substantial sociological wave of pressure, like fashion. However, the tech should not be about way but often is. 

#3 Organizational Culture

Organizational culture is another source of Complexity because often, your company culture could be quickly pushing for:
 * Just worry about features and dont do proper architecture and design.
 * Hiring the cheaper contractors -- who will produce more tech debt.
 * Build Frameworks and Shared Libs -- So Product engineers dont need to "think" just use frameworks.
 * Push too much on estimates(deliver on dates) -- resulting in no discovery and no proper requirements -- guess what happens? Lots of Complexity in the software. 

Easily the post could be just about the organizational culture, which is a huge source of technical Complexity and, therefore, debt. 

#4 Convenience

This is another tricky one. You might think that Developer Experience(DX) is always a good thing. However, it is not. Convenience has a price—idiomatic means couping. As more convenience your engineers/developers have as more coupling, you gonna have it. Typing should not be an issue for any engineers/developer. Often frameworks, libs, and vendors are picked up because they are "loved brands," and thats wrong; it should be for other reasons. Often having more convenience happens because convenience is considered productivity. If you look in the long run, it is not always accurate, and convenience can result in Complexity, coupling, and debt. 

#5 Binary Coupling

Binary(in the form of a framework on liberty) is a more natural form of reuse. However, you need to keep in mind  2 essential things. First is the fact that you will need to maintain everything public. Second that you very likely o have 3rd party dependencies.  3rd party dependencies are often silly or straightforward at first glance, but as time pass you might have a distributed monolith because of them. Binary coupling makes everything harder, and as much as you can, if possible, you should leverage Service, Tools, Platforms, Sidecars, and other forms of distribution, which are beyond binary.  It's possible to have libraries and still dont have bad coupling or acceptable coupling, but that requires thought and care. 

#6 Contract By Accident

Many engineers believe that public contract is only their REST interfaces. Thats is not 100% sure. Everything visible to your consumers is your contract. Contract by accident is an excellent source of Complexity because it is an excellent source of coupling. You can consider sources of tables, configuration files, classes, aspects, pojos, anything that people might be sing directly.  Binary coupling is a tremendous potentializing of Contract by Accident. Botton line is: the less you show, the less coupled you are therefore less Complexity. Hiding is an essential concept in software engineer, especially in distributed systems. 

#7 Concept Coupling

Concept Coupling means there is one concept, and you coupled with another. Therefore you create confusion with is a HUGE source of coupling. Legacy is the software that is in your company before you. Often associated with harmful software. A monolith is a unit of deloyment. Monolith does not necessarily mean that it is terrible. However, the industry, coupled with these 2 things together: Legacy == Monolith. Therefore all monoliths are bad. Thats not true. Concept coupling is really bad because it blinds you, and you end up just seeing one side of the coins, and guess what? It's a vast source of Complexity, therefore, debt. 

Complexity can be induced by many forms. It's important to be aware of these sources of complexity but also by applying thoughtful design process by applying questions likes:
 1. What requirements do we really have? 
 2. What pros/cons we do gain if we go approach A vs approach B? 
 3. What principles do we want to leverage?
 4. What we are really gaining by the X method or Y framework or Z process? 
 5. Are we doing something because it is better for the company or because someone asked us? 
 6. Are we going X because we are envy and want to be cool or because we really thought about and at the end of the days the benefits are bigger than the drawbacks? 
 7. Can we see drawbacks on the Y approach or Z solution? 

Software architecture and design are not easy however we need to start being more thoughtful about our choices therefore we can reduce complexity and the whole business will benefit in a long rung. 

Cheers,
Diego Pacheco

Monday, June 15, 2020

Software Architecture Hidden Costs

Software has hidden costs. For this post specifically, I want to cover in more depth the hidden costs of software architecture.  Making decisions is pretty cheap, you or your team could just say let's do this and that it. The cost of a decision could be not cheap at all, also the cost of a decision could be manifested only overtime when it is too late and you can't afford it any longer but them it is too late. That's why thinking will be(when it's possible and make sense) much cheaper than doing it. Cheaper is a relative concept. If we think about innovation and product discovery there is no thinking up to the front, only experimentation. However, as we get into software engineering depending on the nature of the problem(high related to isolation/coupling and reversibility of the decisions) you might really want to think a bit more. This thinking could be called Architecture, Design, or just simple Due Diligence. In previous posts, I explore a lot the role coupling and isolation or lack of both. For this post I actually want to take a different direction but yet correlated, let's analyze the hidden cost of some architecture, design, or just team decisions beyond the classical management iron triangle(cost, scope, and time). 
The Role of Debt

Enterprise software means Debt. It's impossible to have a successful company without Debt. There are different sources of debt. It could be a result of poor architecture decisions, wrong technical structure(not having architects or business dictating tech decisions) or just ignoring architecture at the team level, not paying the debt over time or maybe other sources. Some engineers think about the debt they have but very few think about the debt they are creating. In other words, are you really fixing a problem or are you making it worst? Technical Debt has a huge impact on architectural decisions. Making it some possibilities affordable or not. Debt has an "erosion" effect. Overtime Debt gets worst and really ends up killing you. 

It's not enough to acknowledge the debt before making any decision but also have a concrete strategy to help to eliminate or at least mitigate the debt in place. I always like the Boys Scout Rule(I was never a boy scout btw): Let the place better than you found it. 

The Role of Reversibility

This is a big Amazon principle. Avoid one-way doors. You always want to have versability, meaning if can recover, rollback, or move to something else. Having two ways means you have more flexibility and allow you to change your mind in the future. This aspect is important because it could drastically reduce the impact of a bad decision or could give you the flexibility to shift gears as you learn and move forward. Not having reversibility makes some decisions much more critically and requires much more thinking and due diligence on top of it. 

The Role of Isolation

Microservices are about isolation. Great architectures are about isolation. Isolation is not only about your Data Stores(databases, caches, configs) but also about making your contract: simple, lean, and easy to use. However, your implementation can be FAT and COMPLEX and that's fine because complexity needs to live somewhere. Sometimes to think about proper isolation is really hard because we are pushed to this "micro" level by several movements like microservices, nodejs, docker, serverless and sometimes you need a DETOX JUICE and step back and take a different direction. 

Having proper isolation also means your decisions have less impact on the whole(if you were sure and correct about it). The reason I say this with "some doubts" is because is so easy to do binary coupling and have contract by accident nowadays. IF you get it right you wrong decision cost will be minimized and also you will have the flexibility for future changes. 

The four Architectural Hidden Costs

So far we talk about 3 BIG forces that will make our life easier or harder, being: Debt, Reversibility, and Isolation. Regardless of what you have or not for each of those(cases by cases) now let's look into 4 hidden costs moments that you might not be accounting properly.  The big 4 are:
 #1 Build vs Buy Hidden Costs
 #2 Design Hidden Costs
 #3 Upgrade Hidden Costs
 #4 Decommission Hidden Costs 

Let's take a deep look on each of the moments and hidden costs associated with them. 

#1 Build vs Buy Hidden Costs

As Software Engineers we build software so the first thing we want is to build new software. Because new software is easy and sexy however not always is the right decision. Because not always you should build, for sure you could build anything but the question is should you? I believe one important aspect is how much this is close to your core business or how critical is this for the core business in terms of differentiation. This decision is not easy, oftentimes you need to cross-check several aspects on a matrix-like evaluation taking into account:
 * How long would take it to build it? 
 * How much it would cost? 
 * How much cost in the long term are you gaining? 
 * You have so few things you can build and manage it, does any market/oss solution is better? 
 * What features are you gaining? 
 * How many uses cases can you cover or not? 

Sometimes does not make sense to build it. This changes from business to business and the important aspect here is to consider because you build it. Several companies dont think about just buying it or they just consider buying it, very few companies I worked got this right and establish the right balance. Perhaps this is the biggest hidden cost, could you imagine a solution that would not require you to build any software to much less software to archive it? It's could really be the ultimate cost saver. This is not one-size-fits-all-folks, I'm not saying let's always buy neither let's always build. One sample that makes a look of sense to buy is observability tools for instances or cloud infrastructure(how much make sense or do you really need to build your own cloud?). 



#2 Design Hidden Costs

Design costs tend to be huge hidden costs because several times, there are design gaps, design flaws, design limitations that will turn out to be a huge issue for the business in the long run. It's easy to think that you dont have design issues just because your solution is doable or will work. Find design issues requires teamwork and lots of os thinking and is hard exercise but you can practice and you can get it better.  Business that just want some features delivered no matter what often pay a huge price for wrong or incomplete designs. Bad designs manifest them selfs in forms of:
 * Complexity
 * Difficult to Reason / Understand systems
 * Slow Delivery Peace
 * High bug Rate
 * High Effort to change

At the end of the day is a like a leaking bucket. You solution might work but you might be paying too much for something that you should not. So your value(money) is leaking away. 

Not all changes are equal, it does not mean all changes will be expensive but for sure PowerPoint, change is much cheaper than release something in production :-) Software is not hard to change as Hardware, Boats, Bridges, Buildings therefore if you are agile mean you change. Well, it really depends, sometimes the change is super expensive. Remember Debt, Reversibility, Isolation, and how much something is decoupled or couple will make a huge influence here.  

#3 Upgrade Hidden Costs

This is a very interesting one. We always think about how long to take to build something. If it is a new microservices maybe it is fine, however, if it is a shared services, platform library, or data service/engine well it's a completely different game. Because you might need to Refactor your consumer's code in order to use it. Them we have a different tension here, you build a better service or tool but would people actually use it? This might sound silly but the history is full of interesting stories like:
* Python 2 vs Python 3 (How long it took to python 2 to die? a lot :-) ) 
* Java 8 to Java 11 (Correcto is here to say java 8 still a long way to die)
* IP V4 to IP V6

No matter if you are using a 3rd party lib like Spring or Quarkkus, this is beyond in-site vs external-site provider relationship. Inside or outside of you company it does not matter, the dynamics are the same. Meaning the is a cost of "code migration" people need to refactor and use your stuff. Let's look at Frontend world like Javascript frameworks, there is zero COST, right? (Kidding) what happens is that the community is so used to refactor every 3 months and is fine they are always using latest. If you look java is the other way around, the culture for backend is why the hell are you making me change my code? 

Just realize you might need to be backward compatible or have a migration script/program or help consumers to migrate their code or any least make sure it is on their budget time to then to work on migrating to your new stuff. Engineering organizations are a great pattern in SV and you have budget to build, but do you have budget to upgrade? 


Why this is important? Well is the key difference between Discovery and HIPPO. Value Vs Perceived value. It does not matter the value you "think" it has and matter what consumers "really perceived". So value is on consumer perspective, for architecture is the same, if people can't afford your upgrades or don't see the benefit it's a problem. 

#4 Decommission Hidden Costs

Finally the last hidden cost. If you dont delete code you will pay a high price in the long term. Because it will affect your ability to reason about your codebase and figure out whats used and whats is not used. It mind sound silly because we got this Gmail-like culture of never deleting emails, iPhone app-like culture of not deleting apps, at cloud(AWS|Google) there is infinite storage(corporate credit card-backed) so why delete? You need to. Sooner or later you will be migrating old code, fixing bugs you dont have it, and will be dragging you down with past decisions. If you don't want to take my word for it it's fine to look Lean principles for instance. Lean has one principle called Motion, and motion is part of the 7 classical Lean Wastes. 

Dead / Zombie code / Data is so bad that it actually will be classified as other wastes like(Overproduction and Overprocessing) for refactoring and upgrading things you dont need it and Defects for Bugs.

Architecture is not only about tradeoffs and the right design give decisions/requirements but is also how you navigate over cost complexities and what strategy you pick. Understanding architecture hidden costs is important aspect of being successful meaning: People are using your stuff and you actually make the world a better place rather than just thinking you make it. 

Cheers,
Diego Pacheco



Chuyên mục văn hoá giải trí của VnExpress

.

© 2017 www.blogthuthuatwin10.com

Tầng 5, Tòa nhà FPT Cầu Giấy, phố Duy Tân, Phường Dịch Vọng Hậu, Quận Cầu Giấy, Hà Nội
Email: nguyenanhtuan2401@gmail.com
Điện thoại: 0908 562 750 ext 4548; Liên hệ quảng cáo: 4567.