<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Roman Leventov</title>
    <description>The latest articles on DEV Community by Roman Leventov (@leventov).</description>
    <link>https://dev.to/leventov</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F335570%2F458d47c2-ef47-4e96-8466-047208e10aa4.jpeg</url>
      <title>DEV Community: Roman Leventov</title>
      <link>https://dev.to/leventov</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/leventov"/>
    <language>en</language>
    <item>
      <title>Enable CORS with custom headers for an AWS Lambda function behind API Gateway in Serverless framework</title>
      <dc:creator>Roman Leventov</dc:creator>
      <pubDate>Thu, 09 Apr 2020 06:37:58 +0000</pubDate>
      <link>https://dev.to/leventov/enable-cors-with-custom-headers-for-an-aws-lambda-function-behind-api-gateway-in-serverless-framework-3702</link>
      <guid>https://dev.to/leventov/enable-cors-with-custom-headers-for-an-aws-lambda-function-behind-api-gateway-in-serverless-framework-3702</guid>
      <description>&lt;p&gt;To properly enable CORS with custom headers for a Lambda function deployed behind API Gateway using Serverless framework, you need to do &lt;strong&gt;three separate things&lt;/strong&gt;:&lt;/p&gt;

&lt;h3&gt;
  
  
  Add &lt;code&gt;cors&lt;/code&gt; configurations to HTTP points of the function definitions in your &lt;code&gt;serverless.yml&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;This includes CORS headers to &lt;em&gt;preflight&lt;/em&gt; &lt;code&gt;OPTIONS&lt;/code&gt; requests to your API:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;functions:
  getProduct:
    handler: bin/get_product
    events:
      - http:
          path: product/{id}
          method: get
          cors:
            origin: "*"
            headers:
              - Content-Type
              - X-Amz-Date
              - Authorization
              - X-Api-Key
              - X-Amz-Security-Token
              - X-Amz-User-Agent
              - &amp;lt;your-custom-header-goes-here&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h3&gt;
  
  
  Add &lt;code&gt;resources&lt;/code&gt; section to &lt;code&gt;serverless.yml&lt;/code&gt; to include CORS headers in API Gateway-level error responses
&lt;/h3&gt;

&lt;p&gt;Such as due to expired authentification token, unauthorized access, or 404:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;resources:
  Resources:
    GatewayResponseDefault4XX:
      Type: 'AWS::ApiGateway::GatewayResponse'
      Properties:
        ResponseParameters:
          gatewayresponse.header.Access-Control-Allow-Origin: "'*'"
          gatewayresponse.header.Access-Control-Allow-Headers: "'Content-Type,X-Amz-Date,Authorization,X-Api-Key,X-Amz-Security-Token,X-Amz-User-Agent,&amp;lt;your-custom-header-goes-here&amp;gt;'"
        ResponseType: DEFAULT_4XX
        RestApiId:
          Ref: 'ApiGatewayRestApi'
    GatewayResponseDefault5XX:
      Type: 'AWS::ApiGateway::GatewayResponse'
      Properties:
        ResponseParameters:
          gatewayresponse.header.Access-Control-Allow-Origin: "'*'"
          gatewayresponse.header.Access-Control-Allow-Headers: "'Content-Type,X-Amz-Date,Authorization,X-Api-Key,X-Amz-Security-Token,X-Amz-User-Agent,&amp;lt;your-custom-header-goes-here&amp;gt;'"
        ResponseType: DEFAULT_5XX
        RestApiId:
          Ref: 'ApiGatewayRestApi'
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;&lt;code&gt;ResponseType&lt;/code&gt; fields control what type of responses the corresponding resource section applies to. If you don't want to include CORS headers in every 4XX or 5XX error response, you can find some more specific ResponseTypes &lt;a href="https://gist.github.com/jonatassaraiva/4c33dd8225605c02318cd71a55b2335d"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Note: &lt;code&gt;GatewayResponseDefault4XX&lt;/code&gt; and &lt;code&gt;GatewayResponseDefault5XX&lt;/code&gt; just resource names and have no significance.&lt;/p&gt;

&lt;h3&gt;
  
  
  Include CORS headers in the normal responses in your lambda handler
&lt;/h3&gt;

&lt;p&gt;Example in Go:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;Handler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Context&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;req&lt;/span&gt; &lt;span class="n"&gt;events&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;APIGatewayProxyRequest&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;events&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;APIGatewayProxyResponse&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;rsp&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;apiGatewayAdapter&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ProxyWithContext&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;req&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;rsp&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Headers&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"access-control-allow-origin"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"*"&lt;/span&gt;
    &lt;span class="n"&gt;rsp&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Headers&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"access-control-allow-headers"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"Content-Type,X-Amz-Date,Authorization,X-Api-Key,X-Amz-Security-Token,X-Amz-User-Agent,&amp;lt;your-custom-header-goes-here&amp;gt;"&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;rsp&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Resources:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://forum.serverless.com/t/custom-header-in-options-preflight-for-cors/3122"&gt;Custom header in OPTIONS preflight for CORS&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/serverless/serverless/issues/3896#issuecomment-478945726"&gt;chrisoverzero's comment on Github&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>serverless</category>
      <category>aws</category>
    </item>
    <item>
      <title>Engineering Ideas #9</title>
      <dc:creator>Roman Leventov</dc:creator>
      <pubDate>Fri, 13 Mar 2020 14:16:17 +0000</pubDate>
      <link>https://dev.to/leventov/engineering-ideas-9-42d5</link>
      <guid>https://dev.to/leventov/engineering-ideas-9-42d5</guid>
      <description>&lt;h3&gt;
  
  
  &lt;a href="https://blog.discordapp.com/why-discord-is-switching-from-go-to-rust-a190bbca2b1f"&gt;Why Discord is switching from Go to Rust&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;The following statement caught my attention in this post by Jesse Howarth:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Discord has never been afraid of embracing new technologies that look promising.&lt;/strong&gt; For example, we were early adopters of Elixir, React, React Native, and Scylla. If a piece of technology is promising and gives us an advantage, we do not mind dealing with the inherent difficulties and instability of the bleeding edge. &lt;strong&gt;This is one of the ways we’ve quickly reached 250+ million users with less than 50 engineers.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Which sounds almost the direct opposite of the experience at Instagram (citation from “&lt;a href="https://www.effectiveengineer.com/"&gt;The Effective Engineer&lt;/a&gt;” by Edmond Lau):&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Whenever they could, the Instagram team picked proven and solid technologies instead of shiny or sexy new ones.&lt;/strong&gt; “Every single, additional [technology] you add,” Krieger cautions, “is guaranteed mathematically over time to go wrong, and at some point, you’ll have consumed your entire team with operations.” And so, whereas many other startup teams adopted trendy NoSQL data stores and then struggled to manage and operate them, the Instagram team stuck with tried and true options like PostgreSQL, Memcache, and Redis that were stable, easy to manage, and simple to understand. They avoided re-inventing the wheel and writing unnecessary custom software that they would have to maintain. &lt;strong&gt;These decisions made it significantly easier for the small team to operate and scale their popular app.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The conclusion that I make from this contradiction is that sticking to proven tech vs. embracing new tech is not really that important for the scalability of engineering resources. Perhaps, instead of trying to explain our successes, we should focus on understanding what helped us to avoid failure. Nassim Taleb’s &lt;a href="https://www.rationalwalk.com/?p=16047"&gt;Via negativa&lt;/a&gt; and Will Larson’s &lt;a href="https://lethain.com/iterative-elimination-tournaments/"&gt;Iterative Elimination Tournaments&lt;/a&gt; come to mind.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;a href="https://martinfowler.com/articles/nosqlKeyPoints.html"&gt;Key Points from NoSQL Distilled&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;These points from Pramod Sadalage’s and Martin Fowler’s book “&lt;a href="https://martinfowler.com/books/nosql.html"&gt;NoSQL Distilled&lt;/a&gt;” that I found most insightful:&lt;/p&gt;

&lt;p&gt;The rise of NoSQL appears to be connected (or enabled by) to the rise of service-oriented architectures:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;There is a movement away from using databases as integration points towards encapsulating databases within applications and integrating through services.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;One of the main factors to consider when choosing between a relational and a NoSQL database:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Aggregate-oriented databases work best when most data interaction is done with the same aggregate; aggregate-ignorant databases are better when interactions use data organized in many different formations.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;On the tradeoff between technology suitability and the toolbox size (connects to the discussion above about variety vs uniformity in the tech stack):&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Adding more data storage technologies increases complexity in programming and operations, so the advantages of a good data storage fit need to be weighed against this complexity.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  &lt;a href="http://thinkrelevance.com/blog/2011/11/15/documenting-architecture-decisions"&gt;Documenting Architecture Decisions&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;Michael Nygard presents a simple framework for documenting the changes and additions to the design of the system. The benefits:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The motivation behind previous decisions is visible for everyone, present and future. Nobody is left scratching their heads to understand, "What were they thinking?" and the time to change old decisions will be clear from changes in the project's context.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The architecture decision records (ADRs) could be committed to the project repository under a separate directory, like doc/adr/. The structure of an ADR:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Title.&lt;/strong&gt;  These documents have names that are short noun phrases. For example, "ADR 1: Deployment on Ruby on Rails 3.0.10" or "ADR 9: LDAP for Multitenant Integration"&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Context.&lt;/strong&gt;  This section describes the forces at play, including technological, political, social, and project local. These forces are probably in tension, and should be called out as such. The language in this section is value-neutral. It is simply describing facts.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Decision.&lt;/strong&gt;  This section describes our response to these forces.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Status.&lt;/strong&gt;  "Proposed"/"accepted"/"superseded" with a reference to its replacement.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Consequences.&lt;/strong&gt;  This section describes the resulting context, after applying the decision. All consequences should be listed here, not just the "positive" ones. A particular decision may have positive, negative, and neutral consequences, but all of them affect the team and project in the future.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href="https://github.com/npryce/adr-tools/tree/master/doc/adr"&gt;Here are some real examples&lt;/a&gt;. In Apache Druid project, “&lt;a href="https://github.com/apache/druid/issues?q=is%3Aissue+is%3Aopen+sort%3Aupdated-desc+label%3AProposal"&gt;Proposal&lt;/a&gt;” label serves some similar purpose.&lt;/p&gt;

&lt;p&gt;For foundational decisions, I think it makes sense to use a more elaborate structure, for example, the one described in the following article:&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;a href="https://personal.utdallas.edu/~chung/SA/zz-Impreso-architecture_decisions-tyree-05.pdf"&gt;Architecture Decisions: Demystifying Architecture&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;Jeff Tyree and Art Akerman enumerate five types of objectives that drive architecture decisions: &lt;strong&gt;business needs&lt;/strong&gt; (aka functional requirements), &lt;strong&gt;risks&lt;/strong&gt; , &lt;strong&gt;system issues&lt;/strong&gt; , &lt;strong&gt;&lt;a href="http://agilemodeling.com/artifacts/changeCase.htm"&gt;change cases&lt;/a&gt;&lt;/strong&gt; (which can be addressed by &lt;a href="https://architectelevator.com/architecture/architecture-options/"&gt;creating options&lt;/a&gt;), and &lt;strong&gt;non-functional requirements&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;When does a decision require heavyweight documentation?&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;To test a decision’s architectural significance, an architect should ask the following question: &lt;strong&gt;does this decision affect one or more system qualities (performance, availability, modifiability, security, and so on)?&lt;/strong&gt; If so, an architect should make this decision and document it completely.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Authors propose the following sections for a decision document:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Issue (problem, subject matter). Explain the urge for making the decision (rather than deferring it for later, which should be the default strategy): “Describe the architectural design issue you’re addressing, leaving no questions about why you’re addressing this issue &lt;em&gt;now&lt;/em&gt;.”&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Decision (short statement)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Status&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Assumptions&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Constraints (boundary conditions): organizational, human, schedule, cost, risk constraints, non-functional requirements, alignment with the business and technology strategy.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Positions (alternatives, options). “This section also helps ensure that you heard others’ opinions; &lt;strong&gt;explicitly stating other opinions helps enroll their advocates in your decision&lt;/strong&gt;.”&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Decision: a longer description&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Implications of the decision&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Related decisions&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Related requirements. Show how the decision is driven by the objectives: “Decisions should be business-driven. To show accountability, explicitly map your decisions to the objectives or requirements. […] &lt;strong&gt;If a decision doesn’t contribute to meeting a requirement, don’t make that decision.&lt;/strong&gt; ”&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Related principles. “If the enterprise has an agreed-upon set of principles, make sure the decision is consistent with one or more of them. This helps ensure alignment along domains or systems.” I think that industry best practices or the prior experience (within the team, personal, or found online) could also be referenced here.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If that was not enough, I think it makes sense to emphasize a few more things (deriving mostly from &lt;a href="https://www.amazon.com/Effective-Executive-Definitive-Getting-Things/dp/B01N51TCT1"&gt;The Effective Executive&lt;/a&gt; and &lt;a href="https://www.effectiveengineer.com/book"&gt;The Effective Engineer&lt;/a&gt;):&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;What hard data (evidence) supports the decision?&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;What conflict is baked into the decision (every important decision has it)? This could be a separate section “Drawbacks”, or a sub-section within “Implications”. &lt;strong&gt;How the conflict is addressed (drawbacks mitigated)?&lt;/strong&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;What metric of feedback loop will help to verify that the decision is effective in the future?&lt;/strong&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Who is responsible for carrying out the decision? What is the implementation plan?&lt;/strong&gt; The specific next step?&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Is there anything else that you think is important to check in architecture documents? Please share it in comments!&lt;/p&gt;




&lt;p&gt;&lt;a href="https://github.com/joelparkerhenderson/architecture_decision_record"&gt;This repository&lt;/a&gt; curated by Joel Parker Henderson has many links for further reading and alternative architecture decision record templates.&lt;/p&gt;




