<?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: Sergey</title>
    <description>The latest articles on DEV Community by Sergey (@sazonov).</description>
    <link>https://dev.to/sazonov</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%2F1439906%2F162ea686-673b-4e11-9f80-e9cb1377d707.jpg</url>
      <title>DEV Community: Sergey</title>
      <link>https://dev.to/sazonov</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/sazonov"/>
    <language>en</language>
    <item>
      <title>Twelve Books I’ve read in 2024 as a Product Team Technical Leader</title>
      <dc:creator>Sergey</dc:creator>
      <pubDate>Mon, 06 Jan 2025 13:13:43 +0000</pubDate>
      <link>https://dev.to/sazonov/twelve-books-ive-read-in-2024-as-a-product-team-technical-leader-4eal</link>
      <guid>https://dev.to/sazonov/twelve-books-ive-read-in-2024-as-a-product-team-technical-leader-4eal</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;According to Darwin's Origin of Species, it is not the most intellectual of the species that survives; it is not the strongest that survives; but the species that survives is the one that is able best to adapt and adjust to the changing environment in which it finds itself.&lt;/em&gt;&lt;br&gt;
— &lt;strong&gt;Leon C. Megginson&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;




&lt;p&gt;I started 2024 by leading the architectural design for a complex, distributed, data-intensive feature, and eventually stepped up as a Tech Lead of a Product Team. Along the way, I realized I needed to deepen my skills in areas like product discovery, user experience, building solutions that truly deliver value to users and the business, as well as diving deeper into architecture, systems design, and delivery processes.&lt;/p&gt;

&lt;p&gt;As I’m not the fastest reader, I faced the challenge of fitting all these areas of improvement into my limited time - so I had to pick titles very wisely. The company I work for - Welltory - helped immensely by nudging our whole team onto a steep learning curve through recommended reading and an external coaching opportunity. That’s how the books by Marty Cagan and Teresa Torres landed on my list. The rest I handpicked to ensure both breadth and relevance to my work challenges, and it turned out great - I've got tons of value and inspiration reading these books. Moreover, I’ve found a number of titles on my list that perfectly complement each other, creating a broader and more complete vision.&lt;/p&gt;

&lt;p&gt;So here is my list with very brief reviews:&lt;/p&gt;




&lt;p&gt;When 2024 kicked off, I was neck-deep in one of the most exciting (and challenging) projects I've ever worked on - leading the architecture for a distributed, data-heavy feature within &lt;a href="https://welltory.com" rel="noopener noreferrer"&gt;Welltory Health app&lt;/a&gt;. Not long after, I leveled up to Tech Lead for a Product Team. Sounds cool, right? As any career challenge, this one required a ton of learning.&lt;/p&gt;

&lt;p&gt;I needed to get better at things like understanding users, designing solutions that actually solve their problems, and delivering real value to both users and the business. Oh, and on top of that, I wanted to dig deeper into architecture, systems design, and delivery workflows.&lt;/p&gt;

&lt;p&gt;Here’s the catch: I’m not a fast reader, and there’s only so much time in a day. So, I had to choose my learning resources carefully. Thankfully, the company I work for, Welltory, really came through by encouraging us to grow, sharing great book recommendations, and even offering external coaching. That’s how books by Marty Cagan and Teresa Torres ended up on my desk.&lt;/p&gt;

&lt;p&gt;The rest of my reading list? I handpicked it to make sure it covered a range of topics but stayed super relevant to my work. It worked out better than I expected! Not only did I learn a ton, but a lot of the books complemented each other, giving me a clearer, bigger picture of what I needed to grow as a Tech Lead and a member of a Product Team.&lt;/p&gt;

&lt;p&gt;My reading list can be divided into three categories:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Product Discovery and Delivery &lt;/li&gt;
&lt;li&gt;Systems Design&lt;/li&gt;
&lt;li&gt;Personal Productivity and Creativity&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Below is the reading list I put together, along with my thoughts on each book. I hope it might inspire you, too!&lt;/p&gt;

&lt;h2&gt;
  
  
  Product Discovery and Delivery
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. Empowered. Marty Cagan, Chris Jones (&lt;a href="https://www.amazon.com/EMPOWERED-Ordinary-Extraordinary-Products-Silicon/dp/111969129X?crid=2SBT4A1XCDB6I&amp;amp;dib=eyJ2IjoiMSJ9._Uk6Fuwj2Rm2wDwOy60Hz1dC1cB059zkLePCIptzpqfE_W94u36nj7uFL4J2rid5CgtnnzWoxrFMzo5EHDlLo_xtx7TtTHFPuOP2mskr8r6awLEM2WlboB3XhoP_OvydzHhd0dtTfInHFbHgzjp75ilZ6o4N5IP4ATw3fMGSKFOm8TkBDKstztE9a0_bKY4gTMkgDhodQ_FIMaZY-fP2I6aMt0s1ZEZeo5CwYYzJhGM.qpDmXpQhILoYao29tD3udgy0e0j6EISn8V6cyUwxVHA&amp;amp;dib_tag=se&amp;amp;keywords=empowered&amp;amp;qid=1734870253&amp;amp;s=books&amp;amp;sprefix=empowere%2Cstripbooks-intl-ship%2C227&amp;amp;sr=1-1" rel="noopener noreferrer"&gt;Amazon&lt;/a&gt;, &lt;a href="https://www.audible.com/pd/Empowered-Audiobook/1663709777?eac_link=nv2U1sN4qpBz&amp;amp;ref=web_search_eac_asin_2&amp;amp;eac_selected_type=asin&amp;amp;eac_selected=1663709777&amp;amp;qid=b3NRWosRPk&amp;amp;eac_id=138-0708236-4963718_b3NRWosRPk&amp;amp;sr=1-2" rel="noopener noreferrer"&gt;Audible&lt;/a&gt;)
&lt;/h3&gt;

