<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:itunes="http://www.itunes.com/dtds/podcast-1.0.dtd" xmlns:googleplay="http://www.google.com/schemas/play-podcasts/1.0"><channel><title><![CDATA[Iouri Khramtsov]]></title><description><![CDATA[Iouri Khramtsov]]></description><link>https://www.i-kh.net</link><image><url>https://substackcdn.com/image/fetch/$s_!V9Qv!,w_256,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F64d2997e-d235-41e8-8ece-611b5f6c9f21_512x512.png</url><title>Iouri Khramtsov</title><link>https://www.i-kh.net</link></image><generator>Substack</generator><lastBuildDate>Thu, 27 Aug 2026 06:33:06 GMT</lastBuildDate><atom:link href="https://www.i-kh.net/feed" rel="self" type="application/rss+xml"/><copyright><![CDATA[Iouri Khramtsov]]></copyright><language><![CDATA[en]]></language><webMaster><![CDATA[iourikhramtsov@substack.com]]></webMaster><itunes:owner><itunes:email><![CDATA[iourikhramtsov@substack.com]]></itunes:email><itunes:name><![CDATA[Iouri Khramtsov]]></itunes:name></itunes:owner><itunes:author><![CDATA[Iouri Khramtsov]]></itunes:author><googleplay:owner><![CDATA[iourikhramtsov@substack.com]]></googleplay:owner><googleplay:email><![CDATA[iourikhramtsov@substack.com]]></googleplay:email><googleplay:author><![CDATA[Iouri Khramtsov]]></googleplay:author><itunes:block><![CDATA[Yes]]></itunes:block><item><title><![CDATA[Canadian housing crisis: what will it take to fix it?]]></title><description><![CDATA[What exactly is the scale of the housing crisis in Canada?]]></description><link>https://www.i-kh.net/p/housing-crisis-what-will-it-take-to-fix</link><guid isPermaLink="false">https://www.i-kh.net/p/housing-crisis-what-will-it-take-to-fix</guid><dc:creator><![CDATA[Iouri Khramtsov]]></dc:creator><pubDate>Sun, 08 Sep 2024 21:09:00 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!4pe1!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7005a585-eacf-441a-a17e-737486c45aca_867x409.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>What exactly is the scale of the housing crisis in Canada? Fortunately, most of the data is pretty straightforward to find. You can go to the Statistics Canada website, grab the <a href="https://www150.statcan.gc.ca/t1/tbl1/en/tv.action?pid=3610068801">housing stock table</a> and the <a href="https://www150.statcan.gc.ca/t1/tbl1/en/tv.action?pid=1710000501">population by age table</a> (click &#8220;Add/remove data&#8221; to see more years), and pretty quickly arrive at something like this:</p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;plaintext&quot;,&quot;nodeId&quot;:&quot;963c62b3-e6f4-4e8c-9e80-bd1e2dfd46ec&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-plaintext">                                  2016          2024
Population &gt; 18               29,027,447    32,600,713
Units available               15,507,364    16,786,020
Units/person                       0.534         0.515
Units needed to get to
2016 levels                           -       630,000</code></pre></div><p>I.e. we need <strong>630,000</strong> houses or apartments just to get back to 2016 levels of housing availability. A bit over half of this number comes from Ontario; repeating the math for that province gives us a shortage of 333,000 units compared to 2016.</p><p>To be clear, this number misses a lot of nuances: we don&#8217;t know which of these &#8220;units&#8221; are 8-bedroom houses and which are micro-condos, and we don&#8217;t know which of these adults are single and which have families.</p><p>On the surface, this shortage of 630,000 units doesn&#8217;t seem too horrifying: in 2023, the construction industry has started building 240,267 new units (<a href="https://www150.statcan.gc.ca/t1/tbl1/en/tv.action?pid=3410013501">CMHC housing starts table</a>) &#8212; down from the peak of 271,198 in 2021 &#8212; so it might look like it should take a bit less than three years to catch up.</p><p>But remember: Canada is a growing country, so as we&#8217;re building these housing units, new people over 18 are appearing. So let&#8217;s update our math. Suppose Canada&#8217;s growth follows StatCan&#8217;s moderate growth projections (M2 scenario <a href="https://www150.statcan.gc.ca/t1/tbl1/en/tv.action?pid=1710005701">in this table</a>), and we continue building houses at the same rate as we did in 2021 (the best year we&#8217;ve seen so far). How long will it take to catch up to the 2016 housing level?</p><p>Well, then the projection looks something like this:</p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;plaintext&quot;,&quot;nodeId&quot;:&quot;7c939164-0f1d-4a1e-939a-7a82372a2498&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-plaintext">Year    Population &gt; 18    Units short
2025        33,283,800         577,130
2026        33,548,800         495,079
2027        33,822,800         418,454
2028        34,312,900         457,893
2029        34,800,100         496,398
2030        35,280,800         532,044
2031        35,761,400         568,248
2032        36,241,000         604,527
2033        36,715,500         638,690
2034        37,187,400         672,071
2035        37,652,100         702,210</code></pre></div><p>Uh-oh, we never catch up.</p><h2>So what will it take?</h2><p>I&#8217;ll spare you the math and go straight to the answer: if we want to get back to 2016 housing stock levels by 2035, then over the next five years we need to increase the housing starts by <strong>26%</strong> over the 2021 levels to about 380,000 starts/year, with the bulk of this increase happening in Ontario, which needs to raise its housing starts by ~45%.</p><p>It&#8217;s not a small amount, but not impossible either. For comparison, in the years between 2016 and 2021, housing starts have increased 37% Canada-wide ans 33% in Ontario.</p><h2>But there are a few problems in the way</h2><p>A lot of the discourse online and among activists has been focused on <a href="https://www.cmhc-schl.gc.ca/blog/2023/approval-delays-linked-lower-housing-affordability">onerous regulations</a>, <a href="https://www.youtube.com/watch?v=Xy5xnYLWffE">slow approvals</a>, and <a href="https://www.youtube.com/watch?v=ozwkP9Zsi0Y&amp;t=519s">unhelpful building codes</a> &#8212; and rightfully so. That said, these seem to be improving as the public mood shifts towards building more housing, and, looking at the industry reports, it seems like at <a href="https://www.altusgroup.com/insights/cost-escalation-in-new-construction-a-2024-update/?utm_source=google&amp;utm_medium=organic">least some of the insiders</a> no longer see the public policy as the biggest long-term drag on construction.</p><p>There are a couple of other major problems though.</p><p>First, we need the new housing starts to go up, but instead since 2021, they&#8217;ve been going down. The explanation for this is fairly straightforward: less money has been spent on building new houses because the interest rates have gone up and house purchases have slowed down.</p><p>This problem will partly fix itself as the Bank of Canada <a href="https://www.canadianmortgagetrends.com/2024/07/will-the-bank-of-canada-deliver-another-175-bps-in-rate-cuts-td-and-cibc-say-yes/">lowers its policy interest rate</a>. However, it won&#8217;t cut the rate back down to 0.25%, and the total investment into new housing isn&#8217;t projected to go back up to the 2021 levels either (source: <a href="https://www.buildforce.ca/system/files/forecast_summary_reports/2024%20Canada%20Const%20%26amp%3B%20Maint%20Looking%20Forward.pdf?language=en">BuildForce National Summary for 2024</a>):</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!4pe1!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7005a585-eacf-441a-a17e-737486c45aca_867x409.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!4pe1!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7005a585-eacf-441a-a17e-737486c45aca_867x409.png 424w, https://substackcdn.com/image/fetch/$s_!4pe1!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7005a585-eacf-441a-a17e-737486c45aca_867x409.png 848w, https://substackcdn.com/image/fetch/$s_!4pe1!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7005a585-eacf-441a-a17e-737486c45aca_867x409.png 1272w, https://substackcdn.com/image/fetch/$s_!4pe1!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7005a585-eacf-441a-a17e-737486c45aca_867x409.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!4pe1!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7005a585-eacf-441a-a17e-737486c45aca_867x409.png" width="867" height="409" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/7005a585-eacf-441a-a17e-737486c45aca_867x409.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:409,&quot;width&quot;:867,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" title="" srcset="https://substackcdn.com/image/fetch/$s_!4pe1!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7005a585-eacf-441a-a17e-737486c45aca_867x409.png 424w, https://substackcdn.com/image/fetch/$s_!4pe1!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7005a585-eacf-441a-a17e-737486c45aca_867x409.png 848w, https://substackcdn.com/image/fetch/$s_!4pe1!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7005a585-eacf-441a-a17e-737486c45aca_867x409.png 1272w, https://substackcdn.com/image/fetch/$s_!4pe1!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7005a585-eacf-441a-a17e-737486c45aca_867x409.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>But we need the investment to go much higher: if the average historic costs per housing unit stay the same, we&#8217;ll need to be investing as much as $54 billion per year more than we&#8217;re forecast to catch up to our 2016 housing availability target. If that money doesn&#8217;t materialize from somewhere, no amount of regulation reform will help plug the gap.</p><p>The second problem is the shortage of skilled labor in the construction industry, which is projected to worsen due to retirement. In the short-term, construction is limited by lack of people with a few specific skill sets like crane operators, elevator mechanics, or ironworkers, especially in major cities like Toronto (source: <a href="https://www.buildforce.ca/system/files/forecast_summary_reports/2024%20ON%20Constr%20Maint%20Looking%20Forward.pdf?language=en">BuildForce Ontario report 2024</a>):</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!7tKH!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F605244c5-aea5-4eb9-b9de-c5f7c157d365_733x429.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!7tKH!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F605244c5-aea5-4eb9-b9de-c5f7c157d365_733x429.png 424w, https://substackcdn.com/image/fetch/$s_!7tKH!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F605244c5-aea5-4eb9-b9de-c5f7c157d365_733x429.png 848w, https://substackcdn.com/image/fetch/$s_!7tKH!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F605244c5-aea5-4eb9-b9de-c5f7c157d365_733x429.png 1272w, https://substackcdn.com/image/fetch/$s_!7tKH!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F605244c5-aea5-4eb9-b9de-c5f7c157d365_733x429.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!7tKH!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F605244c5-aea5-4eb9-b9de-c5f7c157d365_733x429.png" width="733" height="429" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/605244c5-aea5-4eb9-b9de-c5f7c157d365_733x429.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:429,&quot;width&quot;:733,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" title="" srcset="https://substackcdn.com/image/fetch/$s_!7tKH!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F605244c5-aea5-4eb9-b9de-c5f7c157d365_733x429.png 424w, https://substackcdn.com/image/fetch/$s_!7tKH!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F605244c5-aea5-4eb9-b9de-c5f7c157d365_733x429.png 848w, https://substackcdn.com/image/fetch/$s_!7tKH!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F605244c5-aea5-4eb9-b9de-c5f7c157d365_733x429.png 1272w, https://substackcdn.com/image/fetch/$s_!7tKH!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F605244c5-aea5-4eb9-b9de-c5f7c157d365_733x429.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!HdK-!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff3720a1f-6137-4676-ba1a-7c9bd7b0aadd_729x396.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!HdK-!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff3720a1f-6137-4676-ba1a-7c9bd7b0aadd_729x396.png 424w, https://substackcdn.com/image/fetch/$s_!HdK-!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff3720a1f-6137-4676-ba1a-7c9bd7b0aadd_729x396.png 848w, https://substackcdn.com/image/fetch/$s_!HdK-!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff3720a1f-6137-4676-ba1a-7c9bd7b0aadd_729x396.png 1272w, https://substackcdn.com/image/fetch/$s_!HdK-!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff3720a1f-6137-4676-ba1a-7c9bd7b0aadd_729x396.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!HdK-!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff3720a1f-6137-4676-ba1a-7c9bd7b0aadd_729x396.png" width="729" height="396" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/f3720a1f-6137-4676-ba1a-7c9bd7b0aadd_729x396.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:396,&quot;width&quot;:729,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" title="" srcset="https://substackcdn.com/image/fetch/$s_!HdK-!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff3720a1f-6137-4676-ba1a-7c9bd7b0aadd_729x396.png 424w, https://substackcdn.com/image/fetch/$s_!HdK-!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff3720a1f-6137-4676-ba1a-7c9bd7b0aadd_729x396.png 848w, https://substackcdn.com/image/fetch/$s_!HdK-!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff3720a1f-6137-4676-ba1a-7c9bd7b0aadd_729x396.png 1272w, https://substackcdn.com/image/fetch/$s_!HdK-!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff3720a1f-6137-4676-ba1a-7c9bd7b0aadd_729x396.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>In the long-term, from the same report, based on the current hiring levels and trades education pipeline, Ontario alone is expected to be short 35,500 construction workers by 2033 &#8212; and that&#8217;s assuming BuildForce&#8217;s own not-quite-adequate construction investment forecast seen in the earlier graph. To get back to 2016 affordability levels in a reasonable time, we&#8217;d need to find more skilled construction workers somewhere, either by attracting more young people to trades locally, or through immigration.</p><h2>Or&#8230; what if we lower the population growth?</h2><p>While we work on addressing the supply-side issues of housing, there&#8217;s one lever in the hands of the federal government that can easily control the demand side: immigration levels.</p><p>How will the changes to the immigration policy affect the outcomes?</p><p>Let&#8217;s tweak some numbers and redo the math:</p><ul><li><p>StatCan&#8217;s M2 growth projection scenario already assumes a net departure of around 212k non-permanent residents per year between 2025 and 2027. That&#8217;s roughly consistent with reducing foreign students to about 2019 numbers and losing about half of the temporary foreign worker permit holders. Let&#8217;s keep this as-is.</p></li><li><p>The current permanent resident admission target is 500k/year. Let&#8217;s lower it to 350k until 2035, which will still keep it mostly above the <a href="https://en.wikipedia.org/wiki/Canada_immigration_statistics">historic levels</a> and at around 0.8% of the current population.</p></li></ul><p>Let&#8217;s keep the construction industry output at their 2021 levels and see what the situation looks like:</p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;plaintext&quot;,&quot;nodeId&quot;:&quot;4c1e7291-a306-4514-b037-f05a07fb1232&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-plaintext">Year    Population &gt; 18    Units short
2025        33,283,800         668,723
2026        33,548,800         521,036
2027        33,822,800         382,890
2028        34,312,900         250,171
2029        34,800,100         233,516
2030        35,280,800         215,927
2031        35,761,400         195,478
2032        36,241,000         175,588
2033        36,715,500         155,773
2034        37,187,400         111,129
2035        37,652,100          85,173</code></pre></div><p>We gradually catch up! Not quickly, but the effects should start being felt after the first year, and should improve every year after that. And if the construction industry raises its output by just 3%/year (for a total of 12% in 5 years), we get to 2016 housing availability levels by 2031.</p><h2>Conclusions</h2><p>It took a while to get into the current housing crisis, and it will likely take a while to get out. Whoever ends up taking on this will have their work cut out for them.</p><p>We&#8217;ll need:</p><ul><li><p>The federal government doing its part in controlling the demand by managing the immigration levels.</p></li><li><p>Cities and provinces, especially Ontario and BC, to keep pushing for regulatory reforms;</p></li><li><p>Provinces continuing to expand capacity for trades education and making it more attractive for young people;</p></li><li><p>The construction industry finding ways to build better houses and apartments for less;</p></li><li><p>Figure out how to keep funding flowing into the construction industry;</p></li></ul><p>Whatever happens, I will keep following this with great interest.</p>]]></content:encoded></item><item><title><![CDATA[My lazy Wordle strategy: same words every time]]></title><description><![CDATA[TL;DR: After the analysis in this post, I started using SLANT/PRICE/DOUGH/BALMY, but it may not be the best sequence for you.]]></description><link>https://www.i-kh.net/p/my-lazy-wordle-strategy</link><guid isPermaLink="false">https://www.i-kh.net/p/my-lazy-wordle-strategy</guid><dc:creator><![CDATA[Iouri Khramtsov]]></dc:creator><pubDate>Fri, 22 Apr 2022 19:21:00 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!wkQp!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fba9e4c5b-a807-43e7-bf0b-f40f115853ee_340x343.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>There are lots of great videos and articles on the optimal <a href="https://en.wikipedia.org/wiki/Wordle">Wordle</a> strategy. I particularly enjoyed <a href="https://www.youtube.com/watch?v=v68zYyaEmEA">this YouTube video</a> by 3Blue1Brown on using the information theory to come up with the best guesses.</p><p>But I can&#8217;t play like that. First, I&#8217;m lazy, and second, my slow human brain can&#8217;t do information theory calculations or depth-first searches.</p><p>Instead, every time I play Wordle, I enter the same sequence of words until it feels like there aren&#8217;t many solutions left, at which point I try to make more tailored guesses.</p><p>Here are a couple examples of my recent games:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!0xXn!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F30e3ba99-6a0d-422a-9c39-9300657b3151_350x288.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!0xXn!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F30e3ba99-6a0d-422a-9c39-9300657b3151_350x288.png 424w, https://substackcdn.com/image/fetch/$s_!0xXn!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F30e3ba99-6a0d-422a-9c39-9300657b3151_350x288.png 848w, https://substackcdn.com/image/fetch/$s_!0xXn!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F30e3ba99-6a0d-422a-9c39-9300657b3151_350x288.png 1272w, https://substackcdn.com/image/fetch/$s_!0xXn!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F30e3ba99-6a0d-422a-9c39-9300657b3151_350x288.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!0xXn!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F30e3ba99-6a0d-422a-9c39-9300657b3151_350x288.png" width="350" height="288" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/30e3ba99-6a0d-422a-9c39-9300657b3151_350x288.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:288,&quot;width&quot;:350,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!0xXn!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F30e3ba99-6a0d-422a-9c39-9300657b3151_350x288.png 424w, https://substackcdn.com/image/fetch/$s_!0xXn!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F30e3ba99-6a0d-422a-9c39-9300657b3151_350x288.png 848w, https://substackcdn.com/image/fetch/$s_!0xXn!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F30e3ba99-6a0d-422a-9c39-9300657b3151_350x288.png 1272w, https://substackcdn.com/image/fetch/$s_!0xXn!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F30e3ba99-6a0d-422a-9c39-9300657b3151_350x288.png 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!wkQp!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fba9e4c5b-a807-43e7-bf0b-f40f115853ee_340x343.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!wkQp!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fba9e4c5b-a807-43e7-bf0b-f40f115853ee_340x343.png 424w, https://substackcdn.com/image/fetch/$s_!wkQp!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fba9e4c5b-a807-43e7-bf0b-f40f115853ee_340x343.png 848w, https://substackcdn.com/image/fetch/$s_!wkQp!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fba9e4c5b-a807-43e7-bf0b-f40f115853ee_340x343.png 1272w, https://substackcdn.com/image/fetch/$s_!wkQp!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fba9e4c5b-a807-43e7-bf0b-f40f115853ee_340x343.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!wkQp!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fba9e4c5b-a807-43e7-bf0b-f40f115853ee_340x343.png" width="340" height="343" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/ba9e4c5b-a807-43e7-bf0b-f40f115853ee_340x343.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:343,&quot;width&quot;:340,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!wkQp!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fba9e4c5b-a807-43e7-bf0b-f40f115853ee_340x343.png 424w, https://substackcdn.com/image/fetch/$s_!wkQp!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fba9e4c5b-a807-43e7-bf0b-f40f115853ee_340x343.png 848w, https://substackcdn.com/image/fetch/$s_!wkQp!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fba9e4c5b-a807-43e7-bf0b-f40f115853ee_340x343.png 1272w, https://substackcdn.com/image/fetch/$s_!wkQp!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fba9e4c5b-a807-43e7-bf0b-f40f115853ee_340x343.png 1456w" sizes="100vw"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>Until today, my go-to words were <code>STALE</code>, <code>CHIRP</code>, <code>MOUND</code>, and <code>GAWKY</code>, picked mostly by gut feel while trying to check as many frequently used letters as possible. So far I&#8217;ve been doing alright with them.</p><h2>But can we do better?</h2><p>Yes! Let&#8217;s use math and programming to do better.</p><p>Though to do computer science, we&#8217;ll need a more precise algorithm than &#8220;play these words until it feels like there aren&#8217;t many solutions left&#8221;. Let&#8217;s go with this:</p><ol><li><p>Pick four words.</p></li><li><p>In every game, keep guessing these words in order.</p></li><li><p>If there are 3 or fewer possible solutions left, make tailored guesses that minimize the number of turns to victory.</p></li></ol><p>Oh, and let&#8217;s use only the list of 2309 valid solution words (heplfully provided in Wordle&#8217;s JavaScript source code), and ignore the larger list of valid guesses. In part, that&#8217;s to make the calculations simpler, and in part because you&#8217;ll forget that <code>THEWY</code> is an acceptable guess by the time you&#8217;ll finish reading this sentence.</p><h2>Pick words that produce fewest remaining possible solutions?</h2><p>That was the first thing I tried.</p><p>For the first word, I picked one that resulted in the lowest remaining <a href="https://en.wikipedia.org/wiki/Entropy_(information_theory)">information entropy</a> (basically, fewest remaining options) on average across any of the 2309 valid solutions. That turned out to be <code>RAISE</code>.</p><p>Then, I picked the next word that gave me (on average, across all solutions) the most information after guessing <code>RAISE</code>. That turned out to be <code>CLOTH</code>. And so on, getting <code>DUMPY</code> and <code>BEGAN</code> as the best third and fourth words.</p><p>But how does it compare to the original <code>STALE</code>&gt;<code>CHIRP</code>&gt;<code>MOUND</code>&gt;<code>GAWKY</code>? If we simulate all 2309 possible games we see that:</p><ul><li><p><code>RAISE</code>/<code>CLOTH</code>/<code>DUMPY</code>/<code>BEGAN</code> wins all games and uses 3.89 guesses on average.</p></li><li><p>My original <code>STALE</code>/<code>CHIRP</code>/<code>MOUND</code>/<code>GAWKY</code> wins all games and uses 3.84 (!) guesses on average.</p></li></ul><p>&#128562; &#8265;&#65039; My original gut-feel word choices did better?</p><h2>Because each word being optimal &#8800; the full set is optimal</h2><p>So it turns out it&#8217;s not enough to optimize each word; instead, we have to jointly optimize the entire sequence <code>WORD1</code> <code>WORD2</code> <code>WORD3</code> <code>WORD4</code> across all possible word sequences.</p><p>But that&#8217;s a lot of sequences! I&#8217;m not sure how much exactly 2309<sup>4</sup> is, but it&#8217;s definitely more than my computer can handle. Even doing some intelligent pruning (e.g. &#8216;a letter must not repeat in the first 3 words&#8217;) still leaves a lot of options to evaluate. What else can we do to cut it down?</p><p>What I ended up doing was ranking all words by the number of bits of information that they provide, picking the top 10-100 words at each position for a total of ~160,000 four-word combinations, and then simulating all possible games for each sequence.</p><p>After two days at 100% CPU, my computer gave me the answer:</p><ul><li><p><code>SLANT</code> <code>PRICE</code> <code>DOUGH</code> <code>BALMY</code>: 3.79991 average guesses to win.</p></li></ul><p>But there were a lot of other sequences that produced similar results. For example #2 sequence was <code>CRANE</code> <code>SPILT</code> <code>DOUGH</code> <code>BALMY</code> that took on average 3.8008 guesses to win.</p><h2>But what if I&#8217;m a smart and tailor my guesses sooner?</h2><p>Or, to be less flippant, you can often get into situations where there are more than three guesses left, but you can easily enumerate them. The simplest example is if your first guess <code>SHARE</code> results in something like </p><p>There are lots of great videos and articles on the optimal <a href="https://en.wikipedia.org/wiki/Wordle">Wordle</a> strategy. I particularly enjoyed <a href="https://www.youtube.com/watch?v=v68zYyaEmEA">this YouTube video</a> by 3Blue1Brown on using the information theory to come up with the best guesses.</p><p>But I can&#8217;t play like that. First, I&#8217;m lazy, and second, my slow human brain can&#8217;t do information theory calculations or depth-first searches.</p><p>Instead, every time I play Wordle, I enter the same sequence of words until it feels like there aren&#8217;t many solutions left, at which point I try to make more tailored guesses.</p><p>Here are a couple examples of my recent games:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!xWZ1!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbf4f992c-3299-485e-b9e5-200a1778b40c_350x288.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!xWZ1!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbf4f992c-3299-485e-b9e5-200a1778b40c_350x288.png 424w, https://substackcdn.com/image/fetch/$s_!xWZ1!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbf4f992c-3299-485e-b9e5-200a1778b40c_350x288.png 848w, https://substackcdn.com/image/fetch/$s_!xWZ1!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbf4f992c-3299-485e-b9e5-200a1778b40c_350x288.png 1272w, https://substackcdn.com/image/fetch/$s_!xWZ1!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbf4f992c-3299-485e-b9e5-200a1778b40c_350x288.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!xWZ1!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbf4f992c-3299-485e-b9e5-200a1778b40c_350x288.png" width="350" height="288" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/bf4f992c-3299-485e-b9e5-200a1778b40c_350x288.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:288,&quot;width&quot;:350,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!xWZ1!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbf4f992c-3299-485e-b9e5-200a1778b40c_350x288.png 424w, https://substackcdn.com/image/fetch/$s_!xWZ1!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbf4f992c-3299-485e-b9e5-200a1778b40c_350x288.png 848w, https://substackcdn.com/image/fetch/$s_!xWZ1!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbf4f992c-3299-485e-b9e5-200a1778b40c_350x288.png 1272w, https://substackcdn.com/image/fetch/$s_!xWZ1!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbf4f992c-3299-485e-b9e5-200a1778b40c_350x288.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!UCj3!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9eaeb361-3bb8-4f15-9846-ebffab573077_340x343.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!UCj3!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9eaeb361-3bb8-4f15-9846-ebffab573077_340x343.png 424w, https://substackcdn.com/image/fetch/$s_!UCj3!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9eaeb361-3bb8-4f15-9846-ebffab573077_340x343.png 848w, https://substackcdn.com/image/fetch/$s_!UCj3!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9eaeb361-3bb8-4f15-9846-ebffab573077_340x343.png 1272w, https://substackcdn.com/image/fetch/$s_!UCj3!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9eaeb361-3bb8-4f15-9846-ebffab573077_340x343.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!UCj3!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9eaeb361-3bb8-4f15-9846-ebffab573077_340x343.png" width="340" height="343" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/9eaeb361-3bb8-4f15-9846-ebffab573077_340x343.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:343,&quot;width&quot;:340,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!UCj3!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9eaeb361-3bb8-4f15-9846-ebffab573077_340x343.png 424w, https://substackcdn.com/image/fetch/$s_!UCj3!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9eaeb361-3bb8-4f15-9846-ebffab573077_340x343.png 848w, https://substackcdn.com/image/fetch/$s_!UCj3!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9eaeb361-3bb8-4f15-9846-ebffab573077_340x343.png 1272w, https://substackcdn.com/image/fetch/$s_!UCj3!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9eaeb361-3bb8-4f15-9846-ebffab573077_340x343.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>Until today, my go-to words were <code>STALE</code>, <code>CHIRP</code>, <code>MOUND</code>, and <code>GAWKY</code>, picked mostly by gut feel while trying to check as many frequently used letters as possible. So far I&#8217;ve been doing alright with them.</p><h2>But can we do better?</h2><p>Yes! Let&#8217;s use math and programming to do better.</p><p>Though to do computer science, we&#8217;ll need a more precise algorithm than &#8220;play these words until it feels like there aren&#8217;t many solutions left&#8221;. Let&#8217;s go with this:</p><ol><li><p>Pick four words.</p></li><li><p>In every game, keep guessing these words in order.</p></li><li><p>If there are 3 or fewer possible solutions left, make tailored guesses that minimize the number of turns to victory.</p></li></ol><p>Oh, and let&#8217;s use only the list of 2309 valid solution words (heplfully provided in Wordle&#8217;s JavaScript source code), and ignore the larger list of valid guesses. In part, that&#8217;s to make the calculations simpler, and in part because you&#8217;ll forget that <code>THEWY</code> is an acceptable guess by the time you&#8217;ll finish reading this sentence.</p><h2>Pick words that produce fewest remaining possible solutions?</h2><p>That was the first thing I tried.</p><p>For the first word, I picked one that resulted in the lowest remaining <a href="https://en.wikipedia.org/wiki/Entropy_(information_theory)">information entropy</a> (basically, fewest remaining options) on average across any of the 2309 valid solutions. That turned out to be <code>RAISE</code>.</p><p>Then, I picked the next word that gave me (on average, across all solutions) the most information after guessing <code>RAISE</code>. That turned out to be <code>CLOTH</code>. And so on, getting <code>DUMPY</code> and <code>BEGAN</code> as the best third and fourth words.</p><p>(Along the way, I had to keep in mind that I had to switch to &#8220;smart&#8221; guesses if I had 3 or fewer valid solutions left.)</p><p>Here&#8217;s what each word contributed:</p><p>Guess Ave. remaining entropy (bits) Ave. options remaining Worst case options remaining <code>RAISE</code> 5.2 17.5 167 <code>CLOTH</code> 1.8 2.38 30 <code>DUMPY</code> 0.8 1.53 6 <code>BEGAN</code> 0.4 1.28 4</p><p>But how does it compare to the original <code>STALE</code>&gt;<code>CHIRP</code>&gt;<code>MOUND</code>&gt;<code>GAWKY</code>? If we simulate all 2309 possible games we see that:</p><ul><li><p><code>RAISE</code> <code>CLOTH</code> <code>DUMPY</code> <code>BEGAN</code> wins all games and uses 3.89 guesses on average.</p></li><li><p>My original <code>STALE</code> <code>CHIRP</code> <code>MOUND</code> <code>GAWKY</code> wins all games and uses 3.84 (!) guesses on average.</p></li></ul><p>&#128562; &#8265;&#65039; My original gut-feel word choices did better?</p><h2>Because each word being optimal &#8800; the full set is optimal</h2><p>So it turns out it&#8217;s not enough to optimize each word; instead, we have to jointly optimize the entire sequence <code>WORD1</code> <code>WORD2</code> <code>WORD3</code> <code>WORD4</code> across all possible word sequences.</p><p>But that&#8217;s a lot of sequences! I&#8217;m not sure how much exactly 2309<sup>4</sup> is, but it&#8217;s definitely more than my computer can handle. Even doing some intelligent pruning (e.g. &#8216;a letter must not repeat in the first 3 words&#8217;) still leaves a lot of options to evaluate. What else can we do to cut it down?</p><p>What I ended up doing was ranking all words by the number of bits of information that they provide, picking the top 10-100 words at each position for a total of ~160,000 four-word combinations, and then simulating all possible games for each sequence.</p><p>After two days at 100% CPU, my computer gave me the answer:</p><ul><li><p><code>SLANT</code> <code>PRICE</code> <code>DOUGH</code> <code>BALMY</code>: 3.79991 average guesses to win.</p></li></ul><p>But there were a lot of other sequences that produced similar results. For example #2 sequence was <code>CRANE</code> <code>SPILT</code> <code>DOUGH</code> <code>BALMY</code> that took on average 3.8008 guesses to win.</p><h2>But what if I&#8217;m a smart and tailor my guesses sooner?</h2><p>Or, to be less flippant, you can often get into situations where there are more than three guesses left, but you can easily enumerate them. The simplest example is if your first guess <code>SHARE</code> results in something like </p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!cac1!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F815cea16-bb19-4b5b-8fb7-39033faa9438_156x42.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!cac1!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F815cea16-bb19-4b5b-8fb7-39033faa9438_156x42.png 424w, https://substackcdn.com/image/fetch/$s_!cac1!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F815cea16-bb19-4b5b-8fb7-39033faa9438_156x42.png 848w, https://substackcdn.com/image/fetch/$s_!cac1!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F815cea16-bb19-4b5b-8fb7-39033faa9438_156x42.png 1272w, https://substackcdn.com/image/fetch/$s_!cac1!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F815cea16-bb19-4b5b-8fb7-39033faa9438_156x42.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!cac1!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F815cea16-bb19-4b5b-8fb7-39033faa9438_156x42.png" width="156" height="42" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/815cea16-bb19-4b5b-8fb7-39033faa9438_156x42.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:42,&quot;width&quot;:156,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:1821,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://iourikhramtsov.substack.com/i/212754173?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F815cea16-bb19-4b5b-8fb7-39033faa9438_156x42.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!cac1!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F815cea16-bb19-4b5b-8fb7-39033faa9438_156x42.png 424w, https://substackcdn.com/image/fetch/$s_!cac1!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F815cea16-bb19-4b5b-8fb7-39033faa9438_156x42.png 848w, https://substackcdn.com/image/fetch/$s_!cac1!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F815cea16-bb19-4b5b-8fb7-39033faa9438_156x42.png 1272w, https://substackcdn.com/image/fetch/$s_!cac1!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F815cea16-bb19-4b5b-8fb7-39033faa9438_156x42.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p>So let&#8217;s say that we start making tailored guesses when there are five possible solutions left instead of three. How does this change our optimal sequence?</p><p>After another day at 100% CPU, I ended up with <code>TRICE</code> <code>SALON</code> <code>DUMPY</code> <code>GLOBE</code>, which solved the puzzle in 3.72 steps on average.</p><p>But <code>SLANT</code> <code>PRICE</code> <code>DOUGH</code> <code>BALMY</code> wasn&#8217;t far behind, at 3.74 average guesses, and even the original <code>STALE</code> <code>CHIRP</code> <code>MOUND</code> <code>GAWKY</code> clocked in at respectable 3.79 guesses.</p><h2>But what if the word list changes?</h2><p>That&#8217;s a good question. It wouldn&#8217;t do to have a set of words that&#8217;s hyper-optimized for Wordle but not other similar puzzles.</p><p>So I took the list of <a href="https://github.com/possibly-wrong/word-frequency">words ranked by their occurrence in Google Books</a>, and selected top 3000 five-letter words.</p><p>Redoing the same analysis here gives us a new winner: <code>SAINT</code> <code>BORED</code> <code>CLUMP</code> <code>FIGHT</code> at 3.91 guesses to win, though again, <code>SLANT</code> <code>PRICE</code> <code>DOUGH</code> <code>BALMY</code> is not far behind with 3.96 guesses (athough with 99.93% win rate), and even my original <code>STALE</code> <code>CHIRP</code> <code>MOUND</code> <code>GAWKY</code> comes in at a not-terrible 3.98 average guesses and 99.90% win rate.</p><h2>So what&#8217;s the lesson?</h2><p>So it turns out that the <em>most</em> optimal sequence really depends on how you play the game and which Worlde-like game you play.</p><p>But if you want a good-enough sequence, it looks like you can pick any three words that cover the most frequently used letters, and then a fourth word that complements the other three well.</p><p>Personally, I think I&#8217;ll try <code>SLANT</code> <code>PRICE</code> <code>DOUGH</code> <code>BALMY</code> for the next while.</p><p>So let&#8217;s say that we start making tailored guesses when there are five possible solutions left instead of three. How does this change our optimal sequence?</p><p>After another day at 100% CPU, I ended up with <code>TRICE</code> <code>SALON</code> <code>DUMPY</code> <code>GLOBE</code>, which solved the puzzle in 3.72 steps on average.</p><p>But <code>SLANT</code> <code>PRICE</code> <code>DOUGH</code> <code>BALMY</code> wasn&#8217;t far behind, at 3.74 average guesses, and even the original <code>STALE</code> <code>CHIRP</code> <code>MOUND</code> <code>GAWKY</code> clocked in at respectable 3.79 guesses.</p><h2>But what if the word list changes?</h2><p>That&#8217;s a good question. It wouldn&#8217;t do to have a set of words that&#8217;s hyper-optimized for Wordle but not other similar puzzles.</p><p>So I took the list of <a href="https://github.com/possibly-wrong/word-frequency">words ranked by their occurrence in Google Books</a>, and selected top 3000 five-letter words.</p><p>Redoing the same analysis here gives us a new winner: <code>SAINT</code> <code>BORED</code> <code>CLUMP</code> <code>FIGHT</code> at 3.91 guesses to win, though again, <code>SLANT</code> <code>PRICE</code> <code>DOUGH</code> <code>BALMY</code> is not far behind with 3.96 guesses (athough with 99.93% win rate), and even my original <code>STALE</code> <code>CHIRP</code> <code>MOUND</code> <code>GAWKY</code> comes in at a not-terrible 3.98 average guesses and 99.90% win rate.</p><h2>So what&#8217;s the lesson?</h2><p>So it turns out that the <em>most</em> optimal sequence really depends on how you play the game and which Worlde-like game you play.</p><p>But if you want a good-enough sequence, it looks like you can pick any three words that cover the most frequently used letters, and then a fourth word that complements the other three well.</p><p>Personally, I think I&#8217;ll try <code>SLANT</code> <code>PRICE</code> <code>DOUGH</code> <code>BALMY</code> for the next while.</p>]]></content:encoded></item><item><title><![CDATA[REST API design: lessons learned from going down the wrong (and right) paths]]></title><description><![CDATA[Recently I had a chance to participate a sort of retrospective at work on how we organize and write REST API endpoints.]]></description><link>https://www.i-kh.net/p/api-design-lessons-learned</link><guid isPermaLink="false">https://www.i-kh.net/p/api-design-lessons-learned</guid><dc:creator><![CDATA[Iouri Khramtsov]]></dc:creator><pubDate>Fri, 22 Apr 2022 19:21:00 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!V9Qv!,w_256,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F64d2997e-d235-41e8-8ece-611b5f6c9f21_512x512.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Recently I had a chance to participate a sort of retrospective at work on how we organize and write REST API endpoints. That made me look back at some API design decisions I&#8217;ve made (and seen) over the years and realize that some of these choices are not at all obvious and that you often don&#8217;t see the tradeoffs until you&#8217;ve done it both ways and seen the results.</p><p>So here are some of the less obvious REST API design lessons that I&#8217;ve learned over the years.</p><h2>1. Do not nest objects in URL paths</h2><p>Suppose you have <code>task</code> objects that always belong to <code>project</code> objects. What would should be the URL to get information about a <code>task</code>? Should it be this:</p><pre><code>GET /api/projects/{projectId}/tasks/{taskId}</code></pre><p>or this?</p><pre><code>GET /api/tasks/{taskId}</code></pre><p>Having gone both ways, I now confidently think that the bottom choice is the best one. If you have a <code>taskId</code>, then <code>projectId</code> is redundant, and by including <code>projectId</code> in the URL you&#8217;re making the caller look up a piece of information that they may not have or need otherwise. And what happens when the caller provides the wrong <code>projectId</code>? Should you return <code>404 Not Found</code> even though you can unambiguously locate the task? You&#8217;ll also have to add extra validation code to check that the task is really in the right project&#8212;something that you wouldn&#8217;t need to do with the shorter version of the URL.</p><p>You may ask: &#8220;But how do you add a task to a project then?&#8221;</p><p>Well, how about this?</p><pre><code>POST /api/tasks
...
{
    &#8220;projectId&#8221;: 1234567,
    ...
}</code></pre><p>You may then ask, &#8220;But how do you look up tasks for a project if you can&#8217;t do <code>GET /api/project/{id}/tasks</code>?&#8221;</p><p>Like this:</p><pre><code>GET /api/tasks?projectId=&lt;projectId&gt;</code></pre><p>As a bonus, you get an endpoint to list <em>all</em> the tasks irrespective of which project they&#8217;re in. And this approach treats <code>projectId</code> as one of multiple optional filters that may be applied on <code>/api/tasks</code>, alongside maybe <code>status</code>, <code>assignedTo</code>, or any others.</p><h2>2. Of the 2xx HTTP status codes, you only need 200 OK</h2><p>This one wasn&#8217;t obvious to me until a coworker recently pointed out that he&#8217;s never seen a case where the caller had to make a decision based on the type of 2xx return code they got back.</p><p>And indeed, although <a href="https://www.rfc-editor.org/rfc/rfc9110.html">RFC 9116</a> &#8212; the current HTTP spec &#8212; defines <a href="https://www.rfc-editor.org/rfc/rfc9110.html#name-successful-2xx">seven different 2xx success codes</a>, in practice, the client-side code almost never needs to make a decision based on whether it receives e.g. <code>200 OK</code> or <code>201 Created</code>. Alright, in very rare cases it&#8217;s convenient when the server returns <code>204 No Content</code> when you&#8217;re debugging and trying whether the request is really supposed to be missing a body. But you can accomplish the same thing with <code>Content-Length</code> header, or by some other means.</p><p>I have, however, seen developers spend hours going back and forth on which 2xx code should be used for a specific endpoint. So to save everyone&#8217;s time, let&#8217;s just use <code>200 OK</code> and forget about the rest.</p><h2>3. Encode timestamps in a human-readable format</h2><p>If you&#8217;re sending or receiving timestamps, it may be tempting to use something like the <a href="https://currentmillis.com/">Unix epoch time in milliseconds</a> (the number of milliseconds since 00:00 UTC on Jan 1, 1970). It&#8217;s not a bad choice, and it&#8217;s quite convenient to work with.</p><p>Except it&#8217;s not human readable. Something like <a href="https://en.wikipedia.org/wiki/ISO_8601">ISO 8601</a> (e.g. <code>2023&#8208;07&#8208;12T23:57:23Z</code>) is easier to read for a human, and you can even drop the colons (<code>2023&#8208;07&#8208;12T235723Z</code>) to make it URL-compatible.</p><p>It may take a bit extra work to configure your framework to emit times in the right format, but it will make using (and debugging) the API a lot easier.</p><p>By the way, don&#8217;t forget to include time zone in your timestamps, even if it&#8217;s just a <code>Z</code> at the end.</p><h2>4. Pagination: avoid offsets and provide a link to the next page</h2><p>There are broadly two ways to do pagination:</p><ul><li><p><strong>Page number and page size</strong>: e.g. <code>https://.../things?page=10&amp;pageSize=20</code>. This will work alright up to maybe page 10,000 or so, at which point, if the server is fetching the results from a database, you&#8217;ll start running into a quirk with <code>OFFSET</code> that can <a href="https://stackoverflow.com/questions/67057110/offset-fetch-is-slow-on-high-paging-value">substantially degrade performance</a>. So while this pagination approach is convenient when the results go into a paginated UI, it&#8217;s a bad idea to use it for an endpoint that will be called by export jobs or by anything else that will ask for a large number of pages with high offsets. Instead, it&#8217;s much better to use&#8230;</p></li><li><p><code>WHERE</code><strong>-based pagination</strong>: where the caller provides something akin to a <code>where</code> clause, like <code>https://.../things?fromId=12345678</code>. If this argument corresponds to a DB index, the response times should stay constant-ish as <code>fromId</code> argument increases, unlike <code>OFFSET</code> whose response times tend to increase linearly.</p></li></ul><p>Oh, and if anyone will be iterating over multiple pages of responses, it really helps to include the URL of the next page in the response body:</p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;json&quot;,&quot;nodeId&quot;:&quot;00e8e208-d4b9-46a5-8043-3db9681eb3c4&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-json">{
    "data": [ ... ],
    "metadata": {
        "nextPage": "https://..."
    }
}</code></pre></div>]]></content:encoded></item><item><title><![CDATA[Progress in neural electrodes]]></title><description><![CDATA[Suppose you want to collect some signals from neurons in the brain.]]></description><link>https://www.i-kh.net/p/progress-in-neural-electrodes</link><guid isPermaLink="false">https://www.i-kh.net/p/progress-in-neural-electrodes</guid><dc:creator><![CDATA[Iouri Khramtsov]]></dc:creator><pubDate>Mon, 28 Jun 2021 00:34:00 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!D9D1!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F82f36db4-0043-41a5-8b99-d96bccf7825a_3409x2655.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Suppose you want to collect some signals from neurons in the brain. What kind of wire should you stick into the brain to do that? Could it be just any wire, or do you need some special brain-grade wire?</p><p>That&#8217;s something that I&#8217;ve been curious about for a while now, so I&#8217;ve read a bunch of papers on the subject.</p><h2>Metal electrodes</h2><p>Surprisingly, off-the-shelf <a href="https://www.remingtonindustries.com/magnet-wire/magnet-wire-200c-44-awg-polyamideimide-5-spool-sizes/">44 AWG insulated copper wire</a> is not a completely terrible choice. Its 51&#956;m diameter (plus insulation) is a bit on the high end for a typical intracortical electrode, but it&#8217;s about the right order of magnitude. If you stick it in, for a short time it has a decent chance of picking up electric spikes that nearby neurons send when they get excited.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!D9D1!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F82f36db4-0043-41a5-8b99-d96bccf7825a_3409x2655.jpeg" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!D9D1!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F82f36db4-0043-41a5-8b99-d96bccf7825a_3409x2655.jpeg 424w, https://substackcdn.com/image/fetch/$s_!D9D1!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F82f36db4-0043-41a5-8b99-d96bccf7825a_3409x2655.jpeg 848w, https://substackcdn.com/image/fetch/$s_!D9D1!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F82f36db4-0043-41a5-8b99-d96bccf7825a_3409x2655.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!D9D1!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F82f36db4-0043-41a5-8b99-d96bccf7825a_3409x2655.jpeg 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!D9D1!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F82f36db4-0043-41a5-8b99-d96bccf7825a_3409x2655.jpeg" width="1456" height="1134" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/82f36db4-0043-41a5-8b99-d96bccf7825a_3409x2655.jpeg&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1134,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!D9D1!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F82f36db4-0043-41a5-8b99-d96bccf7825a_3409x2655.jpeg 424w, https://substackcdn.com/image/fetch/$s_!D9D1!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F82f36db4-0043-41a5-8b99-d96bccf7825a_3409x2655.jpeg 848w, https://substackcdn.com/image/fetch/$s_!D9D1!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F82f36db4-0043-41a5-8b99-d96bccf7825a_3409x2655.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!D9D1!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F82f36db4-0043-41a5-8b99-d96bccf7825a_3409x2655.jpeg 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>But it&#8217;s still a terrible choice. First, the copper will quickly oxidize and corrode in the brain&#8217;s electrolyte-rich fluid. And second, copper is toxic to the neural tissue. So don&#8217;t put copper electrodes into anyone you love.</p><p>Okay, let&#8217;s try something else. How about an off-the-shelf <a href="https://wireandstuff.co.uk/product/0-04mm-46-awg-ss316l-marine-grade-stainless-steel-wire-596-83-ohms-m/">stainless steel 40&#956;m wire</a>? These are actually a legit choice, once you figure out how to insulate and sharpen them. In 1958, at UCLA, Felix Strumwasser sharpened 80&#956;m stainless steel wires with hydrochloric acid and <a href="https://science.sciencemag.org/content/127/3296/469">used them to record spikes</a> in neurons of ground squirrels for over a week. The wires were likely insulated by dipping them into lacquer, <a href="https://www.nature.com/articles/182962a0">as described by Green</a>, also from UCLA, later the same year.</p><p>However, the most popular electrode metal these days seems to be tungsten or <a href="https://www.fishersci.ca/shop/products/platinum-wire-0-025mm-0-001-in-dia-99-95-metals-basis-alfa-aesar-3/p-4782059#?keyword=platinum+wire">platinum</a>. Though noticeably pricier, it seems that these give you a better signal-to-noise ratio without messing with the brain chemistry.</p><p>So let&#8217;s say we get some platinum or wire, coat it with tissue-friendly <a href="https://en.wikipedia.org/wiki/Parylene">parylene C</a> for insulation, and then expose and sharpen its tip. Are we good?</p><p>Not quite.</p><h2>Multiple electrodes</h2><p>According to <a href="https://link.springer.com/chapter/10.1007/978-1-4939-1969-7_1">Techniques for Large-Scale Multiunit Recording</a>, inserting one electrode by itself is often not that useful. First, in addition to neural signals, the electrode will also pick up the background noise, including the AC power lines in the walls. Second, we often want to collect spikes from multiple sites to observe the behavior of more neurons.</p><p>The simplest way to increase the number of electrodes is to twist a few of them together, insert them, and measure the difference in voltage between some of the pairs. Taking the difference in voltage between the electrodes helps not only remove the background noise but also isolate individual neurons because the electrodes closer to the spiking neuron will register higher voltage swings.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!qY5-!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F57605b00-cee1-453a-8be3-36c397a45be6_589x307.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!qY5-!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F57605b00-cee1-453a-8be3-36c397a45be6_589x307.png 424w, https://substackcdn.com/image/fetch/$s_!qY5-!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F57605b00-cee1-453a-8be3-36c397a45be6_589x307.png 848w, https://substackcdn.com/image/fetch/$s_!qY5-!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F57605b00-cee1-453a-8be3-36c397a45be6_589x307.png 1272w, https://substackcdn.com/image/fetch/$s_!qY5-!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F57605b00-cee1-453a-8be3-36c397a45be6_589x307.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!qY5-!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F57605b00-cee1-453a-8be3-36c397a45be6_589x307.png" width="589" height="307" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/57605b00-cee1-453a-8be3-36c397a45be6_589x307.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:307,&quot;width&quot;:589,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;A tetrode (a probe with four electrodes) can distinguish spikes from different neurons in its neighborhood because the electrodes closer to the neuron will pick up bigger voltage spikes. Courtesy of Stuartlayton via Wikipedia https://en.wikipedia.org/wiki/File:HippocampalTetrodeExample.png.&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="A tetrode (a probe with four electrodes) can distinguish spikes from different neurons in its neighborhood because the electrodes closer to the neuron will pick up bigger voltage spikes. Courtesy of Stuartlayton via Wikipedia https://en.wikipedia.org/wiki/File:HippocampalTetrodeExample.png." title="A tetrode (a probe with four electrodes) can distinguish spikes from different neurons in its neighborhood because the electrodes closer to the neuron will pick up bigger voltage spikes. Courtesy of Stuartlayton via Wikipedia https://en.wikipedia.org/wiki/File:HippocampalTetrodeExample.png." srcset="https://substackcdn.com/image/fetch/$s_!qY5-!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F57605b00-cee1-453a-8be3-36c397a45be6_589x307.png 424w, https://substackcdn.com/image/fetch/$s_!qY5-!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F57605b00-cee1-453a-8be3-36c397a45be6_589x307.png 848w, https://substackcdn.com/image/fetch/$s_!qY5-!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F57605b00-cee1-453a-8be3-36c397a45be6_589x307.png 1272w, https://substackcdn.com/image/fetch/$s_!qY5-!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F57605b00-cee1-453a-8be3-36c397a45be6_589x307.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">A tetrode (a probe with four electrodes) can distinguish spikes from different neurons in its neighborhood because the electrodes closer to the neuron will pick up bigger voltage spikes. Courtesy of Stuartlayton via Wikipedia https://en.wikipedia.org/wiki/File:HippocampalTetrodeExample.png.</figcaption></figure></div><p>The next step up is electrode arrays, which help measure signals over larger areas or a range of depths. Here, silicon probes became popular, like the widely used <a href="https://www.blackrockmicro.com/products/#electrodes">Utah array</a> with as many as 100 needle-like electrodes, or a <a href="https://www.neuropixels.org/">Neuropixels probe</a>, which has a single shank with 960 electrodes.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!dm-H!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F38d53d25-db69-481a-9960-67ff13dfcffe_843x492.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!dm-H!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F38d53d25-db69-481a-9960-67ff13dfcffe_843x492.png 424w, https://substackcdn.com/image/fetch/$s_!dm-H!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F38d53d25-db69-481a-9960-67ff13dfcffe_843x492.png 848w, https://substackcdn.com/image/fetch/$s_!dm-H!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F38d53d25-db69-481a-9960-67ff13dfcffe_843x492.png 1272w, https://substackcdn.com/image/fetch/$s_!dm-H!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F38d53d25-db69-481a-9960-67ff13dfcffe_843x492.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!dm-H!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F38d53d25-db69-481a-9960-67ff13dfcffe_843x492.png" width="843" height="492" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/38d53d25-db69-481a-9960-67ff13dfcffe_843x492.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:492,&quot;width&quot;:843,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;2mm x 2mm Utah array. Image from patent US5215088A.&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="2mm x 2mm Utah array. Image from patent US5215088A." title="2mm x 2mm Utah array. Image from patent US5215088A." srcset="https://substackcdn.com/image/fetch/$s_!dm-H!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F38d53d25-db69-481a-9960-67ff13dfcffe_843x492.png 424w, https://substackcdn.com/image/fetch/$s_!dm-H!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F38d53d25-db69-481a-9960-67ff13dfcffe_843x492.png 848w, https://substackcdn.com/image/fetch/$s_!dm-H!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F38d53d25-db69-481a-9960-67ff13dfcffe_843x492.png 1272w, https://substackcdn.com/image/fetch/$s_!dm-H!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F38d53d25-db69-481a-9960-67ff13dfcffe_843x492.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">2mm x 2mm Utah array. Image from patent US5215088A.</figcaption></figure></div><p>Utah array in particular featured in a number of really cool experiments, like <a href="https://www.ncbi.nlm.nih.gov/pmc/articles/PMC5516547/">this BrainGate experiment</a> where researchers implanted Utah arrays into a tetraplegic individual and connected them to electrodes implanted in the hand muscles, allowing the subject to move his hands.</p><p>However, it turns out that silicon probes have their own problems, and aren&#8217;t the best thing to insert into the brain either.</p><h2>Biocompatibility</h2><p>So what&#8217;s the problem with the silicon probes?</p><p>Well, <a href="https://iopscience.iop.org/article/10.1088/1741-2560/8/2/025027/meta">a number</a> <a href="https://www.ncbi.nlm.nih.gov/pmc/articles/PMC4868924/">of studies</a> <a href="https://www.ncbi.nlm.nih.gov/pmc/articles/PMC2724357/">have shown</a> that over the months after the implantation, the signal from the electrodes weakens, and some of the previously working electrodes go silent.</p><p>And metal electrodes aren&#8217;t better either. For example, <a href="https://iopscience.iop.org/article/10.1088/1741-2560/9/5/056015">this study</a> tracked the performance of 50&#956;m tungsten electrodes over 9 months, and found that within the first few months, many electrodes could no longer detect spikes and the few that could, had much weaker or unstable signals. In some individual rats (who got the arrays implanted), by the end of the experiment, zero out of sixteen electrodes could detect useful signals</p><p>To be clear, all of these studies showed that in almost all cases it was still possible to get useful signals at the end of the experiment, just that over time the signal quality got noticeably worse.</p><p>So can we do better?</p><p>A lot of studies have dug into why the signal quality decreases. <a href="https://www.ncbi.nlm.nih.gov/pmc/articles/PMC8152109/">This recent review</a> (section 2) summarizes the causes: (1) the electrodes create small stab wounds on the way in, damaging the tissue and the blood vessels; (2) electrode bodies cause chronic inflammation that results in a scar that surrounds the probe and reduces the signal quality; (3) all of the above cause nearby neurons to die or migrate away from the insertion site.</p><p>This can be made worse by the rigid bodies of the probes. Mammalian brains naturally move inside the skull, swelling with each pulse of blood from the heart, and rigid metal and silicon electrodes cannot deform at the same rate as the brain tissue.</p><p>To top it off, poorly chosen insulation can crack or detach from the probe, letting carefully collected signals leak back into the surrounding tissue.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!NZMT!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6c95e483-7da8-4b9c-b51a-21ea0f6b2b34_356x267.jpeg" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!NZMT!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6c95e483-7da8-4b9c-b51a-21ea0f6b2b34_356x267.jpeg 424w, https://substackcdn.com/image/fetch/$s_!NZMT!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6c95e483-7da8-4b9c-b51a-21ea0f6b2b34_356x267.jpeg 848w, https://substackcdn.com/image/fetch/$s_!NZMT!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6c95e483-7da8-4b9c-b51a-21ea0f6b2b34_356x267.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!NZMT!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6c95e483-7da8-4b9c-b51a-21ea0f6b2b34_356x267.jpeg 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!NZMT!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6c95e483-7da8-4b9c-b51a-21ea0f6b2b34_356x267.jpeg" width="356" height="267" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/6c95e483-7da8-4b9c-b51a-21ea0f6b2b34_356x267.jpeg&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:267,&quot;width&quot;:356,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;Insulation detaching from a tungsten electrode. Abhishek Prasad et al 2012 J. Neural Eng. 9 056015.&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="Insulation detaching from a tungsten electrode. Abhishek Prasad et al 2012 J. Neural Eng. 9 056015." title="Insulation detaching from a tungsten electrode. Abhishek Prasad et al 2012 J. Neural Eng. 9 056015." srcset="https://substackcdn.com/image/fetch/$s_!NZMT!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6c95e483-7da8-4b9c-b51a-21ea0f6b2b34_356x267.jpeg 424w, https://substackcdn.com/image/fetch/$s_!NZMT!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6c95e483-7da8-4b9c-b51a-21ea0f6b2b34_356x267.jpeg 848w, https://substackcdn.com/image/fetch/$s_!NZMT!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6c95e483-7da8-4b9c-b51a-21ea0f6b2b34_356x267.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!NZMT!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6c95e483-7da8-4b9c-b51a-21ea0f6b2b34_356x267.jpeg 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">Insulation detaching from a tungsten electrode. Abhishek Prasad et al 2012 J. Neural Eng. 9 056015.</figcaption></figure></div><h2>Smaller, softer electrodes</h2><p>Various recent reviews, such as <a href="https://www.ncbi.nlm.nih.gov/pmc/articles/PMC8152109/">this one</a> and <a href="https://www.ncbi.nlm.nih.gov/pmc/articles/PMC7523527/">this one</a>, suggest that the best electrodes would be:</p><ul><li><p>Made of very thin wires, comparable in size to neuron&#8217;s appendages (<a href="http://localhost:4000/2020/08/26/the-magic-of-ion-channels/">axons and dendrites</a>) - that&#8217;s &lt;10&#956;m across.</p></li><li><p>Soft, bending as easily as cortical tissue.</p></li><li><p>Covered in well-attached insulation that won&#8217;t agitate neurons or other cells in the brain.</p></li><li><p>&#8220;Floating&#8221;, that is, loosely attached to the skull or signal processing circuitry, allowing the electrodes to move as the brain moves.</p></li></ul><p>Over the last decade, a number of electrodes satisfying these conditions started appearing:</p><ul><li><p><a href="https://www.biorxiv.org/content/10.1101/460949v1.full">NeuroRoots</a>, made of 100nm-thick platinum wires encapsulated in parylene-C insulation; total cross-section: 1.5&#956;m x 7&#956;m.</p></li><li><p>Elon Musk-sponsored <a href="https://www.jmir.org/2019/10/e16194/">Neuralink</a>, which uses insulated gold &#8220;threads&#8221; that are 4-6&#181;m-thick and 5-50&#181;m wide, depending on the number of electrodes per thread.</p></li><li><p><a href="https://advances.sciencemag.org/content/5/3/eaav2842">Neurotassels</a> uses 100nm-thick gold electrodes wrapped in polyimide insulation; total cross-section: 3&#181;m x 12&#181;m.</p></li><li><p>Ultra-soft <a href="https://www.ncbi.nlm.nih.gov/pmc/articles/PMC5512864/">conducting polymer</a> microelectrodes, though at 125&#181;m these were much thicker than others on this list.</p></li><li><p><a href="https://www.ncbi.nlm.nih.gov/pmc/articles/PMC3524530/">Carbon fiber</a> electrodes around 9-10&#181;m in diameter.</p></li><li><p>And a variety of other wires, meshes, and probes.</p></li></ul><p>Most of these came with a study showing how much they outperform the previous generation of electrodes, and how little damage they do in a rat brain. In the case of something like NeuroRoots, it looks pretty impressive on paper: after 7 weeks, all 32 of the 32 implanted electrodes could pick up signals nearly as well as on the day they were implanted. In the case of the conducting polymer above, the study compared it to much thicker tungsten electrodes, making the comparison somewhat unfair.</p><h2>Conclusions</h2><p>So basically, yes, you would need a brain-grade wire to collect signals from neurons, and we&#8217;re still working out the specifics of what makes the wire &#8220;brain-grade&#8221;.</p><p>With the progress above made in the 2010s, I&#8217;m looking forward to seeing what the 2020s will bring.</p>]]></content:encoded></item><item><title><![CDATA[Getting started with FPGAs and Verilog]]></title><description><![CDATA[I&#8217;ve been curious about FPGAs since I first heard about them over ten years ago, and over the past month I finally gave them a try for a couple personal projects.]]></description><link>https://www.i-kh.net/p/getting-started-with-fpga-and-verilog</link><guid isPermaLink="false">https://www.i-kh.net/p/getting-started-with-fpga-and-verilog</guid><dc:creator><![CDATA[Iouri Khramtsov]]></dc:creator><pubDate>Wed, 26 May 2021 12:08:00 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!tLvo!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc2b1e1ac-d356-4a0e-ac28-d8c36d2e79e9_3763x2150.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>I&#8217;ve been curious about <a href="https://en.wikipedia.org/wiki/Field-programmable_gate_array">FPGAs</a> since I first heard about them over ten years ago, and over the past month I finally gave them a try for a couple personal projects.</p><p>The FPGAs are certainly&#8230; different from any other kind of programming, and it took a bit of effort and troubleshooting to get my FPGA calculator working. If you&#8217;re interested in getting into FPGAs, here are a few tips below.</p><h2>1. The basics</h2><p>Programming FPGAs is different from programming in JavaScript, C#, or C. There are no levels of abstraction between you and the hardware, so it&#8217;s essential to learn the foundations of digital logic.</p><p>For me, <a href="https://artofelectronics.net/">The Art of Electronics</a> worked very well &#8212; specifically, chapters 10-14.</p><p>The book first introduces the basic logic circuit elements, and then builds up to other components and concepts: flip-flops, clocking, different logic families, logic interfacing, three-state outputs, busses, etc.</p><p>Almost all of it was useful when I got to programming the FPGA.</p><p>If textbooks are not your thing, there are <a href="https://www.youtube.com/results?search_query=intro+to+digital+logic">lots of YouTube videos</a> covering the same subjects.</p><h2>2. Verilog</h2><p>There are three main hardware definition languages: Verilog, VHDL, and SystemVerilog. Either one is a valid choice, though I found that for Digilent and Xilinx (my choice of FPGA boards and chips) there were more Verilog examples, so I went with that.</p><p>Unfortunately, Verilog just doesn&#8217;t have as much great documentation as, say, TypeScript or C#. The best I could find were these two websites:</p><ul><li><p><a href="https://www.chipverify.com/verilog/verilog-tutorial">Chipverify Verilog Tutorial</a></p></li><li><p><a href="https://verilogguide.readthedocs.io/en/latest/verilog/overview.html">This Verilog guide</a> on readthedocs.io.</p></li></ul><p>I&#8217;ve read these before I started programming, and referred back to them a number of times afterwards.</p><h2>3. The board</h2><p>You can try buying an FPGA chip and soldering it to a board yourself, but it&#8217;s much easier to get a starter board that already includes all the necessary components such as configuration flash memory, USB interface, and voltage regulator.</p><p>For starter boards, I liked <a href="https://reference.digilentinc.com/programmable-logic/start">Digilent</a> boards the most and went with <a href="https://reference.digilentinc.com/programmable-logic/cmod-a7/start">Cmod A7</a> that had a Xilinx <a href="https://www.xilinx.com/products/silicon-devices/fpga/artix-7.html">Artix-7</a> chip on it. It was powerful enough to fit the projects I wanted to build with room to spare, and it could plug into a breadboard.</p><p>Alternatively, if you&#8217;re looking to spend less, <a href="https://reference.digilentinc.com/programmable-logic/cmod-s7/start">Cmod S7</a> seems like a decent choice, and if you&#8217;re looking for more power, there&#8217;s something like <a href="https://reference.digilentinc.com/programmable-logic/arty-a7/start">Arty A7</a>.</p><h2>4. Making the LED blink</h2><p>Now we have everything we need to take FPGA for a test drive.</p><p>If you&#8217;ve gone with a Digilent board, the next step that worked for me was to go through the <a href="https://reference.digilentinc.com/learn/software/tutorials/verilog-project-2/start">Getting started with Vivado</a> guide from Digilent.</p><p>Be aware that there are a few quirks that you may run into:</p><ul><li><p>The LED port name in the module definition must exactly match the port name in the constraints file. For example, it can&#8217;t be <code>led[0]</code> in the constraints file and <code>led</code> in the module definitions - you&#8217;ll get an error when generating the bitstream.</p></li><li><p>Xilinx wants you to create an account before using Vivado, and they want you to enter something that looks like a real address when doing so. They&#8217;ll check the address, but not too thoroughly. You&#8217;ll need to log into the account when starting Vivado.</p></li></ul><h2>5. Now build your first project.</h2><p>From here, build whatever you were thinking of.</p><p>If you&#8217;re looking for an idea for a simple project before moving on to something more interesting, I found a calculator to have just the right amount of complexity:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!tLvo!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc2b1e1ac-d356-4a0e-ac28-d8c36d2e79e9_3763x2150.jpeg" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!tLvo!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc2b1e1ac-d356-4a0e-ac28-d8c36d2e79e9_3763x2150.jpeg 424w, https://substackcdn.com/image/fetch/$s_!tLvo!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc2b1e1ac-d356-4a0e-ac28-d8c36d2e79e9_3763x2150.jpeg 848w, https://substackcdn.com/image/fetch/$s_!tLvo!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc2b1e1ac-d356-4a0e-ac28-d8c36d2e79e9_3763x2150.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!tLvo!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc2b1e1ac-d356-4a0e-ac28-d8c36d2e79e9_3763x2150.jpeg 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!tLvo!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc2b1e1ac-d356-4a0e-ac28-d8c36d2e79e9_3763x2150.jpeg" width="1456" height="832" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/c2b1e1ac-d356-4a0e-ac28-d8c36d2e79e9_3763x2150.jpeg&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:832,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" title="" srcset="https://substackcdn.com/image/fetch/$s_!tLvo!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc2b1e1ac-d356-4a0e-ac28-d8c36d2e79e9_3763x2150.jpeg 424w, https://substackcdn.com/image/fetch/$s_!tLvo!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc2b1e1ac-d356-4a0e-ac28-d8c36d2e79e9_3763x2150.jpeg 848w, https://substackcdn.com/image/fetch/$s_!tLvo!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc2b1e1ac-d356-4a0e-ac28-d8c36d2e79e9_3763x2150.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!tLvo!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc2b1e1ac-d356-4a0e-ac28-d8c36d2e79e9_3763x2150.jpeg 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>From here on, the things that helped me the most were:</p><ul><li><p>Carefully reading the documentation and the guides, as they often contain the answers you&#8217;re looking for. For example, each Digilent board has a <a href="https://reference.digilentinc.com/programmable-logic/cmod-a7/reference-manual">detailed reference manual</a> that explains how to work with each component that&#8217;s on the board.</p></li><li><p>The chip manufacturer has detailed guides as well. For example, if you&#8217;re looking to change the clock frequency on your FPGA chip, or want to work with multiple clock frequencies, Xilinx has a very thorough guide on <a href="https://www.xilinx.com/support/documentation/ip_documentation/mmcm_module.pdf">working with Mixed Mode Clock Managers</a>.</p></li><li><p>If you run into a problem, keep simplifying your logic until it starts working. For example, when I was having trouble sending data over the USB/UART link, I ended up removing all of my logic and just tying the RXD (send) wire to TXD (receive) wire to make sure that I could echo the characters through it using the COM terminal. Turns out I couldn&#8217;t because I mixed up which wire was the input and which was the output. The rest of my logic was correct.</p></li><li><p>If you get stuck, like everywhere else, use Google. Someone has run into a similar problem. If you don&#8217;t find the exact solution, at least you may get an idea that you can try next.</p></li></ul><h2>6. This will save you days</h2><p>I was going to lump this with the tips above, but this deserves its own section.</p><p>Put</p><pre><code>`default_nettype none</code></pre><p>at the beginning of every Verilog file (yes, including the backtick), and</p><pre><code>`default_nettype wire</code></pre><p>at the end.</p><p>This is because by default, if you make a typo in a variable name, Verilog will assume that you&#8217;ve defined a new variable of type <code>wire</code>. Because of this, I literally spent a day debugging a problem that was caused by a typo.</p><p>If you put <code>`default_type none</code>, Verilog will complain that it doesn&#8217;t know the variable type and will bring your attention to the typo.</p><p>The closing <code>`default_nettype wire</code> is necessary because apparently some of Xilinx&#8217;s own modules (called &#8220;IP&#8221; in FPGA terminology) rely on implicitly defined variable types.</p>]]></content:encoded></item><item><title><![CDATA[Human vision system - a simple description]]></title><description><![CDATA[So when we see something in front of us, like a pencil, how exactly does the brain understand that yep, that&#8217;s a pencil?]]></description><link>https://www.i-kh.net/p/human-vision-system-an-overview</link><guid isPermaLink="false">https://www.i-kh.net/p/human-vision-system-an-overview</guid><dc:creator><![CDATA[Iouri Khramtsov]]></dc:creator><pubDate>Mon, 01 Mar 2021 01:45:00 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!818L!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F86bc1629-19d3-4367-83d8-b651a8540614_2897x1454.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!818L!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F86bc1629-19d3-4367-83d8-b651a8540614_2897x1454.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!818L!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F86bc1629-19d3-4367-83d8-b651a8540614_2897x1454.png 424w, https://substackcdn.com/image/fetch/$s_!818L!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F86bc1629-19d3-4367-83d8-b651a8540614_2897x1454.png 848w, https://substackcdn.com/image/fetch/$s_!818L!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F86bc1629-19d3-4367-83d8-b651a8540614_2897x1454.png 1272w, https://substackcdn.com/image/fetch/$s_!818L!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F86bc1629-19d3-4367-83d8-b651a8540614_2897x1454.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!818L!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F86bc1629-19d3-4367-83d8-b651a8540614_2897x1454.png" width="1456" height="731" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/86bc1629-19d3-4367-83d8-b651a8540614_2897x1454.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:731,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" title="" srcset="https://substackcdn.com/image/fetch/$s_!818L!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F86bc1629-19d3-4367-83d8-b651a8540614_2897x1454.png 424w, https://substackcdn.com/image/fetch/$s_!818L!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F86bc1629-19d3-4367-83d8-b651a8540614_2897x1454.png 848w, https://substackcdn.com/image/fetch/$s_!818L!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F86bc1629-19d3-4367-83d8-b651a8540614_2897x1454.png 1272w, https://substackcdn.com/image/fetch/$s_!818L!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F86bc1629-19d3-4367-83d8-b651a8540614_2897x1454.png 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>So when we see something in front of us, like a pencil, how exactly does the brain understand that yep, that&#8217;s a pencil?</p><p>Like, what is the detailed sequence of steps that happens? The eyes presumably convert the light to neural signals (how?), then these get sent to the brain (where?), and then the brain does&#8230; what?</p><p>I&#8217;ve been reading through a bunch of neuroscience textbooks and papers for the past six months, and I think I&#8217;m at the point where I&#8217;ve now got the whole picture.</p><p>So here are the core pieces of this picture, with a lot of details omitted to fit it into a short blog post.</p><p>Let&#8217;s start with the input.</p><h2>What exactly do the eyes do?</h2><p>The main output of the eyes are the neurons called <em>ganglion cells</em> that live in the thin layer of tissue at the back of the eye. To grossly oversimplify, these ganglion cells transmit the brightness of each pixel of the picture that&#8217;s projected onto the back of the eye, though the reality is <a href="https://i-kh.net/2020/10/31/retina-circuits-more-than-just-pixels/">much more complex</a>.</p><p>To transmit this information, the neurons use spikes of voltage &#8211; that&#8217;s when the voltage between the inside and the outside of the cell suddenly rises from somewhere around -60 mV to around 0 mV and falls back down over the course of about a millisecond.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!23cq!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc5d37fd7-bb7c-48d6-9826-923f9e8b65ef_2503x1454.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!23cq!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc5d37fd7-bb7c-48d6-9826-923f9e8b65ef_2503x1454.png 424w, https://substackcdn.com/image/fetch/$s_!23cq!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc5d37fd7-bb7c-48d6-9826-923f9e8b65ef_2503x1454.png 848w, https://substackcdn.com/image/fetch/$s_!23cq!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc5d37fd7-bb7c-48d6-9826-923f9e8b65ef_2503x1454.png 1272w, https://substackcdn.com/image/fetch/$s_!23cq!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc5d37fd7-bb7c-48d6-9826-923f9e8b65ef_2503x1454.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!23cq!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc5d37fd7-bb7c-48d6-9826-923f9e8b65ef_2503x1454.png" width="1456" height="846" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/c5d37fd7-bb7c-48d6-9826-923f9e8b65ef_2503x1454.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:846,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" title="" srcset="https://substackcdn.com/image/fetch/$s_!23cq!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc5d37fd7-bb7c-48d6-9826-923f9e8b65ef_2503x1454.png 424w, https://substackcdn.com/image/fetch/$s_!23cq!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc5d37fd7-bb7c-48d6-9826-923f9e8b65ef_2503x1454.png 848w, https://substackcdn.com/image/fetch/$s_!23cq!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc5d37fd7-bb7c-48d6-9826-923f9e8b65ef_2503x1454.png 1272w, https://substackcdn.com/image/fetch/$s_!23cq!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc5d37fd7-bb7c-48d6-9826-923f9e8b65ef_2503x1454.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>In the eyes, these spikes are caused by light-sensitive proteins called opsins that live in cells of another type, the <em>photoreceptors</em>. When photons hit the photoreceptor cells, the opsins in these cells absorb the photons and slightly change their structure, which causes a rapid cascade of chemical reactions across a few cells. At the end of this series of reactions, the ganglion cells let in some positively charged ions, raise their internal voltage, and start a spike.</p><p>(I&#8217;ve written more about how the ions cause spikes in <a href="https://i-kh.net/2020/08/26/the-magic-of-ion-channels/">another post</a>)</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!fDrR!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff9de19a1-ae59-4fb7-b594-7d4e7d2a40c6_3397x1265.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!fDrR!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff9de19a1-ae59-4fb7-b594-7d4e7d2a40c6_3397x1265.png 424w, https://substackcdn.com/image/fetch/$s_!fDrR!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff9de19a1-ae59-4fb7-b594-7d4e7d2a40c6_3397x1265.png 848w, https://substackcdn.com/image/fetch/$s_!fDrR!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff9de19a1-ae59-4fb7-b594-7d4e7d2a40c6_3397x1265.png 1272w, https://substackcdn.com/image/fetch/$s_!fDrR!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff9de19a1-ae59-4fb7-b594-7d4e7d2a40c6_3397x1265.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!fDrR!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff9de19a1-ae59-4fb7-b594-7d4e7d2a40c6_3397x1265.png" width="1456" height="542" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/f9de19a1-ae59-4fb7-b594-7d4e7d2a40c6_3397x1265.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:542,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" title="" srcset="https://substackcdn.com/image/fetch/$s_!fDrR!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff9de19a1-ae59-4fb7-b594-7d4e7d2a40c6_3397x1265.png 424w, https://substackcdn.com/image/fetch/$s_!fDrR!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff9de19a1-ae59-4fb7-b594-7d4e7d2a40c6_3397x1265.png 848w, https://substackcdn.com/image/fetch/$s_!fDrR!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff9de19a1-ae59-4fb7-b594-7d4e7d2a40c6_3397x1265.png 1272w, https://substackcdn.com/image/fetch/$s_!fDrR!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff9de19a1-ae59-4fb7-b594-7d4e7d2a40c6_3397x1265.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>The whole system is set up to handle different volumes of light: the more light is shining on the photoreceptors, the more spikes are produced by the ganglion cells.</p><p>So, to grossly oversimplify even more, more light =&gt; more spikes in the ganglion cells.</p><p>And now what?</p><h2>Where do the signals go?</h2><p>The ganglion cells live at the back of the eyes, but they have long output extensions (axons) that run from the eye, through the optic nerve, and right into the center of the brain. That&#8217;s where the thalamus &#8211; the brain&#8217;s main switchboard &#8211; is located.</p><p>In an adult human, that&#8217;s about 10 cm or 4 in of length, and that&#8217;s far from the record for the length of a neuron. The spikes travel along the full length.</p><p>One of the interesting things that happen along the way is that the optic nerves cross at about the half-way mark, and the neurons from the left half of each eye end up traveling to the left half of the brain, while the neurons from the right half of each eye go to the right.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!gJT2!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb91dce81-d44e-4c98-8c07-1e70bd93556c_360x500.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!gJT2!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb91dce81-d44e-4c98-8c07-1e70bd93556c_360x500.png 424w, https://substackcdn.com/image/fetch/$s_!gJT2!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb91dce81-d44e-4c98-8c07-1e70bd93556c_360x500.png 848w, https://substackcdn.com/image/fetch/$s_!gJT2!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb91dce81-d44e-4c98-8c07-1e70bd93556c_360x500.png 1272w, https://substackcdn.com/image/fetch/$s_!gJT2!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb91dce81-d44e-4c98-8c07-1e70bd93556c_360x500.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!gJT2!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb91dce81-d44e-4c98-8c07-1e70bd93556c_360x500.png" width="360" height="500" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/b91dce81-d44e-4c98-8c07-1e70bd93556c_360x500.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:500,&quot;width&quot;:360,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;Source: Gray's anatomy, fig. 722, https://www.bartleby.com/107/illus722.html&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="Source: Gray's anatomy, fig. 722, https://www.bartleby.com/107/illus722.html" title="Source: Gray's anatomy, fig. 722, https://www.bartleby.com/107/illus722.html" srcset="https://substackcdn.com/image/fetch/$s_!gJT2!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb91dce81-d44e-4c98-8c07-1e70bd93556c_360x500.png 424w, https://substackcdn.com/image/fetch/$s_!gJT2!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb91dce81-d44e-4c98-8c07-1e70bd93556c_360x500.png 848w, https://substackcdn.com/image/fetch/$s_!gJT2!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb91dce81-d44e-4c98-8c07-1e70bd93556c_360x500.png 1272w, https://substackcdn.com/image/fetch/$s_!gJT2!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb91dce81-d44e-4c98-8c07-1e70bd93556c_360x500.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">Source: Gray's anatomy, fig. 722, https://www.bartleby.com/107/illus722.html</figcaption></figure></div><p>This way, each hemisphere of the brain will be able to construct a stereo picture of each half of the visual field.</p><p>From the thalamus, a new set of neurons picks up the same information and forwards it to the back of the brain - the occipital lobe - where the brain will do its magic.</p><h2>And the brain does&#8230; what?</h2><p>In the brain, visual processing is done through a sequence of visual cortex areas - V1, V2, V3, etc, each of which extracts progressively more complex features from the original signal.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!pvKm!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6c9893a7-5dde-4686-bf53-633cc71fb6e3_2670x1326.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!pvKm!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6c9893a7-5dde-4686-bf53-633cc71fb6e3_2670x1326.png 424w, https://substackcdn.com/image/fetch/$s_!pvKm!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6c9893a7-5dde-4686-bf53-633cc71fb6e3_2670x1326.png 848w, https://substackcdn.com/image/fetch/$s_!pvKm!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6c9893a7-5dde-4686-bf53-633cc71fb6e3_2670x1326.png 1272w, https://substackcdn.com/image/fetch/$s_!pvKm!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6c9893a7-5dde-4686-bf53-633cc71fb6e3_2670x1326.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!pvKm!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6c9893a7-5dde-4686-bf53-633cc71fb6e3_2670x1326.png" width="1456" height="723" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/6c9893a7-5dde-4686-bf53-633cc71fb6e3_2670x1326.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:723,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;Visual processing pipeline. Adapted from https://doi.org/10.1016/S1364-6613%2898%2901171-1, https://doi.org/10.1016/j.tics.2012.03.003&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="Visual processing pipeline. Adapted from https://doi.org/10.1016/S1364-6613%2898%2901171-1, https://doi.org/10.1016/j.tics.2012.03.003" title="Visual processing pipeline. Adapted from https://doi.org/10.1016/S1364-6613%2898%2901171-1, https://doi.org/10.1016/j.tics.2012.03.003" srcset="https://substackcdn.com/image/fetch/$s_!pvKm!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6c9893a7-5dde-4686-bf53-633cc71fb6e3_2670x1326.png 424w, https://substackcdn.com/image/fetch/$s_!pvKm!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6c9893a7-5dde-4686-bf53-633cc71fb6e3_2670x1326.png 848w, https://substackcdn.com/image/fetch/$s_!pvKm!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6c9893a7-5dde-4686-bf53-633cc71fb6e3_2670x1326.png 1272w, https://substackcdn.com/image/fetch/$s_!pvKm!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6c9893a7-5dde-4686-bf53-633cc71fb6e3_2670x1326.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">Visual processing pipeline. Adapted from https://doi.org/10.1016/S1364-6613%2898%2901171-1, https://doi.org/10.1016/j.tics.2012.03.003</figcaption></figure></div><p>The first one of these, V1, is located right at the back of the brain; it represents nearly pixel-for-pixel what the eye sees - that is, the neighboring neurons in V1 represent neighboring points on the image.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!2Kbt!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F435a18ed-b08e-4290-bccb-1266bdf088f3_2321x1454.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!2Kbt!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F435a18ed-b08e-4290-bccb-1266bdf088f3_2321x1454.png 424w, https://substackcdn.com/image/fetch/$s_!2Kbt!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F435a18ed-b08e-4290-bccb-1266bdf088f3_2321x1454.png 848w, https://substackcdn.com/image/fetch/$s_!2Kbt!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F435a18ed-b08e-4290-bccb-1266bdf088f3_2321x1454.png 1272w, https://substackcdn.com/image/fetch/$s_!2Kbt!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F435a18ed-b08e-4290-bccb-1266bdf088f3_2321x1454.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!2Kbt!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F435a18ed-b08e-4290-bccb-1266bdf088f3_2321x1454.png" width="1456" height="912" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/435a18ed-b08e-4290-bccb-1266bdf088f3_2321x1454.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:912,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;Left visual field is faithfully represented in the left V1 area, except the center of vision is exaggerated. Adapted from http://fourier.eng.hmc.edu/e180/lectures/v1/node3.html&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="Left visual field is faithfully represented in the left V1 area, except the center of vision is exaggerated. Adapted from http://fourier.eng.hmc.edu/e180/lectures/v1/node3.html" title="Left visual field is faithfully represented in the left V1 area, except the center of vision is exaggerated. Adapted from http://fourier.eng.hmc.edu/e180/lectures/v1/node3.html" srcset="https://substackcdn.com/image/fetch/$s_!2Kbt!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F435a18ed-b08e-4290-bccb-1266bdf088f3_2321x1454.png 424w, https://substackcdn.com/image/fetch/$s_!2Kbt!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F435a18ed-b08e-4290-bccb-1266bdf088f3_2321x1454.png 848w, https://substackcdn.com/image/fetch/$s_!2Kbt!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F435a18ed-b08e-4290-bccb-1266bdf088f3_2321x1454.png 1272w, https://substackcdn.com/image/fetch/$s_!2Kbt!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F435a18ed-b08e-4290-bccb-1266bdf088f3_2321x1454.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">Left visual field is faithfully represented in the left V1 area, except the center of vision is exaggerated. Adapted from http://fourier.eng.hmc.edu/e180/lectures/v1/node3.html</figcaption></figure></div><p>In V1, a series of neural connections detect basic features like edges, colors, directions, or motion in each patch of the visual field. If the neurons responsible for detecting a specific feature detect it, they fire a series of spikes, letting the downstream areas know what they found.</p><p>The downstream areas - V2, V3, etc. - extract progressively more and more complex features over larger and larger areas.</p><p>If you&#8217;re familiar with Convolutional Neural Networks (if you&#8217;re not, here&#8217;s <a href="https://towardsdatascience.com/a-comprehensive-guide-to-convolutional-neural-networks-the-eli5-way-3bd2b1164a53">a good explainer</a>), that&#8217;s pretty much exactly what&#8217;s going on here.</p><p>Early on, the processing path splits into two branches: the bottom one that&#8217;s focused on recognizing objects, and the top one that&#8217;s focused on building a mental picture of space and motion.</p><p>At the end of the bottom branch are the areas that recognize faces, places, or objects, including the pencil that we started with.</p><p>Here, if the final collection of features extracted along the way add up to a specific known object, a collection of neurons that are associated with that object fires spikes to other areas of the brain, triggering appropriate emotions, thoughts, memories, and other associations that we may need at the moment.</p>]]></content:encoded></item><item><title><![CDATA[Image stabilization - in humans]]></title><description><![CDATA[As I read more neuroscience, I run into more interesting neural circuits.]]></description><link>https://www.i-kh.net/p/image-stabilization-in-humans</link><guid isPermaLink="false">https://www.i-kh.net/p/image-stabilization-in-humans</guid><dc:creator><![CDATA[Iouri Khramtsov]]></dc:creator><pubDate>Fri, 19 Feb 2021 01:09:00 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!FQ1o!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7ecea041-382f-48ba-8844-c697f6079170_1920x1080.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>As I read more neuroscience, I run into more interesting neural circuits. One of these circuits is the Vestibulo-Ocular Reflex (VOR) that helps us keep the eyes locked on a target when the head moves.</p><p>What&#8217;s interesting about it are both its simple wiring (at first glance), and the extensive hidden support circuitry that can tell us more about how the brain works.</p><p>VOR is not the only circuit that helps us keep our eyes locked on target; there are others that work in parallel. I suspect that they probably use the same underlying principles.</p><p>(Note: some links here are behind a paywall. Remember that it&#8217;s illegal to go to Sci-Hub and search for the DOI link of the article to get free access to it.)</p><h2>So what&#8217;s Vestibulo-Ocular Reflex?</h2><p>Pick a point on the screen, and while looking at it, turn your head left to right. Your head will move, but your eyes will stay locked onto that point.</p><p>For that to happen, the muscles that control your eyeballs need to change their tension at exactly the right time and by exactly the right amount to compensate for the movement of the head.</p><p>While at first glance that may seem tricky, in reality, the brain deals with it the same way as the smartphone: it just uses our internal accelerometer, the <em>vestibular apparatus</em>, pictured below in the red box.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!FQ1o!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7ecea041-382f-48ba-8844-c697f6079170_1920x1080.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!FQ1o!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7ecea041-382f-48ba-8844-c697f6079170_1920x1080.png 424w, https://substackcdn.com/image/fetch/$s_!FQ1o!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7ecea041-382f-48ba-8844-c697f6079170_1920x1080.png 848w, https://substackcdn.com/image/fetch/$s_!FQ1o!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7ecea041-382f-48ba-8844-c697f6079170_1920x1080.png 1272w, https://substackcdn.com/image/fetch/$s_!FQ1o!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7ecea041-382f-48ba-8844-c697f6079170_1920x1080.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!FQ1o!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7ecea041-382f-48ba-8844-c697f6079170_1920x1080.png" width="1456" height="819" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/7ecea041-382f-48ba-8844-c697f6079170_1920x1080.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:819,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;The vestibular organ is the collection of tubes in the red box. Source: Blausen.com staff (2014). \&quot;Medical gallery of Blausen Medical 2014\&quot;. WikiJournal of Medicine 1 (2). DOI:10.15347/wjm/2014.010. ISSN 2002-4436&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="The vestibular organ is the collection of tubes in the red box. Source: Blausen.com staff (2014). &quot;Medical gallery of Blausen Medical 2014&quot;. WikiJournal of Medicine 1 (2). DOI:10.15347/wjm/2014.010. ISSN 2002-4436" title="The vestibular organ is the collection of tubes in the red box. Source: Blausen.com staff (2014). &quot;Medical gallery of Blausen Medical 2014&quot;. WikiJournal of Medicine 1 (2). DOI:10.15347/wjm/2014.010. ISSN 2002-4436" srcset="https://substackcdn.com/image/fetch/$s_!FQ1o!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7ecea041-382f-48ba-8844-c697f6079170_1920x1080.png 424w, https://substackcdn.com/image/fetch/$s_!FQ1o!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7ecea041-382f-48ba-8844-c697f6079170_1920x1080.png 848w, https://substackcdn.com/image/fetch/$s_!FQ1o!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7ecea041-382f-48ba-8844-c697f6079170_1920x1080.png 1272w, https://substackcdn.com/image/fetch/$s_!FQ1o!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7ecea041-382f-48ba-8844-c697f6079170_1920x1080.png 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">The vestibular organ is the collection of tubes in the red box. Source: Blausen.com staff (2014). "Medical gallery of Blausen Medical 2014". WikiJournal of Medicine 1 (2). DOI:10.15347/wjm/2014.010. ISSN 2002-4436</figcaption></figure></div><h2>From accelerometer to muscles</h2><p>From the vestibular organ, there&#8217;s a simple three-neuron-long connection that feeds the accelerometer signal to the muscles that move the eyes, first documented <a href="https://doi.org/10.1001/archneurpsyc.1933.02240140009001">in the 1930s</a>. We can follow it to see what it does.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!NkHE!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1c3aac0c-43ca-439e-aff6-13a0417b4ef4_2160x2160.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!NkHE!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1c3aac0c-43ca-439e-aff6-13a0417b4ef4_2160x2160.png 424w, https://substackcdn.com/image/fetch/$s_!NkHE!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1c3aac0c-43ca-439e-aff6-13a0417b4ef4_2160x2160.png 848w, https://substackcdn.com/image/fetch/$s_!NkHE!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1c3aac0c-43ca-439e-aff6-13a0417b4ef4_2160x2160.png 1272w, https://substackcdn.com/image/fetch/$s_!NkHE!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1c3aac0c-43ca-439e-aff6-13a0417b4ef4_2160x2160.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!NkHE!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1c3aac0c-43ca-439e-aff6-13a0417b4ef4_2160x2160.png" width="1456" height="1456" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/1c3aac0c-43ca-439e-aff6-13a0417b4ef4_2160x2160.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1456,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!NkHE!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1c3aac0c-43ca-439e-aff6-13a0417b4ef4_2160x2160.png 424w, https://substackcdn.com/image/fetch/$s_!NkHE!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1c3aac0c-43ca-439e-aff6-13a0417b4ef4_2160x2160.png 848w, https://substackcdn.com/image/fetch/$s_!NkHE!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1c3aac0c-43ca-439e-aff6-13a0417b4ef4_2160x2160.png 1272w, https://substackcdn.com/image/fetch/$s_!NkHE!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1c3aac0c-43ca-439e-aff6-13a0417b4ef4_2160x2160.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>The neurons coming out of the vestibular organ output a steady stream of electric spikes. When the head turns left, the left vestibular neuron starts producing more electric spikes, and the right one - less. When the head stops moving, both vestibular neurons go back to the equal rate of spikes. If the head turns right, the opposite happens.</p><p>The signals from the vestibular neurons end up in the brainstem, the more basic part of the brain that sits between the cerebral cortex and the spine. There, another set of neurons directly connect them to the pools of motor neurons that move the eye muscles.</p><p>The muscle neurons, in turn, work according to rules we won&#8217;t go into right now, but it&#8217;s safe to simplify and say that the more excited they get the more the eye muscles contract.</p><p>So basically, when the head turns left, the increased rate of spikes from the left vestibular neuron is directly fed into the motorneurons that turn the eyes right.</p><p>End-to-end, this circuit is very fast. Experiments show that once the head starts turning, it takes less than 10 ms for the muscles to engage.</p><p>(Btw, Wikipedia has a <a href="https://en.wikipedia.org/wiki/Vestibulo%E2%80%93ocular_reflex">different wiring diagram</a>; I&#8217;ve seen it drawn both ways in papers. In practice, the result is the same either way.)</p><h2>Complication #1: the neural integrator</h2><p>So, on the surface, it seems that we&#8217;re done. The acceleration output feeds directly into the motorneurons, the eyes move, and we&#8217;re happy.</p><p>But here&#8217;s the problem: when the head is done turning, the vestibular organs go back to signaling at the base rate. Then the tension in the eye muscles goes back to equal, pointing the eyes straight. That&#8217;s not what we were hoping to see.</p><p>To fix that, we need to add a <em>neural integrator</em> to the picture.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!mJZ6!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff8d85a6b-ab18-4303-a735-0c0b3a547052_879x923.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!mJZ6!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff8d85a6b-ab18-4303-a735-0c0b3a547052_879x923.png 424w, https://substackcdn.com/image/fetch/$s_!mJZ6!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff8d85a6b-ab18-4303-a735-0c0b3a547052_879x923.png 848w, https://substackcdn.com/image/fetch/$s_!mJZ6!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff8d85a6b-ab18-4303-a735-0c0b3a547052_879x923.png 1272w, https://substackcdn.com/image/fetch/$s_!mJZ6!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff8d85a6b-ab18-4303-a735-0c0b3a547052_879x923.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!mJZ6!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff8d85a6b-ab18-4303-a735-0c0b3a547052_879x923.png" width="879" height="923" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/f8d85a6b-ab18-4303-a735-0c0b3a547052_879x923.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:923,&quot;width&quot;:879,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!mJZ6!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff8d85a6b-ab18-4303-a735-0c0b3a547052_879x923.png 424w, https://substackcdn.com/image/fetch/$s_!mJZ6!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff8d85a6b-ab18-4303-a735-0c0b3a547052_879x923.png 848w, https://substackcdn.com/image/fetch/$s_!mJZ6!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff8d85a6b-ab18-4303-a735-0c0b3a547052_879x923.png 1272w, https://substackcdn.com/image/fetch/$s_!mJZ6!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff8d85a6b-ab18-4303-a735-0c0b3a547052_879x923.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>The neural integrator does this: (1) it collects the total velocity signal sent to the eye muscles, and (2) outputs the spikes at exactly the right rate to keep the eyes pointed in the right direction.</p><p>I.e. it literally integrates the angular velocity to come up with the final position.</p><p>Our best guess that the integrator works using some clever mutually inhibitory feedback. If the left vestibular neuron sends more spikes, the right half of the neural integrator gets more excited, and ends up inhibiting the left half more, which ends up inhibiting the right half less. <a href="https://doi.org/10.1016/B978-008045046-9.01434-0">This entry</a> in the Encyclopedia of Neuroscience describes the math in more detail.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!0zoy!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5a7bb227-1cd1-45ed-90a2-c97ee3c2a050_261x447.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!0zoy!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5a7bb227-1cd1-45ed-90a2-c97ee3c2a050_261x447.png 424w, https://substackcdn.com/image/fetch/$s_!0zoy!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5a7bb227-1cd1-45ed-90a2-c97ee3c2a050_261x447.png 848w, https://substackcdn.com/image/fetch/$s_!0zoy!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5a7bb227-1cd1-45ed-90a2-c97ee3c2a050_261x447.png 1272w, https://substackcdn.com/image/fetch/$s_!0zoy!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5a7bb227-1cd1-45ed-90a2-c97ee3c2a050_261x447.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!0zoy!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5a7bb227-1cd1-45ed-90a2-c97ee3c2a050_261x447.png" width="261" height="447" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/5a7bb227-1cd1-45ed-90a2-c97ee3c2a050_261x447.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:447,&quot;width&quot;:261,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;A sketch of a neural integrator model. Source: Neural Integrator Models, Encyclopedia of Neuroscience (2009), https://doi.org/10.1016/B978-008045046-9.01434-0&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="A sketch of a neural integrator model. Source: Neural Integrator Models, Encyclopedia of Neuroscience (2009), https://doi.org/10.1016/B978-008045046-9.01434-0" title="A sketch of a neural integrator model. Source: Neural Integrator Models, Encyclopedia of Neuroscience (2009), https://doi.org/10.1016/B978-008045046-9.01434-0" srcset="https://substackcdn.com/image/fetch/$s_!0zoy!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5a7bb227-1cd1-45ed-90a2-c97ee3c2a050_261x447.png 424w, https://substackcdn.com/image/fetch/$s_!0zoy!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5a7bb227-1cd1-45ed-90a2-c97ee3c2a050_261x447.png 848w, https://substackcdn.com/image/fetch/$s_!0zoy!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5a7bb227-1cd1-45ed-90a2-c97ee3c2a050_261x447.png 1272w, https://substackcdn.com/image/fetch/$s_!0zoy!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5a7bb227-1cd1-45ed-90a2-c97ee3c2a050_261x447.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">A sketch of a neural integrator model. Source: Neural Integrator Models, Encyclopedia of Neuroscience (2009), https://doi.org/10.1016/B978-008045046-9.01434-0</figcaption></figure></div><p>Some papers indicate that there may be a <a href="https://doi.org/10.1007/978-3-540-29678-2_3916">number of different neurons</a> involved, and this may be a multi-stage process.</p><p>(On a tangent: there isn&#8217;t just one neural integrator. There seem to be a number of them in the brain; for example, if you close your eyes and move around the room, a part of the cerebral cortex will keep an estimate of your position from your motion, though it won&#8217;t be very accurate. One of the papers linked above even argues that accumulating the evidence for two alternatives in a decision process could also be considered an integrator.)</p><h2>Complication #2: controlling the gain</h2><p>Setting the neural integrator aside, here&#8217;s a different question: why is it that a 5&#176; turn of the head causes a 5&#176; turn of the eyes? What makes it not be 4&#176;, or 10&#176;? Are we just lucky that the neural connections work out to be exactly right?</p><p>Turns out, <a href="https://www.nature.com/articles/s41583-020-00392-x">there&#8217;s a circuit</a> that runs through <a href="https://en.wikipedia.org/wiki/Cerebellum">cerebellum</a> that keeps the gain (ratio of head turn to eye turn) at exactly the right value. It&#8217;s a pretty clever circuit that turns out to be so useful that the brain has copy-pasted it thousands of times (with a few changes) and reused it in nearly all motor functions, plus a number of non-motor functions.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!PqGk!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7ab80827-4a62-4c21-a8b5-29fc43dfdd2f_2160x2160.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!PqGk!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7ab80827-4a62-4c21-a8b5-29fc43dfdd2f_2160x2160.png 424w, https://substackcdn.com/image/fetch/$s_!PqGk!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7ab80827-4a62-4c21-a8b5-29fc43dfdd2f_2160x2160.png 848w, https://substackcdn.com/image/fetch/$s_!PqGk!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7ab80827-4a62-4c21-a8b5-29fc43dfdd2f_2160x2160.png 1272w, https://substackcdn.com/image/fetch/$s_!PqGk!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7ab80827-4a62-4c21-a8b5-29fc43dfdd2f_2160x2160.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!PqGk!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7ab80827-4a62-4c21-a8b5-29fc43dfdd2f_2160x2160.png" width="1456" height="1456" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/7ab80827-4a62-4c21-a8b5-29fc43dfdd2f_2160x2160.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1456,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!PqGk!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7ab80827-4a62-4c21-a8b5-29fc43dfdd2f_2160x2160.png 424w, https://substackcdn.com/image/fetch/$s_!PqGk!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7ab80827-4a62-4c21-a8b5-29fc43dfdd2f_2160x2160.png 848w, https://substackcdn.com/image/fetch/$s_!PqGk!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7ab80827-4a62-4c21-a8b5-29fc43dfdd2f_2160x2160.png 1272w, https://substackcdn.com/image/fetch/$s_!PqGk!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7ab80827-4a62-4c21-a8b5-29fc43dfdd2f_2160x2160.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>The center of this circuit are the inhibitory Purkinje cells, which, in this case, output a low, constant stream of spikes that lightly inhibit the connections from the vestibular neurons to the motorneurons.</p><p>The vestibular signal comes in through excitatory parallel fibers that make connections with Purkinje cells. When the head turns, these fibers make the Purkinje cell a bit more excited, making it inhibit the VOR circuit a bit more, kinda like tapping on the break.</p><p>Most of the time, this inhibition is just right to make the 5&#176; head turn result in 5&#176; eye turn. But what if it&#8217;s wrong?</p><p>This is where another set of neurons comes in - the climbing fibers. When the brain detects that the image on the retina lags behind motion (i.e. the inhibition is too strong), these fire. This sets the Purkinje cell ringing like a bell for a bit, and it turns off some of the connections from the parallel fibers, reducing the inhibition, and letting the eyes move faster.</p><p>I haven&#8217;t seen a good description for how the opposite error is fixed (eyes move too fast), but from what I remember from other circuits, the parallel-to-Purkinje connections gradually turn back on when the parallel fibers keep firing, so the error may just fix itself over time.</p><h2>That&#8217;s it</h2><p>That&#8217;s basically all I know about the Vestibulo-Occular Reflex so far. As I mentioned, there are other mechanisms to keep the eyes steady, like the neck reflexes, or the slower and finer <a href="https://en.wikipedia.org/wiki/Optokinetic_response">Opto-Kinetic Reflex</a> that uses the information from the retina instead of the vestibular organ.</p>]]></content:encoded></item><item><title><![CDATA[Neuron circuits in the retina - more than just pixels]]></title><description><![CDATA[There&#8217;s also a YouTube version of this article.]]></description><link>https://www.i-kh.net/p/retina-circuits-more-than-just-pixels</link><guid isPermaLink="false">https://www.i-kh.net/p/retina-circuits-more-than-just-pixels</guid><dc:creator><![CDATA[Iouri Khramtsov]]></dc:creator><pubDate>Sat, 31 Oct 2020 22:37:00 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!gcFG!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F52689e39-3d50-45b6-9b21-e9c947cdfebf_1296x1183.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!gcFG!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F52689e39-3d50-45b6-9b21-e9c947cdfebf_1296x1183.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!gcFG!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F52689e39-3d50-45b6-9b21-e9c947cdfebf_1296x1183.png 424w, https://substackcdn.com/image/fetch/$s_!gcFG!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F52689e39-3d50-45b6-9b21-e9c947cdfebf_1296x1183.png 848w, https://substackcdn.com/image/fetch/$s_!gcFG!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F52689e39-3d50-45b6-9b21-e9c947cdfebf_1296x1183.png 1272w, https://substackcdn.com/image/fetch/$s_!gcFG!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F52689e39-3d50-45b6-9b21-e9c947cdfebf_1296x1183.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!gcFG!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F52689e39-3d50-45b6-9b21-e9c947cdfebf_1296x1183.png" width="1296" height="1183" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/52689e39-3d50-45b6-9b21-e9c947cdfebf_1296x1183.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1183,&quot;width&quot;:1296,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" title="" srcset="https://substackcdn.com/image/fetch/$s_!gcFG!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F52689e39-3d50-45b6-9b21-e9c947cdfebf_1296x1183.png 424w, https://substackcdn.com/image/fetch/$s_!gcFG!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F52689e39-3d50-45b6-9b21-e9c947cdfebf_1296x1183.png 848w, https://substackcdn.com/image/fetch/$s_!gcFG!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F52689e39-3d50-45b6-9b21-e9c947cdfebf_1296x1183.png 1272w, https://substackcdn.com/image/fetch/$s_!gcFG!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F52689e39-3d50-45b6-9b21-e9c947cdfebf_1296x1183.png 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p><em>There&#8217;s also a <a href="https://youtu.be/LMNuOn5B_VA">YouTube version</a> of this article.</em></p><p>The picture above shows some (far from everything!) of what we know about the cells and neural circuits in the human retina.</p><p>What&#8217;s interesting is - the retina is not just a light detection organ. It&#8217;s a complex electro-chemical calculator with three neural layers, and it uses these layers to extract a number of useful signals from the light that hits our eyes.</p><p>Below, we&#8217;ll step through some of the more interesting features of the retina, but if you&#8217;d like to learn more, the above picture (and this article) are mostly based on <a href="https://www.sciencedirect.com/science/article/pii/S1350946220300161">this review article</a> published in Feb 2020 in the journal Progress in Retinal and Eye Research, and on chapter 17 of the latest edition of <a href="https://www.amazon.com/Ryans-Retina-Andrew-P-Schachat/dp/032340197X">Ryan&#8217;s Retina</a>.</p><h2>Photoreceptors are always on - except when there&#8217;s light</h2><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!J2la!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4286735f-8592-492a-ba56-c943ebe95faf_478x348.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!J2la!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4286735f-8592-492a-ba56-c943ebe95faf_478x348.png 424w, https://substackcdn.com/image/fetch/$s_!J2la!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4286735f-8592-492a-ba56-c943ebe95faf_478x348.png 848w, https://substackcdn.com/image/fetch/$s_!J2la!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4286735f-8592-492a-ba56-c943ebe95faf_478x348.png 1272w, https://substackcdn.com/image/fetch/$s_!J2la!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4286735f-8592-492a-ba56-c943ebe95faf_478x348.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!J2la!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4286735f-8592-492a-ba56-c943ebe95faf_478x348.png" width="478" height="348" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/4286735f-8592-492a-ba56-c943ebe95faf_478x348.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:348,&quot;width&quot;:478,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" title="" srcset="https://substackcdn.com/image/fetch/$s_!J2la!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4286735f-8592-492a-ba56-c943ebe95faf_478x348.png 424w, https://substackcdn.com/image/fetch/$s_!J2la!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4286735f-8592-492a-ba56-c943ebe95faf_478x348.png 848w, https://substackcdn.com/image/fetch/$s_!J2la!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4286735f-8592-492a-ba56-c943ebe95faf_478x348.png 1272w, https://substackcdn.com/image/fetch/$s_!J2la!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4286735f-8592-492a-ba56-c943ebe95faf_478x348.png 1456w" sizes="100vw"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>The photoreceptor cells in the vertebrate retina - rods and cones - are at the very back of the eye, behind the other layers of neurons.</p><p>Cones work best in bright light and can detect colors. In humans, there are three types of cone cells, each specializing in detecting red, green, and blue light. Rods work best in the dark, but can&#8217;t detect colors - just the brightness level.</p><p>Since the photoreceptors are at the very back of the retina, light has to navigate a tangled maze of neuronal bodies and wires to get to them. It does so using something called M&#252;ller cells (not shown), that stretch across the entire thickness of the retina and act like fiberoptic cables.</p><p>When the light gets to the photoreceptors, it turns them <em>down</em>. In complete darkness, the photoreceptors continuously emit neurotransmitters (&#8220;fire&#8221;, or &#8220;are excited&#8221;) at their maximum rate. The light inhibits them.</p><h2>Parallel channels for brightness and darkness levels</h2><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!_JTX!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc8984e1a-0ec7-4cb2-acc0-6f90fc2e7625_589x552.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!_JTX!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc8984e1a-0ec7-4cb2-acc0-6f90fc2e7625_589x552.png 424w, https://substackcdn.com/image/fetch/$s_!_JTX!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc8984e1a-0ec7-4cb2-acc0-6f90fc2e7625_589x552.png 848w, https://substackcdn.com/image/fetch/$s_!_JTX!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc8984e1a-0ec7-4cb2-acc0-6f90fc2e7625_589x552.png 1272w, https://substackcdn.com/image/fetch/$s_!_JTX!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc8984e1a-0ec7-4cb2-acc0-6f90fc2e7625_589x552.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!_JTX!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc8984e1a-0ec7-4cb2-acc0-6f90fc2e7625_589x552.png" width="589" height="552" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/c8984e1a-0ec7-4cb2-acc0-6f90fc2e7625_589x552.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:552,&quot;width&quot;:589,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" title="" srcset="https://substackcdn.com/image/fetch/$s_!_JTX!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc8984e1a-0ec7-4cb2-acc0-6f90fc2e7625_589x552.png 424w, https://substackcdn.com/image/fetch/$s_!_JTX!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc8984e1a-0ec7-4cb2-acc0-6f90fc2e7625_589x552.png 848w, https://substackcdn.com/image/fetch/$s_!_JTX!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc8984e1a-0ec7-4cb2-acc0-6f90fc2e7625_589x552.png 1272w, https://substackcdn.com/image/fetch/$s_!_JTX!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc8984e1a-0ec7-4cb2-acc0-6f90fc2e7625_589x552.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>For red and green cones, right from the start, the signal splits into two separate channels: ON cells, which fire neurotransmitters when the light is shining on their cone, and OFF cells that fire when the light is <em>not</em> shining on their cone.</p><p>Since the cones fire most when it&#8217;s dark, we can say that they produce the OFF (darkness) signal. So how do the ON cells fire when there&#8217;s light? Well, the ON bipolar cells are intrinsically excited and want to fire neurotransmitters, but they get inhibited by the photoreceptors. So as long as the photoreceptors are firing, ON bipolar cells aren&#8217;t. When there&#8217;s light (and photoreceptors stop firing), ON bipolar cells are no longer inhibited, and produce more neurotransmitters.</p><p>Why are there two channels instead of just one? Good question. Maybe so that it&#8217;s easier to recognize dark objects on light backgrounds more easily?</p><p>Either way, as far as we can tell, this ON/OFF channel pair only occurs with the red and green cones. Blue cones and rods have only ON bipolar cells. Though with rods, the story is a bit more complicated.</p><h2>Rod signals are carefully fed into cone pathways</h2><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!oUhr!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Faea0f9b1-f655-4716-b49a-c4d557efaa5a_680x571.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!oUhr!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Faea0f9b1-f655-4716-b49a-c4d557efaa5a_680x571.png 424w, https://substackcdn.com/image/fetch/$s_!oUhr!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Faea0f9b1-f655-4716-b49a-c4d557efaa5a_680x571.png 848w, https://substackcdn.com/image/fetch/$s_!oUhr!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Faea0f9b1-f655-4716-b49a-c4d557efaa5a_680x571.png 1272w, https://substackcdn.com/image/fetch/$s_!oUhr!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Faea0f9b1-f655-4716-b49a-c4d557efaa5a_680x571.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!oUhr!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Faea0f9b1-f655-4716-b49a-c4d557efaa5a_680x571.png" width="680" height="571" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/aea0f9b1-f655-4716-b49a-c4d557efaa5a_680x571.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:571,&quot;width&quot;:680,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" title="" srcset="https://substackcdn.com/image/fetch/$s_!oUhr!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Faea0f9b1-f655-4716-b49a-c4d557efaa5a_680x571.png 424w, https://substackcdn.com/image/fetch/$s_!oUhr!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Faea0f9b1-f655-4716-b49a-c4d557efaa5a_680x571.png 848w, https://substackcdn.com/image/fetch/$s_!oUhr!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Faea0f9b1-f655-4716-b49a-c4d557efaa5a_680x571.png 1272w, https://substackcdn.com/image/fetch/$s_!oUhr!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Faea0f9b1-f655-4716-b49a-c4d557efaa5a_680x571.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>Humans (and other primates) have a fantastic vision. One of its crazy feats is that it can see across 10 log units of light intensity by using different light detectors and different retinal circuits in different lighting conditions.</p><p>Rods can detect single photons (!) and become saturated when it gets brighter than dusk/dawn. Rod signals are further amplified by neurons that collect multiple rod signals, suppress the noise, and feed the signals into the cone signal pathways.</p><p>This is done with help of the so-called AII amacrine cells (that&#8217;s roman numeral &#8220;2&#8221;, so it&#8217;s really &#8220;A2&#8221;, but the literature calls it &#8220;AII&#8221; for historical reasons). These AII cells collect inputs from the rod bipolar cells (which come only in ON variety), and use that signal to inhibit the cone OFF bipolar cells, as well as directly feed voltage into the ON bipolar cells through the connections called &#8220;gap junctions&#8221;.</p><p>This way, even when it&#8217;s dark, the same parts of the brain can be used to process the incoming information even though it&#8217;s been collected by a different set of photoreceptors.</p><h2>Motion gets detected starting in the retina</h2><p>Some output neurons - Parasol cells (ON and OFF varieties) and Recursive cells - produce the biggest response when the stimulus moves across its visual field.</p><p>What kind of neuron circuits make that happen?</p><p>For parasol cells, <a href="https://www.cell.com/neuron/pdf/S0896-627318%2930105-3.pdf">this paper</a> suggests that it&#8217;s a network of special diffuse bipolar cells that makes it happen.</p><p>When the signal moves left to right in the image below, the bipolar cells excite each other through gap junctions that let voltage jump from one cell to the next.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!aNmg!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F60528b29-aef1-4801-a099-2b7f4956c315_541x602.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!aNmg!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F60528b29-aef1-4801-a099-2b7f4956c315_541x602.png 424w, https://substackcdn.com/image/fetch/$s_!aNmg!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F60528b29-aef1-4801-a099-2b7f4956c315_541x602.png 848w, https://substackcdn.com/image/fetch/$s_!aNmg!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F60528b29-aef1-4801-a099-2b7f4956c315_541x602.png 1272w, https://substackcdn.com/image/fetch/$s_!aNmg!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F60528b29-aef1-4801-a099-2b7f4956c315_541x602.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!aNmg!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F60528b29-aef1-4801-a099-2b7f4956c315_541x602.png" width="541" height="602" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/60528b29-aef1-4801-a099-2b7f4956c315_541x602.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:602,&quot;width&quot;:541,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" title="" srcset="https://substackcdn.com/image/fetch/$s_!aNmg!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F60528b29-aef1-4801-a099-2b7f4956c315_541x602.png 424w, https://substackcdn.com/image/fetch/$s_!aNmg!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F60528b29-aef1-4801-a099-2b7f4956c315_541x602.png 848w, https://substackcdn.com/image/fetch/$s_!aNmg!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F60528b29-aef1-4801-a099-2b7f4956c315_541x602.png 1272w, https://substackcdn.com/image/fetch/$s_!aNmg!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F60528b29-aef1-4801-a099-2b7f4956c315_541x602.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>Due to the internal mechanisms of neurons, these signals add more than linearly and produce a big response in the last bipolar neuron - ultimately exciting the parasol cell a lot.</p><h2>Horizontal cells sharpen the picture</h2><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!lkaz!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F95496421-ef3a-458c-9600-027b4948e9a6_415x456.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!lkaz!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F95496421-ef3a-458c-9600-027b4948e9a6_415x456.png 424w, https://substackcdn.com/image/fetch/$s_!lkaz!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F95496421-ef3a-458c-9600-027b4948e9a6_415x456.png 848w, https://substackcdn.com/image/fetch/$s_!lkaz!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F95496421-ef3a-458c-9600-027b4948e9a6_415x456.png 1272w, https://substackcdn.com/image/fetch/$s_!lkaz!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F95496421-ef3a-458c-9600-027b4948e9a6_415x456.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!lkaz!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F95496421-ef3a-458c-9600-027b4948e9a6_415x456.png" width="415" height="456" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/95496421-ef3a-458c-9600-027b4948e9a6_415x456.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:456,&quot;width&quot;:415,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" title="" srcset="https://substackcdn.com/image/fetch/$s_!lkaz!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F95496421-ef3a-458c-9600-027b4948e9a6_415x456.png 424w, https://substackcdn.com/image/fetch/$s_!lkaz!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F95496421-ef3a-458c-9600-027b4948e9a6_415x456.png 848w, https://substackcdn.com/image/fetch/$s_!lkaz!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F95496421-ef3a-458c-9600-027b4948e9a6_415x456.png 1272w, https://substackcdn.com/image/fetch/$s_!lkaz!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F95496421-ef3a-458c-9600-027b4948e9a6_415x456.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>Retina also has a number of circuits for sharpening the image and enhancing the contrast.</p><p>One of them involves the so-called &#8220;horizontal cells&#8221; (yellow &#8220;H1&#8221; and &#8220;H2&#8221; cell in the image at the start of this post). These live in the same layer as the bipolar cells and connect to a lot of nearby cones.</p><p>The way the horizontal cells work is pretty clever: they are excited by the cones, and then, in turn, inhibit the cones back.</p><p>To see how these sharpen the image, let&#8217;s carefully look at what happens when the light shines only on one photoreceptor in the picture above.</p><p>If only one cone receives light, then</p><ol><li><p>It fires less, so</p></li><li><p>Horizontal cell is less excited, and so it fires less too, therefore</p></li><li><p>Horizontal cell doesn&#8217;t inhibit the other surrounding cones as much, and so</p></li><li><p>Other cones fire more, producing a stronger OFF (darkness) signal.</p></li></ol><p>The result is that we see a bright dot surrounded by a darker ring, making the dot more prominent.</p><p>By the way, this type of center-surround contrast enhancement is a common feature across all sensory systems, including touch, hearing, and smell.</p><p>Like image sharpening in Photoshop, this process can leave artifacts. The most famous one is below - the <a href="https://en.wikipedia.org/wiki/Grid_illusion">Hermann grid</a>. The dark spots at the intersections disappear when you look straight at them because the surround inhibition fields are larger at the periphery of vision than in the center.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!G38k!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2983003f-8451-4f16-b95c-1faba4aa6941_360x360.gif" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!G38k!,w_424,c_limit,f_webp,q_auto:good,fl_lossy/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2983003f-8451-4f16-b95c-1faba4aa6941_360x360.gif 424w, https://substackcdn.com/image/fetch/$s_!G38k!,w_848,c_limit,f_webp,q_auto:good,fl_lossy/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2983003f-8451-4f16-b95c-1faba4aa6941_360x360.gif 848w, https://substackcdn.com/image/fetch/$s_!G38k!,w_1272,c_limit,f_webp,q_auto:good,fl_lossy/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2983003f-8451-4f16-b95c-1faba4aa6941_360x360.gif 1272w, https://substackcdn.com/image/fetch/$s_!G38k!,w_1456,c_limit,f_webp,q_auto:good,fl_lossy/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2983003f-8451-4f16-b95c-1faba4aa6941_360x360.gif 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!G38k!,w_1456,c_limit,f_auto,q_auto:good,fl_lossy/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2983003f-8451-4f16-b95c-1faba4aa6941_360x360.gif" width="360" height="360" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/2983003f-8451-4f16-b95c-1faba4aa6941_360x360.gif&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:360,&quot;width&quot;:360,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" title="" srcset="https://substackcdn.com/image/fetch/$s_!G38k!,w_424,c_limit,f_auto,q_auto:good,fl_lossy/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2983003f-8451-4f16-b95c-1faba4aa6941_360x360.gif 424w, https://substackcdn.com/image/fetch/$s_!G38k!,w_848,c_limit,f_auto,q_auto:good,fl_lossy/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2983003f-8451-4f16-b95c-1faba4aa6941_360x360.gif 848w, https://substackcdn.com/image/fetch/$s_!G38k!,w_1272,c_limit,f_auto,q_auto:good,fl_lossy/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2983003f-8451-4f16-b95c-1faba4aa6941_360x360.gif 1272w, https://substackcdn.com/image/fetch/$s_!G38k!,w_1456,c_limit,f_auto,q_auto:good,fl_lossy/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2983003f-8451-4f16-b95c-1faba4aa6941_360x360.gif 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><h2>Blue cones are lower-class citizens in the retina.</h2><p>For various reasons, blue cones get treated differently by the retina. They sit a bit farther back from green and red cones, they don&#8217;t get OFF channels, and there aren&#8217;t output (ganglion) cells that produce a pure blue signal.</p><p>Instead, the ganglion cells responsible for blue color combine blue ON signal together with red+green (= yellow) OFF signal to produce a &#8220;relatively blue&#8221; signal.</p><p>Blue cones are also sparser and aren&#8217;t present in the very center of the retina. This is in part because the lens in the eye produces chromatic aberrations at shorter wavelengths, and tighter spacing between blue cones wouldn&#8217;t help us see better.</p><h2>Dopamine acts as additional gain control</h2><p>Retina also adapts to light through Dopaminergic Amacrine Cells (DAC - dark blue on the diagram above). They spread their tentacles throughout the retina and around the bodies of some neurons.</p><p>When the light becomes bright enough, they ramp up the dopamine production, which in turn lowers the volume in the retinal circuits through <a href="https://www.sciencedirect.com/science/article/pii/S1347861319310448">various mecanisms</a>.</p>]]></content:encoded></item><item><title><![CDATA[How neurons create electric spikes]]></title><description><![CDATA[And here&#8217;s the same content as the last blog post, but now in YouTube format.]]></description><link>https://www.i-kh.net/p/how-neurons-make-electric-spikes</link><guid isPermaLink="false">https://www.i-kh.net/p/how-neurons-make-electric-spikes</guid><dc:creator><![CDATA[Iouri Khramtsov]]></dc:creator><pubDate>Tue, 15 Sep 2020 23:00:00 GMT</pubDate><enclosure url="https://substackcdn.com/image/youtube/w_728,c_limit/gPjT1O-4DLU" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>And here&#8217;s the same content as the last blog post, but now in YouTube format.</p><div id="youtube2-gPjT1O-4DLU" class="youtube-wrap" data-attrs="{&quot;videoId&quot;:&quot;gPjT1O-4DLU&quot;,&quot;startTime&quot;:null,&quot;endTime&quot;:null}" data-component-name="Youtube2ToDOM"><div class="youtube-inner"><iframe src="https://www.youtube-nocookie.com/embed/gPjT1O-4DLU?rel=0&amp;autoplay=0&amp;showinfo=0&amp;enablejsapi=0" frameborder="0" loading="lazy" gesture="media" allow="autoplay; fullscreen" allowautoplay="true" allowfullscreen="true" width="728" height="409"></iframe></div></div>]]></content:encoded></item><item><title><![CDATA[Multithreading without locks]]></title><description><![CDATA[Just because you&#8217;re sharing data structures between threads doesn&#8217;t mean you have to use locks.]]></description><link>https://www.i-kh.net/p/multithreading-without-locks</link><guid isPermaLink="false">https://www.i-kh.net/p/multithreading-without-locks</guid><dc:creator><![CDATA[Iouri Khramtsov]]></dc:creator><pubDate>Mon, 10 Feb 2020 23:03:00 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!V9Qv!,w_256,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F64d2997e-d235-41e8-8ece-611b5f6c9f21_512x512.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Just because you&#8217;re sharing data structures between threads doesn&#8217;t mean you have to use locks.</p><p>Over the years I&#8217;ve come across a few approaches that help coordinate work between threads without having to make anyone wait. Here are a couple of them.</p><p>WARNING: I stopped using these patterns because they are easy to misunderstand and misuse, which can lead to random hard-to-diagnose bugs. If you use these patterns, you&#8217;re not helping the next develper understand the code better or avoid mistakes. You have been warned.</p><h2>Reference to an immutable object</h2><p>We know that in a multithreaded environment, modifying a shared object without locks is a bad idea. But what about replacing it?</p><p>For example, consider this code. I&#8217;ll use C#, but the same applies in Java, C++, or another traditional language with threads.</p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;csharp&quot;,&quot;nodeId&quot;:&quot;bb7ea492-9b0c-44a1-8cf5-2f122da94a65&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-csharp">public class FunWithThreads {
    private Thing thing;

    public void InThreadOne() {
        this.thing = new Thing()
    }

    public Result InThreadTwo() {
        var localThing = this.thing;
        var result1 = SomeCalculation1(localThing);
        var result2 = SomeCalculation2(localThing);
        var finalResult = DoMoreWork(localThing, result1, result2);
        return result;
    }
}</code></pre></div><p>Suppose lots of threads are concurrently calling <code>InThreadOne()</code>, while lots of other threads are concurrently calling <code>InThreadTwo()</code>. Will we ever get a wrong result, a race condition, or a conflict?</p><p>Not really. <code>InThreadTwo()</code> always refers to a consistent version of <code>this.thing</code> because it places the reference to it into a local variable, and from then on uses only the local reference. If the calculations take too long, then maybe we get a result that&#8217;s a bit stale, but that result will always be consistent.</p><p><strong>Where it&#8217;s useful</strong>: I found this approach to be useful whenever <code>this.thing</code> is a large, pre-computed data structure that gets infrequently updated but frequently read. Mostly I&#8217;ve used it to cache some data for internal capital markets applications to make the application feel snappier to the user.</p><p><strong>The pitfalls</strong>: It&#8217;s really important to make sure that <code>this.thing</code> is referenced only once at the beginning of the method, or else we&#8217;re back to race conditions. It&#8217;s also really important that <code>this.thing</code> is never modified after it&#8217;s assigned. That means lots of descriptive comments, very careful code reviews, and making sure that every developer that ever looks at this code knows all the gotchas. In a larger codebase, someone (maybe even you!) might still find a way to make a mistake somewhere.</p><h2>Complex atomic operations</h2><p>The reason the above code works is because in C# (and in most other languages) assignment of references is an atomic operation, i.e. while it&#8217;s executing, another thread can&#8217;t sneak in mid-way and do something else.</p><p>Modern processors have a few other interesting atomic operations, like <a href="https://en.wikipedia.org/wiki/Compare-and-swap">compare and swap</a>, implemented in C# as <code>Interlocked.CompareExchange()</code>, and in Java as <code>AtomicInteger.compareAndSet()</code>. This function takes three arguments and does the following as an atomic operation:</p><ol><li><p>Compares the first and the third arguments, then</p></li><li><p>If they&#8217;re equal, sets the first argument to be equal to the second argument, or</p></li><li><p>If they&#8217;re not equal, does nothing.</p></li></ol><p>One case where this can be used is when trying to limit requests for an expensive operation on a limited resource. For example, this code will drop any requests if the expensive operation is already running:</p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;csharp&quot;,&quot;nodeId&quot;:&quot;4dbb8d84-32e6-4c7c-bf45-59c22f72287b&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-csharp">// Let&#8217;s pretend this class is a singleton.
public class ExpensiveOperationLimiter {
    private int isProcessing = 0; 