&lt;h3&gt;
  
  
  &lt;a href="https://stevemcconnell.com/articles/how-to-read-a-technical-article/"&gt;How To Read A Technical Article&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;Steve McConnell defines two main types of reading:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Inspectional: get the most out of a book or article within a given amount of time&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Analytical: get the most out of a book or article with an unlimited amount of time&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The process of inspectional reading:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Study the table of contents. What subject areas are covered? What is the book’s emphasis? Can you infer the author’s main points from the table of contents?&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Read the book’s preface.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Study the book’s index.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Read the introductory text of each chapter.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Dip into the first and last chapters of the book.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;McConnell advises reading inspectionally even when we plan to read analytically anyway:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;In case you do need to perform Analytical reading, Inspectional reading prepares you for that. In reading a book or article for understanding rather than just for information, you need to both acquire an understanding of the way the author has organized the subject matter and an understanding of the subject matter details. &lt;strong&gt;By jumping into the details first, starting at page 1 and reading through to the end, you have to acquire both of these kinds of knowledge simultaneously, which is very difficult.&lt;/strong&gt; By performing Inspectional reading first, you acquire an understanding of the organizational framework quickly, and you can then fit the details into the framework during your more detailed reading of pages 1 to &lt;em&gt;n&lt;/em&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;&lt;a href="https://phauer.com/2019/motivate-team-software-developers/"&gt;How to Motivate a Team of Software Developers&lt;/a&gt;&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Philipp Hauer writes from his experience about nurturing a motivating atmosphere in the team. Below are some ideas that jumped out for me. The first two echo Daniel Coyle’s “&lt;a href="https://engineeringideas.substack.com/p/the-culture-code-by-daniel-coyle"&gt;The Culture Code&lt;/a&gt;”:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;We usually hold a meeting when we have to come up with a database schema, architecture, design decisions or bigger refactorings in our software. After my experience, the outcome of those meetings is great and much better than the solution of a single developer. Swarm intelligence impresses me every time!&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The above also reminds me of Earl Beede’s take on the three best decision-making strategies, two of them are communal:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Delegation&lt;/strong&gt; to those who will be implementing the decision&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;One person decides after a discussion&lt;/strong&gt;. Everybody feels heard and understood.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Consensus&lt;/strong&gt;. &lt;em&gt;Check often that everybody is still on board&lt;/em&gt;, to avoid small disagreements.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Noncontrolling language&lt;/strong&gt;. The phrasing is crucial. This applies not only for &lt;a href="https://phauer.com/2018/code-review-guidelines/"&gt;feedback in code reviews&lt;/a&gt; but also for the daily communication within a team. Try to avoid phrases that contain “must” or “should”. Instead, use “think about …” or “have you considered …”. Again, &lt;em&gt;ask questions.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;At Spreadshirt, a developer can make an “internship” in other teams for one or two weeks. I can’t highlight enough the value of those internships: It’s so interesting to see how other teams work, what are their processes, what are their technologies and solutions and what are the social dynamics. And the knowledge exchange works in both directions.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The following reminds me of Edmond Lau’s idea about &lt;a href="http://www.effectiveengineer.com/blog/pick-the-right-metric-to-incentivize-desired-behavior"&gt;picking the right metric&lt;/a&gt;:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;A developer put a lot of effort into optimizing the performance of a remote call or an algorithm? It’s so rewarding if there are metrics (e.g. in Grafana) showing the improvement in terms of shorter response times and higher throughput.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;p&gt;Thank you for reading thus far!&lt;/p&gt;

&lt;p&gt;You can subscribe to new Engineering Ideas &lt;a href="https://engineeringideas.substack.com/feed"&gt;via RSS&lt;/a&gt; (e. g. using &lt;a href="https://feedly.com/"&gt;Feedly&lt;/a&gt;) or &lt;a href="https://engineeringideas.substack.com/subscribe"&gt;e-mail&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>nosql</category>
      <category>architecture</category>
    </item>
    <item>
      <title>Engineering Ideas #8</title>
      <dc:creator>Roman Leventov</dc:creator>
      <pubDate>Fri, 06 Mar 2020 09:00:40 +0000</pubDate>
      <link>https://dev.to/leventov/engineering-ideas-8-5gg4</link>
      <guid>https://dev.to/leventov/engineering-ideas-8-5gg4</guid>
      <description>&lt;p&gt;ORM dilemma, the curse of Lisp, coping with the complexity of systems, leadership of ICs, software development top mistakes, productivity = prioritisation&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;a href="https://martinfowler.com/bliki/OrmHate.html"&gt;ORM Hate&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;Martin Fowler warns against swinging from using an existing ORM fully back to rolling your own thing:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;For much of the 90's I saw project after project &lt;strong&gt;deal with the object/relational mapping problem by writing their own framework - it was always much tougher than people imagined.&lt;/strong&gt; Usually, you'd get enough early success to commit deeply to the framework and only after a while did you realize you were in a quagmire - this is where I sympathize greatly with Ted Neward's famous quote that object-relational mapping is the &lt;a href="http://blogs.tedneward.com/post/the-vietnam-of-computer-science/"&gt;Vietnam of Computer Science&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;A conclusion from the referenced Ted Neward’s writeup:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Just as it’s conceivable that the US could have achieved some measure of “success” in Vietnam had it kept to a clear strategy and understood a more clear relationship between commitment and results (ROI, if you will), it’s conceivable that &lt;strong&gt;the object/relational problem can be “won” through careful and judicious application of a strategy that is clearly aware of its own limitations.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Fowler suggests the moderate approach:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;This is where the criticism comes that ORM is a leaky abstraction. This is true but isn't necessarily a reason to avoid them. Mapping to a relational database involves lots of repetitive, boilerplate code. A framework that allows me to avoid 80% of that is worthwhile even if it is only 80%. The problem is in me for pretending it's 100% when it isn't. David Heinemeier Hansson, of Active Record fame, has always argued that if you are writing an application backed by a relational database you should damn well know how a relational database works. &lt;strong&gt;Active Record is designed with that in mind, it takes care of boring stuff, but provides manholes so you can get down with the SQL when you have to. That's a far better approach to thinking about the role an ORM should play.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  &lt;a href="https://buttondown.email/hillelwayne/archive/2f70015a-4dbe-44f5-95cf-0ae73a2b05a8"&gt;On Scaling Mental Models&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;Hillel Wayne comes with an interesting idea about why codebases in “cool” programming languages don’t scale:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Programming is an expression of how we think. We take the basic instructions and build abstractions over them. &lt;strong&gt;The more power you have in building abstractions, the more you can tailor those abstractions to your exact needs and exactly how ** _ **you think&lt;/strong&gt; _ &lt;strong&gt;.&lt;/strong&gt; […]&lt;br&gt;&lt;br&gt;
This compounds. If you’re working by yourself, you can shape your code and environment to reflect your mental model. This makes it easy to quickly write terse, simple, maintainable code. &lt;strong&gt;But it’s hard for other people to work with you. They don’t share your mental model&lt;/strong&gt; , and they don’t come in with all your initial assumptions. This is somewhat addressable if you all start working on the project together but falls apart when people join on later.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I cannot say I fully agree with this as an explanation of why technology written in these languages gets rebuilt with more mundane languages later (Wayne gives an example of Reddit website being rewritten from Lisp to Python).&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;There exist huge codebases in Scala with hundreds or even thousands of engineers working on them (&lt;a href="https://sysgears.com/articles/how-and-why-twitter-uses-scala/"&gt;Twitter&lt;/a&gt;), by all accounts is a very powerful language which allows shaping very advanced abstractions.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The reasons for rewrites from Lisp might be just its poor runtime performance or that it’s hard to find engineers to write in it. These may be related to the “expressivity” factor, but nevertheless are different points. There may be problems with scaling Lisp in production, but they may be more prosaic than “hard to scale mental models”, which may actually be a non-problem.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  &lt;a href="https://blog.acolyer.org/2020/01/20/stella-coping-with-complexity-2/"&gt;STELLA: report from the SNAFU-catchers workshop on coping with complexity&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;By David Woods, summary by Adrian Colyer. (SNAFU stands for “Situation Normal: All Fucked Up”, i. e. an accident, a disruption.)&lt;/p&gt;

&lt;p&gt;On the ability to cope with complexity and why one should be really careful adding that to a system:&lt;/p&gt;

&lt;blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;Woods’ Theorem: &lt;strong&gt;As the complexity of a system increases, the accuracy of any single agent’s own model of that system decreases rapidly.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Remember that ‘agent’ here could be a human – trying to form a sufficient mental model to triage an incident for example – or a software agent.&lt;/p&gt;


&lt;/blockquote&gt;

&lt;p&gt;On similarities between failures in complex systems (Sidney Dekker writes almost the same in “&lt;a href="https://engineeringideas.substack.com/p/drift-into-failure-by-sidney-dekker"&gt;Drift into Failure&lt;/a&gt;”):&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Section 3.4.1 in the paper lists some interesting features that all the anomalies had in common, including:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Arising from unanticipated interactions between system components&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Having no single ‘root cause’ (during my holiday reading I discovered by accident that Tolstoy has a lot to say on this topic in ‘War and Peace’ – try reading the first couple of pages from &lt;a href="https://www.gutenberg.org/files/2600/2600-h/2600-h.htm#link2HC0168"&gt;Vol III, Part I, Chapter I&lt;/a&gt; for example!).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Having been lurking in the system as ‘accidents waiting to happen’ for some time&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Being triggered by only slight differences from normal operating conditions&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Intially being buffered by system mechanisms designed to cope with partial failures etc., but eventually exhausting those mechanisms&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  &lt;a href="https://blog.pragmaticengineer.com/how-to-to-become-an-engineering-manager/"&gt;How Can I Prepare to Eventually Move into Engineering Management?&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;Another great post by Gergely Orosz, providing a mental map about how to transition into management, or, I would say, grow as an individual contributor as well.&lt;/p&gt;

&lt;p&gt;It’s hard to cite anything specific, I’d rather suggest you read the whole post. Here are some of the topics:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Lead a project and focus on completing it.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Look for bottlenecks the team is facing that slows work down and fix them.&lt;/strong&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Pick up ungrateful tasks that no one else wants to do.&lt;/strong&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Give credit to others, selflessly.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Start mentoring other developers.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Give candid feedback and don't shy away from difficult conversations.&lt;/strong&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Network with other professionals within or outside the company. Connect with non-engineers, learning about their work.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Observe and learn from your managers.&lt;/strong&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The last point reminds me of a Babak Nivi’s idea about leverage from &lt;a href="https://nav.al/rich"&gt;here&lt;/a&gt;:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Look at who is getting leverage off of the work that you’re doing. Look up the value chain—at who’s above you and who’s above them—and &lt;strong&gt;see how they are taking advantage of the time and work you’re doing and how they’re applying leverage&lt;/strong&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  &lt;a href="http://www.construx.com/uploadedfiles/resources/whitepapers/Software%20Development%E2%80%99s%20Classic%20Mistakes.pdf"&gt;Software Development’s Classic Mistakes&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://www.construx.com/"&gt;Construx Software&lt;/a&gt;, Steve McConnell’s company, conducted a survey about the most frequent mistakes on software projects. Here are the top 14 most damaging mistakes by exposure (frequency multiplied by severity):&lt;/p&gt;

&lt;blockquote&gt;
&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Unrealistic expectations&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Overly optimistic schedules&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Shortchanged quality assurance&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Wishful thinking&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Confusing estimates with targets&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Excessive multi-tasking&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Feature creep&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Noisy, crowded offices&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Abandoning planning under pressure&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Insufficient risk management&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Heroics&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Shortchanged upstream activities&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Inadequate design&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Lack of user involvement&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;/blockquote&gt;

&lt;p&gt;The common themes that I see here:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Wishful thinking&lt;/strong&gt; : mistakes 1, 2, 4, 5, and 10.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Underprioritized planning and quality&lt;/strong&gt; : mistakes 2, 3, 5, 9, 10, 11, 12, and 13.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Requirements and product mistakes&lt;/strong&gt; : 1, 7, and 14.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Developers unable to focus&lt;/strong&gt; : mistakes 6 and 8; cf. “&lt;a href="https://www.calnewport.com/books/deep-work/"&gt;Deep Work&lt;/a&gt;” by Cal Newport.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The white paper includes more elaborate descriptions of mistakes which are also interesting.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;a href="https://www.blog.google/inside-google/googlers/she-word/our-do-list-interview-googles-productivity-expert/"&gt;On our to-do list: an interview with Google’s productivity expert&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;Laura Mae Martin goes straight to the point:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;— What’s one thing people should start doing to manage their workload more efficiently?&lt;br&gt;&lt;br&gt;
— &lt;strong&gt;Determine your top priorities for the quarter, and write them on a note on your desk. If you’re asked to do something that doesn’t align with one of those priorities, say no.&lt;/strong&gt; The more you say no, the more chances you have to say yes to something that really matters.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;p&gt;Thank you for reading thus far!&lt;/p&gt;

&lt;p&gt;You can subscribe to new Engineering Ideas &lt;a href="https://engineeringideas.substack.com/feed"&gt;via RSS&lt;/a&gt; (e. g. using &lt;a href="https://feedly.com/"&gt;Feedly&lt;/a&gt;) or &lt;a href="https://engineeringideas.substack.com/subscribe"&gt;e-mail&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>reliability</category>
      <category>softwaredevelopment</category>
      <category>productivity</category>
      <category>leadership</category>
    </item>
    <item>
      <title>Drift Into Failure by Sidney Dekker – notes on the book</title>
      <dc:creator>Roman Leventov</dc:creator>
      <pubDate>Fri, 28 Feb 2020 14:55:49 +0000</pubDate>
      <link>https://dev.to/leventov/drift-into-failure-by-sidney-dekker-notes-on-the-book-58bh</link>
      <guid>https://dev.to/leventov/drift-into-failure-by-sidney-dekker-notes-on-the-book-58bh</guid>
      <description>&lt;p&gt;I decided to read “&lt;a href="https://www.amazon.com/Drift-into-Failure-Sidney-Dekker/dp/1409422216"&gt;Drift Into Failure&lt;/a&gt;” by &lt;a href="http://sidneydekker.com/"&gt;Sidney Dekker&lt;/a&gt; because of an &lt;a href="https://github.com/lorin/systems-reading/blob/master/README.md#drift-into-failure"&gt;appraisal by Lorin Hochstein&lt;/a&gt; (thanks to him for curating his reading notes). I thought I would learn something about software systems reliability from this book. Apart from that, the book actually gave me more: it introduced me to a number of fascinating philosophical ideas and the &lt;a href="https://en.wikipedia.org/wiki/Complex_system"&gt;complexity and systems theory&lt;/a&gt; with which I was unfamiliar before.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;I highly recommend this book&lt;/strong&gt; , despite it is a bit self-repetitive. It might be that you can learn the same concepts from some other books or papers which are shorter than “Drift Into Failure”, &lt;a href="http://sidneydekker.com/books/"&gt;including some of the newer Dekker’s books&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Below are my notes on the book. All citations are from the book, © Sidney Dekker.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;Drift into failure&lt;/strong&gt; (DIF) is a gradual, incremental decline into disaster driven by environmental pressure, unruly technology, and social processes that normalize growing risk. It's &lt;strong&gt;an inevitable byproduct of normally functioning processes.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Competition and scarcity dictate that organisation borrows more and more from near the safety boundaries, takes greater risks.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The traditional model claims that for accidents to happen something must break, give, malfunction: component, part, person. But organisations drift into failure precisely because they are doing well.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://wiki.p2pfoundation.net/Cartesian-Newtonian_Paradigm"&gt;Cartesian-Newtonian epistemology&lt;/a&gt; = rationalism, reductionism, belief that there is the best (optimal) decision, solution, theory, explanation of events.&lt;/p&gt;

&lt;p&gt;Optimal, rational decision-maker:  &lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Completely informed about alternatives, the consequences of decisions, probability of events.
&lt;/li&gt;
&lt;li&gt;Capable of full objective logical analysis.
&lt;/li&gt;
&lt;li&gt;Sees the finest differences between alternatives.
&lt;/li&gt;
&lt;li&gt;Rationally ranks alternatives based on the priorities.
&lt;/li&gt;
&lt;li&gt;(Doesn’t exist :)&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Before the 1970s, accidents were seen as truly accidental or sent by god. After—as failures in risk management or the result of deliberate amoral choices or neglect. &lt;strong&gt;We also connect the moral gravity to the outcomes of the accident.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The growth of complexity in our society has got ahead of our understanding of how complex systems (CS) work and fail.&lt;/p&gt;

&lt;p&gt;Simplicity and linearity remain the defining characteristic of the stories and theories that we use to explain bad events that emerge from the complexity of the world.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;In complex systems, we can predict only probabilities, not results.&lt;/strong&gt; (In &lt;a href="https://en.wikipedia.org/wiki/Antifragile"&gt;Antifragile&lt;/a&gt;, Nassim Taleb argues that we cannot estimate narrow probabilities with any good precision, too.)&lt;/p&gt;