&lt;p&gt;Addressed to managers of Product Teams and Product Leaders, but definitely a must-read for Product Managers, Product Designers, and Tech Leads. The book highlights the significance of trust, autonomy, and accountability, emphasizes the role of coaching, and provides advice and tools for running discovery and delivery while managing stakeholders and building their trust.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Transformed. Marty Cagan, Lea Hickman, Chris Jones, Christian Idiodi, John Moore (&lt;a href="https://www.amazon.com/Transformed-Moving-Product-Operating-Silicon-ebook/dp/B0CXG97J55?crid=2PLI86U3A746R&amp;amp;dib=eyJ2IjoiMSJ9.U5sTexIkJhX3hmj9oCWbqCwY_1tBhQCpc-IpQbwlvh8F_6LF2vCFgxORLkjWK0Qxt-0JjDrbSlkUCNpRBPhUCX4HiEI7vX2BxB9HWMRKKlfAxgLVKfHYsgYLBYRLQ_drnzqXFyAacO23dnintOKCHg7gmJtrlg7Bmku8LgshkEIItHIzJ4H4h7goLfZ3BKr-ZW6vN4aInlnSSep6GUp5hUUyTD3JCTucbaOaVHbox38.0CaUpNyBvEeldgUDUKvapwubNM6vmiD7mbf9xs8Tl_E&amp;amp;dib_tag=se&amp;amp;keywords=transformed&amp;amp;qid=1734870588&amp;amp;s=digital-text&amp;amp;sprefix=tranformed%2Cdigital-text%2C198&amp;amp;sr=1-1" rel="noopener noreferrer"&gt;Amazon&lt;/a&gt;, &lt;a href="https://www.audible.com/pd/Transformed-Audiobook/B0CV5TZ3R7?qid=1734870581&amp;amp;sr=1-1&amp;amp;ref_pageloadid=not_applicable&amp;amp;pf_rd_p=83218cca-c308-412f-bfcf-90198b687a2f&amp;amp;pf_rd_r=WPA95JMTNREQYZ887D6S&amp;amp;plink=ftrcySNqxSCaus5g&amp;amp;pageLoadId=32P0fnyEq1Ge5u07&amp;amp;creativeId=0d6f6720-f41c-457e-a42b-8c8dceb62f2c&amp;amp;ref=a_search_c3_lProduct_1_1" rel="noopener noreferrer"&gt;Audible&lt;/a&gt;)
&lt;/h3&gt;

&lt;p&gt;A practical, case-based look at how teams and companies can move to a product-based operating model. I really appreciated the diverse perspectives and real-world transformation examples. An essential read for Product Team members - pairs nicely with &lt;em&gt;Continuous Discovery Habits&lt;/em&gt; by Teresa Torres, &lt;em&gt;Lean UX&lt;/em&gt; by  Jeff Gothelf and Josh Seiden and &lt;em&gt;Clean Agile&lt;/em&gt; by Robert Martin.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Continuous Discovery Habits. Teresa Torres  (&lt;a href="https://www.amazon.com/Continuous-Discovery-Habits-Discover-Products-ebook/dp/B094PVB97X?crid=3CEEQ3RD899WS&amp;amp;dib=eyJ2IjoiMSJ9.mK8-Cv8_wY50EpayvfqABe8zMQJhsR7duuFSHpO68qjcYdUAS1ivmNrlZtCGTGIsBz6r62N2y3pYknG05FKRPHu9gow3WHPkW6yWIMZ2D-dcOR5EEPEX_gMBDgy5MF3KtYvNENreYwjXj1i7cLE5hHfersC4Sb-23Fmb7nNqWe2FdcH8ar8w0uOe3Wo2shz1urB35tbXznwmwkTkM6EIBKUThhz5kLtYXliPMcu05V8.FUa6TjFV9a4-vmvORtOoIGe1wJxTwm67wMq7Z7NHFcw&amp;amp;dib_tag=se&amp;amp;keywords=continuous+discovery+habits&amp;amp;qid=1734870956&amp;amp;s=digital-text&amp;amp;sprefix=continous+disco%2Cdigital-text%2C234&amp;amp;sr=1-1" rel="noopener noreferrer"&gt;Amazon&lt;/a&gt;, &lt;a href="https://www.audible.com/pd/Continuous-Discovery-Habits-Audiobook/B09XZGNP41?qid=1734870967&amp;amp;sr=1-1&amp;amp;ref_pageloadid=not_applicable&amp;amp;pf_rd_p=83218cca-c308-412f-bfcf-90198b687a2f&amp;amp;pf_rd_r=Y44P9C2W7PEVC8SNR66N&amp;amp;plink=QD3TxJggJIlmWIJP&amp;amp;pageLoadId=b6RGEzhgWGWhOqcM&amp;amp;creativeId=0d6f6720-f41c-457e-a42b-8c8dceb62f2c&amp;amp;ref=a_search_c3_lProduct_1_1" rel="noopener noreferrer"&gt;Audible&lt;/a&gt;)
&lt;/h3&gt;

&lt;p&gt;This one shines when paired with Marty Cagan’s books, &lt;em&gt;Clean Agile&lt;/em&gt; and &lt;em&gt;Lean UX&lt;/em&gt;. Torres offers a distilled framework for weaving continuous discovery into the day-to-day work of Product Team. The techniques focus not just on gathering and acting upon user feedback but also on understanding real user behaviors. A must read for aspiring Tech Lead. &lt;/p&gt;

