User:BPirkle (WMF)/Stuff/SAG2021

From Meta, a Wikimedia project coordination wiki

Software Architecture Gathering 2021 Notes/Thoughts

I attended the Software Architecture Gathering Conference 2021. The following are some notes and takeaways. Some of these are my own, some are quotes from various speakers, some are my (perhaps incorrect) paraphrase of what speakers intended to communicate, and some are my own thoughts. I also sprinkled in a couple of thoughts from Daniel Kinzler, who also attended.

This conference started at 2:00am in my timezone, which presented some challenges. I tried Biphasic sleep, which worked pretty well. Basically, I went to bed earlier than normal, then took a nap during the conference lunch break (around 6:00am my time). I skipped a session each day around lunchtime so that'd I'd get in a full 2-hour sleep cycle during the nap phase, but that seemed a reasonable sacrifice to be coherent for the rest of the sessions.

Overall takeway[edit]

The idea of Inverse Conway's Law seemed like the overarching theme of this conference. Rather than treating Conway's Law as an interesting quirk or a common consequence to be aware of, several speakers advocated fully embracing it as a truth and reorganizing the entire organization around it. It seems to me that some synergy probably exists between Conway's Law, some interpretation of Dunbar's Number, and in-place decoupling of the Mediawiki monolith.

I was encouraged that even in the very microservice-oriented talks there was recognition that monoliths aren't inherently evil, and that there are places where they still work reasonably well in more "modern" architectures. One notable perspective was that a monolith can work perfectly well within a services-oriented architecture if it is considered to be just a really large service. Another was that it is possible to internally decouple a monolith such that many of the microservice advantages can be realized within one large piece of software. The Expedition Team has already been doing related work.

Modern Architecture by Ted Neward (Director of Technology Culture, QuickenLoans)[edit]

architecture is the design, structure, and behavior of computer systems, including the characteristics of individual components and how they interact

architecture and architecture style are two different things

some things we expect of good architectures

  • "ities": integrity, simplicity, reliability, extensibility, maintainability, modularity, recoverability, composability, parsimony, scalability, security, performability, longevity
  • solves the problem that you have
  • no particular architecture maximizes all the "ities". Your problem will demand different tradeoffs
  • what we're really looking for is an architecture that makes it easy to make the right decisions
  • we want architectures that "make developers fall naturally into the pit of success"

a practical definition of an architecture is "a set of answers to questions that developers ask every day"

"architecture is strategy" Strategy involves a vision (what do we want?), mission (what gets us there?), and execution (how do we get there?). The answers to these, especially the "how" part, is very project-specific. There is no "perfect" architecture, because projects are solving different problems.