&lt;p&gt;Complexity is not designed. It happens or grows (against our will).&lt;/p&gt;

&lt;p&gt;In 2008 debt crisis, the absence of liability of asset managers skewed the incentives from loan quality to loan quality. More was always better.&lt;/p&gt;

&lt;p&gt;Knowledge is inherently subjective. Direct, unmediated, objective knowledge of how a whole complex system works is impossible to get.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Local rationality principle (LRP)&lt;/strong&gt;: people are doing what makes sense to them given situational indictions, organisational pressures, and operational norms that exist at the time. Rational decision making, however, requires massive cognitive resources and all the time in the world.&lt;/p&gt;

&lt;p&gt;In ambiguity and uncertainty of complex systems, options that appear to work are better than perfect options that never get computed. However, decisions that look nice locally can fail globally.&lt;/p&gt;

&lt;p&gt;In complex systems, local actions can have global results.&lt;/p&gt;

&lt;h3&gt;
  
  
  Five characteristics of drift
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;DIF is caused by resource scarcity and competition.&lt;/li&gt;
&lt;li&gt;DIF occurs in small steps.

   In CS, past success is not a guarantee of future success or safety of the same operation.&lt;/li&gt;
&lt;li&gt;CSs are sensitive to small changes in input conditions, early decisions. The potential to DIF may be baked in a very small event when the system was much simpler.&lt;/li&gt;
&lt;li&gt;CSs that can drift into failure are characterized by unruly (unproven, delusional) technology that creates uncertainty.&lt;/li&gt;
&lt;li&gt;Protective (regulatory) structure between CS and the environment which is supposed to protect CS from failure may contribute to DIF because it is subject to the same pressures as the operator.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Philosophy of complex systems
&lt;/h3&gt;

&lt;p&gt;It takes more than one error to push a CS into failure. Theories explaining failure by mistake or broken component (Cartesian-Newtonian) are overapplied and overdeveloped.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Complexity doesn't allow to think in unidirectional terms along which “progress” or “regress” could be plotted.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Though DIF invites the idea of regress: smaller margins, less adaptive capacity, declining standards, CS always simply adapts to whatever happens now or just happened. Any larger historical story is ours, not the system's.&lt;/p&gt;

&lt;p&gt;DIF is a construct in retrospect, or, at the most, it is a construct that can be applied to a CS from the outside. From the inside, drift is invisible.&lt;/p&gt;

&lt;p&gt;Evolution has no visible direction when you are in the middle of it. Evolution, progress, regress in CSs (including society) are perhaps just illusion, our phycological imposition.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The idea that there is a vector of evolution, a “hand” behind it, a cause for its speed and direction is Newtonian.&lt;/strong&gt; (Vectors of forces.) (The “hand” also made me think about the connection of this idea to religion.)&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;&lt;a href="https://en.wikipedia.org/wiki/Exegesis"&gt;Exegesis&lt;/a&gt; is an assumption that the essence of the story is already in the story, ready formed, waiting to be discovered.&lt;/strong&gt; All we need to do is to read the story well, apply the right method, use the correct analytic tools, put things in context, and the essence will be revealed to us. &lt;strong&gt;Such structuralism sees the truth as being within or behind the text.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://en.wikipedia.org/wiki/Eisegesis"&gt;Eisegesis&lt;/a&gt; is reading something into a story. Any directions in adaptations are of our own making. Post-structuralism stresses the relationship between the reader and the text as the engine of truth.&lt;/strong&gt; Reading is not passive consumption of what is already there, provided by somebody who possessed the truth, passing it on. Reading is a creative act. Readers generate meanings out of their own experience and history with text.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Nietzsche, and post-structuralism in general, don't believe that it is a single world that we are interpreting differently. That we could in principle reach agreement when we put all different pictures together. More perspectives don't mean a greater representation of some underlying truth.&lt;/p&gt;

&lt;p&gt;In CSs, more perspectives mean more conflicts. CSs can never be understood or exhaustively described. If they could, they would either be not complex, or the entity understanding them would have to be as complex as the whole system. This contradicts the local rationality principle.&lt;/p&gt;

&lt;p&gt;Events that we want to study, just like any CS, can never be fixed, tied down, circumscribed with a conclusive perimeter telling us what is part of it and what is not.&lt;/p&gt;

&lt;p&gt;By reading drift into a particular failure we will probably learn some interesting things, but we will surely miss or misconstrue other things.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Whether there is a drift into failure depends not on what in the story, but on us, what we bring into the story, how far we read, how deeply, what else we read. It depends on the assumptions and expectations that we have about knowledge, cause, and, ultimately, about morality.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;Newton’s and Descartes’ model, like any model, prevents us from seeing the world in other ways, from learning things about the world that we didn't even know how to ask.&lt;/strong&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;a href="https://en.wikipedia.org/wiki/Galileo_Galilei"&gt;Galileo Galilei&lt;/a&gt; insisted that we should not worry too much about the things that we cannot quantity, like how something tastes or smells, because he thought that is a subjective mental projection and not a material property of the world that can be measured, and, since you cannot measure it, it's not very scientific. That legacy lives with us today. An obsession with metrics and quantifications and downplaying the things that not only help determine the outcome of many phenomena, like our values or feelings, motives, intentions, but also make us human.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href="https://en.wikipedia.org/wiki/Francis_Bacon"&gt;Francis Bacon&lt;/a&gt;: “Science should torture nature’s secrets from her. Nature has to be hounded in her wanderings, bound into service, put into constraint and made a slave.”&lt;/p&gt;

&lt;h3&gt;
  
  
  Analysis of failure
&lt;/h3&gt;

&lt;p&gt;Take the context surrounding component failures seriously. Look for sources of trouble in the organisational, administrative, and regulatory levels of the system, not just the operational or engineering sharp end.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Systems thinking is about&lt;br&gt;&lt;br&gt;
— relationships, not parts&lt;br&gt;&lt;br&gt;
— the complexity of the whole, not the simplicity of the carved out bits&lt;br&gt;&lt;br&gt;
— nonlinearity and dynamics, not linear cause-effect&lt;br&gt;&lt;br&gt;
— accidents that are more than a sum of broken parts&lt;br&gt;&lt;br&gt;
— understanding how accidents can happen when no parts are broken, or no parts are seen as broken.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The work in complex systems is bounded by three types of constraints:&lt;br&gt;&lt;br&gt;
 — &lt;strong&gt;economic boundary&lt;/strong&gt; , beyond which the system cannot sustain itself financially.&lt;br&gt;&lt;br&gt;
 — &lt;strong&gt;workload boundary&lt;/strong&gt; : people or technology not able to perform the task.&lt;br&gt;&lt;br&gt;
 — &lt;strong&gt;safety boundary&lt;/strong&gt; beyond which the system will functionally fail.&lt;/p&gt;

&lt;p&gt;Finance departments and competition push organisations into workload/safety boundary corner.&lt;/p&gt;

&lt;p&gt;In making tradeoffs for efficiency there is a feedback imbalance. Information on whether a tradeoff is cost-efficient is easy to get. How much was borrowed from safety to achieve this benefit is much harder to quantify.&lt;/p&gt;

&lt;p&gt;Operation rules must not be set in stone. They should emerge from production experience and data.&lt;/p&gt;

&lt;p&gt;In practice, practices don’t follow the rules. Rules follow emerging practices.&lt;/p&gt;

&lt;p&gt;Declaring that CS has a safety hole doesn’t help to find when did the hole occur and why.&lt;/p&gt;

&lt;p&gt;The banality of accidents: incidents don’t precede accidents. Normal work does. Accidents result from a combination of factors none of which in isolation cause an accident. These combinations are not usually taken into account in the safety analysis. For this reason, reporting is very ineffective at predicting major disasters.&lt;/p&gt;

&lt;p&gt;The etiology of accidents is fundamentally different from that of incidents: hidden in residual risks of doing normal work under pressure of scarcity and competition.&lt;/p&gt;

&lt;p&gt;The signals now seen as worthy of reporting, or organisational decisions now seen as bad (even though they looked good at the time) are not big, risky events or order-of-magnitude steps. Rather, there is a succession of weak signals and decisions along a steady progression of decremental steps. Each has an empirical success and no obvious sacrifice to safety.&lt;/p&gt;

&lt;p&gt;We need to raise awareness through a language that enables a more functional account. A story of living processes run by people with real jobs and real constraints but no ill intentions, whose understanding co-evolve with the system and the environmental conditions as they try to stay up-to-date with them.&lt;/p&gt;

&lt;p&gt;Looking for organisational, latent causes of incidents is still very Newtonian (cause-effect): broken parts, failures of higher management.&lt;/p&gt;

&lt;p&gt;Newtonian idea: data (metrics) help to understand something real, and some data may be better than other data.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;More redundancy (which itself comes with a fixation on parts) creates greater opacity and complexity. The system can become more difficult to manage and understand.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Individualism was in part fueled by Cartesian dualistic phycology. It’s unnatural in individualistic worldview to think that it may take a team, an organisation, or an entire industry to be responsible for a failure.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;The conceptualisation of risk/failure as build-up and release of energy (physical metaphor) is not necessarily well-suited to explain the organisational and sociotechnical factors behind system breakdown&lt;/strong&gt;, nor equip with a language that can meaningfully handle processes of gradual adaptation or the social processes of risk management and human decision making.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  High-reliability theory
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Four components of a high-reliability organisation&lt;/strong&gt; (HRO) (according to &lt;a href="https://en.wikipedia.org/wiki/High_reliability_organization"&gt;high-reliability theory&lt;/a&gt;):&lt;br&gt;&lt;br&gt;
 — Leadership commitment&lt;br&gt;&lt;br&gt;
 — Redundancy and layers of defence&lt;br&gt;&lt;br&gt;
 — Entrusting people at the sharp edge to do what they think is needed for safety&lt;br&gt;&lt;br&gt;
 — Incremental organisational learning through trial and error, analysis, reflection, simulation. Should not be organised centrally, can (should) be distributed locally as well as decision making.&lt;/p&gt;

&lt;p&gt;HRO needs to keep expecting a surprise. The past should not grow a belief in sustaining future safety. Tactics:&lt;br&gt;&lt;br&gt;
 — Preoccupation with failure&lt;br&gt;&lt;br&gt;
 — Reluctance to simplify. Paying close attention to context and contingencies of events. More differentiation, mindsets, worldviews. Diversity of interpretation helps to anticipate what might go wrong in the future.&lt;br&gt;&lt;br&gt;
 — Sensitivity to actual operations, rather than predefined procedures and conclusions.&lt;br&gt;&lt;br&gt;
 — Deference to expertise. Listen to the minority opinion.&lt;br&gt;&lt;br&gt;
 — Commitment to resilience&lt;/p&gt;

&lt;p&gt;Deference to expertise might be still slippery. &lt;strong&gt;Experts cannot ultimately escape the push towards margins in their expert judgement based on an incomplete understanding of the data.&lt;/strong&gt; From within an organisation, it might be impossible to transcend the routine and political stuff and notice an emerging problem. &lt;strong&gt;What we don’t believe we cannot see.&lt;/strong&gt; Thus, relying on human rationality is unreasonable.&lt;/p&gt;

&lt;p&gt;Conflicting goals are not an exception, they are a rule. They are the essence of most operational systems. Systems don’t exist to be safe, they exist to provide a service.&lt;/p&gt;

&lt;p&gt;Most important goal conflicts are not explicit, they emerge from multiple, irreconcilable directives from different levels and sources, saddle and tacit pressures, from management’s or customers’ reactions to particular tradeoffs.&lt;/p&gt;

&lt;p&gt;Practitioners see their ability to reconcile the irreconcilable as a source of professional pride and a sign of their expertise.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://danluu.com/wat/"&gt;Normalisation of deviance&lt;/a&gt; is the mechanism of how production pressures incubate failures.&lt;/p&gt;

&lt;p&gt;Redundancies, the presence of extraordinary competence, or the use of proven technology can all add to the impression that nothing could go wrong.&lt;/p&gt;

&lt;p&gt;A solution to risk, if any, is for an organisation to continually reflect on and challenging its own definition of “normal”. To prioritize chronic safety concerns over acute production pressures.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Large organisations cannot act as closed, rational mechanisms. They themselves have local rationality precisely because they are made of people put together.&lt;/strong&gt; Problems are ill-defined, often unrecognised. Decision-makers have limited information, shifting allegiances, and uncertain intentions. &lt;strong&gt;Solutions may be laying around actively searching for problems to attach themselves to.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;According to control theory, degradation of safety control structures can be due to asynchronous evolution: one part of the system changes without related charges in the other parts.&lt;/p&gt;

&lt;p&gt;Changes to subsystems may be carefully planned, but their role in overall safety or effect on each other may be neglected or viewed inadequately.&lt;/p&gt;

&lt;h3&gt;
  
  
  Systems thinking
&lt;/h3&gt;

&lt;p&gt;Mechanistic thinking about failures means going &lt;em&gt;down&lt;/em&gt; and &lt;em&gt;into&lt;/em&gt; individual “broken” components. Systems thinking means going &lt;em&gt;up&lt;/em&gt; and &lt;em&gt;out&lt;/em&gt;: understanding comes from seeing how the system is configured in a larger network of systems, tracing the relationships with those, and how those spread out to affect and be affected by factors laying far away in time and space from things went wrong.&lt;/p&gt;

&lt;p&gt;At the subatomic level, the interrelations and interactions between the parts of the whole are more fundamental than the parts themselves. There is motion, but, ultimately, no moving objects. There is activity, but no actors.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;In complex systems, just like in physics, there are no definite predictions, only probabilities.&lt;/strong&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Ironically, as natural and social sciences both shift towards complexity and systems thinking, they become closer again. Natural sciences become “softer”, with an emphasis on unpredictability, relationships, irreducibility, non-linearity, time irreversibility, adaptivity, self-organisation emergence, all sort of things that have always been better suited to capture the social order.&lt;/p&gt;

&lt;p&gt;Systems thinking predates the scientific revolution that gave birth to the Newtonian-Cartesian paradigm. &lt;strong&gt;Leonardo da Vinci was the first systems thinker and complexity theorist.&lt;/strong&gt; He was a relentless empiricist and inventor, a humanist fusion of art and science. He embraced the profound interconnectedness of ideas from multiple fields. His goal was to combine, advance, investigate, and understand processes in the natural world through the interdisciplinary view.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Complexity and systems theory
&lt;/h3&gt;

&lt;p&gt;Foundations of the complexity and systems theory:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Complex system is open, affecting and affected by the environment&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Each component is ignorant of the behaviour of the system as a whole and doesn’t know the full effect of its actions. Components respond locally to the information presented to them there and then. Complexity arises from the huge web of relations between components and their local actions.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Complexity is a feature of the system, not the components.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;CS operates far from equilibrium. Components need to get inputs constantly to keep functioning. Without it, CS won’t survive in a changing environment. &lt;strong&gt;The performance of a CS is typically optimised at the edge of chaos, just before the system’s behaviour can become unrecognisably turbulent.&lt;/strong&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;CS has a history, a path dependence. The past is co-responsible for its present behaviour. Descriptions of complexity have to take history into account. &lt;strong&gt;Synchronous snapshot never represents the CS, only the full &lt;a href="https://en.wikipedia.org/wiki/Synchrony_and_diachrony"&gt;diachronic&lt;/a&gt; lineage can.&lt;/strong&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Interactions in CS are non-linear. Small events can produce large results.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Complicated systems consist of a lot of parts and interactions but are closed, unlike complex systems which are open.&lt;/p&gt;