&lt;h3&gt;
  
  
  4. Lean UX: Designing Great Products with Agile Teams. Jeff Gothelf and Josh Seiden (&lt;a href="https://www.amazon.com/Lean-UX-Designing-Great-Products/dp/1491953608" rel="noopener noreferrer"&gt;Amazon&lt;/a&gt;, &lt;a href="https://www.audible.com/pd/Lean-UX-Designing-Great-Products-with-Agile-Teams-Second-Edition-Audiobook/B08VL2NTZT?qid=1735746578&amp;amp;sr=1-1&amp;amp;ref_pageloadid=not_applicable&amp;amp;pf_rd_p=83218cca-c308-412f-bfcf-90198b687a2f&amp;amp;pf_rd_r=WQEGN70P52BXMRZ4QMGJ&amp;amp;plink=4qUacUArSVBFNlBr&amp;amp;pageLoadId=0RBWFqQoCpK6XmQg&amp;amp;creativeId=0d6f6720-f41c-457e-a42b-8c8dceb62f2c&amp;amp;ref=a_search_c3_lProduct_1_1" rel="noopener noreferrer"&gt;Audible&lt;/a&gt;)
&lt;/h3&gt;

&lt;p&gt;A concise, practical companion to &lt;em&gt;Continuous Discovery Habits&lt;/em&gt;, this book focuses more on building processes  and habits of discovery, rapid experimentation, and continuous feedback across Product Teams than on “traditional” UX techniques. It portrays Product Designers as facilitators of collaborative design and discovery efforts - rather than isolated individual contributors - which resonates with me. If you’re looking to embed a habit of iterative learning and team-centric experimentation in your organization, &lt;em&gt;Lean UX&lt;/em&gt; is definitely worth the read.&lt;/p&gt;

&lt;h3&gt;
  
  
  5. Team Topologies: Organizing Business and Technology Teams for Fast Flow. Matthew Skelton and Manuel Pais (&lt;a href="https://www.amazon.com/Team-Topologies-Organizing-Business-Technology/dp/1942788819?crid=PMIJZEEHI4H1&amp;amp;dib=eyJ2IjoiMSJ9.fkrIHqMAVF-HH87KlVLrbPvwjPCCnMjBq8gIei14er9TJGufa7FUKxBvJbszE6-0p0EWV1x_P3LeYInO5FgJnzn0kCvA0qvkYfUTAjdO28Yzr1Gf2ueLvX6h7VyeaoVcBVO4kLYe8SGO_cijPyo9JfLDC-Uq_dGCFbjxSnQbno9rR4qndyvsqhA2Oyeg47LeUePQIhKHbD1MYWjPFlAgROZTDbtuVQZ3Z_-JngPtEIY.BdoVg1hAtwkdn9h9pWRe6GqZ_GBkFqjmdu1DeqIcFKY&amp;amp;dib_tag=se&amp;amp;keywords=team+topologies&amp;amp;qid=1734871060&amp;amp;s=books&amp;amp;sprefix=team+topo%2Cstripbooks-intl-ship%2C202&amp;amp;sr=1-1" rel="noopener noreferrer"&gt;Amazon&lt;/a&gt;, &lt;a href="https://www.audible.com/pd/Team-Topologies-Organizing-Business-and-Technology-Teams-for-Fast-Flow-Audiobook/B07VZ2JKQP?qid=1734871069&amp;amp;sr=1-1&amp;amp;ref_pageloadid=not_applicable&amp;amp;pf_rd_p=83218cca-c308-412f-bfcf-90198b687a2f&amp;amp;pf_rd_r=HPG1B5PKY3X25PD6PA1N&amp;amp;plink=CJyqiZfA2b1qSlZy&amp;amp;pageLoadId=69rkJFis5m7gvWVy&amp;amp;creativeId=0d6f6720-f41c-457e-a42b-8c8dceb62f2c&amp;amp;ref=a_search_c3_lProduct_1_1" rel="noopener noreferrer"&gt;Audible&lt;/a&gt;)
&lt;/h3&gt;

&lt;p&gt;Introduces tons of concepts - like different team topologies and managing team cognitive capacity - that helped me make sense of the dynamics I’ve observed across various teams. There are plenty of patterns and anti-patterns, all backed by research or real-world case studies, showing how to optimize flow and better align teams with business objectives. As a Tech Lead, I found the framework especially handy for improving cross-team communication and staying mindful of cognitive load of a team.&lt;/p&gt;

&lt;h3&gt;
  
  
  6. Clean Agile. Robert Martin (&lt;a href="https://www.amazon.com/Clean-Agile-Basics-Robert-Martin-ebook/dp/B07XTL99JQ?_encoding=UTF8&amp;amp;dib_tag=se&amp;amp;dib=eyJ2IjoiMSJ9.2TNoJmRxXbWHkNrhUTUjh5cF9ggp4iM3gRdFRIUL_rTDpZ1X6CILJVaKf27P0ntVzM5zgoQnYR4RJhb9l6SR0HKjAg86ScnnbQzQAggBgAfH4UdL4TBDGCF0WBWs7B5beDz20o3h3u_D0C_Om1OoJQ.PR-0UkU5zSAIP44kIdRE79Y21UNTCIexaB2UHdl6yXU&amp;amp;qid=1734870513&amp;amp;sr=1-1" rel="noopener noreferrer"&gt;Amazon&lt;/a&gt;, &lt;a href="https://www.audible.com/pd/Clean-Agile-Audiobook/B08X7D3YFR?qid=1734870489&amp;amp;sr=1-1&amp;amp;ref_pageloadid=not_applicable&amp;amp;pf_rd_p=83218cca-c308-412f-bfcf-90198b687a2f&amp;amp;pf_rd_r=88AR1PPGH9MXVYWE7QKR&amp;amp;plink=fGeAruDNSa0XVZ7E&amp;amp;pageLoadId=G75HZEdeeexvtBLF&amp;amp;creativeId=0d6f6720-f41c-457e-a42b-8c8dceb62f2c&amp;amp;ref=a_search_c3_lProduct_1_1" rel="noopener noreferrer"&gt;Audible&lt;/a&gt;)