    public void RequestExpensiveOperation() {
        // If isProcessing == 1, this does nothing and returns 1.
        // If isProcessing == 0, this sets isProcessing to 1 and returns 0. 
        var wasProcessing = Interlocked.CompareExchange(ref isProcessing, 1, 0);

        if (!wasProcessing) {
            // Only one invocation will be running at a time.
            DoExpensiveOperation()
        }

        isProcessing = 0;
    }

    private void DoExpensiveOperation() {
        // ...
    }
}</code></pre></div><p>If you look at the above code carefully, you&#8217;ll see that you can&#8217;t replace <code>Interlocked.CompareExchange()</code> and still have thread safety - there will always be an opportunity for another thread to sneak in between the instructions.</p><p>With a bit of work, this code can also be expanded to queue up the next request.</p><p><strong>Where it&#8217;s useful</strong>: I&#8217;ve used this kind of code in situations where events can randomly trigger an application server&#8217;s cache to refresh from a database or from another system.</p><p><strong>The pitfalls</strong>: Generally, I&#8217;d consider this to be a micro-optimization and not worth the effort. Many developers understand or have heard of locks, and have an easier time following them than any code that involves compare-and-set. As before, by using this, you&#8217;re risking someone (including you!) eventually making a mistake.</p><h2>The best way to avoid locks</h2><p>Don&#8217;t write multithreaded code!</p>]]></content:encoded></item><item><title><![CDATA[The magic of ion channels in the neurons]]></title><description><![CDATA[A few weeks ago, for various reasons I decided to start reading a neuroscience textbook (Fundamental Neuroscience).]]></description><link>https://www.i-kh.net/p/the-magic-of-ion-channels</link><guid isPermaLink="false">https://www.i-kh.net/p/the-magic-of-ion-channels</guid><dc:creator><![CDATA[Iouri Khramtsov]]></dc:creator><pubDate>Mon, 10 Feb 2020 23:03:00 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!B6RQ!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9c89b3e1-f3e6-43ab-93c8-0556a1aa450c_1920x1080.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>A few weeks ago, for various reasons I decided to start reading a neuroscience textbook (<a href="https://www.sciencedirect.com/book/9780123858702/fundamental-neuroscience">Fundamental Neuroscience</a>). Though dense, it&#8217;s packed with interesting information that filled a lot of gaps in my knowledge about the brain.</p><p>One of those gaps was about how exactly the information travels through a neuron. Up to this point, all I knew was &#8220;something involving electric pulses&#8221;.</p><p>The reality, it turns out, is more interesting: neurons use ion channels to create and strengthen electric signals, and propagate information along their lengths.</p><p>So here is more or less how I understand this so far.</p><h2>The setup - the neuron</h2><p>First, a quick recap of the neuron structure.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!B6RQ!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9c89b3e1-f3e6-43ab-93c8-0556a1aa450c_1920x1080.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!B6RQ!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9c89b3e1-f3e6-43ab-93c8-0556a1aa450c_1920x1080.png 424w, https://substackcdn.com/image/fetch/$s_!B6RQ!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9c89b3e1-f3e6-43ab-93c8-0556a1aa450c_1920x1080.png 848w, https://substackcdn.com/image/fetch/$s_!B6RQ!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9c89b3e1-f3e6-43ab-93c8-0556a1aa450c_1920x1080.png 1272w, https://substackcdn.com/image/fetch/$s_!B6RQ!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9c89b3e1-f3e6-43ab-93c8-0556a1aa450c_1920x1080.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!B6RQ!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9c89b3e1-f3e6-43ab-93c8-0556a1aa450c_1920x1080.png" width="1456" height="819" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/9c89b3e1-f3e6-43ab-93c8-0556a1aa450c_1920x1080.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:819,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;A typical neuron. Source: your brain.&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="A typical neuron. Source: your brain." title="A typical neuron. Source: your brain." srcset="https://substackcdn.com/image/fetch/$s_!B6RQ!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9c89b3e1-f3e6-43ab-93c8-0556a1aa450c_1920x1080.png 424w, https://substackcdn.com/image/fetch/$s_!B6RQ!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9c89b3e1-f3e6-43ab-93c8-0556a1aa450c_1920x1080.png 848w, https://substackcdn.com/image/fetch/$s_!B6RQ!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9c89b3e1-f3e6-43ab-93c8-0556a1aa450c_1920x1080.png 1272w, https://substackcdn.com/image/fetch/$s_!B6RQ!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9c89b3e1-f3e6-43ab-93c8-0556a1aa450c_1920x1080.png 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">A typical neuron. Source: your brain.</figcaption></figure></div><p>A neuron has the main cell body. From that body, it grows a large number of branched extensions called &#8220;dendrites&#8221;. These usually serve as the input &#8220;wires&#8221;, though they also do some signal processing.</p><p>Neuron usually also grows another long extension called an &#8220;axon&#8221;. This is normally the cell&#8217;s output, and it can be up to a meter long in humans, though in the brain it&#8217;s usually shorter.</p><p>Let&#8217;s zoom in to the axon. First, we&#8217;ll look at shorter axons, because longer ones have myelin sheath, which will complicate the picture.</p><h2>Ions provide the electric charge</h2><p>The fluid inside the neuron (cytoplasm) and the intercellular fluid between the neurons have a number of ions dissolved in them: calcium (Ca&#178;&#8314;), potassium (K&#8314;), sodium (Na&#8314;), chlorine (Cl&#8315;), and others.</p><p>For various reasons, neurons actively work to pump out Na&#8314;, Ca&#178;&#8314;, and Cl&#8315;, so these are much more concentrated outside the cell than inside the cell. If the membrane wasn&#8217;t keeping them out, they&#8217;d quickly rush into the cell. Some still leak back in.</p><p>Similarly, neurons actively work to concentrate K&#8314; inside.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!d4Sg!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff90d1b16-752e-4bfb-b8f4-0b84c2049da3_1920x1080.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!d4Sg!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff90d1b16-752e-4bfb-b8f4-0b84c2049da3_1920x1080.png 424w, https://substackcdn.com/image/fetch/$s_!d4Sg!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff90d1b16-752e-4bfb-b8f4-0b84c2049da3_1920x1080.png 848w, https://substackcdn.com/image/fetch/$s_!d4Sg!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff90d1b16-752e-4bfb-b8f4-0b84c2049da3_1920x1080.png 1272w, https://substackcdn.com/image/fetch/$s_!d4Sg!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff90d1b16-752e-4bfb-b8f4-0b84c2049da3_1920x1080.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!d4Sg!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff90d1b16-752e-4bfb-b8f4-0b84c2049da3_1920x1080.png" width="1456" height="819" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/f90d1b16-752e-4bfb-b8f4-0b84c2049da3_1920x1080.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:819,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;A crude depiction of a Na&#8314;-K&#8314; pump, one of the mechanisms maintaining the ion balance in the neuron. Na&#8314;-K&#8314; pump removes three Na&#8314; ions for two K&#8314; ions.&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="A crude depiction of a Na&#8314;-K&#8314; pump, one of the mechanisms maintaining the ion balance in the neuron. Na&#8314;-K&#8314; pump removes three Na&#8314; ions for two K&#8314; ions." title="A crude depiction of a Na&#8314;-K&#8314; pump, one of the mechanisms maintaining the ion balance in the neuron. Na&#8314;-K&#8314; pump removes three Na&#8314; ions for two K&#8314; ions." srcset="https://substackcdn.com/image/fetch/$s_!d4Sg!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff90d1b16-752e-4bfb-b8f4-0b84c2049da3_1920x1080.png 424w, https://substackcdn.com/image/fetch/$s_!d4Sg!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff90d1b16-752e-4bfb-b8f4-0b84c2049da3_1920x1080.png 848w, https://substackcdn.com/image/fetch/$s_!d4Sg!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff90d1b16-752e-4bfb-b8f4-0b84c2049da3_1920x1080.png 1272w, https://substackcdn.com/image/fetch/$s_!d4Sg!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff90d1b16-752e-4bfb-b8f4-0b84c2049da3_1920x1080.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">A crude depiction of a Na&#8314;-K&#8314; pump, one of the mechanisms maintaining the ion balance in the neuron. Na&#8314;-K&#8314; pump removes three Na&#8314; ions for two K&#8314; ions.</figcaption></figure></div><p>Each of the ions carries a charge, so the end result of this pumping is that the cell&#8217;s inside is negatively charged relative to the outside. This voltage difference is called the &#8220;membrane potential&#8221;. Resting membrane potential is typically between -75 and -40 mV (millivolts).</p><h2>Ion channels create voltage spikes</h2><p>Ion channels are small valves set in the cell&#8217;s surface that let ions through if certain conditions are met. Some are opened by specific chemicals binding to them (e.g. neurotransmitters), while others open when the voltage inside the cell rises high enough. The latter are called &#8220;voltage-gated ion channels&#8221;, and they&#8217;re the ones we&#8217;re interested in.</p><p>Voltage-gated ion channels exist on all parts of a neuron, but are most concentrated in the axon. Most let through a specific ion: there are Na&#8314; channels, K&#8314; channels, Ca&#178;&#8314; channels, etc.</p><p>Let&#8217;s take a look at how Na&#8314; channels and K&#8314; channels would work to produce a voltage spike (called an &#8220;action potential&#8221;).</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!HxwR!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F05561557-b552-441c-a733-b00e46e35961_1920x1080.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!HxwR!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F05561557-b552-441c-a733-b00e46e35961_1920x1080.png 424w, https://substackcdn.com/image/fetch/$s_!HxwR!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F05561557-b552-441c-a733-b00e46e35961_1920x1080.png 848w, https://substackcdn.com/image/fetch/$s_!HxwR!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F05561557-b552-441c-a733-b00e46e35961_1920x1080.png 1272w, https://substackcdn.com/image/fetch/$s_!HxwR!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F05561557-b552-441c-a733-b00e46e35961_1920x1080.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!HxwR!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F05561557-b552-441c-a733-b00e46e35961_1920x1080.png" width="1456" height="819" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/05561557-b552-441c-a733-b00e46e35961_1920x1080.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:819,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;Neuron membrane in resting state. Channels are closed; membrane voltage is around -73 mV.&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="Neuron membrane in resting state. Channels are closed; membrane voltage is around -73 mV." title="Neuron membrane in resting state. Channels are closed; membrane voltage is around -73 mV." srcset="https://substackcdn.com/image/fetch/$s_!HxwR!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F05561557-b552-441c-a733-b00e46e35961_1920x1080.png 424w, https://substackcdn.com/image/fetch/$s_!HxwR!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F05561557-b552-441c-a733-b00e46e35961_1920x1080.png 848w, https://substackcdn.com/image/fetch/$s_!HxwR!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F05561557-b552-441c-a733-b00e46e35961_1920x1080.png 1272w, https://substackcdn.com/image/fetch/$s_!HxwR!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F05561557-b552-441c-a733-b00e46e35961_1920x1080.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">Neuron membrane in resting state. Channels are closed; membrane voltage is around -73 mV.</figcaption></figure></div><p>If something increases the cell membrane voltage to -55 mV, Na&#8314; channels quickly open and let in a lot of Na&#8314; ions. These ions carry a positive charge, so they quickly raise the voltage across the membrane to +30 mV. Then the channels automatically close. This happens over the span of milliseconds.</p><p>At the same time, K&#8314; channels open and start letting out some K&#8314; ions, opposing the Na&#8314; current and slowing the voltage increase. The channels first open slowly, but after a while, the K&#8314; current strengthens.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!R1f5!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F46b3a191-6f1b-4c72-b88b-fb431c7f6a41_1920x1080.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!R1f5!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F46b3a191-6f1b-4c72-b88b-fb431c7f6a41_1920x1080.png 424w, https://substackcdn.com/image/fetch/$s_!R1f5!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F46b3a191-6f1b-4c72-b88b-fb431c7f6a41_1920x1080.png 848w, https://substackcdn.com/image/fetch/$s_!R1f5!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F46b3a191-6f1b-4c72-b88b-fb431c7f6a41_1920x1080.png 1272w, https://substackcdn.com/image/fetch/$s_!R1f5!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F46b3a191-6f1b-4c72-b88b-fb431c7f6a41_1920x1080.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!R1f5!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F46b3a191-6f1b-4c72-b88b-fb431c7f6a41_1920x1080.png" width="1456" height="819" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/46b3a191-6f1b-4c72-b88b-fb431c7f6a41_1920x1080.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:819,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;Voltage spikes up after the channels open. Na&#8314; are flowing quickly, and K&#8314; are flowing slowly. Na&#8314; channel is about to close.&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="Voltage spikes up after the channels open. Na&#8314; are flowing quickly, and K&#8314; are flowing slowly. Na&#8314; channel is about to close." title="Voltage spikes up after the channels open. Na&#8314; are flowing quickly, and K&#8314; are flowing slowly. Na&#8314; channel is about to close." srcset="https://substackcdn.com/image/fetch/$s_!R1f5!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F46b3a191-6f1b-4c72-b88b-fb431c7f6a41_1920x1080.png 424w, https://substackcdn.com/image/fetch/$s_!R1f5!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F46b3a191-6f1b-4c72-b88b-fb431c7f6a41_1920x1080.png 848w, https://substackcdn.com/image/fetch/$s_!R1f5!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F46b3a191-6f1b-4c72-b88b-fb431c7f6a41_1920x1080.png 1272w, https://substackcdn.com/image/fetch/$s_!R1f5!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F46b3a191-6f1b-4c72-b88b-fb431c7f6a41_1920x1080.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">Voltage spikes up after the channels open. Na&#8314; are flowing quickly, and K&#8314; are flowing slowly. Na&#8314; channel is about to close.</figcaption></figure></div><p>To start, Na+ channels dominate, but after they close, K&#8314; outflow quickly makes the membrane voltage drop. This drop overshoots the initial resting level before leveling off at the voltage where K&#8314; concentrations stay stable.</p><p>Then K&#8314; channels gradually close.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!52iq!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9c01caf1-c622-49c2-b1b8-ef94596a977d_1920x1080.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!52iq!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9c01caf1-c622-49c2-b1b8-ef94596a977d_1920x1080.png 424w, https://substackcdn.com/image/fetch/$s_!52iq!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9c01caf1-c622-49c2-b1b8-ef94596a977d_1920x1080.png 848w, https://substackcdn.com/image/fetch/$s_!52iq!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9c01caf1-c622-49c2-b1b8-ef94596a977d_1920x1080.png 1272w, https://substackcdn.com/image/fetch/$s_!52iq!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9c01caf1-c622-49c2-b1b8-ef94596a977d_1920x1080.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!52iq!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9c01caf1-c622-49c2-b1b8-ef94596a977d_1920x1080.png" width="1456" height="819" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/9c01caf1-c622-49c2-b1b8-ef94596a977d_1920x1080.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:819,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot; Na&#8314; channel is closed. K&#8314; has concentrations have leveled off around -73 mV, where K&#8314; ions are equally likely to enter and exit the membrane.&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt=" Na&#8314; channel is closed. K&#8314; has concentrations have leveled off around -73 mV, where K&#8314; ions are equally likely to enter and exit the membrane." title=" Na&#8314; channel is closed. K&#8314; has concentrations have leveled off around -73 mV, where K&#8314; ions are equally likely to enter and exit the membrane." srcset="https://substackcdn.com/image/fetch/$s_!52iq!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9c01caf1-c622-49c2-b1b8-ef94596a977d_1920x1080.png 424w, https://substackcdn.com/image/fetch/$s_!52iq!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9c01caf1-c622-49c2-b1b8-ef94596a977d_1920x1080.png 848w, https://substackcdn.com/image/fetch/$s_!52iq!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9c01caf1-c622-49c2-b1b8-ef94596a977d_1920x1080.png 1272w, https://substackcdn.com/image/fetch/$s_!52iq!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9c01caf1-c622-49c2-b1b8-ef94596a977d_1920x1080.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">Na&#8314; channel is closed. K&#8314; has concentrations have leveled off around -73 mV, where K&#8314; ions are equally likely to enter and exit the membrane.</figcaption></figure></div><p>The total number of ions exchanged throughout the whole process is minuscule, and has little impact on the overall concentration of ions inside or outside the cell.</p><h2>Voltage spike opens nearby channels</h2><p>When the channels create a voltage spike, they then trigger other nearby channels, which then trigger other channels, and so on. This makes the voltage spike travel down the length of the neuron.</p><p>The ion channels usually take time to reset before the next firing, so a single voltage spike doesn&#8217;t usually set off the entire neuron ringing indefinitely. However, the voltage can propagate from the base of the axon back into the dendrites, where it can play an important role in influencing whether the next incoming signal will set off the ion channels there.</p><h2>Membrane properties limit the signal speed</h2><p>Neurons are somewhat conductive, but not <em>very</em> conductive - they&#8217;re not copper wires. They&#8217;re also leaky - a large portion of their current seeps out into the surrounding intercellular fluid, partly because the cell membrane is not 100% impermeable to ions, and partly because of the membrane capacitance.</p><p>That means that if a given ion channel generates some voltage locally, that voltage will quickly drop off as we move farther from that channel.</p><p>So the ion channels cannot be spaced too far apart, and the signal will travel only as fast as the channels can open and close between the start and the end of the axon.</p><h2>Myelin speeds up the signal</h2><p>Vertebrates (including humans) have a clever innovation to speed up the propagation of signals: they use myelin sheaths to insulate axons that travel over distances longer than millimeters.</p><p>Myelin sheaths surrounding an axon of the peripheral nervous system (i.e. outside the brain or spine). Source: &#8220;Anatomy and Physiology&#8221; by the US National Cancer Institute&#8217;s Surveillance, Epidemiology and End Results (SEER) Program.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!OX3r!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F09eedbc7-5c9b-4854-b74a-394d40d53e2b.svg" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!OX3r!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F09eedbc7-5c9b-4854-b74a-394d40d53e2b.svg 424w, https://substackcdn.com/image/fetch/$s_!OX3r!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F09eedbc7-5c9b-4854-b74a-394d40d53e2b.svg 848w, https://substackcdn.com/image/fetch/$s_!OX3r!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F09eedbc7-5c9b-4854-b74a-394d40d53e2b.svg 1272w, https://substackcdn.com/image/fetch/$s_!OX3r!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F09eedbc7-5c9b-4854-b74a-394d40d53e2b.svg 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!OX3r!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F09eedbc7-5c9b-4854-b74a-394d40d53e2b.svg" width="1456" height="783" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/09eedbc7-5c9b-4854-b74a-394d40d53e2b.svg&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:783,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;Myelin sheaths surrounding an axon of the peripheral nervous system (i.e. outside the brain or spine). Source: \&quot;Anatomy and Physiology\&quot; by the US National Cancer Institute's Surveillance, Epidemiology and End Results (SEER) Program.&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="Myelin sheaths surrounding an axon of the peripheral nervous system (i.e. outside the brain or spine). Source: &quot;Anatomy and Physiology&quot; by the US National Cancer Institute's Surveillance, Epidemiology and End Results (SEER) Program." title="Myelin sheaths surrounding an axon of the peripheral nervous system (i.e. outside the brain or spine). Source: &quot;Anatomy and Physiology&quot; by the US National Cancer Institute's Surveillance, Epidemiology and End Results (SEER) Program." srcset="https://substackcdn.com/image/fetch/$s_!OX3r!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F09eedbc7-5c9b-4854-b74a-394d40d53e2b.svg 424w, https://substackcdn.com/image/fetch/$s_!OX3r!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F09eedbc7-5c9b-4854-b74a-394d40d53e2b.svg 848w, https://substackcdn.com/image/fetch/$s_!OX3r!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F09eedbc7-5c9b-4854-b74a-394d40d53e2b.svg 1272w, https://substackcdn.com/image/fetch/$s_!OX3r!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F09eedbc7-5c9b-4854-b74a-394d40d53e2b.svg 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">Myelin sheaths surrounding an axon of the peripheral nervous system (i.e. outside the brain or spine). Source: "Anatomy and Physiology" by the US National Cancer Institute's Surveillance, Epidemiology and End Results (SEER) Program.</figcaption></figure></div><p>Myelin sheaths form in 0.2- 1 mm segments over the neurons and are made from layers of cell membrane and protein made by the dedicated cells - oligodendrocytes in the brain and spinal cord, and by Schwann cells everywhere else.</p><p>Myelin significantly thickens the axon&#8217;s wall and reduces the amount of current leaked out through the cell membrane. This allows the myelinated neuron to space their ion channels farther apart, significantly speeding up the propagation of the voltage spikes.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!igMe!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa7e31db3-6a85-4e27-ae85-cdf5c03a0bda_1920x1080.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!igMe!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa7e31db3-6a85-4e27-ae85-cdf5c03a0bda_1920x1080.png 424w, https://substackcdn.com/image/fetch/$s_!igMe!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa7e31db3-6a85-4e27-ae85-cdf5c03a0bda_1920x1080.png 848w, https://substackcdn.com/image/fetch/$s_!igMe!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa7e31db3-6a85-4e27-ae85-cdf5c03a0bda_1920x1080.png 1272w, https://substackcdn.com/image/fetch/$s_!igMe!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa7e31db3-6a85-4e27-ae85-cdf5c03a0bda_1920x1080.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!igMe!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa7e31db3-6a85-4e27-ae85-cdf5c03a0bda_1920x1080.png" width="1456" height="819" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/a7e31db3-6a85-4e27-ae85-cdf5c03a0bda_1920x1080.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:819,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" title="" srcset="https://substackcdn.com/image/fetch/$s_!igMe!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa7e31db3-6a85-4e27-ae85-cdf5c03a0bda_1920x1080.png 424w, https://substackcdn.com/image/fetch/$s_!igMe!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa7e31db3-6a85-4e27-ae85-cdf5c03a0bda_1920x1080.png 848w, https://substackcdn.com/image/fetch/$s_!igMe!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa7e31db3-6a85-4e27-ae85-cdf5c03a0bda_1920x1080.png 1272w, https://substackcdn.com/image/fetch/$s_!igMe!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa7e31db3-6a85-4e27-ae85-cdf5c03a0bda_1920x1080.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div>]]></content:encoded></item><item><title><![CDATA[Newcomen atmospheric engine - an animation]]></title><description><![CDATA[A stylized animation of Newcomen engine that I made a while back.]]></description><link>https://www.i-kh.net/p/newcomen-engine</link><guid isPermaLink="false">https://www.i-kh.net/p/newcomen-engine</guid><dc:creator><![CDATA[Iouri Khramtsov]]></dc:creator><pubDate>Sat, 08 Feb 2020 22:06:00 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!ugmo!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F29c17428-d743-411c-97f0-979cd25191a5_1354x1369.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>A stylized animation of <a href="https://en.wikipedia.org/wiki/Newcomen_atmospheric_engine">Newcomen engine</a> that I made a while back.</p><p>Newcomen engine is one of the first viable steam engines originally made in 1712 in England to pump water out of mines.</p><p>Unlike later steam engines, it was an &#8220;atmospheric engine&#8221; in which the power stroke was produced by the steam condensing into water and thus creating a vacuum; the atmospheric pressure then pushed the cylinder down, moving the big beam.</p><p>It was extremely inefficient by modern standards, but that wasn&#8217;t a big deal if it was sitting next to a coal mine.</p><div class="native-video-embed" data-component-name="VideoPlaceholder" data-attrs="{&quot;mediaUploadId&quot;:&quot;affa3329-d95f-4b6b-af74-c91bd9d58b0e&quot;,&quot;duration&quot;:null}"></div><h2>Some fun details</h2><ul><li><p>This engine is shown pumping the water out of a mine. The bulk of this water was discarded, but some was pumped up to a container at the top that would feed the engine.</p></li><li><p>If too much air got into the main cylinder, it would stall. That&#8217;s why you see the engine leaking a bit of steam through a pipe when it&#8217;s inflating - to make sure that there&#8217;s minimum air in the main cylinder. The valve that the steam is leaking from was called the &#8220;snifting valve&#8221;.</p></li><li><p>The big vertical plank that moves up and down is called the &#8220;plug tree&#8221;.</p></li><li><p>The little stream of water on top of the cylinder is there to create an airtight seal.</p></li><li><p>Fire is really painful to animate by hand if you don&#8217;t have any animation experience.</p></li></ul><p>Not shown in the animation is an avanced feature of some of the engines: a pressure-controlled valve that helped refill the water in the boiler.</p><p>The animation above is rather stylized. This sketch from a 1868 book shows what it actually looked like on the inside:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!ugmo!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F29c17428-d743-411c-97f0-979cd25191a5_1354x1369.jpeg" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!ugmo!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F29c17428-d743-411c-97f0-979cd25191a5_1354x1369.jpeg 424w, https://substackcdn.com/image/fetch/$s_!ugmo!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F29c17428-d743-411c-97f0-979cd25191a5_1354x1369.jpeg 848w, https://substackcdn.com/image/fetch/$s_!ugmo!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F29c17428-d743-411c-97f0-979cd25191a5_1354x1369.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!ugmo!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F29c17428-d743-411c-97f0-979cd25191a5_1354x1369.jpeg 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!ugmo!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F29c17428-d743-411c-97f0-979cd25191a5_1354x1369.jpeg" width="1354" height="1369" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/29c17428-d743-411c-97f0-979cd25191a5_1354x1369.jpeg&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1369,&quot;width&quot;:1354,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;A sketch from Louis Figuer's 1868 book \&quot;Merveilles de la science\&quot;.&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="A sketch from Louis Figuer's 1868 book &quot;Merveilles de la science&quot;." title="A sketch from Louis Figuer's 1868 book &quot;Merveilles de la science&quot;." srcset="https://substackcdn.com/image/fetch/$s_!ugmo!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F29c17428-d743-411c-97f0-979cd25191a5_1354x1369.jpeg 424w, https://substackcdn.com/image/fetch/$s_!ugmo!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F29c17428-d743-411c-97f0-979cd25191a5_1354x1369.jpeg 848w, https://substackcdn.com/image/fetch/$s_!ugmo!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F29c17428-d743-411c-97f0-979cd25191a5_1354x1369.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!ugmo!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F29c17428-d743-411c-97f0-979cd25191a5_1354x1369.jpeg 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">A sketch from Louis Figuer's 1868 book "Merveilles de la science".</figcaption></figure></div><p>Though typically the boiler, the pipes, and the switches would be enclosed in a brick structure like the one below. You can see the same engine in action in <a href="https://www.youtube.com/watch?v=HC6LUWSBXjk">this YouTube video</a>.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!ZufQ!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffab97fd4-5f8b-461b-b2f8-65d5a442f76e_1280x859.jpeg" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!ZufQ!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffab97fd4-5f8b-461b-b2f8-65d5a442f76e_1280x859.jpeg 424w, https://substackcdn.com/image/fetch/$s_!ZufQ!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffab97fd4-5f8b-461b-b2f8-65d5a442f76e_1280x859.jpeg 848w, https://substackcdn.com/image/fetch/$s_!ZufQ!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffab97fd4-5f8b-461b-b2f8-65d5a442f76e_1280x859.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!ZufQ!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffab97fd4-5f8b-461b-b2f8-65d5a442f76e_1280x859.jpeg 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!ZufQ!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffab97fd4-5f8b-461b-b2f8-65d5a442f76e_1280x859.jpeg" width="1280" height="859" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/fab97fd4-5f8b-461b-b2f8-65d5a442f76e_1280x859.jpeg&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:859,&quot;width&quot;:1280,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;A replica of a Newcomen engine at the Black Country Museum in the UK. Source: Wikimedia Commons.&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="A replica of a Newcomen engine at the Black Country Museum in the UK. Source: Wikimedia Commons." title="A replica of a Newcomen engine at the Black Country Museum in the UK. Source: Wikimedia Commons." srcset="https://substackcdn.com/image/fetch/$s_!ZufQ!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffab97fd4-5f8b-461b-b2f8-65d5a442f76e_1280x859.jpeg 424w, https://substackcdn.com/image/fetch/$s_!ZufQ!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffab97fd4-5f8b-461b-b2f8-65d5a442f76e_1280x859.jpeg 848w, https://substackcdn.com/image/fetch/$s_!ZufQ!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffab97fd4-5f8b-461b-b2f8-65d5a442f76e_1280x859.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!ZufQ!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffab97fd4-5f8b-461b-b2f8-65d5a442f76e_1280x859.jpeg 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">A replica of a Newcomen engine at the Black Country Museum in the UK. Source: Wikimedia Commons.</figcaption></figure></div>]]></content:encoded></item><item><title><![CDATA[Making codebases age well]]></title><description><![CDATA[Why are some systems easy to update after a decade, while others are hard to understand after a year or two?]]></description><link>https://www.i-kh.net/p/making-codebase-age-well</link><guid isPermaLink="false">https://www.i-kh.net/p/making-codebase-age-well</guid><dc:creator><![CDATA[Iouri Khramtsov]]></dc:creator><pubDate>Thu, 30 Jan 2020 13:49:00 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!V9Qv!,w_256,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F64d2997e-d235-41e8-8ece-611b5f6c9f21_512x512.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Why are some systems easy to update after a decade, while others are hard to understand after a year or two? And why are some companies drowning in bugs and need a month to complete a change that takes days in other companies?</p><p>Some of the root causes may be organizational, but technical choices also make a big difference.</p><p>After seeing plenty of projects on either end of the spectrum, here are the biggest differences between codebases that age well and the ones that don&#8217;t.</p><h2>1. Have less stuff to maintain</h2><p>The most maintainable systems I&#8217;ve seen had architects that pushed for:</p><ul><li><p>Fewer features by being choosy about which features to implement</p></li><li><p>Fewer technologies rather than more - e.g. avoiding polyglot microservices</p></li><li><p>Sticking to the same patterns over time, even if they&#8217;re imperfect (but good enough)</p></li><li><p>Fewer services, technologies, 3rd party components, etc</p></li><li><p>Fewer lines of code, relying more on third-party libraries and services</p></li><li><p>Cleaning up old unused parts</p></li><li><p>Fewer moving parts overall</p></li></ul><p>Whatever is left would ideally be organized into groups of very similar-looking components so that whoever works on the system in five years would be able to understand it easily.</p><p>The inverse of this &#8212; a technology/feature/sub-system sprawl &#8212; is one of the scariest ways in which the system can become unmaintainable because it is difficult to undo. This can happen when generations of programmers come through an organization, decide that the old way of building things is bad, introduce new technologies/patterns/systems without replacing the old ones, and then are replaced by the next generation. Or by multiple teams working in parallel, independently picking their favorite tech stacks. To a lesser degree, this can happen when less experienced teams keep adding new tech to the mix without thinking through the complexity that comes out.</p><p>Either way, the end result is a system that&#8217;s hard to fully comprehend, easy to break, and probably has team members that can&#8217;t or don&#8217;t want to touch unfamiliar parts of the system.</p><h2>2. Choose mature, popular technologies</h2><p>If you want your codebase to be easy to update in five years, don&#8217;t use a technology that will be dead in five years. Or one that will change so much that upgrading becomes impractical. Anything built on Angular 1, Silverlight, or early milestone Spring Boot versions would be very uncomfortable to work with today.</p><p>For this reason, I prefer to pick popular technologies that are already on v2 or v3 and have largely stabilized.</p><p>As of early 2020, this means:</p><ul><li><p>React: Good. Popular, widely used, about six years old. Probably the best pick on the front end.</p></li><li><p>F#: Bad. Mature, but not widely used. Avoid unless you already have F# experts, or it&#8217;s a solo side project.</p></li><li><p>Svelte: Bad. Popular, high satisfaction, but new; might not survive or might change a lot in the next few years.</p></li><li><p>C: Good. Will likely outlive all of us. Safe choice for its use cases.</p></li></ul><p>There are a number of other, immediate advantages to picking popular, older technologies over newer or less popular ones:</p><ul><li><p>More and better tools + libraries</p></li><li><p>Lots of Stackoverflow answers to frequent problems</p></li><li><p>Easy to find developers who can work with it</p></li></ul><p>There are several variations on this theme; one of my coworkers calls himself &#8220;Service Pack 2 guy&#8221; (service pack 1 is too early for him). <a href="https://mcfunley.com/choose-boring-technology">Choose boring technology</a> is another popular essay that expands on this.</p><h2>3. Tests, tests, tests</h2><p>At my new job, about a month into it, I needed to update a service written in Python that was rarely touched by others. It was written a few years ago and the original authors have left the company. After spending some time browsing around the source code, I discovered that not only did it have great comments, but also 98% unit test coverage! In addition, it was part of a massive integration test suite. A couple weeks later when I was done, I was extremely confident that I didn&#8217;t break any existing functionality, and that my new additions would probably work as expected.</p><p>While automated tests can slow you down in the short run, on systems that have a long life they&#8217;re totally worth the effort.</p><p>I find that the tests that give the most return for the effort are:</p><ul><li><p>Unit tests, because they&#8217;re easy to write and run, and</p></li><li><p>End-to-end tests on the whole system, because they can uncover most integration issues and prove that the entire system works as expected.</p></li></ul><p>In some cases, the latter type can also be run in production after deployments to catch problems early.</p><h2>4. Help the next developer understand the system</h2><p>Whether it&#8217;s a new developer joining a 100-person dev org, or a single dev looking at the source code that has not been touched in the past five years, they&#8217;ll have a hard time modifying a system when they don&#8217;t know what it does or why.</p><p>So help them out in advance. This means:</p><ul><li><p>Don&#8217;t surprise them with unexpected side-effects</p></li><li><p>Leave comments that explain the &#8220;why&#8221;</p></li><li><p>Have clear names</p></li><li><p>High-level documentation</p></li></ul><p>Who knows, the next developer could even be you!</p>]]></content:encoded></item><item><title><![CDATA[TDD is a lot easier with the right tools]]></title><description><![CDATA[I consider myself to be a pragmatic fan of test-driven development (TDD), writing maybe 30-50% of my code using the technique.]]></description><link>https://www.i-kh.net/p/tdd-is-easier-with-right-tools</link><guid isPermaLink="false">https://www.i-kh.net/p/tdd-is-easier-with-right-tools</guid><dc:creator><![CDATA[Iouri Khramtsov]]></dc:creator><pubDate>Mon, 11 Nov 2019 21:38:00 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!V9Qv!,w_256,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F64d2997e-d235-41e8-8ece-611b5f6c9f21_512x512.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>I consider myself to be a pragmatic fan of test-driven development (TDD), writing maybe 30-50% of my code using the technique.</p><p>Having done it in four different tech stacks over the past few years, I look forward to TDD a lot more in some of them than in others.</p><p>Let&#8217;s compare a few of the experiences to see what they get right and what they don&#8217;t, from best to worst:</p><ol><li><p>.Net: xUnit and NCrunch</p></li><li><p>JS/TS: Jest and VS Code Jest extension</p></li><li><p>Python: pytest</p></li><li><p>Java: IntelliJ and Infinitest</p></li></ol><h2>What makes a good TDD experience</h2><p>The main difference between test-driven development and regular development is:</p><ul><li><p>You write a lot more unit tests,</p></li><li><p>You run unit tests more often,</p></li><li><p>You debug the unit test failures more often.</p></li></ul><p>So if the tech stack&#8217;s tools and libraries are better set up to support these, then the TDD process will be more pleasant.</p><h2>The winner: .Net</h2><h3>NCrunch</h3><p>The main star of the .Net TDD ecosystem is <a href="https://www.ncrunch.net/">NCrunch</a> add-in for Visual Studio. The best description of it is this animation from its landing page (unfortunately it looks best on desktops and tablets):</p><div class="native-video-embed" data-component-name="VideoPlaceholder" data-attrs="{&quot;mediaUploadId&quot;:&quot;548e9550-8621-4e26-b0e3-4a0152e3eda6&quot;,&quot;duration&quot;:null}"></div><p>In it we see a few things:</p><ul><li><p>NCrunch runs continuously as you type.</p></li><li><p>The colored dots on the left of each line lets you know whether the line is covered or not.</p></li><li><p>The same dots go red when the tests covering the line fail.</p></li><li><p>Dots turn to a red &#8220;X&#8221; when that line throws an exception. Can hover over the &#8220;X&#8221; to see the exception.</p></li><li><p>Context menu on each line allows to run the test and break at that line.</p></li></ul><p>As a result:</p><ul><li><p>Tests run continuously, with very fast feedback,</p></li><li><p>Feedback is given in the context of the code you&#8217;re looking at,</p></li><li><p>Debugging is very easy and is often unnecessary.</p></li></ul><p>The overall experience is very smooth with most of the time spent on writing the tests and the code, and very little on debugging or troubleshooting the tools.</p><p>The downside is the price. Like with many other tools for the Microsoft stack, NCrunch is proprietary with a $159 one-time fee per named user, though in my experience it is totally worth it.</p><h3>xUnit</h3><p>The other outstanding element of the .Net ecosystem is <a href="https://xunit.net/">xUnit</a> test framework. Similar to other _Unit frameworks, it makes one subtly different choice that makes life easier: it makes a new instance of the test class for each test. Aside from saving a bit of typing (&#8220;before-each&#8221; functions are replaced with constructors), it ensures that the mess left by one test function does not impact another test function, which eliminates a class of test issues.</p><p>Finally, both major .Net test frameworks - NUnit and xUnit - are in a rare group of frameworks that provide an easy way to write in-line test cases like this:</p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;csharp&quot;,&quot;nodeId&quot;:&quot;9a478886-e2f9-47e9-b4b1-27975467aaa7&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-csharp">public class SomeTests 
{
    [Theory]
    [InlineData(&#8221;&#8220;, &#8220;&#8221;)]
    [InlineData(&#8221;/somepath&#8221;, &#8220;/&#8221;)]
    [InlineData(&#8221;/some/deeper/path.png&#8221;, &#8220;/path.png&#8221;)]
    public void ShouldRewritePath(string input, string expectedOutput) {
        // ...
    }
}</code></pre></div><p>Pytest does a good job with this as well. Jest doesn&#8217;t, but at least the flexibility of JavaScript lets you improvise something. Java&#8217;s JUnit 5 introduced something similar with parameterized tests, but its ergonomics is very poor due to JVM&#8217;s quirks.</p><h3>Downsides</h3><p>Moq is a nice mocking framework, but it can mock only what it can override, which in some cases is not a lot. For this reason, mocking many things in ASP.NET and the rest of the .Net Framework is not straightforward. This has been gradually getting better in .Net Core.</p><p>In addition, though C# syntax has evolved a lot over the years, its types sometimes force you to write pretty contrived expressions.</p><h3>Putting it all together</h3><p>The end result is that in .Net my experience writing tests has more &#8220;Oh, you can do that?&#8221; and less &#8220;WTF happened just now?&#8221; than in other tech stacks, which is one of the reasons I chose it my personal projects.</p><h2>Runner-up: JS/TS, Jest, VS Code</h2><p>So how does working with Jest compare to xUnit/NCrunch combo above? Let&#8217;s write something.</p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;javascript&quot;,&quot;nodeId&quot;:&quot;1050c473-9c77-4cee-a520-eac75a993b68&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-javascript">describe(&#8221;Submit button tests&#8221;, () =&gt; {
    test(&#8221;When user clicks the button, show an incomprehensible error.&#8221;, () =&gt; { 
        // Do something
    })
})</code></pre></div><p>The awesome:</p><ul><li><p>Writing simple tests is super simple. Just write the <code>test()</code> function.</p></li><li><p>Test names can be proper English sentences. Great for readability!</p></li><li><p><code>describe()</code> lets us group test suites and sub-suites. And these can also have nice, readable names!</p></li><li><p>The power of JS lets us mock anything. Don&#8217;t like interfaces? Then don&#8217;t use them, mocking still works! (But I like them anyway)</p></li></ul><p>The downsides:</p><ul><li><p>Have to improvise parametrized tests with a <code>.forEach(() =&gt; {test(...)})</code>. It works, but it requires a bit more thinking every time.</p></li><li><p>Test functions can interfere with each other. You learn quickly to not do the stupid things that cause that, but again, it adds a bit of mental overhead.</p></li></ul><p>Running and debugging the tests involves a bit of friction. You have two options for running the tests continuously: (1) <code>jest --watch</code> and (2) VS Code Jest extension.</p><p>The first option works, and it will give you regular feedback when you break or pass the tests. It&#8217;ll point you to the offending line too. But the debugging has to be done through <code>console.log()</code>, and the test runs can take a while even on modest codebases. It also occupies additional real estate as a separate terminal window, which is not terrible, but not fantastic either, especially on a laptop.</p><p>The second option, Jest VS Code extension, integrates the test results with the IDE and gives a handy &#8220;Debug&#8221; link above each test. Clicking that link launches VS Code debugger.</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!PpWK!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb4e5b8d8-0744-4233-a3b0-4df9de1cef40_513x92.jpeg" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!PpWK!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb4e5b8d8-0744-4233-a3b0-4df9de1cef40_513x92.jpeg 424w, https://substackcdn.com/image/fetch/$s_!PpWK!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb4e5b8d8-0744-4233-a3b0-4df9de1cef40_513x92.jpeg 848w, https://substackcdn.com/image/fetch/$s_!PpWK!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb4e5b8d8-0744-4233-a3b0-4df9de1cef40_513x92.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!PpWK!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb4e5b8d8-0744-4233-a3b0-4df9de1cef40_513x92.jpeg 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!PpWK!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb4e5b8d8-0744-4233-a3b0-4df9de1cef40_513x92.jpeg" width="513" height="92" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/b4e5b8d8-0744-4233-a3b0-4df9de1cef40_513x92.jpeg&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:92,&quot;width&quot;:513,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;Some features of the VS Code Jest extension&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="Some features of the VS Code Jest extension" title="Some features of the VS Code Jest extension" srcset="https://substackcdn.com/image/fetch/$s_!PpWK!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb4e5b8d8-0744-4233-a3b0-4df9de1cef40_513x92.jpeg 424w, https://substackcdn.com/image/fetch/$s_!PpWK!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb4e5b8d8-0744-4233-a3b0-4df9de1cef40_513x92.jpeg 848w, https://substackcdn.com/image/fetch/$s_!PpWK!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb4e5b8d8-0744-4233-a3b0-4df9de1cef40_513x92.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!PpWK!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb4e5b8d8-0744-4233-a3b0-4df9de1cef40_513x92.jpeg 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a><figcaption class="image-caption">Some features of the VS Code Jest extension</figcaption></figure></div><p>The debugger integration is quite solid, but the rest is not. After saving the file (and remember, in NCrunch we didn&#8217;t have to do that), you have to be a bit patient and let the extension catch up. After a few hours of work the extension inevitably crashes, and will not start up again until VS Code reloads the folder.</p><p>Alltogether, this leads to a continuous testing experience that&#8217;s workable, but not the best.</p><h2>Python&#8217;s pytest: probably the second place too</h2><p>My experience with Python is not as extensive as with the other three languages on the list, but using VS Code and Pytest seems to have a similar experience to <code>jest --watch</code>.</p><p>Pytest framework itself is a bit more pleasant, and mocking seems a bit easier. The downside is no static types, which means less help from the IDE. Also, there seems to be more limited IDE integration for Python unit testing in general.</p><h2>The laggard: Java, IntelliJ</h2><p>Finally, let&#8217;s write and run some tests using Java, JUnit 5, IntelliJ, and Infinitest.</p><p>Right off the bat, you can run into problems with <code>@Test</code> annotation and other JUnit API elements. They exist in both <code>org.junit</code> (JUnit 4) and <code>org.junit.jupiter.api</code> (JUnit 5) packages. If you&#8217;re using Spring Boot, you probably somehow have both, and it&#8217;s easy to accidentally import the wrong one and spend half an hour troubleshooting the resulting problems (and then helping every new coworker who accidentally does that). After two years with JUnit 5, I still repeat that mistake.</p><p>The second problem we run into is enabling continuous testing. In theory, <a href="https://infinitest.github.io/">Infinitest</a> and IntelliJ should function seamlessly together: just install Infinitest, add it to the project, enable the continuous builds, and done. That&#8217;s the experience with NCrunch and Jest VS Code extension.</p><p>In practice though, something always goes wrong. Just now, for this blog post, I tried to set up a new project with Infinitest. After already doing this a couple times in the past few years, it took me about five minutes just to translate these instructions from the Infinitest website:</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!NYl1!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd59aeca3-f656-4d17-a5ca-fb5c3756edb7_437x191.jpeg" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!NYl1!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd59aeca3-f656-4d17-a5ca-fb5c3756edb7_437x191.jpeg 424w, https://substackcdn.com/image/fetch/$s_!NYl1!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd59aeca3-f656-4d17-a5ca-fb5c3756edb7_437x191.jpeg 848w, https://substackcdn.com/image/fetch/$s_!NYl1!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd59aeca3-f656-4d17-a5ca-fb5c3756edb7_437x191.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!NYl1!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd59aeca3-f656-4d17-a5ca-fb5c3756edb7_437x191.jpeg 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!NYl1!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd59aeca3-f656-4d17-a5ca-fb5c3756edb7_437x191.jpeg" width="437" height="191" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/d59aeca3-f656-4d17-a5ca-fb5c3756edb7_437x191.jpeg&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:191,&quot;width&quot;:437,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" title="" srcset="https://substackcdn.com/image/fetch/$s_!NYl1!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd59aeca3-f656-4d17-a5ca-fb5c3756edb7_437x191.jpeg 424w, https://substackcdn.com/image/fetch/$s_!NYl1!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd59aeca3-f656-4d17-a5ca-fb5c3756edb7_437x191.jpeg 848w, https://substackcdn.com/image/fetch/$s_!NYl1!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd59aeca3-f656-4d17-a5ca-fb5c3756edb7_437x191.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!NYl1!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd59aeca3-f656-4d17-a5ca-fb5c3756edb7_437x191.jpeg 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p>into these steps:</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!SHtT!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbdd9f4e1-f0f2-4815-b612-c2f85c18b04f_329x219.jpeg" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!SHtT!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbdd9f4e1-f0f2-4815-b612-c2f85c18b04f_329x219.jpeg 424w, https://substackcdn.com/image/fetch/$s_!SHtT!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbdd9f4e1-f0f2-4815-b612-c2f85c18b04f_329x219.jpeg 848w, https://substackcdn.com/image/fetch/$s_!SHtT!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbdd9f4e1-f0f2-4815-b612-c2f85c18b04f_329x219.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!SHtT!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbdd9f4e1-f0f2-4815-b612-c2f85c18b04f_329x219.jpeg 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!SHtT!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbdd9f4e1-f0f2-4815-b612-c2f85c18b04f_329x219.jpeg" width="329" height="219" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/bdd9f4e1-f0f2-4815-b612-c2f85c18b04f_329x219.jpeg&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:219,&quot;width&quot;:329,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" title="" srcset="https://substackcdn.com/image/fetch/$s_!SHtT!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbdd9f4e1-f0f2-4815-b612-c2f85c18b04f_329x219.jpeg 424w, https://substackcdn.com/image/fetch/$s_!SHtT!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbdd9f4e1-f0f2-4815-b612-c2f85c18b04f_329x219.jpeg 848w, https://substackcdn.com/image/fetch/$s_!SHtT!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbdd9f4e1-f0f2-4815-b612-c2f85c18b04f_329x219.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!SHtT!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbdd9f4e1-f0f2-4815-b612-c2f85c18b04f_329x219.jpeg 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!x2zC!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3ff80302-912c-436b-b037-5c0860fb1076_317x272.jpeg" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!x2zC!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3ff80302-912c-436b-b037-5c0860fb1076_317x272.jpeg 424w, https://substackcdn.com/image/fetch/$s_!x2zC!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3ff80302-912c-436b-b037-5c0860fb1076_317x272.jpeg 848w, https://substackcdn.com/image/fetch/$s_!x2zC!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3ff80302-912c-436b-b037-5c0860fb1076_317x272.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!x2zC!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3ff80302-912c-436b-b037-5c0860fb1076_317x272.jpeg 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!x2zC!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3ff80302-912c-436b-b037-5c0860fb1076_317x272.jpeg" width="317" height="272" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/3ff80302-912c-436b-b037-5c0860fb1076_317x272.jpeg&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:272,&quot;width&quot;:317,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" title="" srcset="https://substackcdn.com/image/fetch/$s_!x2zC!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3ff80302-912c-436b-b037-5c0860fb1076_317x272.jpeg 424w, https://substackcdn.com/image/fetch/$s_!x2zC!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3ff80302-912c-436b-b037-5c0860fb1076_317x272.jpeg 848w, https://substackcdn.com/image/fetch/$s_!x2zC!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3ff80302-912c-436b-b037-5c0860fb1076_317x272.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!x2zC!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3ff80302-912c-436b-b037-5c0860fb1076_317x272.jpeg 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>due to the different places where you can look at the facets and find a &#8220;+&#8221; button that has an &#8220;Infinitest&#8221; option. It still didn&#8217;t run.</p><p>In any case, in the past I had to stop running Infinitest because the continuous IntelliJ builds were giving me trouble; ultimately, it was easier to just run the tests manually.</p><p>There are also a bunch of other minor frictions, like the &#8220;command line too long&#8221; error on Windows, or an uncomfortable interface for parametrizing the unit tests.</p><p>To be fair, there are some bright spots. Running and debugging the tests is pretty smooth, and I can use the context menu to debug a specific test.</p><p>Or this one if you&#8217;re using Kotlin:</p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;kotlin&quot;,&quot;nodeId&quot;:&quot;a7eb5816-fccd-4e19-b98b-d0ec4d119b4a&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-kotlin">fun `That&#8217;s valid Kotlin function name`() {

}</code></pre></div><p>Which is great for writing descriptive test names.</p><p>But overall, TDD is noticeably less pleasant in Java than in other tech stacks.</p>]]></content:encoded></item><item><title><![CDATA[Kubernetes is useful, but it's not a complete platform]]></title><description><![CDATA[It&#8217;s been almost four months since we&#8217;ve migrated to AWS Elastic Kubernetes Service at HOOPP&#8216;s 90-person Investment Solutions Group, and we&#8217;re starting to get a sense for what it&#8217;s like running on it.]]></description><link>https://www.i-kh.net/p/kubernetes-is-useful-but-its-not-a-complete-platform</link><guid isPermaLink="false">https://www.i-kh.net/p/kubernetes-is-useful-but-its-not-a-complete-platform</guid><dc:creator><![CDATA[Iouri Khramtsov]]></dc:creator><pubDate>Sat, 16 Mar 2019 14:16:00 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!V9Qv!,w_256,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F64d2997e-d235-41e8-8ece-611b5f6c9f21_512x512.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>It&#8217;s been almost four months since we&#8217;ve migrated to AWS Elastic Kubernetes Service at <a href="https://hoopp.com/">HOOPP</a>&#8216;s 90-person Investment Solutions Group, and we&#8217;re starting to get a sense for what it&#8217;s like running on it.</p><p>While we ultimately liked it, right from the first interaction it became apparent that Kubernetes was not a complete platform, just a good backbone for a platform. If we wanted a group of 90 developers, business analysts, and product owners to work comfortably with it day-to-day, we needed to deal with configuration/operation complexities, platform quirks, and some gaps in tooling.</p><p>To deal with that, we did what I&#8217;ve observed as a trend: we put our own platform layer on top of Kubernetes. This post goes into that layer.</p><p>There are three areas where we had to make additional improvements:</p><ol><li><p>Interface between the developers and Kubernetes</p></li><li><p>Operations and maintenance</p></li><li><p>Auxiliary tooling, like logging, monitoring, and dashboards.</p></li></ol><h1>Still, we liked Kubernetes</h1><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!NxDY!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd85f6cbd-be02-48b3-93a2-891fed38d182_476x191.jpeg" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!NxDY!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd85f6cbd-be02-48b3-93a2-891fed38d182_476x191.jpeg 424w, https://substackcdn.com/image/fetch/$s_!NxDY!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd85f6cbd-be02-48b3-93a2-891fed38d182_476x191.jpeg 848w, https://substackcdn.com/image/fetch/$s_!NxDY!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd85f6cbd-be02-48b3-93a2-891fed38d182_476x191.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!NxDY!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd85f6cbd-be02-48b3-93a2-891fed38d182_476x191.jpeg 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!NxDY!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd85f6cbd-be02-48b3-93a2-891fed38d182_476x191.jpeg" width="476" height="191" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/d85f6cbd-be02-48b3-93a2-891fed38d182_476x191.jpeg&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:191,&quot;width&quot;:476,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;It wasn't as simple as this image from the Kubernetes website. But it was still pretty good.&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="It wasn't as simple as this image from the Kubernetes website. But it was still pretty good." title="It wasn't as simple as this image from the Kubernetes website. But it was still pretty good." srcset="https://substackcdn.com/image/fetch/$s_!NxDY!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd85f6cbd-be02-48b3-93a2-891fed38d182_476x191.jpeg 424w, https://substackcdn.com/image/fetch/$s_!NxDY!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd85f6cbd-be02-48b3-93a2-891fed38d182_476x191.jpeg 848w, https://substackcdn.com/image/fetch/$s_!NxDY!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd85f6cbd-be02-48b3-93a2-891fed38d182_476x191.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!NxDY!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd85f6cbd-be02-48b3-93a2-891fed38d182_476x191.jpeg 1456w" sizes="100vw" fetchpriority="high"></picture><div></div></div></a><figcaption class="image-caption">It wasn't as simple as this image from the Kubernetes website. But it was still pretty good.</figcaption></figure></div><p>The migration wasn&#8217;t cheap (for us). It took five months from &#8220;let&#8217;s try it out&#8221; to post-migration cleanup, with two to nine people working on it depending on the time. But ultimately it was worth it.</p><p>Compared to our last platform, AWS Elastic Beanstalk, on Kubernetes we got:</p><ul><li><p><strong>Quick, painless deployments</strong> that needed less attention.</p></li><li><p><strong>Less distractions</strong> for the delivery teams, who could now iterate faster on their features.</p></li><li><p><strong>Stupidly easy high availability</strong>, including 100% uptime during deployments and self-healing after random crashes of service instances.</p></li><li><p><strong><a href="https://helm.sh/">Helm</a> charts</strong>. These are third-party &#8220;packages&#8221; of functionality that you can install on your Kubernetes cluster with a single command. We discovered these after starting work on the migration, and they made our lives much simpler. For example, Splunk (<a href="https://github.com/splunk/splunk-connect-for-kubernetes">Helm chart</a>), ALB Ingress Controller (<a href="https://kubernetes-sigs.github.io/aws-alb-ingress-controller/guide/controller/setup/">Helm instructions</a>) and other components and tools were installed this way.</p></li><li><p><strong>Lower costs</strong> because we could pack more containers on individual EC2 instances.</p></li><li><p><strong>Easier disaster recovery</strong>. With declarative deployments and Helm charts, we&#8217;ll spend a lot less time redeploying a new, fully working production environment.</p></li><li><p><strong>Many convenience features</strong> that made the overall setup easier, including cluster-internal DNS for service discovery and simpler provisioning of AWS load balancers.</p></li></ul><p>Overall, Kubernetes now feels like a solid, stable backbone of our infrastructure. Aside from some initial move-in pains, it is now giving us minimal trouble, and it feels like we won&#8217;t have to think much about for the next five years.</p><p>A side note: pension plan investment management is not the kind of business that requires scaling to a large number of instances. Our problem was making the infrastructure work effectively for a dozen or so teams, and making horizontal scalability not a concern in the few cases where we needed it. I&#8217;ve had people wonder whether Kubernetes was needlessly complex for this kind of organization. With hindsight, and having experienced other platforms and infrastructures, the answer is definitely &#8220;not too complex&#8221;.</p><h3>&#8230;But Kubernetes wasn&#8217;t enough.</h3><p>Though it was a good platform, but if we had made our delivery teams interact with Kubernetes directly, their lives would have become a lot more complicated.</p><h1>1. Developer interactions with Kubernetes</h1><h3>The config files</h3><p>After turning all the knobs and dials, our typical Kubernetes config files ended up being about 100 lines long. Each service needed its own config file, as there were some per-service differences between the files. If each team has 4-10 services, that&#8217;s a lot of config files. Easy to make a subtle mistake and spend days troubleshooting; hard to make wholesale changes to all of them.</p><p>Instead of large config files, wouldn&#8217;t it be nice if each service had a shorter manifest file that explained how it&#8217;s different from other services, like this:</p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;yaml&quot;,&quot;nodeId&quot;:&quot;bec6610e-e4d5-4708-b046-06895d1769ae&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-yaml">name: my-service
service-type: java-8
instances: 2
environments:
  prod:
    instances: 4</code></pre></div><p>We ended up building exactly that. Each service got a <code>service.yml</code> file in its root folder; our build+release tooling interpreted it, generated an appropriate dockerfile and Kubernetes <code>config.yml</code>, and used the right settings in various intermediate commands, like the command to create a container repository in AWS Elastic Container Registry.</p><p>The initial work to implement this was around two people working over four weeks, and included design/development, updating <a href="https://azure.microsoft.com/en-ca/services/devops/pipelines/">Azure Pipelines</a>, educating the teams, and adding <code>service.yml</code> to each existing service. We then spent about as much time on updates and cleanup.</p><p>In case you&#8217;re familiar with Cloud Foundry, the <code>service.yml</code> file was heavily inspired by its manifest files. We didn&#8217;t go with Cloud Foundry because the providers we looked at were either too expensive (Pivotal) or were buggy and had questionable customer service (IBM Bluemix).</p><p>We did look at the options on the market to solve the problem. In each case, the time to evaluate, implement, and deal with the quirks would have been longer than to build our own, and that&#8217;s before adding time for the vendor assessment and contract negotiations.</p><h3>Other interfaces to Kubernetes</h3><p>From our previous experience, we found that:</p><p><strong>Product Owners</strong> liked to control the time of deployment to UAT or production. We already had existing Azure Pipelines deployments, and the product owners were comfortable using them, so we made sure to keep the experience the same for them when switching over to Kubernetes.</p><p><strong>Developers</strong>:<br>The developers&#8217; preferences varied from team to team. Some teams liked continuous deployments to their test environments, and some did not. Some teams had several test environments, and some had only one. The solution to most of these preferences was Azure Pipelines as well.</p><p>We did, however, run into a problem when someone wanted to restart a service. One of the Kubernetes quirks is lack of an explicit rolling restart ability, i.e. the ability to restart all instances in batches, while keeping at some of them online. This is an <a href="https://github.com/kubernetes/kubernetes/issues/27081">explicit design decision</a> that will not be fixed. There is still a way to force a rolling restart to happen, but it&#8217;s rather roundabout.</p><p>After some discussions, it turned out that our developers typicallty restarted services because of application configuration changes. When the config changed in the central configuration Git repository, they needed the service restarted. So we built an Azure Pipelines release that restarted all services affected by the configuration change and reported the event in Slack:</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!XUQh!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9e456105-4d5f-4045-8a06-b1d46eb7574c_646x77.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!XUQh!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9e456105-4d5f-4045-8a06-b1d46eb7574c_646x77.png 424w, https://substackcdn.com/image/fetch/$s_!XUQh!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9e456105-4d5f-4045-8a06-b1d46eb7574c_646x77.png 848w, https://substackcdn.com/image/fetch/$s_!XUQh!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9e456105-4d5f-4045-8a06-b1d46eb7574c_646x77.png 1272w, https://substackcdn.com/image/fetch/$s_!XUQh!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9e456105-4d5f-4045-8a06-b1d46eb7574c_646x77.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!XUQh!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9e456105-4d5f-4045-8a06-b1d46eb7574c_646x77.png" width="646" height="77" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/9e456105-4d5f-4045-8a06-b1d46eb7574c_646x77.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:77,&quot;width&quot;:646,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;The config deployer reporting that it restarted a service.&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="The config deployer reporting that it restarted a service." title="The config deployer reporting that it restarted a service." srcset="https://substackcdn.com/image/fetch/$s_!XUQh!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9e456105-4d5f-4045-8a06-b1d46eb7574c_646x77.png 424w, https://substackcdn.com/image/fetch/$s_!XUQh!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9e456105-4d5f-4045-8a06-b1d46eb7574c_646x77.png 848w, https://substackcdn.com/image/fetch/$s_!XUQh!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9e456105-4d5f-4045-8a06-b1d46eb7574c_646x77.png 1272w, https://substackcdn.com/image/fetch/$s_!XUQh!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9e456105-4d5f-4045-8a06-b1d46eb7574c_646x77.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a><figcaption class="image-caption">The config deployer reporting that it restarted a service.</figcaption></figure></div><p>Sometimes the developers did need to interact directly with Kubernetes, and so everyone got <code>kubectl</code> installed on their machines, and got access to the Kubernetes dashboard.</p><h3>Service dashboard</h3><p>One of the gaps that we still have is a good service dashboard. Kubernetes does <a href="https://kubernetes.io/docs/tasks/access-application-cluster/web-ui-dashboard/">have a dashboard</a>, but it presents a Kubernetes view of the system: separate lists of deployments, pods, namespaces, other Kubernetes objects. To see the complete state of your service, you&#8217;d have to browse across multiple objects on multiple screens.</p><p>The developers, on the other hand, thought of a service as a single line on the dashboard that combined all underlying Kubernetes information from the pods, deployments, and ingresses. It would have maybe the service name, a state indicator (healty/unhealthy/deploying), a few actions (e.g. &#8220;restart&#8221;), and links to relevant resources (e.g. logs).</p><p>This is still on our wish list, and we may build one if we don&#8217;t find one in the next few months.</p><h1>2. Maintenance and operations</h1><p>This is the area where Kubernetes made us do more work than Elastic Beanstalk, our previous platform.</p><p>Once you have yor cluster, you&#8217;ll have to take care of a few operational problems:</p><ul><li><p><strong>Cluster auto-scaling</strong>, i.e. expanding or reducing the number of nodes in the cluster in proportion to the load. This did not come out of the box and we had to build it using AWS auto scaling groups.</p></li><li><p><strong>Cluster upgrades</strong>, including the Kubernetes version, the kubelet agents, and node EC2 images. Some components have to have versions that are in sync with some other Kubernetes components. Any upgrades will need to be done across all clusters you have, without disrupting production or integration testing. The good news is that Kubernetes will help you out with moving the replicas from one node to another and keeping some replicas alive. But we still had to orchestrate the whole upgrade process ourselves and fine-tune it to make sure that it causes minimum disruption.</p></li></ul><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!ZLQm!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F02a5a876-a107-47df-b0cd-d65fb5ffe169_745x206.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!ZLQm!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F02a5a876-a107-47df-b0cd-d65fb5ffe169_745x206.png 424w, https://substackcdn.com/image/fetch/$s_!ZLQm!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F02a5a876-a107-47df-b0cd-d65fb5ffe169_745x206.png 848w, https://substackcdn.com/image/fetch/$s_!ZLQm!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F02a5a876-a107-47df-b0cd-d65fb5ffe169_745x206.png 1272w, https://substackcdn.com/image/fetch/$s_!ZLQm!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F02a5a876-a107-47df-b0cd-d65fb5ffe169_745x206.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!ZLQm!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F02a5a876-a107-47df-b0cd-d65fb5ffe169_745x206.png" width="745" height="206" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/02a5a876-a107-47df-b0cd-d65fb5ffe169_745x206.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:206,&quot;width&quot;:745,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;Service repicas becoming unavailable during the cluster node replacement.&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="Service repicas becoming unavailable during the cluster node replacement." title="Service repicas becoming unavailable during the cluster node replacement." srcset="https://substackcdn.com/image/fetch/$s_!ZLQm!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F02a5a876-a107-47df-b0cd-d65fb5ffe169_745x206.png 424w, https://substackcdn.com/image/fetch/$s_!ZLQm!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F02a5a876-a107-47df-b0cd-d65fb5ffe169_745x206.png 848w, https://substackcdn.com/image/fetch/$s_!ZLQm!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F02a5a876-a107-47df-b0cd-d65fb5ffe169_745x206.png 1272w, https://substackcdn.com/image/fetch/$s_!ZLQm!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F02a5a876-a107-47df-b0cd-d65fb5ffe169_745x206.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a><figcaption class="image-caption">Service repicas becoming unavailable during the cluster node replacement.</figcaption></figure></div><ul><li><p><strong>Container image upgrades</strong>. Sometimes you&#8217;d want to swap out the base image for the containers without changing the code that&#8217;s running on them. In cases of security issues, you&#8217;d want to do this for all containers on the cluster, ideally within a day. Again, without disrupting production or integration testing.</p></li><li><p><strong>Be prepared for service instances getting killed</strong> by any of the above processes at any time. If your teams are not used to programming for random disruptions, they now will have no choice because the service instances <em>will</em> get taken offline at inconvenient times.</p></li></ul><p>None of the above were rare one-off processes; they occured regularly, and you have to be ready for it. For us, the work on this involved not just building CloudFormation templates and back-end processes, but also updating our service framework, working with the teams to educate them about the best architectural decisions for the platform, and helping implement some architectural changes.</p><p>Automation of some of these processes came in very handy when we were fine-tuning the EC2 instance types used as the cluster nodes. This allowed us to try out several instance types and eventually settle on the ones that had the right mix of CPU, memory, and cost.</p><p>We still have not automated container image swaps, in part because it would have require reworking parts of our build+release pipelines and retaining more build artifacts for longer time than we would like.</p><h1>3. Additional tooling</h1><p>The other major functionality that we wanted out of the platform was logs, monitoring, alerts, security scans. As features, these were either barely present in Kubernetes (log viewing), didn&#8217;t work well out of the box (the dashboard), or wasn&#8217;t there at all (the rest).</p><p>Fortunately, with Helm charts it was easy to set up the tools we already had in-house.</p><ul><li><p><strong>Logging</strong>: we added Splunk, which we already using elsewhere. The Helm chart install was straightforward, except for a few minor surprises like incorrect splitting of individual events and incorrect timestamps. Some of it we fixed; some was not worth the trouble.</p></li><li><p><strong>Monitoring and alerting</strong>: added DataDog. Kubernetes and AWS feed some useful metrics into DataDog, though some weren&#8217;t immediately obvious.</p></li><li><p><strong><a href="https://kubernetes.io/docs/tasks/access-application-cluster/web-ui-dashboard/">Kubernetes Dashboard</a></strong>: has nice features and is a good UI alternative to the <code>kubectl</code> command line tool. The biggest issue was that we wanted it to integrate with either AWS access management or with the corporate SAML. It turned out harder than expected; we eventually did it months after the Kubernetes migration. As mentioned before, the dashboard was great for Kubernetes operations, but not quite what the delivery teams needed.</p></li><li><p><strong>Container security scanning</strong> was not necessarily a Kubernetes problem, but it was something new that we had to deal with. After reviewing the options, we went with <a href="https://anchore.com/">Anchore scan</a>, which we also installed as using a Helm chart.</p></li></ul><h1>Final words</h1><p>Kubernetes is a very nice tech, and a great piece of an overall solution. But for now it needs to be combined with custom in-house and third-party tools, otherwise it won&#8217;t help speed up the development or operations.</p><p>I would not be surprised if in five to ten years we will see emergence of a platform that will offer a complete end-to-end service management experience that would combine Kubernetes, Istio, and various other components, just like Kubernetes emerged as an end-to-end solution to the container orchestration problem.</p>]]></content:encoded></item><item><title><![CDATA[Books for technical leads and senior developers]]></title><description><![CDATA[These books help with the &#8220;lead&#8221; part: they help with things ranging from organizing better meetings to getting buy-in for a significant change.]]></description><link>https://www.i-kh.net/p/books-for-technical-leads</link><guid isPermaLink="false">https://www.i-kh.net/p/books-for-technical-leads</guid><dc:creator><![CDATA[Iouri Khramtsov]]></dc:creator><pubDate>Sun, 25 Nov 2018 23:20:00 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!V9Qv!,w_256,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F64d2997e-d235-41e8-8ece-611b5f6c9f21_512x512.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>These books help with the &#8220;lead&#8221; part: they help with things ranging from organizing better meetings to getting buy-in for a significant change. I assume most technical leads are already technically competent, so only one of these books could be called &#8220;technical&#8221;.</p><p>This is not the first list of books to be published on the topic. There are many others like it, but this one is mine. I found these books to be useful after I was first promoted to the Technical Lead role, and even more helpful when I tried to improve the rest of the organization around me.</p><h2>Lean Software Development</h2><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!o9um!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F39a136a4-7594-45a8-81a7-9d0f8eb0edbb_265x348.jpeg" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!o9um!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F39a136a4-7594-45a8-81a7-9d0f8eb0edbb_265x348.jpeg 424w, https://substackcdn.com/image/fetch/$s_!o9um!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F39a136a4-7594-45a8-81a7-9d0f8eb0edbb_265x348.jpeg 848w, https://substackcdn.com/image/fetch/$s_!o9um!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F39a136a4-7594-45a8-81a7-9d0f8eb0edbb_265x348.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!o9um!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F39a136a4-7594-45a8-81a7-9d0f8eb0edbb_265x348.jpeg 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!o9um!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F39a136a4-7594-45a8-81a7-9d0f8eb0edbb_265x348.jpeg" width="265" height="348" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/39a136a4-7594-45a8-81a7-9d0f8eb0edbb_265x348.jpeg&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:348,&quot;width&quot;:265,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!o9um!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F39a136a4-7594-45a8-81a7-9d0f8eb0edbb_265x348.jpeg 424w, https://substackcdn.com/image/fetch/$s_!o9um!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F39a136a4-7594-45a8-81a7-9d0f8eb0edbb_265x348.jpeg 848w, https://substackcdn.com/image/fetch/$s_!o9um!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F39a136a4-7594-45a8-81a7-9d0f8eb0edbb_265x348.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!o9um!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F39a136a4-7594-45a8-81a7-9d0f8eb0edbb_265x348.jpeg 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>You are already familiar with Scrum, Kanban, etc. Now you can learn how to take the scalpel to them to get your team&#8217;s or organization&#8217;s productivity to the next level. <a href="https://www.amazon.com/Lean-Software-Development-Agile-Toolkit/dp/0321150783">Lean Software Development</a> by Mary and Tom Poppendieck explains how to deliver software that solves the right problems, and how to do it efficiently while maintaining quality.</p><p>The key concepts that stayed with me were:</p><ul><li><p><strong>Eliminating waste:</strong> questioning the value of all activities, and eliminating any that do not contribute to better or faster delivery. The book also highlights more subtle sources of waste, such as handoffs, or code sitting in a repository waiting for deployment. Avoiding handoffs (which can add weeks or months to delivery) was high on my mind when I started advocating for teams going into each others&#8217; codebases instead of placing work items on each others&#8217; backlogs.</p></li><li><p><strong>Delaying commitment</strong> until you really need to commit. In particular, for me this translated into avoiding having meetings to make decisions when there is zero chance of these decisions being implemented in the near future. Too often, either (1) the reality changes and the decision is no longer relevant, or (2) different people end up implementing the decision, and, since they have their own opinion, they start the decision-making process from the beginning again.</p></li><li><p><strong>Keeping the feedback cycles short</strong>. On the shortest scales, I could clearly see the improvement when we started using continuous deployments, and the business analysts could give feedback to the developers within minutes of the developers committing their partially completed changes. On larger scales, I&#8217;ve benefited several times from rolling out a partially completed feature to figure out how to develop that feature further.</p></li></ul><h2>Continuous Delivery</h2><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!oNJQ!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff273661c-7f88-4706-83bf-313b100a45d2_263x339.jpeg" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!oNJQ!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff273661c-7f88-4706-83bf-313b100a45d2_263x339.jpeg 424w, https://substackcdn.com/image/fetch/$s_!oNJQ!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff273661c-7f88-4706-83bf-313b100a45d2_263x339.jpeg 848w, https://substackcdn.com/image/fetch/$s_!oNJQ!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff273661c-7f88-4706-83bf-313b100a45d2_263x339.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!oNJQ!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff273661c-7f88-4706-83bf-313b100a45d2_263x339.jpeg 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!oNJQ!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff273661c-7f88-4706-83bf-313b100a45d2_263x339.jpeg" width="263" height="339" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/f273661c-7f88-4706-83bf-313b100a45d2_263x339.jpeg&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:339,&quot;width&quot;:263,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!oNJQ!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff273661c-7f88-4706-83bf-313b100a45d2_263x339.jpeg 424w, https://substackcdn.com/image/fetch/$s_!oNJQ!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff273661c-7f88-4706-83bf-313b100a45d2_263x339.jpeg 848w, https://substackcdn.com/image/fetch/$s_!oNJQ!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff273661c-7f88-4706-83bf-313b100a45d2_263x339.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!oNJQ!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff273661c-7f88-4706-83bf-313b100a45d2_263x339.jpeg 1456w" sizes="100vw"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>Written by Jex Humble and David Farley, <a href="https://www.amazon.com/Continuous-Delivery-Deployment-Automation-Addison-Wesley/dp/0321601912/">Continuous Delivery</a> is the technical counterpart to <em>Lean Software Development</em> above. It lays out specific techniques and practices that help improve delivery and lays out some arguments and case studies for why it&#8217;s a good idea to do so.</p><p>If you&#8217;re working for a company with modern development practices, most of this book should not be a surprise. Some suggestions may be controversial, like encouraging all developers to work on one central branch. If you find yourself shaking your head in disagreement, I suggest avoiding the knee-jerk reaction of slamming the book shut and instead reading to see where the authors are coming from, because they usually have solid reasoning.</p><h2>The Leadership Pipeline</h2><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!O3zT!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F616a42d9-0351-4eee-be35-c70a18f65ea8_236x346.jpeg" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!O3zT!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F616a42d9-0351-4eee-be35-c70a18f65ea8_236x346.jpeg 424w, https://substackcdn.com/image/fetch/$s_!O3zT!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F616a42d9-0351-4eee-be35-c70a18f65ea8_236x346.jpeg 848w, https://substackcdn.com/image/fetch/$s_!O3zT!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F616a42d9-0351-4eee-be35-c70a18f65ea8_236x346.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!O3zT!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F616a42d9-0351-4eee-be35-c70a18f65ea8_236x346.jpeg 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!O3zT!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F616a42d9-0351-4eee-be35-c70a18f65ea8_236x346.jpeg" width="236" height="346" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/616a42d9-0351-4eee-be35-c70a18f65ea8_236x346.jpeg&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:346,&quot;width&quot;:236,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!O3zT!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F616a42d9-0351-4eee-be35-c70a18f65ea8_236x346.jpeg 424w, https://substackcdn.com/image/fetch/$s_!O3zT!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F616a42d9-0351-4eee-be35-c70a18f65ea8_236x346.jpeg 848w, https://substackcdn.com/image/fetch/$s_!O3zT!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F616a42d9-0351-4eee-be35-c70a18f65ea8_236x346.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!O3zT!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F616a42d9-0351-4eee-be35-c70a18f65ea8_236x346.jpeg 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p><a href="https://www.amazon.com/Leadership-Pipeline-Powered-Company-non-Franchise-ebook/dp/B004BA5776/">The Leadership Pipeline</a> by Ram Charan is a simple explainer of what the expectations are from people at different levels in a corporate hierarchy, from an individual contributor to the CEO, with focus on internally building leaders who can move through these levels.</p><p>The book is focused on a hierarchical structure in a large enterprise, but is still relevant in smaller or flatter organizations, with some adjustments. For example, a manager ultimately responsible for work of several teams would ideally be making sure that (1) there is the right set of teams, (2) they have the right key individuals, and (3) that the teams are succeeding, generally by setting expectations, providing support/resources, and holding the teams or the key people accountable. But normally such manager should not be giving direct instructions to the team members or deciding the work at the team level.</p><p>One of the directly actionable takeaways for me (and a lesson after I left the first team where I was a tech lead) was always to be preparing someone to replace me.</p><h2>The First 90 Days</h2><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!ef5B!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F62e4dd8f-a944-42c1-941f-841dac205506_229x346.jpeg" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!ef5B!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F62e4dd8f-a944-42c1-941f-841dac205506_229x346.jpeg 424w, https://substackcdn.com/image/fetch/$s_!ef5B!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F62e4dd8f-a944-42c1-941f-841dac205506_229x346.jpeg 848w, https://substackcdn.com/image/fetch/$s_!ef5B!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F62e4dd8f-a944-42c1-941f-841dac205506_229x346.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!ef5B!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F62e4dd8f-a944-42c1-941f-841dac205506_229x346.jpeg 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!ef5B!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F62e4dd8f-a944-42c1-941f-841dac205506_229x346.jpeg" width="229" height="346" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/62e4dd8f-a944-42c1-941f-841dac205506_229x346.jpeg&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:346,&quot;width&quot;:229,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!ef5B!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F62e4dd8f-a944-42c1-941f-841dac205506_229x346.jpeg 424w, https://substackcdn.com/image/fetch/$s_!ef5B!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F62e4dd8f-a944-42c1-941f-841dac205506_229x346.jpeg 848w, https://substackcdn.com/image/fetch/$s_!ef5B!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F62e4dd8f-a944-42c1-941f-841dac205506_229x346.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!ef5B!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F62e4dd8f-a944-42c1-941f-841dac205506_229x346.jpeg 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>The premise of <a href="https://www.amazon.com/First-Days-Updated-Expanded-Strategies-ebook/dp/B00B6U63ZE/">the book</a> is: &#8220;the President of the United States gets 100 days to prove himself; you get 90&#8221; when you get a new role. That may be a bit over-dramatic, but the book does present a good set of strategies that can help get started in a new position, whether at the same company or a different one.</p><p>What I liked more about it, however, was the emphasis on human interactions to get things done in an organization:</p><ul><li><p>Ensuring that you understand the lay of the land in your organization, what motivates your peers/superiors/reports.</p></li><li><p>Building the right team, and making sure that the team has bought into what you&#8217;re trying to do.</p></li><li><p>Setting the right expectations with the superiors.</p></li></ul><p>These are useful even if you have not moved into a new role anytime recently. Come to think of it, I probably should pay more attention to these than I do now.</p><h2>Death by Meeting</h2><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!rA_x!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F23014caa-d386-4e1a-8b5f-766ea21de5fc_229x346.jpeg" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!rA_x!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F23014caa-d386-4e1a-8b5f-766ea21de5fc_229x346.jpeg 424w, https://substackcdn.com/image/fetch/$s_!rA_x!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F23014caa-d386-4e1a-8b5f-766ea21de5fc_229x346.jpeg 848w, https://substackcdn.com/image/fetch/$s_!rA_x!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F23014caa-d386-4e1a-8b5f-766ea21de5fc_229x346.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!rA_x!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F23014caa-d386-4e1a-8b5f-766ea21de5fc_229x346.jpeg 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!rA_x!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F23014caa-d386-4e1a-8b5f-766ea21de5fc_229x346.jpeg" width="229" height="346" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/23014caa-d386-4e1a-8b5f-766ea21de5fc_229x346.jpeg&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:346,&quot;width&quot;:229,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!rA_x!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F23014caa-d386-4e1a-8b5f-766ea21de5fc_229x346.jpeg 424w, https://substackcdn.com/image/fetch/$s_!rA_x!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F23014caa-d386-4e1a-8b5f-766ea21de5fc_229x346.jpeg 848w, https://substackcdn.com/image/fetch/$s_!rA_x!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F23014caa-d386-4e1a-8b5f-766ea21de5fc_229x346.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!rA_x!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F23014caa-d386-4e1a-8b5f-766ea21de5fc_229x346.jpeg 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>There are two books from Patrick M. Lencioni on this list, each one deserving its own mention.</p><p>Once you get past the tacky case study that comprises the majority of <em><a href="https://www.amazon.com/Death-Meeting-Leadership-Business-Lencioni-ebook/dp/B008L03W7O/">Death by Meeting</a></em>, the general gist is this:</p><ul><li><p>Most meetings are done wrong. They&#8217;re boring, unproductive, and often don&#8217;t get to the real matter.</p></li><li><p>This can be fixed by structuring the meetings right, and ensuring that in-depth, candid discussions occur before making a decision.</p></li></ul><p>The suggested meeting structure is:</p><ol><li><p>Daily status updates. Should be quick. Basically, the daily scrum.</p></li><li><p>Weekly tactical: about 1 hour long. Should have a <em>short</em> status update, plus in-depth discussion on 1-2 topics selected on the spot.</p></li><li><p>Monthly strategic (or ad-hoc): 2-4 hours. Discuss, decide on the 1-2 top critical issues. Should do some homework in advance.</p></li><li><p>Quarterly off-site: 1-2 days. Focus on the overall strategy, general trends, organizational design, etc.</p></li></ol><h2>Sales EQ</h2><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!l9gc!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa8999882-cbbf-42db-b552-db87eb53dfc5_235x353.jpeg" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!l9gc!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa8999882-cbbf-42db-b552-db87eb53dfc5_235x353.jpeg 424w, https://substackcdn.com/image/fetch/$s_!l9gc!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa8999882-cbbf-42db-b552-db87eb53dfc5_235x353.jpeg 848w, https://substackcdn.com/image/fetch/$s_!l9gc!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa8999882-cbbf-42db-b552-db87eb53dfc5_235x353.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!l9gc!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa8999882-cbbf-42db-b552-db87eb53dfc5_235x353.jpeg 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!l9gc!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa8999882-cbbf-42db-b552-db87eb53dfc5_235x353.jpeg" width="235" height="353" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/a8999882-cbbf-42db-b552-db87eb53dfc5_235x353.jpeg&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:353,&quot;width&quot;:235,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!l9gc!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa8999882-cbbf-42db-b552-db87eb53dfc5_235x353.jpeg 424w, https://substackcdn.com/image/fetch/$s_!l9gc!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa8999882-cbbf-42db-b552-db87eb53dfc5_235x353.jpeg 848w, https://substackcdn.com/image/fetch/$s_!l9gc!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa8999882-cbbf-42db-b552-db87eb53dfc5_235x353.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!l9gc!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa8999882-cbbf-42db-b552-db87eb53dfc5_235x353.jpeg 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>I mentioned the emphasis on human interactions to get things done in an organization, right? If you want to crank that up a notch, it&#8217;s worth reading books on sales. Out of the four that I liked, I picked <a href="https://www.amazon.com/Sales-Performers-Sales-Specific-Emotional-Intelligence/dp/1119312574/">Sales EQ</a> by Jeb Blount because it serves as a good entry point, presents the general principles well, and is not overly focused on a specific aspect of the sales pipeline, like prospecting.</p><p>If I get the general gist of it right &#8212; and I&#8217;m not a salesperson, so I may be wrong &#8212; the three main points to making a large sale (e.g. your idea) are:</p><ul><li><p>Make the people feel like you understand them and can relate to them;</p></li><li><p>Figure out what the people&#8217;s problems are and link those to what you&#8217;re selling, e.g. how your idea will help your boss(es) achieve their strategic goals;</p></li><li><p>Just push through the fear of objections, because they won&#8217;t buy if you don&#8217;t ask.</p></li></ul><p>There are more points in the book, but they&#8217;re a bit more sales-specific, like &#8220;don&#8217;t waste time on people who aren&#8217;t moving forward through the sales pipeline&#8221;.</p><p>Aside from Sales EQ, <a href="https://www.amazon.com/Rainmaking-Conversations-Influence-Persuade-Situation/dp/0470922230/">Rainmaking Conversations</a> and <a href="https://www.amazon.com/SPIN-Selling-Neil-Rackham/dp/0070511136/">SPIN Selling</a> also have elements and techniques that can be useful in a non-sales leadership position.</p><h2>The Five Dysfunctions of a Team</h2><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!cf_p!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe95874b6-e62a-4342-aac2-3958fdd0b11d_264x399.jpeg" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!cf_p!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe95874b6-e62a-4342-aac2-3958fdd0b11d_264x399.jpeg 424w, https://substackcdn.com/image/fetch/$s_!cf_p!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe95874b6-e62a-4342-aac2-3958fdd0b11d_264x399.jpeg 848w, https://substackcdn.com/image/fetch/$s_!cf_p!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe95874b6-e62a-4342-aac2-3958fdd0b11d_264x399.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!cf_p!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe95874b6-e62a-4342-aac2-3958fdd0b11d_264x399.jpeg 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!cf_p!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe95874b6-e62a-4342-aac2-3958fdd0b11d_264x399.jpeg" width="264" height="399" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/e95874b6-e62a-4342-aac2-3958fdd0b11d_264x399.jpeg&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:399,&quot;width&quot;:264,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!cf_p!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe95874b6-e62a-4342-aac2-3958fdd0b11d_264x399.jpeg 424w, https://substackcdn.com/image/fetch/$s_!cf_p!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe95874b6-e62a-4342-aac2-3958fdd0b11d_264x399.jpeg 848w, https://substackcdn.com/image/fetch/$s_!cf_p!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe95874b6-e62a-4342-aac2-3958fdd0b11d_264x399.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!cf_p!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe95874b6-e62a-4342-aac2-3958fdd0b11d_264x399.jpeg 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>The last book on this list, <a href="https://www.amazon.com/Five-Dysfunctions-Team-Leadership-Fable/dp/0787960756/">The Five Dysfunctions of a Team</a>, also by Patrick Lencioni, focuses on making a group of people work well as a team.</p><p>Similar to <em>Death by Meeting</em> above, most of the book is a single large case study (what he calls &#8220;a fable&#8221;). This case study presents a dysfunctional executive team and shows how to make them work together and perform well. The conclusions of the book are similar to Google&#8217;s <a href="https://rework.withgoogle.com/blog/five-keys-to-a-successful-google-team/">five keys to a successful team</a> (which is also a good read if you&#8217;re responsible for team performance), except this book makes it a bit more tangible.</p>]]></content:encoded></item><item><title><![CDATA[How to select an API Gateway for (micro)services]]></title><description><![CDATA[TL;DR: Pick an API gateway that goes best with your tech stack, provided it meets the minimum feature/security/maturity threshold.]]></description><link>https://www.i-kh.net/p/how-to-select-api-gateway</link><guid isPermaLink="false">https://www.i-kh.net/p/how-to-select-api-gateway</guid><dc:creator><![CDATA[Iouri Khramtsov]]></dc:creator><pubDate>Tue, 20 Nov 2018 12:46:00 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!9Fur!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F823df5e7-6445-4cdd-a461-b0e94a76fc59_800x533.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>If you&#8217;re starting to implement the API Gateway pattern, in which a single gateway sits in front of a collection of services and routes the requests to them, you have a whole zoo of solutions to choose from. Just doing a quick search, as of this morning, you can pick:</p><ul><li><p>Gateways as libraries, for example <a href="https://spring.io/projects/spring-cloud-gateway">Spring Cloud Gateway</a> and <a href="https://github.com/Netflix/zuul/wiki/Getting-Started-2.0">Netflix Zuul 2</a> for JVM, <a href="http://threemammals.com/ocelot">Ocelot</a> for .NET;</p></li><li><p>From the cloud providers: <a href="https://docs.aws.amazon.com/elasticloadbalancing/latest/application/tutorial-application-load-balancer-cli.html">AWS Application Load Balancer</a>, <a href="https://aws.amazon.com/api-gateway/">AWS API Gateway</a>, <a href="https://azure.microsoft.com/en-ca/services/application-gateway/">Azure Application Gateway</a>, <a href="https://cloud.google.com/endpoints/">GCP Cloud Endpoints</a>;</p></li><li><p><a href="https://www.envoyproxy.io/">Envoy</a>, either by itself, or as <a href="https://www.getambassador.io/">Ambassador</a> for Kubernetes, or as part of <a href="https://istio.io/">Istio</a>;</p></li><li><p>Platform solutions like Kubernetes <a href="https://github.com/kubernetes/ingress-nginx">Nginx ingress controller</a>.</p></li><li><p>Other open source gateways, like <a href="https://www.krakend.io/">KrakenD</a> or <a href="https://konghq.com/kong-community-edition/">Kong</a> (both of which come in open source and enterprise versions).</p></li><li><p>Other commercial ones <a href="https://pages.infor.com/hcl-cloverleaf-api-gateway-enables-full-lifecycle-management-of-apis-brochure.html">Cloverleaf</a>.</p></li></ul><p>It&#8217;s impossible to give a detailed feature comparison for all of them, but after some experience of selecting and running an API gateway in production, I feel that I&#8217;m at least slightly qualified to give advice on how to pick one.</p><h2>Features - What the gateway needs to do</h2><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!9Fur!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F823df5e7-6445-4cdd-a461-b0e94a76fc59_800x533.jpeg" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!9Fur!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F823df5e7-6445-4cdd-a461-b0e94a76fc59_800x533.jpeg 424w, https://substackcdn.com/image/fetch/$s_!9Fur!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F823df5e7-6445-4cdd-a461-b0e94a76fc59_800x533.jpeg 848w, https://substackcdn.com/image/fetch/$s_!9Fur!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F823df5e7-6445-4cdd-a461-b0e94a76fc59_800x533.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!9Fur!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F823df5e7-6445-4cdd-a461-b0e94a76fc59_800x533.jpeg 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!9Fur!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F823df5e7-6445-4cdd-a461-b0e94a76fc59_800x533.jpeg" width="800" height="533" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/823df5e7-6445-4cdd-a461-b0e94a76fc59_800x533.jpeg&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:533,&quot;width&quot;:800,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;This gateway can route only to physical addresses.&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="This gateway can route only to physical addresses." title="This gateway can route only to physical addresses." srcset="https://substackcdn.com/image/fetch/$s_!9Fur!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F823df5e7-6445-4cdd-a461-b0e94a76fc59_800x533.jpeg 424w, https://substackcdn.com/image/fetch/$s_!9Fur!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F823df5e7-6445-4cdd-a461-b0e94a76fc59_800x533.jpeg 848w, https://substackcdn.com/image/fetch/$s_!9Fur!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F823df5e7-6445-4cdd-a461-b0e94a76fc59_800x533.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!9Fur!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F823df5e7-6445-4cdd-a461-b0e94a76fc59_800x533.jpeg 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">This gateway can route only to physical addresses.</figcaption></figure></div><p>Before picking a gateway, let&#8217;s go over what&#8217;s expected from one.</p><h3>Routing and service discovery</h3><p>Routing is the most basic feature of an API gateway; without it, there is no point of having one. At a minimum, a gateway should be able to route via HTTP other URLs.</p><p>Many gateways also come with some form of service discovery, where back-end services register themselves with a registry, and the gateway gets the list of routable services from that registry. From my experience, unless you maintain hundreds or more distinct services, built-in service discovery is not that helpful because sometimes you may want to keep a service not accessible through the gateway but still discoverable by other services. (This assumes that gateway is only used by users <em>outside</em> your system, like human users or other external callers.) In that case, you&#8217;d want the services to opt into the routing explicitly.</p><p>On top of that, the platform on which you run the services may already have a built-in rough service discovery capability, e.g. DNS on Kubernetes. It&#8217;s also not that hard to roll your own crude &#8220;service discovery&#8221; with DNS naming conventions.</p><h2>Authentication and authorization</h2><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!qoYh!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F28d0554c-a52e-4f72-8212-127882d38d87_800x533.jpeg" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!qoYh!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F28d0554c-a52e-4f72-8212-127882d38d87_800x533.jpeg 424w, https://substackcdn.com/image/fetch/$s_!qoYh!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F28d0554c-a52e-4f72-8212-127882d38d87_800x533.jpeg 848w, https://substackcdn.com/image/fetch/$s_!qoYh!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F28d0554c-a52e-4f72-8212-127882d38d87_800x533.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!qoYh!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F28d0554c-a52e-4f72-8212-127882d38d87_800x533.jpeg 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!qoYh!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F28d0554c-a52e-4f72-8212-127882d38d87_800x533.jpeg" width="800" height="533" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/28d0554c-a52e-4f72-8212-127882d38d87_800x533.jpeg&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:533,&quot;width&quot;:800,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;An API gateway on the lookout for predators.&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="An API gateway on the lookout for predators." title="An API gateway on the lookout for predators." srcset="https://substackcdn.com/image/fetch/$s_!qoYh!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F28d0554c-a52e-4f72-8212-127882d38d87_800x533.jpeg 424w, https://substackcdn.com/image/fetch/$s_!qoYh!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F28d0554c-a52e-4f72-8212-127882d38d87_800x533.jpeg 848w, https://substackcdn.com/image/fetch/$s_!qoYh!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F28d0554c-a52e-4f72-8212-127882d38d87_800x533.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!qoYh!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F28d0554c-a52e-4f72-8212-127882d38d87_800x533.jpeg 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">An API gateway on the lookout for predators.</figcaption></figure></div><p>Whether this is a requirement will depend on your specific authentication and authorization architecture. However, having a gateway that does not support auth in any form will definitely limit your architectural choices. Fortunately, almost all of them support auth in some way; as of writing this, Azure Application Gateway is the only major exception.</p><p>Here, the gateways split into three camps.</p><p><strong>Gateways-as-libraries</strong>, such as Ocelot or Spring Cloud Gateway, can integrate with their respective frameworks &#8212; ASP.NET Core and Spring Framework. This makes it possible to let the gateway fully handle auth using any method supported by the framework (and usually there are a lot of choices) with minimal additional work.</p><p>You will also get the choice of letting the same framework handle user sessions in the gateway, which again can be set up with minimal effort.</p><p>If you choose not to use JWT (<a href="https://jwt.io/introduction/">JSON Web Tokens</a>), you will have to invent your own way of passing the user information from the gateway to the back-end services. This was the choice my team made a couple of years ago due to the capabilities of our OAuth 2 provider that we did not have a say in selecting. Today, I&#8217;d suggest sticking with JWT, which is widely supported. Depending on your web framework, you may also have to come up with a way of having the back-end services extract JWT/other user info and stick it into the service&#8217;s security context.</p><p><strong>Delegating gateways:</strong> some gateways either require or give an option to authorize each request by making a sub-request to an authorization service, which you&#8217;re expected to provide. Kubernetes Nginx ingress controller, Envoy, and AWS API Gateway are in this category. Generally, the gateway would expect a simple pass/fail answer from such service and not anything fancy like a redirect.</p><p>Each of the gateways has their own requirements:</p><ul><li><p>AWS API Gateway can delegate authorization sub-requests <a href="https://docs.aws.amazon.com/apigateway/latest/developerguide/apigateway-control-access-to-api.html">only to an AWS Lambda or to AWS Cognito</a>. That&#8217;s fine if you already have both feet in the AWS serverless world, but not great otherwise.</p></li><li><p>Kubernetes Nginx ingress controller wraps Nginx auth functionality <a href="https://kubernetes.github.io/ingress-nginx/user-guide/nginx-configuration/annotations/#external-authentication">in Kubernetes annotations</a>. In this setup, Nginx makes an HTTP sub-request to a service that&#8217;s <a href="https://docs.nginx.com/nginx/admin-guide/security-controls/configuring-subrequest-authentication/">expected to return 2xx or 401/403</a>.</p></li><li><p>Envoy expects a gRPC or HTTP service that handles a <a href="https://www.envoyproxy.io/docs/envoy/latest/intro/arch_overview/ext_authz_filter">specific request/response schema</a>. It passes the whole request context (location, headers, etc) to the delegated service. Envoy can also verify JWT tokens.</p></li></ul><p>In all of these cases, the gateway&#8217;s primary role is routing, and you&#8217;re expected to bring your own components for authentication, sessions, and propagating user information to the back-end services.</p><p><strong>Standalone gateways with auth</strong> provide opinionated authentication/authorization support, usually limited to JWT (JSON Web Tokens):</p><ul><li><p>KrakenD works <a href="https://www.krakend.io/docs/authorization/jwt-overview/">exclusively with JWT</a>. It can verify, sign, and revoke them, but it cannot issue them. You&#8217;d need to bring your own service that would log in users and issue tokens.</p></li><li><p>Standalone Envoy can also verify JWT tokens, but it cannot handle the revocation.</p></li><li><p>Istio, which comes with a built-in Envoy, <a href="https://cloud.google.com/endpoints/docs/openapi/authentication-method">supports only JWT</a> and has streamlined integrations with several sources. Istio docs don&#8217;t mention support for token revocation. The price of Istio is that you have to install, manage, and use it; Istio includes a lot more than the gateway. This works well if you&#8217;re already planning to use Istio, but is not great otherwise.</p></li><li><p>Kong provides the <a href="https://docs.konghq.com/hub/">most authentication options</a> among the standalone gateways; some of the options are available only in the enterprise version. Kong also provides its own <a href="https://docs.konghq.com/0.14.x/getting-started/adding-consumers/">user repository</a>. The possible downside with Kong is that you&#8217;d have to set up and manage Postgres or Cassandra. This is not a big deal if you already use either of these, but not optimal if your organization has deep expertise in other database types.</p></li><li><p>Google Cloud Endpoints <a href="https://cloud.google.com/endpoints/docs/openapi/authentication-method">supports JWT</a>, and also has streamlined integrations with various sources. But, as with AWS, you&#8217;d need to be on GCP to take advantage of this gateway.</p></li></ul><p><strong>Overall</strong> by now you should start seeing a subtle theme: if you&#8217;re using a gateway that integrates very well with your tech stack, you&#8217;ll be able to set up more features faster, and it will be easier to maintain. Later in this post, I will make it a lot less subtle.</p><h3>Routing to static websites</h3><p>You may be interested in deploying website front-ends as static sites behind the gateway, e.g. in S3 buckets or in containers that have only Nginx and the website files. This has a few benefits:</p><ul><li><p>All API URLs in your front-end code will be in form of <code>"/some/path"</code> instead of <code>envHostname + "/some/path"</code>.</p></li><li><p>The gateway can block unauthorized users from loading a front-end page.</p></li><li><p>Potentially simpler local development experience.</p></li><li><p>Not having to deal with CORS.</p></li></ul><p>If you do that, you&#8217;ll run into an interesting routing conflict. Many front-end frameworks such as <a href="https://reacttraining.com/react-router/web/guides/quick-start">React</a> and <a href="https://vuejs.org/v2/guide/routing.html">Vue</a> have their own routing that rewrites the contents of the browser URL bar to make it look like the user has moved to another page. The new URL might not correspond to a real resource on the back end, and when the user presses Refresh in the browser, your system should be prepared to deal with it.</p><p>For example, if the user presses the refresh button and the browser tries to load <code>/portal/settings/app.bundle.js</code>, your system has to know that it should go to the <code>portal-service</code> and load <code>/app.bundle.js</code> instead of <code>/settings/app.bundle.js</code>.</p><p>You have several options to handle this:</p><ol><li><p>Have the gateway rewrite the URLs before forwarding the request to the static website service. This requires a gateway that can match and rewrite URLs based on a regex prefix. Some gateways can do that (Spring Cloud Gateway, Envoy), while others can&#8217;t (AWS API Gateway). Alternatively, if your gateway supports custom filters, you could write one to deal with this problem.</p></li><li><p>Let the static site service deal with it, by either setting up the appropriate rules in Nginx or wrapping the static site in a framework of your choice (e.g. Spring) and letting it handle the routing issues. The latter option will add slight complications all over the place and will require more compute resources.</p></li><li><p>Don&#8217;t host static sites behind the gateway; instead, put them on a CDN, or somewhere else. You&#8217;ll need to deal with CORS (generally not a big problem), and you may have to control authorization separately.</p></li></ol><h3>Protocols and TLS offloading</h3><p>Generally, all gateways can handle HTTP/1.1 and TLS offloading, and by now majority can handle incoming HTTP/2 connections. It will be surprising if your top gateway choice cannot do these.</p><p>When it comes to protocols, the main differentiators are:</p><ol><li><p>Whether the gateway can handle WebSockets: most can, but some can&#8217;t (AWS API Gateway, Netflix Zuul 1). This may be either critical for you, or completely irrelevant. However, if you pick a gateway that doesn&#8217;t support WebSockets and it turns out that you need them, you will spend a lot of effort on workarounds (that happened to us).</p></li><li><p>Whether the gateway can use HTTP/2 to communicate with the back-end services. For most people, it will not be critical, but you do get better performance with HTTP/2, so it&#8217;s definitely a nice feature to have.</p></li></ol><p>With TLS, your biggest problem will be not whether the gateway can handle it, but how you&#8217;re going to store, distribute, and rotate the certificates securely. Certificate renewal can be painful, especially if you do it infrequently, and I suggest awarding bonus points to gateways that support easy certificate provisioning/rotation.</p><p>For example, Kubernetes Nginx ingress controller can be set up to renew the certificates from Let&#8217;s Encrypt automatically. On AWS, using a certificate from the AWS Certificate Manager is quite painless.</p><p>But on Azure, as of writing this, you cannot just link a certificate from the Key Vault to the Application Gateway.</p><p>Alternatively, you don&#8217;t have to do TLS offloading on the gateway. Instead, you could place another piece of infrastructure in front of the gateway (e.g. AWS Elastic Load Balancer) and have it offload TLS. This is the setup that we went with, and I think we got the best of both worlds: easy TLS certificate management and other features from AWS ELB, and an API gateway that fit our service ecosystem like a glove.</p><h3>Other filters</h3><p>Broadly, filtering is the stuff that the gateway can do between receiving the incoming request and forwarding it to the back-end service, or between receiving and forwarding the response.</p><p>In addition to the features mentioned in previous sections, filters can provide extra protection (rate limiting, header sanitization), fault-tolerance (retries), or other useful features (gzip compression, redirects). I&#8217;d classify these in the same category as heated car seats in Canadian winter: they&#8217;re handy, but if they&#8217;re not present, there are other ways to deal with these problems. That said, depending on your scale and architecture, some of these may turn out to be very useful to have specifically in the gateway, so I suggest thinking about that in advance.</p><h3>Logging and request tracing</h3><p>All gateways have some request logging capability; some can add tracing information to the requests for easier request correlation in the logs, e.g. <a href="https://www.envoyproxy.io/docs/envoy/latest/intro/arch_overview/tracing">tracing in Envoy</a>. Tracing can be very useful when the request might be handled by multiple services, though as with most other filters, there are other solutions for it.</p><p>For me, the main differentiator is the <em>timeliness</em> of the logs. A gateway that logs to stdout or a file can have its logs shipped to a log aggregator like Splunk or SumoLogic in under a second. AWS API Gateway logs can show up in AWS CloudWatch after as much as a minute, and log aggregators often poll the S3 bucket with logs less often than that.</p><p>This difference may not seem like much, but which one would you rather have when you&#8217;re trying to troubleshoot a live issue?</p><h2>Developer friendliness</h2><p>Once you have a gateway, someone will have to feed it and take it out for walks. Let&#8217;s think through that ahead of time.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!kG8C!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3416cdb1-c794-4a0a-a243-694173362859_800x533.jpeg" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!kG8C!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3416cdb1-c794-4a0a-a243-694173362859_800x533.jpeg 424w, https://substackcdn.com/image/fetch/$s_!kG8C!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3416cdb1-c794-4a0a-a243-694173362859_800x533.jpeg 848w, https://substackcdn.com/image/fetch/$s_!kG8C!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3416cdb1-c794-4a0a-a243-694173362859_800x533.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!kG8C!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3416cdb1-c794-4a0a-a243-694173362859_800x533.jpeg 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!kG8C!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3416cdb1-c794-4a0a-a243-694173362859_800x533.jpeg" width="800" height="533" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/3416cdb1-c794-4a0a-a243-694173362859_800x533.jpeg&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:533,&quot;width&quot;:800,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;He may be cute, but he's a lot more work than you expect.&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="He may be cute, but he's a lot more work than you expect." title="He may be cute, but he's a lot more work than you expect." srcset="https://substackcdn.com/image/fetch/$s_!kG8C!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3416cdb1-c794-4a0a-a243-694173362859_800x533.jpeg 424w, https://substackcdn.com/image/fetch/$s_!kG8C!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3416cdb1-c794-4a0a-a243-694173362859_800x533.jpeg 848w, https://substackcdn.com/image/fetch/$s_!kG8C!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3416cdb1-c794-4a0a-a243-694173362859_800x533.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!kG8C!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3416cdb1-c794-4a0a-a243-694173362859_800x533.jpeg 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">He may be cute, but he's a lot more work than you expect.</figcaption></figure></div><h3>Organizational fit</h3><p>Let&#8217;s imagine you just got a gateway. Now, someone will have to:</p><ul><li><p>Deploy and manage it.</p></li><li><p>Deploy and maintain the configuration, including the routes.</p></li><li><p>Handle unforeseen problems and requirements.</p></li><li><p>Run multiple environments (production, test environments, local development environments).</p></li><li><p>Promote the configuration changes between the environments.</p></li><li><p>Upgrade and apply security patches for the gateway, the host server, and, if you&#8217;re using one, the container.</p></li><li><p>Have a disaster recovery plan in case everything goes wrong.</p></li></ul><p>All of this has to be done efficiently, and while keeping production errors to a minimum.</p><p>Also, consider how the gateway will fit into your organization. If the gateway is entirely different from the rest of your service ecosystem, and if the process to configure it is complicated, you will end up with one or a handful of people who will be &#8220;gateway people&#8221;, and every time the gateway will need to be touched, one of them will have to be involved.</p><p>This can lead to more handoffs, slower deliveries, avoiding the gateway (or worse, working around it), and key-person risk.</p><p>If configuring the gateway is easy, and if the gateway looks and feels like just another service in your system, then any experienced developer will be able to work on it.</p><p>For this reason, I recommend the following:</p><ol><li><p>Pick a gateway that most of your developers will be comfortable with.</p></li><li><p>Take an infrastructure-as-code approach to the gateway deployment and configuration, keeping the configuration in source control and deploying both the gateway and the configuration automatically.</p></li><li><p>Make it easy to set up and manage the routes.</p></li><li><p>Pick a gateway that&#8217;s easy to patch and upgrade; ideally, one that is distributed through a repository like Docker Hub, npm, or Maven.</p></li></ol><h3>Managing the routes</h3><p>Broadly, there are ways to make the route configuration easy to maintain:</p><ol><li><p>Keep the all route configuration in a central repository and deploy it automatically, or</p></li><li><p>Whenever a new service is created, update the route on the gateway, either through a REST call or through service discovery.</p></li></ol><p>At this point, every gateway supports one or the other or both. But whatever the approach, keep in mind that you may want to occasionally repoint the route from one service to another without changing the service names, or have a route pointed to something outside your service ecosystem.</p><p>At HOOPP, we&#8217;ve set up the route configuration in our regular configuration git repository, along with the rest of the gateway config. Any developer can submit a pull request with a change, and many have. The pull request has to pass a CI build that lints the config files, and be approved by someone on the Core Platform team (usually happens within 5-60 min). Then the config is automatically applied to test environments, and, if those start up successfully, to production. The gateway configuration is updated maybe every couple weeks; aside from a few initial hiccups, it did not cause any production issues. But if an issue does happen, git has the full revision history, and any change is easy to revert.</p><p>This is not the only way to do it, and probably not the best, but it was easy to set up and results in the least amount of work for everyone involved.</p><h3>Local development experience</h3><p>Something that&#8217;s easily overlooked: if you&#8217;d like the local development environment to resemble production as closely as possible, then you&#8217;d need to find a way to run the gateway on the developers&#8217; workstations, including providing a route map that&#8217;s appropriate for local development, i.e. one that points to <code>localhost</code> routes.</p><p>At HOOPP, we found that some developers hated the idea of running the gateway locally, and some thought it was essential. You may need to accommodate both, but if you have to pick, I&#8217;d pick the run-the-gateway-locally side, and make the local startup and config management as fast and as painless as possible.</p><p>Gateways-as-libraries have an unfair advantage here. Since you already know how to start and manage configuration for your other services, and gateway-as-library is just another service, you will have an inherent head start when working with them.</p><h3>Other considerations</h3><p>There are other criteria when picking a gateway, but most of them tend not to be big differentiators for the major gateway solutions:</p><ul><li><p>Documentation: is it thin on information, or is it extensive and detailed?</p></li><li><p>Answer availability: is it easy to search for answers on StackOverflow, Google, Github, or the vendor&#8217;s forum?</p></li><li><p>Maturity: more mature products tend to be more secure and more battle-tested.</p></li><li><p>Adoption: is it popular? Winners typically attract more resources for improvements, documentation, security patches, plugins, etc.</p></li><li><p>Security: what&#8217;s the vendor&#8217;s security posture? Have they had security audits, is there a bug bounty program, etc? If you&#8217;re not sure how to evaluate that, I suggest involving someone with information security expertise.</p></li></ul><h2>Making the choice</h2><p>Unless you&#8217;re prepared to have a team dedicated to the gateway, you&#8217;re almost certainly better off picking one that (1) is easy for <em>you</em> to automate and integrate into your systems, and that (2) <em>your</em> developers can support with minimal additional training.</p><p>Once you apply all the constraints from the preceding 2,800 words of the post, you will find that gateway-as-library in your organization&#8217;s language of choice is likely the front-runner, provided that it exists and satisfies the requirements in this post.</p><p>In the absence of that, the top choice would be the gateway that can be easily deployed on your existing infrastructure, like KrakenD or Envoy on a container-based infrastructure. This usually gives enough options that you don&#8217;t have to venture farther afield to pick another gateway.</p>]]></content:encoded></item><item><title><![CDATA[Leveling up the team's communication habits]]></title><description><![CDATA[After working with various teams over the past years, I&#8217;ve noticed that a specific group of communication habits significantly help speed up the delivery.]]></description><link>https://www.i-kh.net/p/leveling-up-the-teams-communication-habits</link><guid isPermaLink="false">https://www.i-kh.net/p/leveling-up-the-teams-communication-habits</guid><dc:creator><![CDATA[Iouri Khramtsov]]></dc:creator><pubDate>Fri, 24 Aug 2018 21:45:00 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!V9Qv!,w_256,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F64d2997e-d235-41e8-8ece-611b5f6c9f21_512x512.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>After working with various teams over the past years, I&#8217;ve noticed that a specific group of communication habits significantly help speed up the delivery. When the team members practice these, the delivery flows smoothly; otherwise, there are lags and misunderstandings along the way, and the <a href="https://www.scrum.org/resources/blog/limiting-work-progress-wip-scrum-kanban-what-when-who-how">work in progress</a> builds up. This post presents only three of these habits; the overall framework is still only partly formed, and I&#8217;d like to have more discussions and testing before putting together something more concrete.</p><p>The fundamental idea underpinning these habits is that the development team is doing well when it is delivering the right, high quality features quickly, with an emphasis being on the quick turnaround time for each feature, i.e. the <a href="https://age-of-product.com/agile-metrics-good-bad-ugly/">cycle time</a>. To do that, all team members need to be on the same page, and the development process for each feature should be moving along with minimum lag or rework. Basically, the development should be <a href="https://www.amazon.com/Lean-Software-Development-Agile-Toolkit/dp/0321150783/">lean</a>.</p><p>The corollary of this is that the team members need to:</p><ul><li><p>Be able to work together, possibly in the same complex codebase, with a large subset of the team working on the same feature until it&#8217;s done and then smoothly moving on to the next one;</p></li><li><p>Continuously keep each other up-to-date on major developments;</p></li><li><p>Smoothly hand over the work to the next person as it becomes ready, e.g. hand over the requirements to developers, hand over built features to QA or product owner for testing, etc.;</p></li><li><p>Proactively unblock themselves if unforeseen blockages occur, such as a need to consult someone or get an external dependency moving.</p></li></ul><p>To do that well, the team needs technology, architecture, and development practices that support rapid, quality development; good planning and product management practices; and, of course, great communication.</p><p>To build great communication, I found it useful to help the team members develop these specific communication habits.</p><h2>1. Communicate continuously</h2><p>Here, &#8220;continuously&#8221; being in the sense of &#8220;<a href="https://martinfowler.com/articles/continuousIntegration.html">continuous integration</a>&#8220;, not &#8220;constant, non-stop communication&#8221;; constant communication is undesirable because then no work gets done. Instead, continous communication, like continuous integration, should happen as soon as it needs to happen, not on a set schedule or at the end of some task. This practice is best illustrated by an example.</p><h3>Meet the team</h3><p>Let&#8217;s say three developers, Sam, Mandy, and Ali, are working on the same codebase and they&#8217;ve agreed on the technical design. Sam starts writing the code, but as he works, he keeps noticing imperfections in the design and gradually adjusts the code to account for those. Next day, when the time comes to integrate the code with Mary and Ali, it turns out that Sam&#8217;s code has substantially deviated from the original design, and the other two have to do a significant amount of rework.</p><p>Sam could have avoided this by letting his teammates know that he found a problem with the design and offering a correction. Mandy and Ali could have reviewed the correction and suggested improvements. Thus, for the cost of a quick interruption, Sam could have ensured that the team delivered faster and better.</p><p>Similarly, Mandy doesn&#8217;t need to dot every &#8220;i&#8221; in the code before handing the feature to the product owner for testing or showing the code to the other developers for a code review. Instead, she could start showing partially ready work, so that her colleagues could sooner discover any issues with the code, the requirements, or the design.</p><h3>Building the habit</h3><p>This continuous communication does not naturally occur to everyone, especially if they have worked in environments that do not encourage it. There are several mechanisms to make it happen:</p><ul><li><p>Suggest it to the team; some team members will likely agree and will start doing it.</p></li><li><p>A technical lead managing junior developers could just decree it.</p></li><li><p>In a team with more experienced members, it will likely be necessary for the team to meet, discuss, and agree that this is expected.</p></li><li><p>With new hires, I have set the expectation of continuous communication in the interviews and during the onboarding.</p></li></ul><p>In either case, it is worth emphasizing that the regular communication is not for the scrum master, the manager, or the product owner to check on the work, but for the team to keep the work flowing and to discover surprises as early as possible.</p><p>Whatever the method, it&#8217;s essential to keep the team members accountable to this standard. In the case of Sam above, if he is new to this habit, someone could casually ask him whether he needs to update Ali or Mandy on anything. If Sam shows a persistent pattern of not updating his teammates, this may warrant a 1-on-1 discussion with a warning that his actions are affecting the team.</p><h2>2. Shared communication channels over 1-on-1 communication</h2><p>The purpose of shared communication channels is to make the communication scale efficiently.</p><p>Discussing something one central place is more efficient than discussing it one-on-one and updating each teammate later. If Ali sends a pull request approval privately to Sam, then Mary will not know about it. She may not be needed to review the pull request, and may not even be interested in it now, but by posting the request in a shared chat channel, Ali would give her an opportunity to be aware that it is happening without doing any extra work.</p><p>Shared communication channels could take many forms, all of them with the purpose of making the communication scale:</p><ul><li><p>Scheduled meetings to review or discuss something;</p></li><li><p>Chat channels, group email, and mailing lists;</p></li><li><p>Ad-hoc conversations;</p></li><li><p>Shared task boards, task lists;</p></li><li><p>Wiki, or other documentation;</p></li><li><p>Whiteboard with a design on it and a big &#8220;do not erase&#8221; sign.</p></li></ul><p>Whatever the channel, I find the focus on the efficiency is critical; otherwise the team could get bogged down with needless meetings. Not everyone needs to show up to talk with an external vendor for two hours; instead, one or two people could go, and then update everyone in a 5-minute meeting, or, better yet, by email.</p><p>Similarly, I&#8217;ve given up on multi-hour planning on the first day of a sprint because most topics are not interesting to half of the people present, and detailed plans for work later in the sprint tend to change anyway. Instead, by combining the principles of efficient and continuous communication, we could shorten the sprint planning meeting to a 15-minute overview of upcoming features, and do the detailed design and planning as the team gets close to starting the work on the next item.</p><p>Well-organized written communication, such as documentation, or diagrams, tends to scale well but has a higher upfront cost. Chat channels and email tend to scale moderately. Meetings tend to drop in efficiency as more people join them, so it&#8217;s important to keep them focused and require presence only of those people who need to be there. Ad-hoc, one-on-one or group communication scales the worst but is best for resolving blocking questions.</p><h3>Building the habit</h3><p>The two parts to building this habit are figuring out the right communication channels and developing the habit of using them.</p><p>If the team does not meet regularly to discuss and decide something, Agile frameworks such as Scrum provide a good start, with meetings like planning, daily scrum, and retrospectives. These build the habit of regularly meeting together for a specific purpose. Over time, however, the team would benefit from reorganizing meetings, reducing some and adding others, like group code reviews or requirements reviews.</p><p>With written communication channels, I&#8217;ve gotten excellent returns from having a Wiki and a group chat like Slack.</p><p>The other side of this habit is redirecting the communication to the shared channels as much as possible. In my experience, repeated suggestions usually get the team most of the way there. For example, if a developer would ask me to review a piece of code, I&#8217;d suggest doing this with a substantial subset of the team instead. Or when someone sends a request for another team to do something, I&#8217;d ask to CC the rest of our team. Repeating the message of the importance of using the shared channels in the retrospectives also tends to help.</p><h2>3. Proactive resolution of blockers</h2><p>Extending the idea of not waiting to communicate, this habit has the team members act immediately when they find an unforeseen blockage.</p><p>For example, suppose a business analyst Fiona is almost done preparing the requirements when she realizes that she still doesn&#8217;t know what the source for a specific field should be. She could wait until the next scheduled meeting with the client, Bill, to find out, but that could mean delaying the implementation. Instead, ideally she would either call Bill right away or walk over to his desk to clarify this. Failing that, she would preferably email, or leave a voicemail, and only then fall back to the scheduled meetings.</p><p>Like with any interaction, this depends on whether Bill is receptive to unexpected calls. If they are infrequent and help resolve blockages, he probably will be. In fact, he may be glad that Fiona asked the right question that helped deliver a better product.</p><p>Similarly, if Ali (the developer) is troubleshooting a complicated bug and needs to involve another team, he should first try to walk over or call them right away and ask them to help, instead of sending an email and waiting a couple of days for a response.</p><p>Since ad-hoc, one-on-one communication scales the worst, this should be generally reserved for unforeseen blockages or urgent situations that were not identified during the planning.</p><p>This habit also helps in larger organizations where requests sometimes tend to fall between the cracks or get stalled at the bottom of someone&#8217;s to-do list. A polite in-person or phone question about the delivery timeline sometimes gets the request moving surprisingly quickly.</p><h3>Building the habit</h3><p>This habit requires the team members to overcome the anxiety of interrupting or inconveniencing someone. Unfortunately, the only way to become more comfortable with interrupting others is to do it enough times. Here, a more experienced team member could help someone new to this habit by setting an example or taking them along to talk to someone who did not expect them.</p><p>I usually introduce this to the new team members as soon as possible by taking them with me to talk to someone the first time they need something. With existing team members, often just a suggestion is enough (&#8220;Why don&#8217;t we ask her now?&#8221;), with an offer to come along if necessary.</p>]]></content:encoded></item><item><title><![CDATA[Why your service needs a client library]]></title><description><![CDATA[Specifically, I&#8217;m talking about the case of a back-end service that supports other back-end services within a single enterprise, e.g.]]></description><link>https://www.i-kh.net/p/why-your-service-needs-client-lib</link><guid isPermaLink="false">https://www.i-kh.net/p/why-your-service-needs-client-lib</guid><dc:creator><![CDATA[Iouri Khramtsov]]></dc:creator><pubDate>Thu, 19 Jul 2018 18:12:00 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!V9Qv!,w_256,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F64d2997e-d235-41e8-8ece-611b5f6c9f21_512x512.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Specifically, I&#8217;m talking about the case of a back-end service that supports other back-end services within a single enterprise, e.g. in a microservice setup. To be fair, we can still get away with just exposing an HTTP endpoint or a queue where the client directly submits the message, but we can go a step further and make everyone&#8217;s life easier by providing a client library alongside the service.</p><p>With a well-designed client library, the service consumer gets:</p><ul><li><p>Less typing on the keyboard,</p></li><li><p>Compile-time error checks instead of run-time checks,</p></li><li><p>Easier mocking and unit testing,</p></li><li><p>Hinting and autocomplete when using an IDE,</p></li></ul><p>And in general all the good things that lead to reduced time to delivery on features and bug fixes.</p><p>These benefits are offset by the cost of writing and maintaining a client library, so it may not make sense to do so when the consumer should be allowed to use any language they want, e.g. in case of external-facing APIs. Or when there&#8217;s only one consumer for the client library, like a combination of tightly coupled back-end and front-end in a simple application.</p><p>Fortunately, there are often tools to make it easy to write and maintain client libraries.</p><h2>A simple example</h2><p>Let&#8217;s suppose we&#8217;re writing a service that maintains the list of users. If the service consumer wants to add another user, they submit a POST request like this:</p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;javascript&quot;,&quot;nodeId&quot;:&quot;0462098e-5102-4e7f-85e2-6aba4c4e4d63&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-javascript">{
    &#8220;name&#8221;: &#8220;Bob Li&#8221;,
    &#8220;email&#8221;: &#8220;bli@somewhere.com&#8221;
    // More details
}</code></pre></div><p>It returns <code>200 OK</code> if everything went fine; otherwise, it returns a <code>4xx</code>/<code>5xx</code> error code with a message in the body.</p><p>This will work fine and will do its job. The first consumer of the service will probably write their own copy of the model and will use a convert it to JSON with a simple one-liner that is available in their language of choice. They may add a wrapper for mocking the service in the unit tests as well. The second consumer will probably do the same but in a separate piece of code, different from the first one. And so will the third.</p><p>There is, of course, a chance that they will all get together and decide to do this in a central, shared library that will have message models, call signatures, and some convenience functionality like retries or logging. This assumes that the service consumers are all aware of each others&#8217; actions, have the time and willingness to get together to do this, and that the company culture supports taking time out of writing features to do foundational work. From my observations, unless there&#8217;s planning in advance, the odds of this shared library emerging aren&#8217;t high.</p><h2>Writing a client library</h2><p>In the above case, the advance planning would be writing the client library and making it available to the consumers of the service. This doesn&#8217;t have to be a lot of work. For the same user service, the library would include <code>AddUserMessage</code> type, possibly a return type, and a piece of code that wraps the process of making the HTTP call and handling the response.</p><p>For example, in Spring framework with <a href="https://kotlinlang.org/docs/reference/server-overview.html">Kotlin</a>, we could write the client library using <a href="https://cloud.spring.io/spring-cloud-netflix/multi/multi_spring-cloud-feign.html">Feign</a> like this:</p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;kotlin&quot;,&quot;nodeId&quot;:&quot;3af8927b-b0fe-4108-ae39-2a192e456502&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-kotlin">class AddUserMessage(val name: String, val email: String)

// This will be auto-implemented by Feign
@FeignClient(&#8221;&lt;url&gt;&#8221;)
interface UserService {
    // Throws exception on failure
    @PostMapping()
    fun addUser(user: AddUserMessage)  
}</code></pre></div><p>This is a basic blocking implementation and could use some improvement, but the service consumers already get: compile-time error checking, easy mocking for unit tests, and the IDE will help autocomplete the function and class names.</p><p>In cases of communicating over a queue, the client library would hide implementation details for the queue call, allowing the caller to think just about the call to the service and not worry about the underlying details. In case of async calls or long-running requests, the library could also provide correlation between the requests and responses, handling de-duplication, or managing other complexities. The client library could also manage retries, extracting meaningful error details, and emit progress notifications.</p><h2>Automating client library generation</h2><p>On a larger scale, there are some interesting examples of client libraries being generated automatically. For example, <a href="https://twitter.com/mbryzek?lang=en">Michael Bryzek</a> showed how Flow.io maintains a large number of microservices by <a href="https://www.infoq.com/news/2018/07/bryzek-microservice-architecture">generating client libraries from JSON declarations</a>. The same generation system produces mock clients for testing; these mock clients have, according to Michael, mostly removed the need for integration testing.</p><p>In another example, <a href="https://aws.amazon.com/tools/">AWS SDKs</a> have all the signs of being automatically generated. Given Amazon&#8217;s other internal automation, it sounds unlikely that they chose instead to use an army of engineers to type out the highly repetitive implementation code.</p><p>Taking the idea to the next step, if the service consumer only uses the client library, then they do not need to be aware of the underlying protocol. Then we can switch from HTTP and REST to something like <a href="https://grpc.io/">grpc</a> and <a href="https://developers.google.com/protocol-buffers/">Protocol Buffers</a>, and use the same declaration to generate multiple client libraries for several languages. At this point, unlike AWS above, we lose the option of supporting an arbitrary client language through an HTTP endpoint.</p><p>Taking this another step further, client libraries don&#8217;t even need to be just for services in the &#8220;microservice&#8221; sense. For example, an internal data warehouse could be considered a service. To improve cycle time for the whole company, the team maintaining the data warehouse could publish a shared library that provides type definitions and mappings (auto-generated from the database schema) that correspond to the underlying tables and views which it allows querying. Over time, the library could be enriched with change notification updates, transparent calls to cache instead of the database, query limits, and other restrictions that otherwise would have to be communicated to the developers.</p>]]></content:encoded></item></channel></rss>