&lt;p&gt;Paradox: complexity should support resilience because CS can adapt to the environment and survive. How can complexity lead to failure? Complexity opens a path to a particular kind of brittleness:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Drift into failure cannot be seen synchronically. Only a diachronic study can reveal where the system is headed.&lt;/strong&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Non-linearity can amplify small events into a failure.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Local reactions and reasoning support decremental steps toward failure through normalisation of deviance.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Unruly technology introduces and sustains uncertainties about how and when things may fail.&lt;/strong&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Technology can be a source of complexity. Even if parts can be modelled exhaustively (thus are merely complicated), their operation with each other in a dynamic environment generates unpredictabilities and unruliness of complexity.&lt;/strong&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Emergence
&lt;/h3&gt;

&lt;p&gt;Emergence: a system has an emergent property if what it produces can not be explained by the properties of the parts.&lt;/p&gt;

&lt;p&gt;Organized complexity is emergent, bottom-up, a result of local interactions and a cumulative effect of simple rules.&lt;/p&gt;

&lt;p&gt;Accidents are emergent properties of CS.&lt;/p&gt;

&lt;p&gt;Beware of renaming things that renegotiates the perceived risk down from what it was before, because it may have far-reaching consequences (phase transition).&lt;/p&gt;

&lt;h3&gt;
  
  
  Exploration-exploitation tradeoff
&lt;/h3&gt;

&lt;p&gt;The optimum (maximum) behaviour is determined in the relationship between the CS and the environment.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;A tradeoff between exploration and exploitation (by local agents) lies behind much of the system’s adaptation. This is also why adaptation is sometimes unsuccessful.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Exploration can produce big failures (e. g. trying a new technology in production can produce an outage because the technology fails under the load). This is the reason why the optimum balance between the exploration and exploitation puts the system near the edge of chaos.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Arriving at the edge of chaos is the logical endpoint of DIF. The system has tuned itself into maximum capability.&lt;/strong&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;In a CS, an action controls almost nothing but influences almost everything.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Diversity
&lt;/h3&gt;

&lt;p&gt;Diversity is critical for resilience. One way to ensure diversity is to push authority about safety decisions down to people closest to the problem.&lt;/p&gt;

&lt;p&gt;High-reliability theory also recommends attuning to minority opinions, which helps diversity.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Greater diversity of agents in a CS leads to richer emergent patterns (including for good qualities). It typically produces greater adaptive capacity.&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
  =&amp;gt; Diversity is good for an organisation.&lt;/p&gt;

&lt;p&gt;Diversity of people will likely enhance creativity on a team. More stories get told about the things we should be afraid of. More hypothesis might be generated about how to improve the system.&lt;/p&gt;

&lt;p&gt;Diversity of opinion in a CS should be seen as a strength, not a weakness. &lt;strong&gt;The more angles and perspectives, the more opportunities to learn.&lt;/strong&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Tactics to manage the complexity of drift (“drift into success”)
&lt;/h3&gt;

&lt;p&gt;1. Resource/safety tradeoff:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Full optimization of CS is undesirable because the lack of slack and margins can turn small perturbations into large events. Diversity of opinion helps to prevent exhaustive optimization.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;2. Small steps offer two levers for preventing drift:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Small steps happen all the time, providing a lot of opportunity for reflection.&lt;/strong&gt; What this step can mean for safety? Ask people in different parts of the org (since the step can reverberate to there).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Small steps don’t generate defensive posturing when they are questioned, and cheap to rollback.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Hiring people from outside provides an opportunity to calibrate the practices and correct deviance. Rotation between teams also works. An additional benefit of people rotation is constant ongoing training, including of the safety procedures.&lt;/p&gt;

&lt;p&gt;3. Unruly technology:&lt;/p&gt;

&lt;p&gt;We may have traditionally seen unruly technology as a pest that needs further tweaking before it becomes optimal. This is a Newtonian commitment. &lt;strong&gt;Complexity theory suggests that we see unruly technology not as a partially finished product but as a tool for discovery. Turn small steps into experiments. If results surprise us, it’s an opportunity to learn from about the system, or about ourselves.&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Why did this happen?&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Why are we surprised that this happened?&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;But consider the post-structural view, and that &lt;strong&gt;the insights that we could possibly have are limited by our local rationality and prior experience. This is where diversity matters, again.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;4. Protective structure:&lt;/p&gt;

&lt;p&gt;The idea of safety “oversight” is problematic. Oversight implies a “big picture”. A big picture in the sense of a complete description is impossible to achieve over a CS. CS evolve and adapt all the time. Nailing its description down at any one moment means very little to how it will look in the next moment.&lt;/p&gt;

&lt;p&gt;If oversight implies sensitivity to the features of complexity and drift, it might work. Oversight may try to explore complex properties:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Interconnectedness, interdependence: less is better&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Diversity, rates of learning: more is better&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Selection (e. g. for &lt;a href="https://en.wikipedia.org/wiki/Groupthink"&gt;groupthink&lt;/a&gt; culture)&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Protective structure should adopt the co-evolving or counter-evolving mindset. When inspecting parts, it should relentlessly follow dependencies and connections and explore interactions.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Rather than working on &lt;em&gt;the&lt;/em&gt; safety strategy or &lt;em&gt;the&lt;/em&gt; accident prevention program, we should create preconditions that can give rise to innovation, to new emergent orders and ideas, without necessarily our own careful attending and crafting.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;There are thousands of small steps that can lead to failure. No prevention strategy tinkered by one designer can foresee them all.&lt;/strong&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Complexity and accountability
&lt;/h3&gt;

&lt;p&gt;In a CS, it’s impossible to determine whose view is right and whose view is wrong, since the agents effectively live in different environments.&lt;/p&gt;

&lt;p&gt;Blaming someone, beware the limited knowledge and selection bias and post-structural nature of this act.&lt;/p&gt;

&lt;p&gt;There may almost always be several authentic stories of an incident.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Complexity theory doesn’t provide the answer about who is responsible for DIF, but it at least dispels the belief that there exists an easy answer.&lt;/strong&gt;&lt;/p&gt;




&lt;p&gt;Thanks for reading thus far!&lt;/p&gt;

&lt;p&gt;You can subscribe to new Engineering Ideas &lt;a href="https://engineeringideas.substack.com/feed"&gt;via RSS&lt;/a&gt; (e. g. using &lt;a href="https://feedly.com/"&gt;Feedly&lt;/a&gt;) or &lt;a href="https://engineeringideas.substack.com/subscribe"&gt;e-mail&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>reliability</category>
      <category>complexsystems</category>
      <category>systemdesign</category>
      <category>philosophy</category>
    </item>
    <item>
      <title>Single Responsibility Principle Unpacked</title>
      <dc:creator>Roman Leventov</dc:creator>
      <pubDate>Tue, 25 Feb 2020 18:00:00 +0000</pubDate>
      <link>https://dev.to/leventov/single-responsibility-principle-unpacked-jea</link>
      <guid>https://dev.to/leventov/single-responsibility-principle-unpacked-jea</guid>
      <description>&lt;p&gt;This article explains the Single Responsibility Principle (SRP): what does it practically mean? And when and how should we apply it?&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
What does the Single Responsibility Principle say? 

&lt;ul&gt;
&lt;li&gt;Types of responsibilities&lt;/li&gt;
&lt;li&gt;
How small or large should a responsibility be?
&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;
The impact of the Single Responsibility Principle on different software qualities

&lt;ul&gt;
&lt;li&gt;
Understandability and Learning Curve
&lt;/li&gt;
&lt;li&gt;
Flexibility
&lt;/li&gt;
&lt;li&gt;
Reusability
&lt;/li&gt;
&lt;li&gt;
Testability
&lt;/li&gt;
&lt;li&gt;
Debuggability
&lt;/li&gt;
&lt;li&gt;
Observability and Operability
&lt;/li&gt;
&lt;li&gt;
Reliability
&lt;/li&gt;
&lt;li&gt;
Code Size
&lt;/li&gt;
&lt;li&gt;
Performance
&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;Summary&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What Does the Single Responsibility Principle Say?
&lt;/h2&gt;

&lt;p&gt;The Single Responsibility Principle may feel a bit vague at first. Let's try to deconstruct it and look at what it actually means.&lt;/p&gt;

&lt;p&gt;The Single Responsibility Principle applies to the software that we develop on different levels: methods, classes, modules, and services (collectively, I'll call all these things &lt;em&gt;components&lt;/em&gt; later in this article). So, &lt;strong&gt;the SRP states that each &lt;em&gt;component&lt;/em&gt; should have a single responsibility&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;This phrase is a little more concrete, but it still doesn't explain what a &lt;em&gt;responsibility&lt;/em&gt; is and &lt;em&gt;how small or large a responsibility should be&lt;/em&gt; for each particular method, class, module, or service.&lt;/p&gt;

&lt;h3&gt;
  
  
  Types Of Responsibilities
&lt;/h3&gt;

&lt;p&gt;Instead of defining a &lt;em&gt;responsibility&lt;/em&gt; in abstract terms, it may be more intuitive to list the actual types of responsibilities. Here are some examples (they are derived from Adam Warski's classification of objects in applications which he distilled in his thought-provoking post about &lt;a href="https://blog.softwaremill.com/zio-environment-meets-constructor-based-dependency-injection-6a13de6e000"&gt;dependency injection in Scala&lt;/a&gt;):&lt;/p&gt;

&lt;h4&gt;
  
  
  Business Logic
&lt;/h4&gt;

&lt;p&gt;For example, extracting a phone number from text, converting an XML document into JSON, or classifying a money transaction as fraud. On the level of classes and above, a business logic responsibility is &lt;em&gt;knowing how to do&lt;/em&gt; (or encapsulating) the business function: for example, a class knowing how to convert XML documents into JSON, or a service encapsulating the detection of fraud transactions.&lt;/p&gt;

&lt;h4&gt;
  
  
  External Integration
&lt;/h4&gt;

&lt;p&gt;On the lowest level, this can be an integration between modules within the application, such as putting a message into a queue which is processed by another subsystem. Then, there are integrations with the system, such as logging or checking the system time (&lt;code&gt;System.currentTimeMillis()&lt;/code&gt;). Finally, there are integrations with external systems, such as database transactions, reading from or writing to a distributed message queue such as Kafka, or RPC calls to other services.&lt;/p&gt;

&lt;p&gt;On the level of classes, modules, and services, an external integration responsibility is &lt;em&gt;knowing how to integrate&lt;/em&gt; (or encapsulating integration with) the external part: for example, a class knowing how to read the system time (which is exactly what &lt;a href="https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/time/Clock.html"&gt;&lt;code&gt;java.time.Clock&lt;/code&gt;&lt;/a&gt; is), or a service encapsulating talking with an external API.&lt;/p&gt;

&lt;h4&gt;
  
  
  Data
&lt;/h4&gt;

&lt;p&gt;A profile of a person on a website, a JSON document, a message. Embodying a piece of data can only be a responsibility of a class (object), but not of a method, module, or service. A specific kind of data is &lt;strong&gt;configuration&lt;/strong&gt;: a collection of parameters for some other method, class, or system.&lt;/p&gt;

&lt;h4&gt;
  
  
  Control Flow
&lt;/h4&gt;

&lt;p&gt;A piece of an application's control flow, execution, or data flow. An example of this responsibility is a method that orchestrates calls to components that each have other responsibilities:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;processTransaction&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Transaction&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;isFraud&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt; &lt;span class="c1"&gt;// Business logic&lt;/span&gt;
    &lt;span class="c1"&gt;// External integration: logging&lt;/span&gt;
    &lt;span class="n"&gt;logger&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;log&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Detected fraud transaction {}"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="c1"&gt;// Integration with external service&lt;/span&gt;
    &lt;span class="n"&gt;alertingService&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;sendAlert&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;FraudTransactionAlert&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="o"&gt;));&lt;/span&gt;
  &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;On the level of classes, an example of a data flow responsibility may be a &lt;code&gt;BufferedLogger&lt;/code&gt; class which buffers logging statements in memory and manages a separate background thread that takes statements from the buffer and writes them to actual external logger:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;BufferedLogger&lt;/span&gt; &lt;span class="kd"&gt;implements&lt;/span&gt; &lt;span class="nc"&gt;Logger&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;Logger&lt;/span&gt; &lt;span class="n"&gt;delegate&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
  &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;ExecutorService&lt;/span&gt; &lt;span class="n"&gt;backgroundWorker&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
  &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;BlockingQueue&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Statement&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;buffer&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

  &lt;span class="nc"&gt;BufferedLogger&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Logger&lt;/span&gt; &lt;span class="n"&gt;delegate&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;delegate&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;delegate&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;backgroundWorker&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;newSingleThreadExecutor&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;buffer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;ArrayBlockingQueue&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;gt;(&lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;backgroundWorker&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;execute&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;writeStatementsInBackground&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
  &lt;span class="o"&gt;}&lt;/span&gt;

  &lt;span class="nd"&gt;@Override&lt;/span&gt; &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Statement&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;putUninterruptibly&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;buffer&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
  &lt;span class="o"&gt;}&lt;/span&gt;

  &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;writeStatementsInBackground&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
      &lt;span class="nc"&gt;Statement&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;takeUninterruptibly&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;buffer&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
      &lt;span class="n"&gt;delegate&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;log&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
  &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Method &lt;code&gt;writeStatementsInBackground()&lt;/code&gt; itself has a control flow responsibility.&lt;/p&gt;

&lt;p&gt;In a distributed system, examples of services with a control or data flow responsibility could be a proxy, a load balancer, or a service transparently caching responses from or buffering requests to some other service.&lt;/p&gt;

&lt;h3&gt;
  
  
  How Small or Large Should a Responsibility Be?
&lt;/h3&gt;

&lt;p&gt;I hope the examples above give some more grounded sense of what responsibility of a method, class, module, or service could be. However, they still provide no actionable guidance on how finely we should chop responsibilities between the components of your system. For example:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Should conversion from XML to JSON be a responsibility of a single method (or a class), or should we split it between two methods? One translates XML into a tree, and another serializes a tree into JSON? Or should these be separate methods belonging to a single class?&lt;/li&gt;
&lt;li&gt;Should individual types of interactions with an external service (such as different RPC operations) be responsibilities of separate classes,  or should they all belong to a single class? Or, perhaps, should interactions be grouped, such as read operations going to one class and write operations going to another?&lt;/li&gt;
&lt;li&gt;How should we split responsibilities across (micro)services?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Uncle Bob Martin (who first proposed the Single Responsibility Principle) suggests that components should be broken down until each one has only one &lt;em&gt;reason to change&lt;/em&gt;. However,  to me, this criterion still doesn't feel very instructive. Consider the &lt;code&gt;processTransaction&lt;/code&gt; method above. There may be many reasons to change it:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Increment counters of normal and fraudulent transactions to gather statistics.&lt;/li&gt;
&lt;li&gt;Enrich or reformat the logging statement.&lt;/li&gt;
&lt;li&gt;Wrap sending an alert into error-handling &lt;code&gt;try-catch&lt;/code&gt; and log a failure to send an alert.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Does this mean that the &lt;code&gt;processTransaction()&lt;/code&gt; method is too large and we should split it further into smaller methods? According to Uncle Bob, &lt;a href="https://sites.google.com/site/unclebobconsultingllc/one-thing-extract-till-you-drop"&gt;we probably should&lt;/a&gt;, but many other people may think that &lt;code&gt;processTransaction&lt;/code&gt; is already small enough.&lt;/p&gt;