&lt;/h3&gt;

&lt;p&gt;A very brief, straight-to-the-point re-introduction to Agile, reminding us what those core principles really mean in practice - beyond the usual ceremonies and rituals. It pairs seamlessly with works by Marty Cagan and Teresa Torres on product-centric, discovery-driven approaches. Personally, I felt inspired to gradually refine our backlog and delivery practices to adopt TDD and Continuous Delivery (in broader terms that what you see in CI/CD pipelines), better aligning our team with continuous discovery and the delivery of value to user and business.&lt;/p&gt;

&lt;h2&gt;
  
  
  Systems Design
&lt;/h2&gt;

&lt;h3&gt;
  
  
  7. Designing Data Intensive Applications. Martin Kleppmann  (&lt;a href="https://www.amazon.com/Designing-Data-Intensive-Applications-Reliable-Maintainable/dp/1449373321?crid=2L5HEGY7FA6W2&amp;amp;dib=eyJ2IjoiMSJ9.qKMpaeqG8Tk9d-cfMY0ga-12ydPbEIyi-xZgKi01GOPEXwEFY3uGawMhqGD37Na53EmpX5bpV9taT34H935Gj5lbNEDTyRkzoN3UvsNIzCJQNn1r46XpHX-Dspt_lX0R6VIDaOj9pPgaAOd31j0j7v06sXbtg3zmWoFzIE8QDkVI1OROkQRRxfetcNrd6Rfz_CU2HHz3iLziBXt5SnmiZdOyeF5_AFfgXsCwpVz0xxg.KGp8w7YW7QvZdtATLT2lCvHwG8JAcQPpUwwHf2kTMQo&amp;amp;dib_tag=se&amp;amp;keywords=designing+data-intensive+applications&amp;amp;qid=1734870183&amp;amp;s=books&amp;amp;sprefix=designing+data%2Cstripbooks-intl-ship%2C228&amp;amp;sr=1-1" rel="noopener noreferrer"&gt;Amazon&lt;/a&gt;, &lt;a href="https://www.audible.com/pd/Designing-Data-Intensive-Applications-Audiobook/B08VLGDK32?eac_link=YXHwNblLCQnk&amp;amp;ref=web_search_eac_asin_2&amp;amp;eac_selected_type=asin&amp;amp;eac_selected=B08VLGDK32&amp;amp;qid=SxpcRjC1mA&amp;amp;eac_id=138-0708236-4963718_SxpcRjC1mA&amp;amp;sr=1-2" rel="noopener noreferrer"&gt;Audible&lt;/a&gt;)
&lt;/h3&gt;

&lt;p&gt;By far the most important piece of wisdom on distributed systems and data-intensive applications I've read. This is my technology bible - I’ve read it twice and refer to it at least weekly for an inspiration in solving real-life architecture problems.&lt;/p&gt;

&lt;p&gt;Apart from incredible value of content, two other characteristics of the book impressed me:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Despite the book’s depth and complexity, it’s surprisingly consumable as an audiobook.&lt;/li&gt;
&lt;li&gt;It’s very easy to comprehend. I was a bit intimidated before starting, but now I see it’s very approachable. Certain parts may even inspire less-technical roles like Product Managers - particularly “Chapter 12. The Future of Data Systems.”&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Looking forward to 2nd edition later this year!&lt;/p&gt;

&lt;h3&gt;
  
  
  8. Fundamentals of Software Architecture. An Engineering Approach. Mark Richards and Neal Ford (&lt;a href="https://www.amazon.com/Fundamentals-Software-Architecture-Engineering-Approach/dp/B08X8H15BW?crid=9G30ATFHT82Y&amp;amp;dib=eyJ2IjoiMSJ9.JlSyji6FLRpvHFfg1g_3l2W3FTiongnl-TVtWhRfnHSqj1aiXFXWxM-RvPctQ5rNcijrf2BEnCHN8Zel-eTlNk0jTTa_Q2LYbr7xu0lu9wH6cKSOXoY3BTsMPlYezcOvQN4nfy45joIbjADVthasKcZkVozbk4mlFrp2fUIa1FpaM_ru01PQKo-cHISX8q_FfZGMPwouzrDdYBYxWZkuLS4nqJhGwMvPD2_DJlXlQVE.amZgOixK8PXsSheZ3NMGCm2-dkdoV8CKy3B6E4SQKE8&amp;amp;dib_tag=se&amp;amp;keywords=Fundamentals+of+Software+Architecture&amp;amp;qid=1734870352&amp;amp;s=books&amp;amp;sprefix=fundamentals+of+software+architecture%2Cstripbooks-intl-ship%2C361&amp;amp;sr=1-1" rel="noopener noreferrer"&gt;Amazon&lt;/a&gt;, &lt;a href="https://www.audible.com/pd/Fundamentals-of-Software-Architecture-Audiobook/B08X917VLR?qid=1734870345&amp;amp;sr=1-1&amp;amp;ref_pageloadid=not_applicable&amp;amp;pf_rd_p=83218cca-c308-412f-bfcf-90198b687a2f&amp;amp;pf_rd_r=CXGS9QRVN3PDB8237ZT7&amp;amp;plink=2XreMZmmWfbd732q&amp;amp;pageLoadId=BuPPNOV5k6jvCJ7t&amp;amp;creativeId=0d6f6720-f41c-457e-a42b-8c8dceb62f2c&amp;amp;ref=a_search_c3_lProduct_1_1" rel="noopener noreferrer"&gt;Audible&lt;/a&gt;)