a "good" architecture

  • gives a set of principles developers will follow most of the time
  • covers the "80" in 80/20
  • heuristics, not algorithms (they won't always apply, sometimes devs have to use good judgement)
  • descriptive, not proscriptive
  • signposts, not guardrails

One way to express your architecture is "simple rules"

  • decision-making tools
  • heuristics to govern behavior
  • expression of intent and direction
  • limited to a handful in number: 7ish is good
  • tailored specifically to the problem at hand (and the people solving them)
  • apply to a well-defined activity or set of decisions (to avoid being too broad)
  • provide clear guidance but allow for deviation
  • leave room to exercise creativity and handle unanticipated scenarios

He used REST as an example I should actually read Roy Fielding's dissertation on REST And maybe Ian Jacobs and Normal Walsh's document on the World Wide Web

"transactional means never having to say you're sorry"

Event Driven Architecture @ Allianz Advisory by Annegret Junker (Passionate Lead Architect)[edit]

Events are things that have happened - past oriented

Commands are things that should happen - future oriented

How to Deliver Sustainable Quality in an Ever-Changing Environment by Peter Götz (Scrum & DevOps)[edit]

What is software architecture?

  • "the important stuff, whatever that is"
  • "the set of design decisions which, if made incorrectly, may cause your project to be canceled"
  • "the significant design decisions that shape a system, where significant is measured by cost of change"

If something doesn't have a high cost of change, it probably isn't really architecture

What is DevOps?

  • flow/systems thinking
  • amplify feedback loops
  • culture of continual experimentation and learning

Software Architecture, Team Topologies, and Complexity Science by James Lewis (Director, ThoughtWorks)[edit]

Analogy of information flow in an org vs blood in circulatory system. When an artery splits to take blood to limbs the cross-sectional area of the two arteries after the split equals the cross-sectional area before the split. If you want to grow your org, make sure you don't constrict your flow as you go down your hierarchy. Things like having to "ask someone" on another team is similar to plague in arteries - it restricts flow. Designing your organization in a way that maximizes flow leads to greater efficiency.

Sublinear vs superlinear growth - as you double in size, do you get more or less than twice as much out?

Part of how Amazon achieve superlinear revenue growth was requiring teams to communicate via interfaces.

Things that exhibit superlinear growth tend to have the equivalent of many small teams rather than one huge hierarchy. Independence, loose coupling, and self-service are the main points - teams should be able to do what they need to do without asking for or blocking on other teams.

Architectural Patterns for Rapid, Reliable, Frequent and Sustainable Development by Chris Richardson (Developer and architect)[edit]

Dark Energy vs Dark Matter as analogy for dividing things into services. Some factors (like dark energy) push parts of the software apart, while others (like dark matter) pull them together. There will usually be some of both in anything you're considering decoupling, so find the right balance that makes sense.

Monolith not necessarily bad. Overdividing leads to essentially a divided monolith that is fragile and makes things worse, not better. Decompose the problem you have to maintain team autonomy while grouping things that need to be grouped. Sometimes teams may not be 100% autonomous, and if that's your best tradeoff, that's okay.

With that said, the arguments for dividing a monolith are as much organizational as technical. It might be compelling from an organizational standpoint to divide a monolith, even if it would continue to function technically if it remains undivided. The runtime behavior of an application is important, but so is our ability to organize around supporting, maintaining, extending, and evolving it.

Domain-Driven Design & Legacy: Evolution Not Revolution by Eberhard Wolff (Fellow, INNOQ)[edit]

Bounded Contexts help identify data models. An e-commerce system might have 3 bounded contexts:

  • Order (catalog, shopping cart)
  • Invoicing (payment-related)
  • Shipping (carrier, speed)

All three of these involve Products, but they involve them differently. Suppose someone is buying a laptop. During ordering, we care about all available options. During invoicing, we care about pricing of specific skus/configuration. During shipping, we care about weight. So the "product" in each bounded context is different. If we make one Product class that addresses all these, we end up with a bulky Product class that is trying to serve multiple purposes.

Instead, we might have a different Product class within each of the three Bounded Contexts that contains just what each one cares about.

For legacy systems that were not constructed in this way, migration to this way of thinking can be very hard. Identifying the bounded contexts is important and can be hard, but it relatively easy compared to to actually making the code changes. Rearranging a complex legacy system could take years or decades.

You could just break off one piece at a time and do it. But that can be a lot of work, and it can be hard to show value at each step so it is hard to maintain momentum.

Another approach is Bubble Contexts. Some work by Eric Evans (not WMF's Eric Evans, who is equally smart but didn't do this particular thing) can help. But I got lost in Domain Driven Design terminology and didn't completely understand all the details of how. The general idea seems like it is to isolate a piece at a time and rework those independently within the existing legacy system.

Another approach is to expose legacy assets as services. The idea here seems to be to keep the old messy legacy code around, but split into services so each identifiable chunk can be walled off and accessed via an API. "Open Host Service" is the relevant Domain Driven Design term.

Yet another approach is "setting priorities". Maybe you're mixing concerns, such as migrating to a new technology AND creating Bounded Contexts. Identify what you care most about and do just that first. The example shared was an org with both e-commerce and bricks-and-mortar, who migrated only the e-commerce because the bricks-and-mortar systems are harder to migrate and were working just fine. You end up with some legacy code around forever, but you also get the higher priority done.

Whatever you do, make sure to consider business strategy alignment. Synergy between business strategy and software architecture will make everything go more smoothly. Feeding off the previous example, maybe brick-and-mortar shops are being de-emphasized due to Covid. Doing lots of work to migrate them might not even make sense and might lean you toward the "priorities" approach rather than one of the other alternatives.

How to Read Complex Code? by Felienne Hermans (Programming for all!)[edit]

One study showed that programmers spend 58% of their time reading code. But we don't teach anyone strategies for doing it, we just sort of assume people will figure it out.

The Art of Improving Software: Legacy Evolution, Done Right by Gernot Starke (INNOQ Fellow, software architect)[edit]

There should be only one reason to change: to increase a system's value. If you aren't creating value, why change it?

Daniel Kinzler: It should be clear that this is "business value", not immediate "value to the customer". In other words, this doesn't have to be "features", it can be improved testability or rate of deployment.

Analyze => Evaluate => Improve iterative cycle Balance between strategy and tactics to achieve objective priorities based on methodical assessment

Aim42.org: Architecture Improvement Method

Only solve problems when the solution is cheaper than the problem

The Lost Art of Software Design by Simon Brown (Independent Consultant)[edit]

"Big design up front is dumb. Doing no design up front is even dumber."

Retrospecitves Antipatterns by Aino Vonge Corry (Author of “Retrospectives Antipatterns”, agile coach, teacher)[edit]

Patterns become anti-patterns if applied incorrectly or to the wrong problems.

Retrospectives are time you set aside to become better

Sometimes the things that pop up in retros are not the actual problems. They're the symptoms of the problems. Look for the deeper issues that need to be addressed.

Some ways to think about it differently:

  • "if the last sprint were a car, what kind of car would it be"
  • build trust in the team so people will actually share instead of saying what they think they're supposed to

Soup/Influence/Do retrospectives. Concentric circles. Useful when people are complaining a lot about unchangeable stuff. Do post-it notes with the problems, then move then into Do (center circle), Influence (next biggest) or Soup (can't change) to decide what action to take.

Avoid scapegoating. Assume everyone did the best they could given the place they were in at the time.

Mix things up and do different retrospective types so people don't get bored and to get people to think about things from a different perspective.

If you don't have a dedicated facilitator, do cross-team facilitation, so that a team member doesn't have to facilitate. Have someone from a different team facilitate yours, and then have one of you facilitate theirs.

Evolutionary Architecture: Principles and Patterns by Rebecca Parsons (Chief Technology Officer, ThoughtWorks)[edit]

"How is long-term planning possible under constant change?" "There is no one good architecture for every system" "An evolutionary architecture supports guided incremental change across multiple dimensions" "An architectural fitness function characterizes how close a system is to the desired architectural characteristics"

General idea is to bring agile principles to architecture. Some try to say microservices is the only evolvable architecture, and it may be the maximally evolvable one we know so far, but others can be evolved too. In many ways, a structured monolith is almost as evolvable, as long as you keep boundaries between components clear. You won't get the ability to separately deploy parts, but you get most of the rest. Layered monoliths are harder because they're not as easy to reconfigure as a structured monolith. The only non-evolvable architecture is the "big ball of mud" Micro-kernal architectures are reasonably evolvable along certain dimensions.

I should make sure I actually understand the difference between "Structured Monolith" and "Layered Monolith", to make sure my intuitive mental picture matches how architects actually use these terms.

Postel's Law: "be as forgiving as we can about what we read and as conservative as we can in what we set". Basically, make sure you do things exactly right when you're the one setting/sending data, and expect the other party to do things wrong when you're the one receiving data. The second part, in the context used in this talk, could be restated as "deal as gracefully with dirty data is possible to avoid creating fragile applications".

One thing this law means is don't overvalidate data that you read, or you'll break unnecessarily.

Inverse Conway's Law: decide what architecture you want, then reconfigure your organization to match it.

Daniel Kinzler: Yes, but don't go too far ahead: if you create a bunch of "vertical" teams, but the code is horizontally coupled, and you do not immediately invest into decoupling it, then everyone is stepping on everyone's toes, and you get a big old mess. WMF has been there, we are still recovering. Or maybe it could be: "decide what architecture you want, then reconfigure your organization to match it, and then focus on reorganizing the code until it matches the noew org structure"

Governance can't be a situation where a single small group can make decisions for a small army of developers. Use fitness functions as architecture drivers. Automate them wherever possible. This frees the humans to dig into the edge cases, exceptions, and really hard architectural issues.

Focus on outcomes and not implementations

One of the biggest disconnects between developers and architects is that they don't understand each other's problems. Architects are necessarily thinking longer term. Fitness functions are a way to focus developers on the outcomes that architects are after. Fitness functions can almost be a communications mechanism.