&lt;p&gt;Let's return to the purpose of using the Single Responsibility Principle. Obviously, it's to improve the overall quality of the codebase and of its production behavior (Carlo Pescio calls these two domains &lt;a href="http://www.carlopescio.com/2010/06/notes-on-software-design-chapter-6.html"&gt;artifact space and runtime space&lt;/a&gt;, respectively).&lt;/p&gt;

&lt;p&gt;So, what will ultimately help us to apply the Single Responsibility Principle effectively is &lt;strong&gt;making clearer for ourselves how SRP affects the quality of the code and the running application&lt;/strong&gt;. The optimal scope of the responsibility for a component highly depends on the context:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The responsibility itself (i. e. what the component actually does)&lt;/li&gt;
&lt;li&gt;The non-functional requirements to the application or the component we're developing&lt;/li&gt;
&lt;li&gt;How long we plan to support the code in the future&lt;/li&gt;
&lt;li&gt;How many people will work with this code&lt;/li&gt;
&lt;li&gt;Etc.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;However, this shouldn't intimidate us. &lt;strong&gt;We should just split (or merge) components while we see that the software qualities we're interested in keep improving.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Thus, the next step is to analyze how the Single Responsibility Principle affects the specific software qualities.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Impact Of the Single Responsibility Principle On Different Software Qualities
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Understandability and Learning Curve
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;When we split responsibilities between smaller methods and classes, usually the system becomes easier to learn overall.&lt;/strong&gt; We can learn bite-sized components one at a time, iteratively. When we jump into a new codebase, we can learn fine-grained components as we need them, ignoring the internals of the other components which are not yet relevant for us.&lt;/p&gt;

&lt;p&gt;If you have ever worked with code in which the Single Responsibility Principle was not regarded much, you probably remember the frustration when you  stumble upon a three-hundred-line method or a thousand-line class about which you need to understand something (probably a little thing), but to figure that out, you are forced to read through the whole method or the class. This not only takes a lot of time and mental energy, but also fills the "memory cache" of your brain with junk information that is completely irrelevant at the moment.&lt;/p&gt;

&lt;p&gt;However, &lt;strong&gt;it's possible to take the separation of concerns so far that it might actually become harder to understand the logic.&lt;/strong&gt; Returning to the &lt;code&gt;processTransaction()&lt;/code&gt; example, consider the following way of implementing it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;TransactionProcessor&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;TransactionInstrumentation&lt;/span&gt; &lt;span class="n"&gt;instrumentation&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

  &lt;span class="o"&gt;...&lt;/span&gt;

  &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;processTransaction&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Transaction&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;isFraud&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
      &lt;span class="n"&gt;instrumentation&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;detectedFraud&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
  &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;TransactionInstrumentation&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;Logger&lt;/span&gt; &lt;span class="n"&gt;logger&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
  &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;AlertingService&lt;/span&gt; &lt;span class="n"&gt;alertingService&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

  &lt;span class="o"&gt;...&lt;/span&gt;

  &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;detectedFraud&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Transaction&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;logger&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;log&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Detected fraud transaction {}"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;alertingService&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;sendAlert&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;FraudTransactionAlert&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="o"&gt;));&lt;/span&gt;
  &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;We extracted the observation part of the logic into a separate &lt;code&gt;TransactionInstrumentation&lt;/code&gt; class. This approach is not unreasonable. Compared to the original version, it aids the &lt;em&gt;flexibility&lt;/em&gt; and the &lt;em&gt;testability&lt;/em&gt; of the code, as we will discuss below in this article. (In fact, I took the idea directly from the excellent article about &lt;a href="https://martinfowler.com/articles/domain-oriented-observability.html"&gt;domain-oriented observability&lt;/a&gt; by Pete Hodgson.)&lt;/p&gt;

&lt;p&gt;On the other hand, it smears the logic so thin across multiple classes and methods that it would take longer to learn it than the original, at least for me.&lt;/p&gt;

&lt;p&gt;Extracting responsibilities into separate modules or services (rather than just classes) doesn't help to further improve understandability per se, however, it may help with other qualities related the learning curve: the &lt;em&gt;discoverability&lt;/em&gt; of the functionality (for example, through service API discovery) and the &lt;em&gt;observability&lt;/em&gt; of the system, which we will discuss below.&lt;/p&gt;

&lt;p&gt;Understandability itself is somewhat less important when we work on the code alone, rather than in a team. But don't abuse this - we tend to underestimate how quickly we forget the details of the code on which we worked just a little while ago and how hard it is to relearn its purpose :).&lt;/p&gt;

&lt;h3&gt;
  
  
  Flexibility
&lt;/h3&gt;

&lt;p&gt;We can easily combine independent components (via separate &lt;em&gt;control flow&lt;/em&gt; components) in different ways for different purposes or depending on configuration. Let's take &lt;code&gt;TransactionProcessor&lt;/code&gt; again:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;TransactionProcessor&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;AlertingService&lt;/span&gt; &lt;span class="n"&gt;alertingService&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

  &lt;span class="o"&gt;...&lt;/span&gt;

  &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;processTransaction&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Transaction&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;isFraud&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
      &lt;span class="n"&gt;logger&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;log&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Detected fraud transaction {}"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
      &lt;span class="n"&gt;alertingService&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;sendAlert&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;FraudTransactionAlert&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="o"&gt;));&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
  &lt;span class="o"&gt;}&lt;/span&gt;

  &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kt"&gt;boolean&lt;/span&gt; &lt;span class="nf"&gt;isFraud&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Transaction&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt; &lt;span class="o"&gt;...&lt;/span&gt; &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;To allow the operators of the system to disable alerting, we can create a &lt;code&gt;NoOpAlertingService&lt;/code&gt; and make it configurable for &lt;code&gt;TransactionProcessor&lt;/code&gt; via dependency injection. On the other hand, if the &lt;code&gt;sendAlert()&lt;/code&gt; responsibility was not separated into the &lt;code&gt;AlertingService&lt;/code&gt; interface, but rather was just a method in &lt;code&gt;TransactionProcessor&lt;/code&gt;, to make alerting configurable we would have to add a boolean field &lt;code&gt;sendAlerts&lt;/code&gt; to the class.&lt;/p&gt;

&lt;p&gt;Imagine now that we want to analyze historical transactions in a batch process. Since the &lt;code&gt;isFraud()&lt;/code&gt; method (that is, the fraud detection responsibility) is a part of &lt;code&gt;TransactionProcessor&lt;/code&gt;, this method is called during batch processing. If online and batch processing require different initialization logic, &lt;code&gt;TransactionProcessor&lt;/code&gt; has to provide a different constructor for each use case. On the other hand, if fraud detection was a concern of a separate &lt;code&gt;FraudDetection&lt;/code&gt; class, we could prevent &lt;code&gt;TransactionProcessor&lt;/code&gt; from swelling.&lt;/p&gt;

&lt;p&gt;We can notice a pattern: &lt;strong&gt;it's still possible to support different use cases and configuration for a component with multiple responsibilities, but only by increasing the size and the complexity of the component itself&lt;/strong&gt;, like adding flags and conditional logic. Little by little, this is how &lt;a href="https://en.wikipedia.org/wiki/Big_ball_of_mud"&gt;big ball of mud&lt;/a&gt; systems (aka monoliths) and &lt;a href="https://michaelfeathers.typepad.com/michael_feathers_blog/2012/09/runaway-methods.html"&gt;runaway methods&lt;/a&gt; and classes emerge. When each component has a single responsibility, we can keep the complexity of any single one of them limited.&lt;/p&gt;

&lt;p&gt;What about the "lean" approach of splitting responsibilities only when we actually need to make them configurable? I think this is a good strategy if applied with moderation. It is similar to Martin Fowler's idea of &lt;a href="https://www.martinfowler.com/articles/preparatory-refactoring-example.html"&gt;preparatory refactoring&lt;/a&gt;. Keep in mind, however, that &lt;strong&gt;if we don't keep responsibilities separate from early on, the code for them may grow to have many subtle interdependencies, so it might take much more effort to split them apart further down the road.&lt;/strong&gt; And to do this, we might also need to spend time relearning the workings of the code in more detail than we would like to.&lt;/p&gt;

&lt;h3&gt;
  
  
  Reusability
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;It becomes possible to reuse components when they have a single, narrow responsibility.&lt;/strong&gt; The &lt;code&gt;FraudDetection&lt;/code&gt; class from the previous section is an example of this: we could reuse it in online processing &lt;em&gt;and&lt;/em&gt; batch processing components. To do this in the &lt;em&gt;artifact space&lt;/em&gt;, we could pull it into a shared library. Another direction is to move fraud detection into a separate microservice: we can think about this as reusability in the &lt;em&gt;runtime space&lt;/em&gt;. The &lt;code&gt;FraudDetection&lt;/code&gt; class within our application will then turn from having business logic responsibility to do external integration with the new service.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Most methods with a narrow responsibility shouldn't have side effects and shouldn't depend on the state of the class&lt;/strong&gt;, which enables sharing and calling them from any place. In other words, the Single Responsibility Principle nudges us toward a  &lt;a href="https://en.wikipedia.org/wiki/Functional_programming"&gt;functional programming&lt;/a&gt; style.&lt;/p&gt;

&lt;p&gt;&lt;b&gt;Pro tip:&lt;/b&gt; thinking about responsibilities helps to notice &lt;a href="https://learning.oreilly.com/library/view/the-art-of/9781449318482/ch10.html"&gt;unrelated subproblems&lt;/a&gt; hiding in our methods and classes. When we extract them, we can then see opportunities to reuse them in other places. Moving unrelated subproblems out of the way keeps a component at a &lt;a href="http://principles-wiki.net/principles:single_level_of_abstraction"&gt;single level of abstraction&lt;/a&gt;, which makes easier to understand the logic of the component.&lt;/p&gt;

&lt;h3&gt;
  
  
  Testability
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;It's easier to write and maintain tests for methods and classes with focused, independent concerns.&lt;/strong&gt; This is what the &lt;a href="http://xunitpatterns.com/Humble%20Object.html"&gt;Humble Object&lt;/a&gt; pattern is all about. Let's continue playing with &lt;code&gt;TransactionProcessor&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;TransactionProcessor&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

  &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;processTransaction&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Transaction&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;boolean&lt;/span&gt; &lt;span class="n"&gt;isFraud&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="c1"&gt;// Some logic detecting that the transaction is fraud,&lt;/span&gt;
    &lt;span class="c1"&gt;// many lines of code omitted&lt;/span&gt;
    &lt;span class="o"&gt;...&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;isFraud&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
      &lt;span class="n"&gt;logger&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;log&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Detected fraud transaction {}"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
      &lt;span class="n"&gt;alertingService&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;sendAlert&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;FraudTransactionAlert&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="o"&gt;));&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
  &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;In this variant, there is no separate &lt;code&gt;isFraud()&lt;/code&gt; method. &lt;code&gt;processTransaction()&lt;/code&gt; combines fraud detection and the reporting logic. &lt;/p&gt;

&lt;p&gt;Then, to test the fraud detection, we may need to mock the &lt;code&gt;alertingService&lt;/code&gt;, which pollutes the test code with boilerplate. &lt;strong&gt;Not only does it take effort to set up mocks in the first place, but mock-based tests also tend to break every time we change anything in the production code.&lt;/strong&gt; Such tests become a permanent maintenance burden.&lt;/p&gt;

&lt;p&gt;Alternatively, to test the fraud detection logic in the example above, we could intercept and check the logging output. However, this is also cumbersome, and it hinders the ability to execute tests in parallel.&lt;/p&gt;

&lt;p&gt;It's simpler to test a separate &lt;code&gt;isFraud()&lt;/code&gt; method. But we would still need to construct a &lt;code&gt;TransactionProcessor&lt;/code&gt; object and to pass some dummy &lt;code&gt;Logger&lt;/code&gt; and &lt;code&gt;AlertingService&lt;/code&gt; objects into it. &lt;/p&gt;

&lt;p&gt;So, it's even easier to test the variant with the separate &lt;code&gt;FraudDetection&lt;/code&gt; class. Notice that to test the intermediate version without a separate &lt;code&gt;FraudDetection&lt;/code&gt; class, we often find ourselves changing the visibility of the method under test (&lt;code&gt;isFraud()&lt;/code&gt;, in this example) from private to default (package-private). &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Changing visibility of a method and the &lt;code&gt;@VisibleForTesting&lt;/code&gt; annotation are clues to think about whether it's better to split the responsibilities of the enclosing class.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Pete Hodgson also explains how extracting observability like the alerting feature into a separate class (like &lt;code&gt;TransactionInstrumentation&lt;/code&gt;) &lt;a href="https://martinfowler.com/articles/domain-oriented-observability.html#DomainProbesEnableCleanerMore-focusedTests"&gt;enables clearer, more focused tests&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;In contrast to methods and classes, &lt;strong&gt;smaller (micro)services complicate the local setup for integration testing.&lt;/strong&gt; &lt;a href="https://docs.docker.com/compose/"&gt;Docker Compose&lt;/a&gt; is a godsend, but it doesn't solve the problem fully.&lt;/p&gt;

&lt;h3&gt;
  
  
  Debuggability
&lt;/h3&gt;

&lt;p&gt;When methods and classes are focused on a single concern, we can write equally focused tests for them. &lt;strong&gt;If tests covering only a single production method or class fail we immediately know where the bug is and thus we don't need to debug.&lt;/strong&gt; Sometimes, debugging may become a large portion of the development process: for example, Michael Malis &lt;a href="https://malisper.me/how-to-improve-your-productivity-as-a-working-programmer/"&gt;reports&lt;/a&gt; that for him, it used to take as much as a quarter of the total time.&lt;/p&gt;

&lt;p&gt;When we still have to debug, we can accelerate the debugging loop by testing isolated pieces of functionality without building large graphs of objects through dependency injection or spinning up databases in &lt;a href="https://www.testcontainers.org/"&gt;Testcontainers&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;However, keep in mind that many bugs are due to one component incorrectly using another. &lt;a href="https://phauer.com/2019/focus-integration-tests-mock-based-tests/"&gt;Mistakes happen exactly in the integration of real components&lt;/a&gt;. So, &lt;strong&gt;it's important to have &lt;em&gt;both&lt;/em&gt; narrowly focused unit tests to quickly fix certain types of errors without lengthy debugging, and more integration-like tests to check that components use each other properly.&lt;/strong&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Observability and Operability
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Having methods with single responsibilities also helps to quickly pinpoint performance problems because the results of profiling become more informative&lt;/strong&gt;. At the top of a profiler's output, we can see the methods that perform badly and will know what exact responsibilities they have.&lt;/p&gt;