&lt;/h3&gt;

&lt;p&gt;A fundamental deep dive into software architecture characteristics, metrics, and patterns, packed with tons of practical advice and tools for designing, communicating, and implementing systems effectively. There’s a big emphasis on maintaining architectural compliance and evolution, plus a focus on the soft skills needed to guide teams. Overall, it’s very well structured and highly approachable - an essential read for anyone looking to solidify their architectural chops.&lt;/p&gt;

&lt;h3&gt;
  
  
  9. Clean Architecture. Robert Martin (&lt;a href="https://www.amazon.com/Clean-Architecture-Craftsmans-Software-Structure-ebook/dp/B075LRM681?crid=2VRRJF62TC01H&amp;amp;dib=eyJ2IjoiMSJ9.mcwhwAcECXs-NuEmL5TaW2Jo-v5tTiEUKfajkKJCMoRbTfUaWxpVZW8jkg0Ds2pwbJ2TtYJUAO6621Ble4qv82Iv4mLBabiFUb2tpyZuaKS-TZVYPXlW53TTHROxcq-n7FB7OZq_j45oyjcdsY-HhJiFA2f8vGFrP51xWTOx6vUE8pTnEYmcKh8Y0eCGXlrb-2S3gPpMXf0sNvk6Ow3-f0Dto3dEOYjKScUAcASKa78.ghbowhi_sezyL7eZCz-Dp31c8zrGqj5Uf0hjWZ9qxBI&amp;amp;dib_tag=se&amp;amp;keywords=clean+architecture&amp;amp;qid=1734870862&amp;amp;s=digital-text&amp;amp;sprefix=clean+architectur%2Cdigital-text%2C213&amp;amp;sr=1-1" rel="noopener noreferrer"&gt;Amazon&lt;/a&gt;, &lt;a href="https://www.audible.com/pd/Clean-Architecture-Audiobook/B08X8L9MJZ?eac_link=nPbEQlplDWTJ&amp;amp;ref=web_search_eac_asin_1&amp;amp;eac_selected_type=asin&amp;amp;eac_selected=B08X8L9MJZ&amp;amp;qid=7XFxmuNyGU&amp;amp;eac_id=138-0708236-4963718_7XFxmuNyGU&amp;amp;sr=1-1" rel="noopener noreferrer"&gt;Audible&lt;/a&gt;)
&lt;/h3&gt;

&lt;p&gt;A strong and somewhat more practical complement to &lt;em&gt;Fundamentals of Software Architecture&lt;/em&gt; by Mark Richards and Neal Ford. “Uncle Bob” once again shares his wisdom, backed by real-life stories and anecdotes. I’ve seen measurable positive impact after weaving these strategies into my team’s processes and feature design - it’s definitely worth reading.&lt;/p&gt;

&lt;h3&gt;
  
  
  10. NoSQL Distilled. A Brief Guide to the Emerging World of Polyglot Persistence. Pramod J. Sadalage, Martin Fowler  (&lt;a href="https://www.amazon.com/NoSQL-Distilled-Emerging-Polyglot-Persistence/dp/0321826620/ref=sr_1_1?crid=2VH71D6HU8QZQ&amp;amp;dib=eyJ2IjoiMSJ9.gVPeYA6BXDbK5Qg9Ve2jtMom6Wp4b3Jdwu1pUN5jTqbGjHj071QN20LucGBJIEps.R2E9d2L-EWoYb78htWP9w5ATOVL72zgCQJv_wGtqm4c&amp;amp;dib_tag=se&amp;amp;keywords=NoSQL+Distilled.+A+Brief+Guide+to+the+Emerging+World+of+Polyglot+Persistence&amp;amp;qid=1736075268&amp;amp;s=books&amp;amp;sprefix=%2Cstripbooks-intl-ship%2C491&amp;amp;sr=1-1" rel="noopener noreferrer"&gt;Amazon&lt;/a&gt;)
&lt;/h3&gt;

&lt;p&gt;Despite being quite short, the book felt fundamental to me. The authors dive into the key concepts of databases and distributed systems, starting with Relational Databases and moving on to various flavors of NoSQL and beyond. Sadalage and Fowler walk you through different NoSQL data models and the concept of polyglot persistence - choosing the right tool for each job rather than forcing a single solution. This book won’t go super deep on any single technology, but it’s excellent for building breadth in your understanding of available options.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;A few notes:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The book dates back to 2012, so some details may be outdated - though the core principles remain strong. Some of the DBMSs mentioned aren’t heard of much anymore, while others have evolved significantly, and new players have entered the scene.&lt;/li&gt;
&lt;li&gt;The chapter recaps (“Key Points”) are simply amazing.&lt;/li&gt;
&lt;li&gt;This is a great source of "Further reading" suggestions if you’re keen to explore distributed systems and data stores more deeply.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  11. The DynamoDB Book. Alex DeBrie (&lt;a href="https://www.amazon.com/DynamoDB-Book-Alex-DeBrie/dp/B0BN7S1GQK" rel="noopener noreferrer"&gt;Amazon&lt;/a&gt;)
&lt;/h3&gt;

&lt;p&gt;We extensively use DynamoDB in my team, but reading this book made me realize we’d only scratched the surface - particularly when it comes to managing complex relationships and implementing single-table designs. Alex shares inspiration I needed in my thinking of possible options to evolve my team's product as we approach (financially sensible) scalability limits of a relational database. &lt;/p&gt;

&lt;p&gt;The writing itself is both educational and occasionally humorous - with nice little quirks like attributing Satya Nadella to Google in one of the data model examples. My only wish is that the author had gone deeper on why DynamoDB might be preferable over other NoSQL options like Cassandra or MongoDB. Overall, important read for anyone serious about modern Systems Design.&lt;/p&gt;