&lt;p&gt;When components (not only methods and classes, but also modules and distributed services) are connected with queues (either in-memory, in-process &lt;code&gt;Queue&lt;/code&gt;s, or distributed message brokers such as Kafka), we can easily monitor the sizes of the backlogs in the pipeline. Matt Welsh, the engineer who proposed the &lt;a href="https://en.wikipedia.org/wiki/Staged_event-driven_architecture"&gt;staged event-driven architecture&lt;/a&gt; (SEDA), regarded this observability of load and resource bottlenecks as &lt;a href="http://matt-welsh.blogspot.com/2010/07/retrospective-on-seda.html"&gt;the most important contribution of SEDA&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Decoupled services could be scaled up and down independently in response to the changing load, without overuse of resources. Within an application, we can control the distribution of CPU resources between method, class, and module responsibilities by sizing the corresponding thread pools. &lt;code&gt;ThreadPoolExecutor&lt;/code&gt; even supports dynamic reconfiguration in runtime via the &lt;a href="https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/util/concurrent/ThreadPoolExecutor.html#setCorePoolSize%28int%29"&gt;&lt;code&gt;setCorePoolSize()&lt;/code&gt;&lt;/a&gt; method.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;When microservices have focused responsibilities, it also helps to investigate incidents.&lt;/strong&gt; If we monitor the request success rates and health status of each service and see that one service which connects to a particular database is failing or unavailable, we may assume that the root problem lies in this database rather than any other part of the system.&lt;/p&gt;

&lt;p&gt;However, despite the advantages of finer-grained monitoring and scaling, &lt;strong&gt;splitting responsibilities between smaller services generally increases the burden of operating the system.&lt;/strong&gt; Smaller services mean more work:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Setting up and operating intermediate message queues (like Kafka) between the services.&lt;/li&gt;
&lt;li&gt;DevOps: setting up and managing separate delivery pipelines, monitoring, configuration, machine and container images.&lt;/li&gt;
&lt;li&gt;Deployment and orchestration: Kubernetes doesn't fully alleviate it.&lt;/li&gt;
&lt;li&gt;To ensure &lt;a href="https://aws.amazon.com/builders-library/ensuring-rollback-safety-during-deployments/"&gt;rollback safety&lt;/a&gt;, the deployments should be multi-phase, shared state and messages sent between services should be versioned.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Reliability
&lt;/h3&gt;

&lt;p&gt;Reliability is the first software quality in the list that we mostly hurt, not aid when we split smaller responsibilities between the components. &lt;/p&gt;

&lt;p&gt;If engineered properly (an important caveat!), a microservice architecture can increase reliability: when one service is sick, others can still serve something for the users. However, the inherent &lt;a href="https://en.wikipedia.org/wiki/Fallacies_of_distributed_computing"&gt;fallibility of distributed systems&lt;/a&gt; hits harder: more remote communications between services mean more ways of how things could go wrong, including network partition or degradation.&lt;/p&gt;

&lt;p&gt;Discussing the pros and the cons of microservices is not the main goal of this article, but there are plenty of good materials on this topic, the reliability aspect in particular: &lt;a href="https://www.martinfowler.com/articles/microservice-trade-offs.html"&gt;1&lt;/a&gt;, &lt;a href="https://dwmkerr.com/the-death-of-microservice-madness-in-2018/"&gt;2&lt;/a&gt;, &lt;a href="https://developer.ibm.com/technologies/microservices/articles/challenges-and-benefits-of-the-microservice-architectural-style-part-1/"&gt;3&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Code Size
&lt;/h3&gt;

&lt;p&gt;Smaller responsibility of each component means that there are more components in total in the system.&lt;/p&gt;

&lt;p&gt;Each method needs a signature declaration. Each class needs constructors, static factory methods, field declarations, and other ceremony. Each module needs a separate configuration class and a dependency injection setup. Each service needs separate configuration files, startup scripts, CI/CD/orchestration infrastructure, and so on.&lt;/p&gt;

&lt;p&gt;Therefore, &lt;strong&gt;the more focused responsibilities of the components we make, the more code we will need to write.&lt;/strong&gt; This impacts the long-term maintainability much less than all the qualities discussed above: understandability, flexibility, reusability, etc. However, it means that &lt;strong&gt;it takes more time and effort to develop the first version of the application with finely separated responsibilities than with larger components&lt;/strong&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Performance
&lt;/h3&gt;

&lt;p&gt;This shouldn't be a concern normally, but for the sake of completeness, we should note that a large number of smaller classes may impact the application startup time. &lt;a href="https://spring.io/blog/2018/12/12/how-fast-is-spring"&gt;An entry in the Spring blog&lt;/a&gt; has a nice chart illustrating this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--y35p6p4f--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/6ergxo8g6m8wby43ksb1.png" class="article-body-image-wrapper"&gt;&lt;img alt="JVM startup vs. classes" src="https://res.cloudinary.com/practicaldev/image/fetch/s--y35p6p4f--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/6ergxo8g6m8wby43ksb1.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Having lots of small methods taxes the application performance through method calls and returns. This is not a problem at hotspots thanks to &lt;a href="https://www.baeldung.com/jvm-method-inlining"&gt;method inlining&lt;/a&gt;, but in applications with a "flat" performance profile (no obvious hotspots), an excessive number of method calls might considerably affect the cumulative throughput.&lt;/p&gt;

&lt;p&gt;On a higher level, &lt;strong&gt;the size of services might significantly impact the efficiency of the distributed system due to the costs of RPC calls and message serialization.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;p&gt;The Single Responsibility Principle applies to software components on all levels: methods, classes, modules, and distributed services.&lt;/p&gt;

&lt;p&gt;The Single Responsibility Principle itself doesn't include guidance about how large or small a responsibility for a component should be. The optimal size depends on the specific component, the type of the application, the current development priorities, and other context.&lt;/p&gt;

&lt;p&gt;We should analyze how making the responsibilities of components smaller or larger affects the &lt;em&gt;qualities&lt;/em&gt; of the code and the system that we are developing.&lt;/p&gt;

&lt;p&gt;If we are writing proof-of-concept or throwaway code, or the relative cost of time to market/penalty for missing some deadline is super high, it's important to keep in mind that following the Single Responsibility Principle "properly" requires more effort and therefore may delay the delivery time.&lt;/p&gt;

&lt;p&gt;In other cases, we should split up responsibilities into separate methods and classes as long as the flexibility, reusability, testability, debuggability, and observability of the software keep improving, and while the code doesn't bloat too much and we still see the "forest" of the logic behind the "trees" of small methods and classes (in more formal language, the understandability of the code doesn't begin to deteriorate).&lt;/p&gt;

&lt;p&gt;This may sound overwhelming, but of course, this analysis shouldn't be done for each and every method and class in separation, but instead done infrequently to establish a guideline on the project, or just to train our intuition.&lt;/p&gt;

&lt;p&gt;On the level of the distributed system, the trade-off is much less in favor of extracting (micro)services with more narrow responsibilities: discoverability, flexibility, reusability, and observability improve, but testability, operability, reliability, and performance mostly decline. On the other hand, the Single Responsibility Principle probably shouldn't be the first thing to consider when sizing microservices. Most people in the industry think that it's more important to follow the &lt;a href="https://martinfowler.com/articles/microservices.html#OrganizedAroundBusinessCapabilities"&gt;team boundaries&lt;/a&gt;, &lt;a href="https://martinfowler.com/bliki/BoundedContext.html"&gt;bounded contexts&lt;/a&gt;, and &lt;a href="https://www.martinfowler.com/bliki/DDD_Aggregate.html"&gt;aggregates&lt;/a&gt; (the last two are concepts from Domain-Driven Design).&lt;/p&gt;




&lt;p&gt;P. S.: I explore the idea of analyzing software design practices and principles through the lenses of distinct software qualities such as understandability, testability, performance, and so on in the &lt;a href="https://en.wikiversity.org/wiki/Software_Design"&gt;Software Design&lt;/a&gt; project on Wikiversity.&lt;/p&gt;

&lt;p&gt;P. P. S.: I publish weekly &lt;a href="https://engineeringideas.substack.com/?no_cover=true"&gt;Engineering Ideas&lt;/a&gt; where I share articles and papers about software development, cloud architecture, data engineering, reliability, operations, and team culture which I find insightful.&lt;/p&gt;

</description>
      <category>softwaredesign</category>
      <category>codequality</category>
      <category>cleancode</category>
      <category>ddd</category>
    </item>
    <item>
      <title>Engineering Ideas #7</title>
      <dc:creator>Roman Leventov</dc:creator>
      <pubDate>Fri, 21 Feb 2020 14:03:08 +0000</pubDate>
      <link>https://dev.to/leventov/engineering-ideas-7-584p</link>
      <guid>https://dev.to/leventov/engineering-ideas-7-584p</guid>
      <description>&lt;h3&gt;
  
  
  &lt;a href="https://blog.acolyer.org/2020/01/17/synthesizing-data-structure-transformations/"&gt;Synthesizing data structure transformations from input-output examples&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;John Feser, Swarat Chaudhuri, Isil Dillig have created a program synthesizer capable of recreating pretty advanced functional algorithms:&lt;/p&gt;

&lt;blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;We have used λ2 to synthesize a program originally invented by Barron and Strachey. Danvy and Spivey call this program “arrestingly beautiful” and believe it to be “the world’s first functional pearl”.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The program is required to produce the Cartesian product of a set of lists.&lt;/p&gt;

&lt;p&gt;Barron and Strachey’s pearl to implement this transformation looks like this:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;cprod xss = foldr f [[]] xss where f xs yss = foldr g [] xs where g x zss = foldr h zss yss where h ys qss = cons(cons(x, ys), qss)&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Give the examples below,  synthesises exactly this program in ~84 seconds.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;[] -&amp;gt; [[]][[]] -&amp;gt; [][[], []] -&amp;gt; [][[1,2,3], [5,6]] -&amp;gt; [[1,5],[1,6],[2,5],[2,6],[3,5],[3,6]]&lt;/code&gt;&lt;/p&gt;


&lt;/blockquote&gt;

&lt;p&gt;You may say that this is very far from generating useful real-world programs. But think how long would it take you to write the algorithm above yourself? Is it less than 84 seconds? I think the machine power to apply brute force shouldn’t be discounted. And it’s easy to imagine the above synthesizer could be used to generate small utility functions in real projects.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;a href="https://lorinhochstein.wordpress.com/2020/01/19/there-is-no-escape-from-the-adaptive-universe/"&gt;There is no escape from the adaptive universe&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;By Lorin Hochstein&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;In his 2018 paper titled &lt;a href="https://www.researchgate.net/publication/327427067_The_Theory_of_Graceful_Extensibility_Basic_rules_that_govern_adaptive_systems"&gt;The theory of graceful extensibility: basic rules that govern adaptive systems&lt;/a&gt;, Woods describes the two assumptions of the adaptive universe:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Resources are always finite.&lt;/strong&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Change is ongoing.&lt;/strong&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;At first glance, the assumptions sound banal. Nobody believes in infinite resources! Nobody believes that things will stop changing! &lt;strong&gt;Yet, when we design our systems, it’s remarkable how often we don’t take these into account.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  &lt;a href="https://martinfowler.com/bliki/MonolithFirst.html"&gt;Monolith First&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;A refreshing perspective from Martin Fowler:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;I've noticed a common pattern.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Almost all the successful microservice stories have started with a monolith that got too big and was broken up&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Almost all the cases where I've heard of a system that was built as a microservice system from scratch, it has ended up in serious trouble.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This pattern has led many of my colleagues to argue that  &lt;strong&gt;you shouldn't start a new project with microservices, even if you're sure your application will be big enough to make it worthwhile.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;However, he himself acknowledged back in 2015 that this a very nuanced question and the opposite approach, as to start building a brand new system of microservices, might sometimes be a better alternative. At least, we shouldn’t choose it blindly.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The counter-argument says that starting with microservices allows you to get used to the rhythm of developing in a microservice environment. It takes a lot, perhaps too much, discipline to build a monolith in a sufficiently modular way that it can be broken down into microservices easily. By starting with microservices you get everyone used to developing in separate small teams from the beginning, and having teams separated by service boundaries makes it much easier to scale up the development effort when you need to. This is especially viable for system replacements where you have a better chance of coming up with stable-enough boundaries early.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  &lt;a href="https://martinfowler.com/articles/on-pair-programming.html"&gt;On Pair Programming&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;This is a practical overview of pair programming setup, benefits, and challenges by Birgitta Böckeler and Nina Siessegger. What I found most evocative though in this article is the conclusion, which echoes some of the ideas from Daniel Coyle’s &lt;a href="https://engineeringideas.substack.com/p/the-culture-code-by-daniel-coyle"&gt;The Culture Code&lt;/a&gt;:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;We talked a lot about the benefits of pair programming, but even more about its challenges. Pairing requires a lot of different skills to get it right, and might even influence other processes in the team. So why bother? Is it really worth the hassle?&lt;/p&gt;

&lt;p&gt;For a team to be comfortable with and successful at pair programming, they will have to work on all the skills helpful to overcome its challenges: Concentration and focus, task organisation, time management, communication, giving and receiving feedback, empathy, vulnerability - &lt;strong&gt;and these are actually all skills that help immensely to become a well-functioning, collaborative and effective team. Pairing gives everybody on the team a chance to work on these skills together.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Consider this headline from Harvard Business Review: &lt;a href="https://hbr.org/2016/09/diverse-teams-feel-less-comfortable-and-thats-why-they-perform-better"&gt;"Diverse Teams Feel Less Comfortable - and That's Why They Perform Better"&lt;/a&gt;. The authors are making the point that "Homogeneous teams feel easier - but easy is bad for performance. (...) this idea goes against many people's intuitions".&lt;/p&gt;

&lt;p&gt;In &lt;a href="https://www.youtube.com/watch?v=S92vVAEofes"&gt;this talk&lt;/a&gt;, Pia Nilsson describes measures her team at Spotify took to get over the uncomfortable friction initially caused by introducing practices like pair programming. Among other things, she mentions feedback culture, non-violent communication, &lt;a href="https://hbr.org/2017/08/high-performing-teams-need-psychological-safety-heres-how-to-create-it"&gt;psychological safety&lt;/a&gt;, humility, and having a sense of purpose.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  &lt;a href="https://www.thoughtworks.com/insights/blog/what-are-our-core-values-and-practices-building-software"&gt;The core values and practices for building software at ThoughtWorks&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;Evan Bottcher distils the software design and development strategy to four core values:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Fast feedback&lt;/strong&gt; : unit tests, CI, pair programming&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Repeatability&lt;/strong&gt; : automation, infra as code, containers, &lt;a href="https://medium.com/@maximebeauchemin/functional-data-engineering-a-modern-paradigm-for-batch-data-processing-2327ec32c42a"&gt;data immutability&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Simplicity&lt;/strong&gt; : software design, TDD&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Clean code&lt;/strong&gt; : design, refactoring, collective code ownership&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These principles apply to mobile and web development, backend development, data engineering, and Cloud and Dev Ops alike.&lt;/p&gt;

&lt;p&gt;A simple answer to whether to practice TDD or not (or any other XP/Agile practice):&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;So what if you don’t use TDD? &lt;strong&gt;Then, I’d be asking what you have in place to ensure your design is simple and you have good, fast feedback.&lt;/strong&gt; If you can convince me that the thing you’ve replaced TDD with is working (or that you’ll know when it’s not), then I’ll be happy. Same with pair programming, or any others of our core practices.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  &lt;a href="https://medium.com/@bchesky/dont-fuck-up-the-culture-597cde9ee9d4"&gt;Don’t Fuck Up the Culture&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;Brian Chesky (CEO of Airbnb) explains what culture is, in essence:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Culture is simply a shared way of doing something with passion.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;And why it is important:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Why is culture so important to a business? Here is a simple way to frame it. The stronger the culture, the less corporate process a company needs. When the culture is strong, you can trust everyone to do the right thing. &lt;strong&gt;People can be independent and autonomous. They can be entrepreneurial.&lt;/strong&gt; And if we have a company that is entrepreneurial in spirit, we will be able to take our next “(wo)man on the moon” leap.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I see parallels here with the idea from Ron Davison’s &lt;a href="http://thefourtheconomy.com/yahoo_site_admin/assets/docs/the_fourth_for_createspace_27_june_12_introductory_section.17875431.pdf"&gt;The Fourth Economy&lt;/a&gt; (see &lt;a href="https://taylorpearson.me/the-fourth-economy/"&gt;summary&lt;/a&gt; by Taylor Pearson) that one of the drivers of growth in the 21st century will be entrepreneurship.&lt;/p&gt;




&lt;p&gt;You can subscribe to new Engineering Ideas &lt;a href="https://engineeringideas.substack.com/feed"&gt;via RSS&lt;/a&gt; (e. g. using &lt;a href="https://feedly.com/"&gt;Feedly&lt;/a&gt;) or &lt;a href="https://engineeringideas.substack.com/subscribe"&gt;e-mail&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>complexsystems</category>
      <category>microservices</category>
      <category>agile</category>
      <category>culture</category>
    </item>
    <item>
      <title>Engineering Ideas #6</title>
      <dc:creator>Roman Leventov</dc:creator>
      <pubDate>Fri, 14 Feb 2020 13:53:13 +0000</pubDate>
      <link>https://dev.to/leventov/engineering-ideas-6-4oa6</link>
      <guid>https://dev.to/leventov/engineering-ideas-6-4oa6</guid>
      <description>&lt;h3&gt;
  
  
  &lt;a href="https://blog.softwaremill.com/will-project-loom-obliterate-java-futures-fb1a28508232"&gt;Will Project Loom obliterate Java Futures?&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;Another great post by Adam Warski discussing the tradeoffs of different models of concurrent programming: futures, green threads, coroutines, &lt;code&gt;IO&lt;/code&gt; monad, actors.&lt;/p&gt;

&lt;p&gt;Warski makes an analogy of RPC to demonstrate that boilerplate around async calls (which Project Loom aims to eliminate) is not necessarily a bad thing:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;RPCs, and any network calls in general, have a significantly different characteristic than a normal function call. They are unpredictable: can  &lt;strong&gt;arbitrarily fail&lt;/strong&gt; , regardless of the value of input parameters. They can take an  &lt;strong&gt;arbitrary amount of time&lt;/strong&gt;  to complete, while a normal function completes, fails or loops. And even if a network call  &lt;strong&gt;seems to have failed&lt;/strong&gt; , it might have still succeeded from the viewpoint of the other system. […] The fact that a normal function call is also  &lt;strong&gt;syntactically distinct&lt;/strong&gt;  from an RPC call, might be an advantage to readability.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Martin Thompson brings insight into why Loom Fibers won’t magically solve all performance problems with our concurrent applications:&lt;/p&gt;


&lt;blockquote class="ltag__twitter-tweet"&gt;

  &lt;div class="ltag__twitter-tweet__main"&gt;
    &lt;div class="ltag__twitter-tweet__header"&gt;
      &lt;img class="ltag__twitter-tweet__profile-image" src="https://res.cloudinary.com/practicaldev/image/fetch/s--MFvID0JD--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://pbs.twimg.com/profile_images/1467106821/Ren_normal.jpg" alt="Martin Thompson profile image"&gt;
      &lt;div class="ltag__twitter-tweet__full-name"&gt;
        Martin Thompson
      &lt;/div&gt;
      &lt;div class="ltag__twitter-tweet__username"&gt;
        @mjpt777
      &lt;/div&gt;
      &lt;div class="ltag__twitter-tweet__twitter-logo"&gt;
        &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--P4t6ys1m--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://practicaldev-herokuapp-com.freetls.fastly.net/assets/twitter-f95605061196010f91e64806688390eb1a4dbc9e913682e043eb8b1e06ca484f.svg" alt="twitter logo"&gt;
      &lt;/div&gt;
    &lt;/div&gt;
    &lt;div class="ltag__twitter-tweet__body"&gt;
      &lt;a href="https://twitter.com/pressron"&gt;@pressron&lt;/a&gt; &lt;a href="https://twitter.com/rafaelcodes"&gt;@rafaelcodes&lt;/a&gt; Physics is teaching that the only way to advance IO operations is asynchronous &amp;amp; batching, IO APIs are evolving to this. Fibers encourage using synchronous imperative code, i.e. old APIs. It is the delusion of RPC all over again.
    &lt;/div&gt;
    &lt;div class="ltag__twitter-tweet__date"&gt;
      07:31 AM - 24 Sep 2019
    &lt;/div&gt;


    &lt;div class="ltag__twitter-tweet__actions"&gt;
      &lt;a href="https://twitter.com/intent/tweet?in_reply_to=1176398670033502209" class="ltag__twitter-tweet__actions__button"&gt;
        &lt;img src="/assets/twitter-reply-action.svg" alt="Twitter reply action"&gt;
      &lt;/a&gt;
      &lt;a href="https://twitter.com/intent/retweet?tweet_id=1176398670033502209" class="ltag__twitter-tweet__actions__button"&gt;
        &lt;img src="/assets/twitter-retweet-action.svg" alt="Twitter retweet action"&gt;
      &lt;/a&gt;
      0
      &lt;a href="https://twitter.com/intent/like?tweet_id=1176398670033502209" class="ltag__twitter-tweet__actions__button"&gt;
        &lt;img src="/assets/twitter-like-action.svg" alt="Twitter like action"&gt;
      &lt;/a&gt;
      4
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/blockquote&gt;


&lt;p&gt;Warski distills a persuasive strategy about picking up a concurrency model for the task:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;When doing a  &lt;strong&gt;simple service&lt;/strong&gt; , small application or a quick script, I don’t want to deal with any kind of wrappers, be it &lt;code&gt;Future&lt;/code&gt; or &lt;code&gt;IO&lt;/code&gt;. Fibers and their “codes like sync, works like async” model will make my life much easier.&lt;/p&gt;

&lt;p&gt;When writing a  &lt;strong&gt;business application&lt;/strong&gt; , I might want to use the synchronous-like API that Loom &lt;code&gt;Fiber&lt;/code&gt;s enable to express the business logic, using well-known constructs to express the control flow within a business process. However, to orchestrate concurrently running computations, handle errors and allocate resources, I’ll use an &lt;code&gt;IO&lt;/code&gt;-like abstraction.&lt;/p&gt;

&lt;p&gt;Finally, for a  &lt;strong&gt;high-performance&lt;/strong&gt;  asynchronous system, I’ll probably take the fully-asynchronous approach, working with state machines, callbacks or &lt;code&gt;Future&lt;/code&gt;s.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I want to contrast the above discourse with a quote from &lt;a href="https://bradfitz.com/2020/01/30/joining-tailscale"&gt;this blog post&lt;/a&gt; by Brad Fitzpatrick:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The Go runtime is relatively complex internally but it permits simple APIs and programming models for users who then don't need to worry about memory management, thread management, blocking, the &lt;a href="https://journal.stuffwithstuff.com/2015/02/01/what-color-is-your-function/"&gt;color of their functions&lt;/a&gt;, etc.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;By not having Futures, indeed, Go avoids &lt;a href="https://github.com/code-review-checklists/java-concurrency"&gt;a lot of complexity which we have with concurrency in Java&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;a href="https://aws.amazon.com/builders-library/avoiding-fallback-in-distributed-systems/"&gt;Avoiding fallback in distributed systems&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;Jacob Gabrielson shares many non-intuitive observations and actionable tactics for improving reliability.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;At Amazon, we avoid fallback in our systems because it’s difficult to prove and its effectiveness is hard to test. Fallback strategies introduce an operational mode that a system enters only in the most chaotic moments where things begin to break, and switching to this mode only increases the chaos.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Pre-allocate:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;For critical single-machine applications that must work in case of memory allocation failures, one solution is to pre-allocate all heap memory on startup and never rely on malloc again, even under error conditions.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;In “&lt;a href="https://medium.com/@adrianco/failure-modes-and-continuous-resilience-6553078caad5"&gt;Failure Modes and Continuous Resilience&lt;/a&gt;”, Adrian Cockcroft mentions a similar idea in the context of failover to a different availability zone: at a critical moment, the control plane service may fail, too (or appear to not work due to problems in code or configuration, that was not noticed earlier because it is not usually exercised), so instances/databases/networks could instead be pre-allocated in the secondary region in a cold standby fashion.&lt;/p&gt;

&lt;p&gt;Replace pull with push:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The IAM service needs to provide signed, rotated credentials to code running on EC2 instances. To avoid ever needing to fall back, the credentials are proactively pushed to every instance and remain valid for many hours. This means that IAM role-related requests keep working in the unlikely event of a disruption in the push mechanism.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Convert fallback into failover, which falls into the pattern of &lt;strong&gt;constant work&lt;/strong&gt; :&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;A service must run both the fallback and the non-fallback logic continuously. It must not merely run the fallback case but also treat it as an equally valid source of data. For example, a service might randomly choose between the fallback and non-fallback responses (when it gets both back) to make sure they're both working.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Do you monitor retries in your system already?&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;We maintain metrics that monitor overall retry rates and alarms that alert our teams if retries are happening frequently.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;&lt;a href="https://keavy.com/work/where-to-start/"&gt;Where to Start&lt;/a&gt;&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Keavy McMinn on how to start a new project: talk with people. Customers, colleagues, industry peers.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;A great question I learnt more recently, while sitting in on a colleague interviewing a customer, was “What question do you wish I’d asked you?”.&lt;/p&gt;

&lt;p&gt;My experiences have taught me that if you want to produce the &lt;em&gt;right&lt;/em&gt; thing, that has rich and lasting impact, this starting point of finding people, talking to and learning from them is fundamental. For me it’s the precursor before the technical research and experiments can truly begin.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  &lt;a href="https://news.ycombinator.com/item?id=5496914"&gt;What makes engineers productive&lt;/a&gt;?
&lt;/h3&gt;

&lt;p&gt;From an HN comment by Jonathan Tang:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;a href="https://www.newyorker.com/magazine/2018/12/10/the-friendship-that-made-google-huge"&gt;Jeff &amp;amp; Sanjay&lt;/a&gt; have a reputation as rockstars because they can apply this productivity to things that really matter; they're able to pick out the really important parts of the problem and then focus their efforts there so that the end result ends up being much more impactful than what the SWE3 wrote. The SWE3 may spend his time writing a bunch of unit tests that catch bugs that wouldn't really have happened anyway, or migrating from one system to another that isn't really a large improvement, or going down an architectural dead-end that'll just have to be rewritten later.  &lt;/p&gt;

&lt;p&gt;Jeff or Sanjay will spend their time running a proposed API by clients to ensure it meets their needs, or measuring the performance of subsystems so they fully understand their building blocks, or mentally simulating the operation of the system before building it so they rapidly test out alternatives. They don't actually write more code than a junior developer (oftentimes, they write less), but the code they do write gives them more information, which makes them ensure that they write the right code.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;… these developers rapidly become 1x developers (or worse) if you don't let them make their own architectural choices - the reason they're excellent in the first place is because they know how to determine if certain work is going to be useless and avoid doing it in the first place.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  &lt;a href="https://srvaroa.github.io/paas/infrastructure/platform/kubernetes/cloud/2020/01/02/talk-how-to-build-a-paas-for-1500-engineers.html"&gt;How to build a PaaS for 1500 engineers&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;Galo Navarro highlights the most important question every platform infrastructure team should ask themselves:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;A Platform team should really avoid competing against AWS, Google, or any commercial company&lt;/strong&gt;. It doesn’t matter if their homegrown CI system is superior, today, to &lt;code&gt;$commercial_ci_system&lt;/code&gt;. The market will catch up, faster than expected, and make that team redundant. Every Platform team should be asking themselves: what is our differentiator? What do we offer than makes it worthwhile &lt;em&gt;for our company&lt;/em&gt; to invest in &lt;em&gt;our&lt;/em&gt; team, rather than throwing those engineers at the product?&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The main value we provide is in the joints, the articulation, the glue.&lt;/strong&gt; In how we integrate together all these systems. […] We focus on what is specific for &lt;em&gt;our&lt;/em&gt; company, tailoring off-the-shelf solutions to &lt;em&gt;our&lt;/em&gt; needs.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  &lt;a href="https://danluu.com/learning-to-program/"&gt;How I learned to program&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;Dan Luu on the benefits of having an up-front design phase on project with the invention and implementation phases more challenging than the discovery phase (see &lt;a href="https://twitter.com/grady_booch/status/956953058574876672"&gt;Grady Booch’s phases&lt;/a&gt;):&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Working through a design collaboratively teaches everyone on the team everyone else's tricks. It's a lot like the kind of skill transfer you get with pair programming, but applied to design.&lt;/p&gt;

&lt;p&gt;The iteration speed is much faster in the design phase, where throwing away a design just means erasing a whiteboard. Once you start coding, iterating on the design can mean throwing away code; for infrastructure projects, that can easily be person-years or even tens of persons-years of work. […] &lt;strong&gt;I've seen teams on projects of similar scope insist on getting "working" code as soon as possible. In every single case, that resulted in massive delays as huge chunks of code had to be re-written&lt;/strong&gt; , and in a few cases the project was fundamentally flawed in a way that required the team had to start over from scratch.&lt;/p&gt;

&lt;p&gt;I get that on product-y projects, where you can't tell how much traction you're going to get from something, you might want to get an &lt;a href="https://en.wikipedia.org/wiki/Minimum_viable_product"&gt;MVP&lt;/a&gt; out the door and iterate, but for pure infrastructure, it's often possible to predict how useful something will be in the design phase.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;He also confirms the importance of design docs, which lines up with &lt;a href="https://engineeringideas.substack.com/p/engineering-ideas-5"&gt;the practices at Uber&lt;/a&gt; shared by Gergely Orosz:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;I noticed a curiously strong correlation between the quality of initial design docs and the success of projects.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;p&gt;You can subscribe to new Engineering Ideas &lt;a href="https://engineeringideas.substack.com/feed"&gt;via RSS&lt;/a&gt; (e. g. using &lt;a href="https://feedly.com/"&gt;Feedly&lt;/a&gt;) or &lt;a href="https://engineeringideas.substack.com/subscribe"&gt;e-mail&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>java</category>
      <category>reliability</category>
      <category>productivity</category>
      <category>systemdesign</category>
    </item>
    <item>
      <title>The Culture Code by Daniel Coyle - notes on the book</title>
      <dc:creator>Roman Leventov</dc:creator>
      <pubDate>Fri, 24 Jan 2020 16:39:20 +0000</pubDate>
      <link>https://dev.to/leventov/the-culture-code-by-daniel-coyle-notes-on-the-book-3lep</link>
      <guid>https://dev.to/leventov/the-culture-code-by-daniel-coyle-notes-on-the-book-3lep</guid>
      <description>&lt;p&gt;I’ve listened to Daniel Coyle’s &lt;a href="http://danielcoyle.com/the-culture-code/"&gt;The Culture Code&lt;/a&gt; after reading &lt;a href="http://danielcoyle.com/excerpt-culture-code/"&gt;the excerpt&lt;/a&gt; which resonated with me greatly. Thanks to Subbu Allamaraju who pointed to this book in his post about &lt;a href="https://m.subbu.org/status-management-d632e3c73d12"&gt;Status Management&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The book has changed the way I think about work profoundly: even more than &lt;strong&gt;&lt;a href="https://www.amazon.com/Effective-Executive-Definitive-Getting-Things/dp/B01N51TCT1"&gt;The Effective Executive&lt;/a&gt;&lt;/strong&gt; by Peter Drucker and &lt;strong&gt;&lt;a href="https://www.principles.com/"&gt;Principles: Life and Work&lt;/a&gt;&lt;/strong&gt; by Ray Dalio, and comparably to Cal Newport’s &lt;strong&gt;&lt;a href="https://www.calnewport.com/books/deep-work/"&gt;Deep Work&lt;/a&gt;&lt;/strong&gt;. I would say “The Culture Code” is a must-read for everyone who works in a team. These “Engineering Ideas” are my notes on the book. Many of them are direct citations from the book, © Daniel Coyle.&lt;/p&gt;