&lt;h2&gt;
  
  
  Personal Productivity and Creativity
&lt;/h2&gt;

&lt;h3&gt;
  
  
  12. Building a Second Brain. Tiago Forte (&lt;a href="https://www.amazon.com/Building-Second-Brain-Organize-Potential/dp/1982167386?crid=LWBB6ZQIDI9F&amp;amp;dib=eyJ2IjoiMSJ9.9qeW84-SbFAOg44UY11scobX7Vpx3ktZZnAicZu74hiATpbSHVNqmSPwrII9EfoBCH_o1F8x-aMXPgXsquzBhWu3NS3X2-VDzI-sDyXYy3zl42fxB6EYijPMrU6YxoCtWr5uIMT3xIF_gUSDUTGVXHtArUicGptHd7hqsHBcEIYqyoGWkircTApclzlkBFHVPpHDRJK-2YvGkoH2rOdzlly2U9XmcEMIo4U0wTIiZPw.a_3yodVu31VZftPS58ZtFkCZ31ON4caEsxu6Ohw2njQ&amp;amp;dib_tag=se&amp;amp;keywords=building+a+second+brain&amp;amp;qid=1734870097&amp;amp;s=books&amp;amp;sprefix=building+a+second+brain%2Cstripbooks-intl-ship%2C212&amp;amp;sr=1-1" rel="noopener noreferrer"&gt;Amazon&lt;/a&gt;, &lt;a href="https://www.audible.com/pd/Building-a-Second-Brain-Audiobook/B09MGHPVP4?eac_link=UqUUrrrZ5qYa&amp;amp;ref=web_search_eac_asin_1&amp;amp;eac_selected_type=asin&amp;amp;eac_selected=B09MGHPVP4&amp;amp;qid=h3LOaBFo05&amp;amp;eac_id=138-0708236-4963718_h3LOaBFo05&amp;amp;sr=1-1" rel="noopener noreferrer"&gt;Audible&lt;/a&gt;)
&lt;/h3&gt;

&lt;p&gt;Finally, I’ve found a note-taking and research-and-creativity framework that really works for me. The book is definitely worth reading, although the motivational tone sometimes takes center stage and slightly overshadows the practical advice.&lt;/p&gt;

&lt;h1&gt;
  
  
  Conclusion
&lt;/h1&gt;

&lt;p&gt;These twelve books have helped me expand beyond just the technical elements of software architecture to include product discovery, user experience, and team organization - all of which are crucial for my day-to-day challenges. By diving into topics such as continuous discovery, designing data-intensive applications, team topologies, and agile methodologies, I’ve gained a more holistic perspective on how to deliver real value to both users and the business.&lt;/p&gt;

&lt;p&gt;But this is just the beginning of the journey. I’m always looking for more books that address the multifaceted challenges of leading a product-focused tech team. If you have any recommendations or hidden gems that you’ve found particularly valuable, please let me know - I’d love to add them to my reading list!&lt;/p&gt;

&lt;p&gt;&lt;em&gt;“Disclaimer: The links in this post are not affiliate links; I receive no commission if you choose to purchase through them.”&lt;/em&gt;&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Analysing FastAPI Middleware Performance</title>
      <dc:creator>Sergey</dc:creator>
      <pubDate>Mon, 22 Apr 2024 10:34:27 +0000</pubDate>
      <link>https://dev.to/sazonov/analysing-fastapi-middleware-performance-2n61</link>
      <guid>https://dev.to/sazonov/analysing-fastapi-middleware-performance-2n61</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;FastAPI is a well-known and beloved (almost 70k⭐️ on GitHub) modern, fast, asynchronous web framework for building APIs with Python. It is designed for ease of use and high performance, while being robust and production-ready.&lt;/p&gt;

&lt;p&gt;My team quite enjoyed the process of developing apps with FastAPI, finding it a rewarding learning experience. However, one learning was a bit hard: when it came to performance testing, we faced unexpectedly low Requests Per Second (RPS) values, which prompted a deeper investigation, that in turn lead us to learn more about FastAPI Middlewares.&lt;/p&gt;

&lt;p&gt;The purpose of this note is to explore the impact of BaseHTTPMiddleware and ASGIMiddleware on FastAPI application&lt;br&gt;
performance and to share our learnings.&lt;/p&gt;

&lt;p&gt;Spoiler: this is how the performance of real-life production application may change depending on the type of middlewares&lt;br&gt;
we use to implement some common logic:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnngfzxgkyce9mo2scnb2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnngfzxgkyce9mo2scnb2.png" alt="Real-life performance of different middlewares" width="800" height="156"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Background
&lt;/h2&gt;

&lt;p&gt;In FastAPI, middleware plays a crucial role in the request-response lifecycle, acting as a layer that processes requests and responses before they reach the core application logic, or after they leave it. This functionality is pivotal for implementing various features like authentication, data processing, request logging, and error handling.&lt;/p&gt;