&lt;blockquote&gt;
&lt;p&gt;Culture is not something you are, it’s something you do.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Safety
&lt;/h3&gt;

&lt;p&gt;Small features of groups with chemistry (&lt;em&gt;belonging queues&lt;/em&gt;):&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Close physical proximity, often in circles&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;A profuse amount of eye-contact&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Physical touch, handshakes, fist bumps, hugs&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Lots of short energetic exchanges, no long speeches&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;High level of mixing, everyone talks to everyone&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Few interruptions&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Lots of questions&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Intensive, active listening&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Humour&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Laughter&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Small attentive courtesies, thank yous, opening doors&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Qualities of belonging queues:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Energy: they invest in the exchange that is occurring.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Individualization: they treat the person as unique and valued.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Future-orientation: they signal the relationship will continue.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Belonging queues translate into the message: “You are safe here”.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Believe firmly in what you are saying if you want others to believe in it.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Team performance is driven by five measurable factors:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Everyone in the group talks and listens in roughly equal measure, keeping contribution short.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Members maintain high levels of eye contact, and their conversations and gestures are energetic.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Members communicate directly with one another, not just with the team leader.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Members carry on back-channel or side conversations within the team.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Members periodically break, go explore outside the team and bring back what they have found to share information with the others.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;/blockquote&gt;

&lt;p&gt;Words are noise. Group performance is determined by behaviors that translate one powerful and overarching idea: “We are safe and connected”.&lt;/p&gt;

&lt;p&gt;Three models in startups:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Star model: hire the best.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Professional model: build groups around specific skillsets.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Commitment model: build a group with shared values and strong emotional bonds. This model leads to a higher rate of success.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Give people a signal that you care about them to boost their motivation.&lt;/p&gt;

&lt;p&gt;Thinking about our connections boosts our sense of autonomy.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Belonging needs to be committed and reinforced constantly.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Connect when interviewing to see if you can become friends with these people.&lt;/p&gt;

&lt;p&gt;Connect on something that is bigger than the profession with colleagues. Eat together.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Not achieving happiness, but solving hard problems.&lt;/strong&gt; Look if people are oriented at that.&lt;/p&gt;

&lt;p&gt;Magic feedback: “ &lt;strong&gt;I’m giving this feedback because I have very high expectations, and I know that you can reach it.”&lt;/strong&gt; There are three queues in this phrase: “You are part of this group”, “This place is special”, “I believe in you.”&lt;/p&gt;

&lt;h3&gt;
  
  
  Cooperation and Vulnerability
&lt;/h3&gt;

&lt;p&gt;Look into persons’ faces when they speak. Nod. Ask “What do you mean by that?”, “Could you tell more about this?”&lt;/p&gt;

&lt;p&gt;Listen with eyes wide open, still, slightly leaning towards the speaker, eyebrows slightly up, generating a constant stream of affirmations.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;It’s important not to interrupt the speaker. Top salespeople hardly ever interrupt others.&lt;/strong&gt; Distinguish, however, between interruptions from mutual excitement and due to lack of concern.&lt;/p&gt;

&lt;p&gt;Spotlight your fallibility early on, especially if you are a leader. Show your mistakes. Invite input with phrases like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;These are just my two cents.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Of course, I could be wrong here.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;What am I missing?&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;What do you think?&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Ask questions. Listen keenly. Radiate humility.&lt;/p&gt;

&lt;p&gt;Say something emotional, like “I’m terrified of”, to invite a deeper connection because it sparks a response in the listener “How can I help you?”&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Proactively invite feedback. It’s hard for people to raise a hand and say “I have something tentative to say.”&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Thank people over the top. It ignites cooperation, even with very different persons. Thank the least powerful person in the group.&lt;/p&gt;

&lt;p&gt;Ensure everyone has a voice.&lt;/p&gt;

&lt;p&gt;Find ways to show equality and do small favors to the group, e. g. pick up trash. These actions send a signal: “We are all here together.”&lt;/p&gt;

&lt;p&gt;Pay attention to the day of joining the group. Note this special moment: “We are together, now.”&lt;/p&gt;

&lt;p&gt;Separate positive and negative feedback into separate processes.&lt;/p&gt;

&lt;p&gt;Handle negative feedback as a dialogue:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Ask if a person wants feedback.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Have a learning focus to a two-way conversation about the needed growth.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Note positives through ultra-clear bursts of recognition and praise.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Embrace fun. &lt;strong&gt;Laughter is the most fundamental sign of safety and connection.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Vulnerability doesn’t come after trust, it precedes it.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;When it comes to creating cooperation, vulnerability is not a risk, but a phycological requirement.&lt;/p&gt;

&lt;p&gt;Leaving yourself wide open, so that everybody knows who you are, if done right, can build the level of trust times higher that you can get any other way.&lt;/p&gt;

&lt;p&gt;One person telling other people what to do is not a reliable way to make good decisions.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Try to avoid &lt;a href="https://en.wikipedia.org/wiki/Authority_bias"&gt;authority bias&lt;/a&gt;.&lt;/strong&gt; You have to go around those barriers, but they never go away.&lt;/p&gt;

&lt;p&gt;When giving your opinion, be careful to attach phrases like “Let’s see if someone can poke holes in this”, “Tell me what’s wrong with this idea?”&lt;/p&gt;

&lt;p&gt;Steer away from giving orders, and instead ask a lot of questions. “Anybody have any ideas?”&lt;/p&gt;

&lt;p&gt;Tell subordinates explicitly that they must speak up whenever it seems to them that something is wrong with your decision or conduct.&lt;/p&gt;

&lt;p&gt;Spending time outside work together helps to avoid authority bias. Hard challenges work even better (like going through an obstacle race under a rain).&lt;/p&gt;

&lt;p&gt;Design truth-telling sessions, reflections/retrospectives on past projects.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;“I skewed that up” might be the most important thing any leader can say.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Good retrospectives follow a template. Go over the project chronologically and ask a lot of “why” questions.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The goal of retrospectives is to build shared mental models that could be applied in future projects.&lt;/strong&gt; Eventually, everybody should be able to see what’s really happening, not just a small piece of it.&lt;/p&gt;

&lt;p&gt;Make sure people understand how their actions affect others.&lt;/p&gt;

&lt;p&gt;“Backbone of humility” is the tone of a good retrospective. The relentless will to see the truth and take ownership.&lt;/p&gt;

&lt;p&gt;Combining openness with discipline is not easy, but does pay off.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Real courage is seeing the truth and speaking the truth to each other. Nobody wants to say “Wait a second, what’s really going on here?”&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Combine warmth and curiosity. Capture what someone is doing, throw some new ideas at them and ask “Why don’t you try that?”&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;a href="http://danielcoyle.com/tips-cooperation/"&gt;Make sure the leader is vulnerable first and often.&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Deliver the message “I’m scared” with steadiness, confidence, and comfort that underline the deeper message: “It’s safe to tell the truth here.”&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Laszlo Bock, head of People Analytics at Google, recommends that leaders ask their people three questions:&lt;br&gt;&lt;br&gt;
&lt;strong&gt;– What is one thing that I currently do that you’d like me to continue to do?&lt;br&gt;&lt;br&gt;
– What is one thing that I don’t currently do frequently enough that you think I should do more often?&lt;br&gt;&lt;br&gt;
– What can I do to make you more effective?&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
“The key is to ask not for five or ten things but just one,” Bock says. “That way it’s easier for people to answer. And when a leader asks for feedback in this way, it makes it safe for the people who work with them to do the same. It can get contagious.”&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Overcommunicate expectations. The successful groups I’ve visited did not presume that cooperation would happen on its own.&lt;/strong&gt; Instead, they were explicit and persistent about sending big, clear signals that established expectations, modeled cooperation, and aligned language and roles to maximize helpful behavior.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The more complex the problem, the more help you need to solve it. Explicitly define helpful roles and generate vulnerabilities. Fill chats with help requests.  &lt;/p&gt;

&lt;p&gt;Collaborate. Make others successful. &lt;strong&gt;Going out of your way to help others is a secret sauce.&lt;/strong&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;a href="http://danielcoyle.com/tips-cooperation/"&gt;Deliver the Negative Stuff in Person&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This was an informal rule that I encountered at several groups I researched. It goes like this: if you have negative news or feedback to give someone—even as small as a rejected item on an expense report—you are obligated to deliver that news face to face. This rule is not easy to follow (it’s far more comfortable for both the sender and receiver to communicate electronically), but it works because it deals with tension in an up-front, honest way that avoids misunderstandings and creates shared clarity and connection.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Two critical moments in forming of a group:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;The first vulnerability&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The first disagreement&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;These are doorways to paths:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Appearing “strong” and winning interactions.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Exploring the landscape and learning together.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Good listening is not just nodding attentively. It’s about adding insight and creating moments of mutual discovery.&lt;/strong&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Effective listeners&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Interact in a way that makes the other person feel safe and supported.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Take a helpful, cooperative stance.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Occasionally ask questions that gently and constructively challenge old assumptions.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Make occasional suggestions to open up alternative paths.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Effective listeners are active responders, absorbing what the other person gives, supporting them, and adding energy to help the conversation gain velocity.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;When asking questions, don’t stop at the first response. Find different ways to explore the area of tension, ask secondary “whys”. The first response is usually not the answer, it’s just the first response.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;In conversations, resist the temptation to reflexively add value. Vulnerability is often created by what you do&lt;/strong&gt; _ &lt;strong&gt;not&lt;/strong&gt; _ &lt;strong&gt;say.&lt;/strong&gt; Don’t interrupt with “quick ideas” or your experiences.&lt;/p&gt;

&lt;p&gt;Candour, not brutal honesty. &lt;strong&gt;Make feedback smaller, more targeted, less personal, less judgemental.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Flash mentorship: shadow every teammate for a few hours.&lt;/p&gt;

&lt;h3&gt;
  
  
  Purpose
&lt;/h3&gt;

&lt;p&gt;Repeat your mission every day during a standup.&lt;/p&gt;

&lt;p&gt;Mental contrasting:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Think of your goal and imagine you’ve achieved it.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Picture the obstacles vividly.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Motivation is not a possession, but rather a result of a two-part process of channeling your attention: where you are and where you want to go.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Stories are the best thing ever created for delivering mental models that drive behavior.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Effective learning culture:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Conceptualize learning as something that will help end goal (or customers) rather than as an add-on to existing practices.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Explicitly tell why each role on the team is important for ultimate success.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Don’t just dive into action. Design deliberate learning practice with post-analysis and talking about communication.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Encourage people to speak up if they see any problem and use active coaching.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Use retrospectives.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Response to setbacks with energy to fix things (love problems). Help colleagues. The number one job is to take care of each other.&lt;/p&gt;

&lt;p&gt;If somebody behaves poorly, you should avoid judging them and instead give them the benefit of the doubt.&lt;/p&gt;

&lt;p&gt;Don’t spread negative energy in the workplace (e. g. if you have a bad mood).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;You have priorities, whether you name them or not. If you want to grow, you would better name them explicitly, as well as the behaviors that support these priorities.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Create engagement around a clear, simple set of priorities.&lt;/p&gt;

&lt;p&gt;Creating purpose in a creative group is about building systems that can churn through lots of ideas in order to help unearth the right choices.&lt;/p&gt;

&lt;p&gt;Non-catchy phrases for teams of people who need to discover what to do for themselves (creativity):&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Hire people smarter than you.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Fail early, fail often.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Listen to everyone’s ideas.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Face toward the problems.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;It’s more important to invest in good people than in good ideas.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;Building creative purpose isn’t about creativity. It’s about building ownership, providing support, and aligning the group’s energy towards an arduous, error-filled, ultimately fulfilling journey of making something new.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;(This description reminds me of the &lt;a href="https://en.wikipedia.org/wiki/Hero%27s_journey"&gt;hero’s journey&lt;/a&gt;.)&lt;/p&gt;

&lt;p&gt;Successful cultures use crises to crystallize their purpose. Be grateful when reflecting on failures. They are crucial to discover what you (or the team) can be.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;a href="http://danielcoyle.com/tips-purpose/"&gt;Name and Rank Your Group’s Priorities&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Obvious but true: in order to move toward a target, you must first have a target. Listing your priorities, which means wrestling with the choices that define your identity, is the first step. Most successful groups end up with a small handful of priorities (five or fewer), and &lt;strong&gt;many, not coincidentally, end up placing their in-group relationships—how they treat one another—at the top of the list. This reflects the truth that many successful groups realize: their greatest project is building and sustaining the group itself. If they get their own relationships right, everything else will follow.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Be ten times as clear about your priorities as you think you should be. &lt;strong&gt;It’s necessary to drastically overcommunicate priorities.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Regularly challenge the company’s values and purpose. Create conversations that encourage people to grapple with the big questions. What are we about? Where are we headed?&lt;/p&gt;

&lt;p&gt;Figure out where your group aims for proficiency, and where it aims for creativity.&lt;/p&gt;

&lt;p&gt;Proficiency: building purpose to perform these skills is like building a vivid map. Spotlight the goal and provide crystal-clear directions to the checkpoints along the way.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Fill the group’s windshield with clear, accessible models of excellence.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Provide high-repetition, high-feedback training.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Build vivid, memorable rules of thumb: if X, then Y.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Spotlight and honor the fundamentals of the skill.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Creativity: empowering the group to do the hard work of doing something that has never existed before. “Supplying an expedition”: provide support, fuel, and tools.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Keenly attend the team’s composition and dynamics.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Define, reinforce, and relentlessly protect the team’s creative autonomy.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Make it safe to fail and to give feedback.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Celebrate hugely when the group takes initiative.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;You can subscribe to new Engineering Ideas &lt;a href="https://engineeringideas.substack.com/feed"&gt;via RSS&lt;/a&gt; (e. g. using &lt;a href="https://feedly.com/"&gt;Feedly&lt;/a&gt;) or &lt;a href="https://engineeringideas.substack.com/subscribe"&gt;e-mail&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>teams</category>
      <category>culture</category>
      <category>leadership</category>
      <category>communication</category>
    </item>
  </channel>
</rss>