&lt;p&gt;Whenever you want to apply some common logic to request processing in more than one endpoint, you might consider using middlewares. FastAPI (more precisely - Starlette on which FastAPI is grounded) offers two types of middleware:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;BaseHTTPMiddleware&lt;/strong&gt;: This type of middleware is designed around a simple and straightforward interface. When using   BaseHTTPMiddleware, you define an async function that takes the request, calls the next item in the middleware chain, and then you can modify the response.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;ASGIMiddleware&lt;/strong&gt;: ASGI (Asynchronous Server Gateway&lt;br&gt;
Interface) &lt;a href="https://asgi.readthedocs.io/en/latest/specs/main.html#middleware"&gt;specification&lt;/a&gt; states:&lt;br&gt;
&lt;code&gt;It is possible to have ASGI “middleware” - code that plays the role of both server and application, taking in a scope and the send/receive awaitable callables, potentially modifying them,and then calling an inner application.&lt;/code&gt; ASGIMiddleware functions within ASGI application, which is a core components of frameworks like FastAPI and Starlette. Moreover, such middleware shares the same &lt;code&gt;coroutine application(scope, receive, send)&lt;/code&gt; signature with ASGI applications. Generally, implementing and supporting ASGIMiddleware is more complex than BaseHTTPMiddleware due to its lower level of abstraction, offering more direct interaction with the ASGI protocol. It's important to note that ASGIMiddleware is not subject to some of the important &lt;a href="https://www.starlette.io/middleware/#limitations"&gt;limitations&lt;/a&gt; of BaseHTTPMiddleware.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;As far as middlewares act as a layer in request-response lifecycle, they are expected to have an impact on application performance. The question is - how much? And what is the difference between two types of middlewares supported within FastAPI?&lt;/p&gt;
&lt;h2&gt;
  
  
  The Discovery Process
&lt;/h2&gt;

&lt;p&gt;During performance load testing with ApacheBench (ab) we found that although the application can handle the required RPS it still seems quite low for an async application which does not contain any significant CPU-bound calls. Another point of worry, RPS didn't scale linearly with the number of application instances. We decided to investigate the issue further.&lt;/p&gt;

&lt;p&gt;After intensive research, we came down to reviewing our middlewares and found performance caveats that I will illustrate with experiments below.&lt;/p&gt;
&lt;h2&gt;
  
  
  Experimentation and Analysis
&lt;/h2&gt;

&lt;p&gt;Here are five experiments that nicely represent the investigation process our team went through. I will be running ApacheBench (ab) requests against each experimental case with concurrency 100 to measure RPS of our sample application with different middlewares. I will run each case five times and average the results.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; ab &lt;span class="nt"&gt;-c&lt;/span&gt; 100 &lt;span class="nt"&gt;-n&lt;/span&gt; 1000 http://127.0.0.1:8000/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Experiment Setup
&lt;/h3&gt;

&lt;h4&gt;
  
  
  Case 0: Baseline (No Middlewares)
&lt;/h4&gt;

&lt;p&gt;Let's start with a simple FastAPI application that contains a single endpoint and no middlewares.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;fastapi&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;FastAPI&lt;/span&gt;

&lt;span class="n"&gt;app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;FastAPI&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;


&lt;span class="nd"&gt;@app.get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;/&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;read_root&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Hello&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;World&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Case 1: Single Simple Middleware
&lt;/h4&gt;

&lt;p&gt;Here are the implementations of both types of middlewares. Both are effectively doing nothing.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# BaseHTTPMiddleware
&lt;/span&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;urllib.request&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Request&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;starlette.middleware.base&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;BaseHTTPMiddleware&lt;/span&gt;


&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;HTTPMiddleware&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;__call__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;call_next&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;call_next&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;


&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add_middleware&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;BaseHTTPMiddleware&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;dispatch&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nc"&gt;HTTPMiddleware&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;

&lt;span class="c1"&gt;# ASGIMiddleware
&lt;/span&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;starlette.types&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;ASGIApp&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Send&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Scope&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Receive&lt;/span&gt;


&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ASGIMiddleware&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;__init__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;ASGIApp&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;app&lt;/span&gt;

    &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;__call__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;scope&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Scope&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;receive&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Receive&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;send&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Send&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;app&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;scope&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;receive&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;send&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;


&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add_middleware&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ASGIMiddleware&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Case 2: Five Stacked Simple Middlewares
&lt;/h4&gt;

&lt;p&gt;Middlewares are still doing nothing, but let's stack them up to find the impact.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# BaseHTTPMiddleware
&lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add_middleware&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;BaseHTTPMiddleware&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;dispatch&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nc"&gt;HTTPMiddleware&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;

&lt;span class="c1"&gt;# ASGIMiddleware
&lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add_middleware&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ASGIMiddleware&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Case 3: Five Stacked Blocking Middlewares
&lt;/h4&gt;

&lt;p&gt;So far our tests were very synthetic. Let's try to make them more realistic by adding some logic to our middlewares. In asynchronous application it's very important to avoid synchronous calls that block the entire event loop and may have dramatic performance impact, but some blocking calls are unavoidable - like logging (off-topic: offloading logging to a separate thread may help minimize impact).&lt;/p&gt;

&lt;p&gt;Let's add some massive blocking calls to our middlewares.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# BaseHTTPMiddleware
&lt;/span&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;HTTPMiddleware&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;__call__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;call_next&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="nf"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;/tmp/middleware.log&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;a&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;HTTPMiddleware&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;call_next&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;


&lt;span class="c1"&gt;# ASGIMiddleware
&lt;/span&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ASGIMiddleware&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;__init__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;ASGIApp&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;app&lt;/span&gt;

    &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;__call__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;scope&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Scope&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;receive&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Receive&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;send&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Send&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="nf"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;/tmp/middleware.log&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;a&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;ASGIMiddleware&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;app&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;scope&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;receive&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;send&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Case 4: Five Stacked Non-Blocking Middlewares
&lt;/h4&gt;

&lt;p&gt;Let's see whether adding async calls to our middlewares have different impact. Here I'm including an asyncio.sleep for 10ms call to our logic.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# BaseHTTPMiddleware
&lt;/span&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;HTTPMiddleware&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;__call__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;call_next&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;asyncio&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sleep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;0.01&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;call_next&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;


&lt;span class="c1"&gt;# ASGIMiddleware
&lt;/span&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ASGIMiddleware&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;__init__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;ASGIApp&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;app&lt;/span&gt;

    &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;__call__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;scope&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Scope&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;receive&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Receive&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;send&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Send&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;asyncio&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sleep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;0.01&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;app&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;scope&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;receive&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;send&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Case 5: Five Stacked Non-Blocking Middlewares with 100ms sleep
&lt;/h4&gt;

&lt;p&gt;Same as previous case but with increased sleep time to 100ms - take it as a representation of a few async database or services discovery calls.&lt;/p&gt;

&lt;h3&gt;
  
  
  Results and Observations
&lt;/h3&gt;

&lt;p&gt;Here is the summary of the results from the experiments above.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3m6i2g3qycfpm765cdxq.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3m6i2g3qycfpm765cdxq.png" alt="Summary of middleware test cases" width="800" height="558"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Case 1: Single Simple Middleware (doing nothing)&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Impact from adding a single middleware is pretty visible, telling us there is a noticeable overhead of running a middleware.&lt;/li&gt;
&lt;li&gt;BaseHTTPMiddleware is ~15% slower.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Case 2: Five Stacked Simple Middlewares (doing nothing)&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The impact of executing five BaseHTTPMiddlewares is significant. RPS drops by an order of magnitude, comparing to Baseline.&lt;/li&gt;
&lt;li&gt;ASGIMiddleware virtually not affected by stacking up.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Case 3: Five Stacked Blocking Middlewares (writing to a file)&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Heavy blocking call is not adding much impact to BaseHTTPMiddleware performance, telling us that response time is probably already saturated by middleware overhead.&lt;/li&gt;
&lt;li&gt;Impact on ASGIMiddleware is significant, which is expected.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Case 4: Five Stacked Non-Blocking Middlewares (asyncio.sleep(0.01))&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;BaseHTTPMiddleware with &lt;code&gt;sleep&lt;/code&gt; performs just a tiny bit slower than in case 2 where middleware is doing nothing,      this somewhat supports the idea that we maxed-out middleware overhead impact.&lt;/li&gt;
&lt;li&gt;ASGIMiddleware still faster but to a lesser extent.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Case 5: Five Stacked Non-Blocking Middlewares with 100ms sleep&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Finally, middlewares of different types have gotten on par with each other.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Findings and Recommendations
&lt;/h2&gt;

&lt;p&gt;Based on experiments above BaseHTTPMiddleware has a measurable performance overhead comparing to ASGIMiddleware. The shorter the processing time of a middleware logic, the more significant the difference in performance between the two types of middlewares will be.&lt;/p&gt;

&lt;p&gt;It looks, this overhead comes from &lt;a href="https://anyio.readthedocs.io/en/stable/index.html"&gt;anyio&lt;/a&gt; task management routines used by Starlette to handle middlewares.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/encode/starlette/blob/master/starlette/middleware/base.py#L94"&gt;&lt;strong&gt;BaseHTTPMiddleware&lt;/strong&gt;&lt;/a&gt; class provides a nice and simple abstraction to user. By giving the immediate access to the &lt;code&gt;Request&lt;/code&gt; it makes development and support of middlewares effortless and cost-effective. At the same time, abstraction comes at a cost of overhead (task execution, exception and stream management through anyio library).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;ASGIMiddleware&lt;/strong&gt; in turn is way more involving to implement and maintain. Actually it forces you drop down abstraction to the level of ASGI protocol. It steepens the learning curve and raises the requirements to testing and quality assurance, but may bring reasonable performance benefit.&lt;/p&gt;

&lt;p&gt;Here is how a real-life impact of migration from BaseHTTPMiddleware to ASGIMiddleware looks like (optimized middlewares are marked with arrows) - 20%-30% improvement in request processing time in a single endpoint.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3lpro9zjvoazm9y015j2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3lpro9zjvoazm9y015j2.png" alt="Real-life performance of different middlewares with pointers" width="800" height="147"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Even the performance benefit looks impressive, as it happens often - it's a tradeoff with complexity. Unless you heavily relay on multiple stacked middlewares for you business logic, I would not suggest to use ASGIMiddleware before RPS and/or request processing time requirements will force you to. But it's important to keep this option under the belt and use it when other more obvious optimizations opportunities are exhausted.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;FastAPI middlewares are a powerful tool for implementing various features like authentication, CORS handling, logging, adding custom metrics and many more. However, overhead of middleware execution may be significant and should be taken into account while sizing an application. I strongly suggest avoiding the premature optimization and keeping the design as simple as possible which helps to increase Time to Market and reduce maintenance costs. While, if requirements force you to optimize - migrating to ASGIMiddleware might be a good option to consider.&lt;/p&gt;

&lt;h2&gt;
  
  
  References and Further Reading
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;FastAPI documentation on middleware: &lt;a href="https://fastapi.tiangolo.com/tutorial/middleware/"&gt;https://fastapi.tiangolo.com/tutorial/middleware/&lt;/a&gt; and ASGI
Middlewares &lt;a href="https://fastapi.tiangolo.com/advanced/middleware/"&gt;https://fastapi.tiangolo.com/advanced/middleware/&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Starlette documentation on middleware: &lt;a href="https://www.starlette.io/middleware/"&gt;https://www.starlette.io/middleware/&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Discussion at FastAPI GitHub: &lt;a href="https://github.com/tiangolo/fastapi/issues/2696"&gt;https://github.com/tiangolo/fastapi/issues/2696&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Another experiment on the topic &lt;a href="https://kisspeter.github.io/fastapi-performance-optimization/middleware"&gt;https://kisspeter.github.io/fastapi-performance-optimization/middleware&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h1&gt;
  
  
  FastAPI #Middleware #Performance #BaseHTTPMiddleware #Python
&lt;/h1&gt;

</description>
    </item>
  </channel>
</rss>
