<?xml version="1.0" encoding="UTF-8"?>
<feed xmlns="http://www.w3.org/2005/Atom" xmlns:sy="http://purl.org/rss/1.0/modules/syndication/" xmlns:media="http://search.yahoo.com/mrss/" xml:lang="en">
  <id>http://sedimental.org/</id>
  <title type="text">Sedimental</title>
  <subtitle type="text">Accretionary thoughts by Mahmoud Hashemi</subtitle>
  <link rel="alternate" type="text/html" href="http://sedimental.org/" />
  <link rel="self" type="application/atom+xml" href="http://sedimental.org/atom.xml" />
  <updated>2024-01-26T22:27:45Z</updated>
  <sy:updatePeriod>hourly</sy:updatePeriod>
  <sy:updateFrequency>1</sy:updateFrequency>

  <rights type="html">&amp;copy; 2023 &lt;a href=&quot;http://sedimental.org/about.html&quot;&gt;Mahmoud Hashemi&lt;/a&gt; &lt;img height=&quot;14&quot; src=&quot;/img/by-sa.png&quot; /&gt;</rights>
  <generator uri="https://github.com/mahmoud/chert">Chert 0.1</generator>
  
  <entry>
    <id>http://sedimental.org/cruising_through_data.html</id>
    <author>
      <name>Mahmoud Hashemi</name>
      <uri>http://sedimental.org/</uri>
    </author>
    <title>Cruising through complex data</title>
    <link rel="alternate" type="text/html" href="http://sedimental.org/cruising_through_data.html" />
    <published>2023-01-19T14:00:00Z</published>
    <updated>2023-01-19T14:00:00Z</updated>
    <category term="python"/><category term="glom"/><category term="data"/><category term="software"/>
    

    <content type="html">&lt;p&gt;&lt;p&gt;&lt;em&gt;This post is a showcase of data wrangling techniques in Python, using &lt;a href=&quot;https://glom.readthedocs.io/en/latest/&quot;&gt;glom&lt;/a&gt;. 
If you haven&#x27;t heard of glom, it&#x27;s a data transformation library and CLI designed for Python. 
Think HTML templating, but for objects, dicts, and other data structures.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;http://sedimental.org/uploads/illo/comet_multi.png&quot; align=&quot;right&quot; width=&quot;30%&quot; /&gt;&lt;/p&gt;
&lt;p&gt;It&#x27;s been almost five years since &lt;a href=&quot;http://sedimental.org/glom_restructured_data.html&quot;&gt;the first release of glom&lt;/a&gt;. 
That version now looks quaint in comparison to the just-released glom 23. 
Out of all the new functionality, we&#x27;re going to take a look at six techniques 
that&#x27;ll level up your complex data handling.&lt;/p&gt;
&lt;div class=&quot;toc&quot;&gt;&lt;span class=&quot;toctitle&quot;&gt;Contents&lt;/span&gt;&lt;ul&gt;&lt;li&gt;&lt;a href=&quot;#star_path_selectors&quot;&gt;Star path selectors&lt;/a&gt;&lt;li&gt;&lt;a href=&quot;#deep_assignment_and_deletion&quot;&gt;Deep assignment and deletion&lt;/a&gt;&lt;li&gt;&lt;a href=&quot;#the_data_trace&quot;&gt;The Data Trace&lt;/a&gt;&lt;li&gt;&lt;a href=&quot;#pattern_matching&quot;&gt;Pattern matching&lt;/a&gt;&lt;li&gt;&lt;a href=&quot;#streaming&quot;&gt;Streaming&lt;/a&gt;&lt;li&gt;&lt;a href=&quot;#flattening_and_merging&quot;&gt;Flattening and Merging&lt;/a&gt;&lt;li&gt;&lt;a href=&quot;#other_core_updates&quot;&gt;Other core updates&lt;/a&gt;&lt;ul&gt;&lt;li&gt;&lt;a href=&quot;#scope&quot;&gt;Scope&lt;/a&gt;&lt;li&gt;&lt;a href=&quot;#modes&quot;&gt;Modes&lt;/a&gt;&lt;li&gt;&lt;a href=&quot;#extensions&quot;&gt;Extensions&lt;/a&gt;&lt;/ul&gt;&lt;/ul&gt;&lt;/div&gt;&lt;p&gt;&lt;em&gt;NB: Throughout the post, you&#x27;ll note examples linking to a site called &lt;a href=&quot;https://yak.party/glompad/&quot;&gt;glompad&lt;/a&gt;. 
Like so many regex and JS playgrounds, glompad is glom in the browser. 
Very much an alpha, I&#x27;ll save the details for another post. 
In the meantime, try it out and let me know how it goes!&lt;/em&gt;&lt;/p&gt;
&lt;h2 id=&quot;star_path_selectors&quot;&gt;&lt;a href=&quot;#star_path_selectors&quot; class=&quot;toclink&quot;&gt;Star path selectors&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Years in the making, glom&#x27;s newest feature is one of the longest anticipated.
Since its first release, glom&#x27;s deep get has excelled at fetching single values:&lt;/p&gt;
&lt;div class=&quot;codehilite&quot; style=&quot;background: #f8f8f8&quot;&gt;&lt;pre style=&quot;line-height: 125%;&quot;&gt;&lt;span&gt;&lt;/span&gt;target &lt;span style=&quot;color: #666666&quot;&gt;=&lt;/span&gt; {&lt;span style=&quot;color: #BB4444&quot;&gt;&#x27;a&#x27;&lt;/span&gt;: {&lt;span style=&quot;color: #BB4444&quot;&gt;&#x27;b&#x27;&lt;/span&gt;: {&lt;span style=&quot;color: #BB4444&quot;&gt;&#x27;c&#x27;&lt;/span&gt;: &lt;span style=&quot;color: #BB4444&quot;&gt;&#x27;d&#x27;&lt;/span&gt;}}}
glom(target, &lt;span style=&quot;color: #BB4444&quot;&gt;&#x27;a.b.c&#x27;&lt;/span&gt;)
&lt;span style=&quot;color: #008800; font-style: italic&quot;&gt;# &#x27;d&#x27;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;As of the latest release, glom now does &lt;a href=&quot;https://docs.python.org/3/library/glob.html&quot;&gt;glob&lt;/a&gt;-style &lt;code&gt;*&lt;/code&gt; and &lt;code&gt;**&lt;/code&gt; as path segments, 
aka wildcard expansion:&lt;/p&gt;
&lt;div class=&quot;codehilite&quot; style=&quot;background: #f8f8f8&quot;&gt;&lt;pre style=&quot;line-height: 125%;&quot;&gt;&lt;span&gt;&lt;/span&gt;glom({&lt;span style=&quot;color: #BB4444&quot;&gt;&#x27;a&#x27;&lt;/span&gt;: [{&lt;span style=&quot;color: #BB4444&quot;&gt;&#x27;k&#x27;&lt;/span&gt;: &lt;span style=&quot;color: #BB4444&quot;&gt;&#x27;v1&#x27;&lt;/span&gt;}, {&lt;span style=&quot;color: #BB4444&quot;&gt;&#x27;k&#x27;&lt;/span&gt;: &lt;span style=&quot;color: #BB4444&quot;&gt;&#x27;v2&#x27;&lt;/span&gt;}]}, &lt;span style=&quot;color: #BB4444&quot;&gt;&#x27;a.*.k&#x27;&lt;/span&gt;)  &lt;span style=&quot;color: #008800; font-style: italic&quot;&gt;# * is single-level&lt;/span&gt;
&lt;span style=&quot;color: #008800; font-style: italic&quot;&gt;# [&#x27;v1&#x27;, &#x27;v2&#x27;]&lt;/span&gt;

glom({&lt;span style=&quot;color: #BB4444&quot;&gt;&#x27;a&#x27;&lt;/span&gt;: [{&lt;span style=&quot;color: #BB4444&quot;&gt;&#x27;k&#x27;&lt;/span&gt;: &lt;span style=&quot;color: #BB4444&quot;&gt;&#x27;v3&#x27;&lt;/span&gt;}, {&lt;span style=&quot;color: #BB4444&quot;&gt;&#x27;k&#x27;&lt;/span&gt;: &lt;span style=&quot;color: #BB4444&quot;&gt;&#x27;v4&#x27;&lt;/span&gt;}]}, &lt;span style=&quot;color: #BB4444&quot;&gt;&#x27;**.k&#x27;&lt;/span&gt;)  &lt;span style=&quot;color: #008800; font-style: italic&quot;&gt;# ** is recursive&lt;/span&gt;
&lt;span style=&quot;color: #008800; font-style: italic&quot;&gt;# [&#x27;v3&#x27;, &#x27;v4&#x27;]&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Notably, this is one of the only breaking features in glom&#x27;s history. 
Star selectors were added as an option in glom 22, and baked for a year 
(with warnings for any users with stars in their paths) 
before becoming the default in glom 23.&lt;/p&gt;
&lt;h2 id=&quot;deep_assignment_and_deletion&quot;&gt;&lt;a href=&quot;#deep_assignment_and_deletion&quot; class=&quot;toclink&quot;&gt;Deep assignment and deletion&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;By default, glom makes and returns new data structures. But glom&#x27;s default immutable 
approach isn&#x27;t always a perfect fit for the messy, deeply-nested structures one gets 
from scraped DOMs, ancient XML, or idiosyncratic API wrappers.&lt;/p&gt;
&lt;p&gt;So one of glom&#x27;s earliest additions, way back in 2018, 
enabled declarative deep assignments that would work across virtually all mutable Python objects. 
First with &lt;code&gt;Assign()&lt;/code&gt; and the &lt;code&gt;assign()&lt;/code&gt; &lt;a href=&quot;https://glom.readthedocs.io/en/latest/faq.html#what-s-a-convenience-function&quot;&gt;convenience function&lt;/a&gt; (&lt;a href=&quot;https://yak.party/glompad/#spec=%23+Modify+a+dictionary+in-place.%0AAssign%28Path%28%22a%22%2C+%22e%22%29%2C+%22new+value%22%29%0A&amp;amp;target=%7B%22a%22%3A+%7B%22b%22%3A+%7B%22c%22%3A+%22d%22%7D%7D%7D%0A&amp;amp;v=1&quot;&gt;example&lt;/a&gt;, &lt;a href=&quot;https://glom.readthedocs.io/en/latest/mutation.html#assignment&quot;&gt;docs&lt;/a&gt;):&lt;/p&gt;
&lt;div class=&quot;codehilite&quot; style=&quot;background: #f8f8f8&quot;&gt;&lt;pre style=&quot;line-height: 125%;&quot;&gt;&lt;span&gt;&lt;/span&gt;target &lt;span style=&quot;color: #666666&quot;&gt;=&lt;/span&gt; {&lt;span style=&quot;color: #BB4444&quot;&gt;&#x27;a&#x27;&lt;/span&gt;: [{&lt;span style=&quot;color: #BB4444&quot;&gt;&#x27;b&#x27;&lt;/span&gt;: &lt;span style=&quot;color: #BB4444&quot;&gt;&#x27;c&#x27;&lt;/span&gt;}, {&lt;span style=&quot;color: #BB4444&quot;&gt;&#x27;d&#x27;&lt;/span&gt;: &lt;span style=&quot;color: #AA22FF; font-weight: bold&quot;&gt;None&lt;/span&gt;}]}
assign(target, &lt;span style=&quot;color: #BB4444&quot;&gt;&#x27;a.1.d&#x27;&lt;/span&gt;, &lt;span style=&quot;color: #BB4444&quot;&gt;&#x27;e&#x27;&lt;/span&gt;)  &lt;span style=&quot;color: #008800; font-style: italic&quot;&gt;# let&#x27;s give &#x27;d&#x27; a value of &#x27;e&#x27;&lt;/span&gt;
&lt;span style=&quot;color: #008800; font-style: italic&quot;&gt;# {&#x27;a&#x27;: [{&#x27;b&#x27;: &#x27;c&#x27;}, {&#x27;d&#x27;: &#x27;e&#x27;}]}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;&lt;code&gt;Assign&lt;/code&gt; also unlocked a super useful pattern of 
automatically creating nested objects without the need for &lt;code&gt;defaultdict&lt;/code&gt; and friends (&lt;a href=&quot;https://yak.party/glompad/#spec=%23+Automatically+create+dicts+for+missing+keys.%0AAssign%28Path%28%22user%22%2C+%22contact%22%2C+%22email%22%29%2C+%22foobar%40example.com%22%2C+missing%3Ddict%29%0A&amp;amp;target=%7B%0A++++%22user%22%3A+%7B%0A++++++++%22location%22%3A+%7B%22city%22%3A+%22Berlin%22%2C+%22country%22%3A+%22DE%22%7D%2C%0A++++++++%22username%22%3A+%22foobar%22%2C%0A++++++++%22created%22%3A+1672950417%2C%0A++++%7D%0A%7D%0A&amp;amp;v=1&quot;&gt;example&lt;/a&gt;):&lt;/p&gt;
&lt;div class=&quot;codehilite&quot; style=&quot;background: #f8f8f8&quot;&gt;&lt;pre style=&quot;line-height: 125%;&quot;&gt;&lt;span&gt;&lt;/span&gt;target &lt;span style=&quot;color: #666666&quot;&gt;=&lt;/span&gt; {}
assign(target, &lt;span style=&quot;color: #BB4444&quot;&gt;&#x27;a.b.c&#x27;&lt;/span&gt;, &lt;span style=&quot;color: #BB4444&quot;&gt;&#x27;hi&#x27;&lt;/span&gt;, missing&lt;span style=&quot;color: #666666&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #AA22FF&quot;&gt;dict&lt;/span&gt;)
&lt;span style=&quot;color: #008800; font-style: italic&quot;&gt;# {&#x27;a&#x27;: {&#x27;b&#x27;: {&#x27;c&#x27;: &#x27;hi&#x27;}}}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;And for something more destructive, there&#x27;s &lt;code&gt;Delete()&lt;/code&gt; and &lt;code&gt;delete()&lt;/code&gt; (&lt;a href=&quot;https://yak.party/glompad/#spec=Delete%28%27a.b.1%27%29&amp;amp;target=%7B%27a%27%3A+%7B%27b%27%3A+%5B5%2C+6%2C+7%5D%7D%7D&amp;amp;v=1&quot;&gt;example&lt;/a&gt;, &lt;a href=&quot;https://glom.readthedocs.io/en/latest/mutation.html#deletion&quot;&gt;docs&lt;/a&gt;):&lt;/p&gt;
&lt;div class=&quot;codehilite&quot; style=&quot;background: #f8f8f8&quot;&gt;&lt;pre style=&quot;line-height: 125%;&quot;&gt;&lt;span&gt;&lt;/span&gt;target &lt;span style=&quot;color: #666666&quot;&gt;=&lt;/span&gt; {&lt;span style=&quot;color: #BB4444&quot;&gt;&#x27;a&#x27;&lt;/span&gt;: [{&lt;span style=&quot;color: #BB4444&quot;&gt;&#x27;b&#x27;&lt;/span&gt;: &lt;span style=&quot;color: #BB4444&quot;&gt;&#x27;c&#x27;&lt;/span&gt;}, {&lt;span style=&quot;color: #BB4444&quot;&gt;&#x27;d&#x27;&lt;/span&gt;: &lt;span style=&quot;color: #AA22FF; font-weight: bold&quot;&gt;None&lt;/span&gt;}]}
delete(target, &lt;span style=&quot;color: #BB4444&quot;&gt;&#x27;a.0.b&#x27;&lt;/span&gt;)
&lt;span style=&quot;color: #008800; font-style: italic&quot;&gt;# {&#x27;a&#x27;: [{}, {&#x27;d&#x27;: None}]}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;&lt;code&gt;Assign()&lt;/code&gt; and &lt;code&gt;Delete()&lt;/code&gt; both shine when manipulating ElementTree-style documents from &lt;a href=&quot;https://docs.python.org/3/library/xml.etree.elementtree.html&quot;&gt;etree&lt;/a&gt;, &lt;a href=&quot;https://lxml.de/&quot;&gt;lxml&lt;/a&gt;, &lt;a href=&quot;https://github.com/html5lib/html5lib-python&quot;&gt;html5lib&lt;/a&gt;, and the like.&lt;/p&gt;
&lt;p&gt;Like glom&#x27;s other path-based functionality, the nuances of assigning Python &lt;code&gt;dict&lt;/code&gt; keys, object attributes, and sequence indices are handled for you.
There&#x27;s also an &lt;a href=&quot;https://glom.readthedocs.io/en/latest/api.html#setup-and-registration&quot;&gt;extension system&lt;/a&gt; for adding support especially unique types.&lt;/p&gt;
&lt;h2 id=&quot;the_data_trace&quot;&gt;&lt;a href=&quot;#the_data_trace&quot; class=&quot;toclink&quot;&gt;The Data Trace&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The main appeal of glom has always been succinct and robust data access and transformation. 
No single glom feature showcases this quite as much as the &lt;em&gt;data trace&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;Data traces make glom&#x27;s errors far more debuggable than Python&#x27;s default exceptions. 
You don&#x27;t see internal glom or Python stack frames; just you, your code, and your data:&lt;/p&gt;
&lt;div class=&quot;codehilite&quot; style=&quot;background: #f8f8f8&quot;&gt;&lt;pre style=&quot;line-height: 125%;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;span style=&quot;color: #666666&quot;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; target &lt;span style=&quot;color: #666666&quot;&gt;=&lt;/span&gt; {&lt;span style=&quot;color: #BB4444&quot;&gt;&#x27;planets&#x27;&lt;/span&gt;: [{&lt;span style=&quot;color: #BB4444&quot;&gt;&#x27;name&#x27;&lt;/span&gt;: &lt;span style=&quot;color: #BB4444&quot;&gt;&#x27;earth&#x27;&lt;/span&gt;, &lt;span style=&quot;color: #BB4444&quot;&gt;&#x27;moons&#x27;&lt;/span&gt;: &lt;span style=&quot;color: #666666&quot;&gt;1&lt;/span&gt;}]}
&lt;span style=&quot;color: #666666&quot;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; spec &lt;span style=&quot;color: #666666&quot;&gt;=&lt;/span&gt; (&lt;span style=&quot;color: #BB4444&quot;&gt;&#x27;planets&#x27;&lt;/span&gt;, [&lt;span style=&quot;color: #BB4444&quot;&gt;&#x27;rings&#x27;&lt;/span&gt;])  &lt;span style=&quot;color: #008800; font-style: italic&quot;&gt;# a spec we expect to fail&lt;/span&gt;
&lt;span style=&quot;color: #666666&quot;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; glom(target, spec)
 Traceback (most recent call last):
   File &lt;span style=&quot;color: #BB4444&quot;&gt;&quot;&amp;lt;stdin&amp;gt;&quot;&lt;/span&gt;, line &lt;span style=&quot;color: #666666&quot;&gt;1&lt;/span&gt;, &lt;span style=&quot;color: #AA22FF; font-weight: bold&quot;&gt;in&lt;/span&gt; &lt;span style=&quot;color: #666666&quot;&gt;&amp;lt;&lt;/span&gt;module&lt;span style=&quot;color: #666666&quot;&gt;&amp;gt;&lt;/span&gt;
   File &lt;span style=&quot;color: #BB4444&quot;&gt;&quot;/home/mahmoud/projects/glom/glom/core.py&quot;&lt;/span&gt;, line &lt;span style=&quot;color: #666666&quot;&gt;1787&lt;/span&gt;, &lt;span style=&quot;color: #AA22FF; font-weight: bold&quot;&gt;in&lt;/span&gt; glom
     &lt;span style=&quot;color: #AA22FF; font-weight: bold&quot;&gt;raise&lt;/span&gt; err
 glom&lt;span style=&quot;color: #666666&quot;&gt;.&lt;/span&gt;core&lt;span style=&quot;color: #666666&quot;&gt;.&lt;/span&gt;PathAccessError: error raised &lt;span style=&quot;color: #AA22FF; font-weight: bold&quot;&gt;while&lt;/span&gt; processing, details below&lt;span style=&quot;color: #666666&quot;&gt;.&lt;/span&gt;
  Target&lt;span style=&quot;color: #666666&quot;&gt;-&lt;/span&gt;spec trace (most recent last):
  &lt;span style=&quot;color: #666666&quot;&gt;-&lt;/span&gt; Target: {&lt;span style=&quot;color: #BB4444&quot;&gt;&#x27;planets&#x27;&lt;/span&gt;: [{&lt;span style=&quot;color: #BB4444&quot;&gt;&#x27;name&#x27;&lt;/span&gt;: &lt;span style=&quot;color: #BB4444&quot;&gt;&#x27;earth&#x27;&lt;/span&gt;, &lt;span style=&quot;color: #BB4444&quot;&gt;&#x27;moons&#x27;&lt;/span&gt;: &lt;span style=&quot;color: #666666&quot;&gt;1&lt;/span&gt;}]}
  &lt;span style=&quot;color: #666666&quot;&gt;-&lt;/span&gt; Spec: (&lt;span style=&quot;color: #BB4444&quot;&gt;&#x27;planets&#x27;&lt;/span&gt;, [&lt;span style=&quot;color: #BB4444&quot;&gt;&#x27;rings&#x27;&lt;/span&gt;])
  &lt;span style=&quot;color: #666666&quot;&gt;-&lt;/span&gt; Spec: &lt;span style=&quot;color: #BB4444&quot;&gt;&#x27;planets&#x27;&lt;/span&gt;
  &lt;span style=&quot;color: #666666&quot;&gt;-&lt;/span&gt; Target: [{&lt;span style=&quot;color: #BB4444&quot;&gt;&#x27;name&#x27;&lt;/span&gt;: &lt;span style=&quot;color: #BB4444&quot;&gt;&#x27;earth&#x27;&lt;/span&gt;, &lt;span style=&quot;color: #BB4444&quot;&gt;&#x27;moons&#x27;&lt;/span&gt;: &lt;span style=&quot;color: #666666&quot;&gt;1&lt;/span&gt;}]
  &lt;span style=&quot;color: #666666&quot;&gt;-&lt;/span&gt; Spec: [&lt;span style=&quot;color: #BB4444&quot;&gt;&#x27;rings&#x27;&lt;/span&gt;]
  &lt;span style=&quot;color: #666666&quot;&gt;-&lt;/span&gt; Target: {&lt;span style=&quot;color: #BB4444&quot;&gt;&#x27;name&#x27;&lt;/span&gt;: &lt;span style=&quot;color: #BB4444&quot;&gt;&#x27;earth&#x27;&lt;/span&gt;, &lt;span style=&quot;color: #BB4444&quot;&gt;&#x27;moons&#x27;&lt;/span&gt;: &lt;span style=&quot;color: #666666&quot;&gt;1&lt;/span&gt;}
  &lt;span style=&quot;color: #666666&quot;&gt;-&lt;/span&gt; Spec: &lt;span style=&quot;color: #BB4444&quot;&gt;&#x27;rings&#x27;&lt;/span&gt;
 glom&lt;span style=&quot;color: #666666&quot;&gt;.&lt;/span&gt;core&lt;span style=&quot;color: #666666&quot;&gt;.&lt;/span&gt;PathAccessError: could &lt;span style=&quot;color: #AA22FF; font-weight: bold&quot;&gt;not&lt;/span&gt; access &lt;span style=&quot;color: #BB4444&quot;&gt;&#x27;rings&#x27;&lt;/span&gt;, part &lt;span style=&quot;color: #666666&quot;&gt;0&lt;/span&gt; of Path(&lt;span style=&quot;color: #BB4444&quot;&gt;&#x27;rings&#x27;&lt;/span&gt;), got error: &lt;span style=&quot;color: #D2413A; font-weight: bold&quot;&gt;KeyError&lt;/span&gt;(&lt;span style=&quot;color: #BB4444&quot;&gt;&#x27;rings&#x27;&lt;/span&gt;)
&lt;/pre&gt;&lt;/div&gt;


&lt;div style=&quot;float: right; width: 40%; margin-left: 10px; padding: 5px; border: 1px solid silver;&quot;&gt;
&lt;div style=&quot;width: 100%&quot;&gt;
&lt;a target=&quot;_blank&quot; href=&quot;http://sedimental.org/uploads/data_trace_before_after.png&quot;&gt;&lt;img src=&quot;http://sedimental.org/uploads/data_trace_before_after.png&quot; align=&quot;right&quot; width=&quot;100%&quot; /&gt;&lt;/a&gt;
&lt;/div&gt;
&lt;div&gt;&lt;i&gt;Failures before and after the data trace. Full text &lt;a href=&quot;https://gist.github.com/mahmoud/a0923541c2c59c7cb167802c0d09a895&quot;&gt;here&lt;/a&gt;.&lt;/i&gt;&lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;One day I&#x27;ll write a post about how tracebacks are an oft-neglected part of a library&#x27;s interface.
The right traceback can turn an all-night debugging session into a quick fix anyone can push. &lt;/p&gt;
&lt;p&gt;For now, see the doc with examples and more explanation &lt;a href=&quot;https://glom.readthedocs.io/en/latest/debugging.html#reading-a-glom-exception&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;pattern_matching&quot;&gt;&lt;a href=&quot;#pattern_matching&quot; class=&quot;toclink&quot;&gt;Pattern matching&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;While glom started as a data transformer, you often need to validate data before transforming it. 
Data validation fits nicely into spec format, and so glom&#x27;s &lt;a href=&quot;https://glom.readthedocs.io/en/latest/matching.html#validation-with-match&quot;&gt;&lt;code&gt;Match&lt;/code&gt; specifier&lt;/a&gt; was born:&lt;/p&gt;
&lt;div class=&quot;codehilite&quot; style=&quot;background: #f8f8f8&quot;&gt;&lt;pre style=&quot;line-height: 125%;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;span style=&quot;color: #008800; font-style: italic&quot;&gt;# load some data&lt;/span&gt;
target &lt;span style=&quot;color: #666666&quot;&gt;=&lt;/span&gt; [{&lt;span style=&quot;color: #BB4444&quot;&gt;&#x27;id&#x27;&lt;/span&gt;: &lt;span style=&quot;color: #666666&quot;&gt;1&lt;/span&gt;, &lt;span style=&quot;color: #BB4444&quot;&gt;&#x27;email&#x27;&lt;/span&gt;: &lt;span style=&quot;color: #BB4444&quot;&gt;&#x27;alice@example.com&#x27;&lt;/span&gt;}, 
          {&lt;span style=&quot;color: #BB4444&quot;&gt;&#x27;id&#x27;&lt;/span&gt;: &lt;span style=&quot;color: #666666&quot;&gt;2&lt;/span&gt;, &lt;span style=&quot;color: #BB4444&quot;&gt;&#x27;email&#x27;&lt;/span&gt;: &lt;span style=&quot;color: #BB4444&quot;&gt;&#x27;bob@example.com&#x27;&lt;/span&gt;}]

&lt;span style=&quot;color: #008800; font-style: italic&quot;&gt;# let&#x27;s validate that the data has the types we expect&lt;/span&gt;
spec &lt;span style=&quot;color: #666666&quot;&gt;=&lt;/span&gt; Match([{&lt;span style=&quot;color: #BB4444&quot;&gt;&#x27;id&#x27;&lt;/span&gt;: &lt;span style=&quot;color: #AA22FF&quot;&gt;int&lt;/span&gt;, &lt;span style=&quot;color: #BB4444&quot;&gt;&#x27;email&#x27;&lt;/span&gt;: &lt;span style=&quot;color: #AA22FF&quot;&gt;str&lt;/span&gt;}])

result &lt;span style=&quot;color: #666666&quot;&gt;=&lt;/span&gt; glom(target, spec)
&lt;span style=&quot;color: #008800; font-style: italic&quot;&gt;# result here is equal to the data itself&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Glom&#x27;s pattern matching now features its own shorthand &lt;a href=&quot;https://glom.readthedocs.io/en/latest/matching.html#m-expressions&quot;&gt;&lt;code&gt;M&lt;/code&gt; spec&lt;/a&gt;, which is great for quick guards, 
and a &lt;code&gt;Regex&lt;/code&gt; helper, too:&lt;/p&gt;
&lt;div class=&quot;codehilite&quot; style=&quot;background: #f8f8f8&quot;&gt;&lt;pre style=&quot;line-height: 125%;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;span style=&quot;color: #008800; font-style: italic&quot;&gt;# using the example data above, we can also validate the contents of the data&lt;/span&gt;
spec &lt;span style=&quot;color: #666666&quot;&gt;=&lt;/span&gt; Match([{&lt;span style=&quot;color: #BB4444&quot;&gt;&#x27;id&#x27;&lt;/span&gt;: And(M &lt;span style=&quot;color: #666666&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span style=&quot;color: #666666&quot;&gt;0&lt;/span&gt;, &lt;span style=&quot;color: #AA22FF&quot;&gt;int&lt;/span&gt;), &lt;span style=&quot;color: #BB4444&quot;&gt;&#x27;email&#x27;&lt;/span&gt;: Regex(&lt;span style=&quot;color: #BB4444&quot;&gt;&#x27;[^@]+@[^@]+&#x27;&lt;/span&gt;)}])

result &lt;span style=&quot;color: #666666&quot;&gt;=&lt;/span&gt; glom(target, spec)
&lt;span style=&quot;color: #008800; font-style: italic&quot;&gt;# result here is again equal to the target data&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Even a simple pattern matching example shows the power of the glom data trace. 
Check out the error message when some bad data gets added:&lt;/p&gt;
&lt;div class=&quot;codehilite&quot; style=&quot;background: #f8f8f8&quot;&gt;&lt;pre style=&quot;line-height: 125%;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;span style=&quot;color: #666666&quot;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; target&lt;span style=&quot;color: #666666&quot;&gt;.&lt;/span&gt;append({&lt;span style=&quot;color: #BB4444&quot;&gt;&#x27;id&#x27;&lt;/span&gt;: &lt;span style=&quot;color: #BB4444&quot;&gt;&#x27;3&#x27;&lt;/span&gt;, &lt;span style=&quot;color: #BB4444&quot;&gt;&#x27;email&#x27;&lt;/span&gt;: &lt;span style=&quot;color: #BB4444&quot;&gt;&#x27;charlie@example.com&#x27;&lt;/span&gt;})
&lt;span style=&quot;color: #666666&quot;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; result &lt;span style=&quot;color: #666666&quot;&gt;=&lt;/span&gt; glom(target, spec)
Traceback (most recent call last):
  File &lt;span style=&quot;color: #BB4444&quot;&gt;&quot;&amp;lt;stdin&amp;gt;&quot;&lt;/span&gt;, line &lt;span style=&quot;color: #666666&quot;&gt;1&lt;/span&gt;, &lt;span style=&quot;color: #AA22FF; font-weight: bold&quot;&gt;in&lt;/span&gt; &lt;span style=&quot;color: #666666&quot;&gt;&amp;lt;&lt;/span&gt;module&lt;span style=&quot;color: #666666&quot;&gt;&amp;gt;&lt;/span&gt;
  File &lt;span style=&quot;color: #BB4444&quot;&gt;&quot;../glom/core.py&quot;&lt;/span&gt;, line &lt;span style=&quot;color: #666666&quot;&gt;2294&lt;/span&gt;, &lt;span style=&quot;color: #AA22FF; font-weight: bold&quot;&gt;in&lt;/span&gt; glom
    &lt;span style=&quot;color: #AA22FF; font-weight: bold&quot;&gt;raise&lt;/span&gt; err
glom&lt;span style=&quot;color: #666666&quot;&gt;.&lt;/span&gt;matching&lt;span style=&quot;color: #666666&quot;&gt;.&lt;/span&gt;TypeMatchError: error raised &lt;span style=&quot;color: #AA22FF; font-weight: bold&quot;&gt;while&lt;/span&gt; processing, details below&lt;span style=&quot;color: #666666&quot;&gt;.&lt;/span&gt;
 Target&lt;span style=&quot;color: #666666&quot;&gt;-&lt;/span&gt;spec trace (most recent last):
 &lt;span style=&quot;color: #666666&quot;&gt;-&lt;/span&gt; Target: [{&lt;span style=&quot;color: #BB4444&quot;&gt;&#x27;email&#x27;&lt;/span&gt;: &lt;span style=&quot;color: #BB4444&quot;&gt;&#x27;alice@example.com&#x27;&lt;/span&gt;, &lt;span style=&quot;color: #BB4444&quot;&gt;&#x27;id&#x27;&lt;/span&gt;: &lt;span style=&quot;color: #666666&quot;&gt;1&lt;/span&gt;}, {&lt;span style=&quot;color: #BB4444&quot;&gt;&#x27;email&#x27;&lt;/span&gt;: &lt;span style=&quot;color: #BB4444&quot;&gt;&#x27;bob@example.com&#x27;&lt;/span&gt;, &lt;span style=&quot;color: #BB4444&quot;&gt;&#x27;id&#x27;&lt;/span&gt;: &lt;span style=&quot;color: #666666&quot;&gt;2&lt;/span&gt;}, {&lt;span style=&quot;color: #BB4444&quot;&gt;&#x27;ema... (len=3)&lt;/span&gt;
 &lt;span style=&quot;color: #666666&quot;&gt;-&lt;/span&gt; Spec: Match([{&lt;span style=&quot;color: #BB4444&quot;&gt;&#x27;email&#x27;&lt;/span&gt;: &lt;span style=&quot;color: #AA22FF&quot;&gt;str&lt;/span&gt;, &lt;span style=&quot;color: #BB4444&quot;&gt;&#x27;id&#x27;&lt;/span&gt;: &lt;span style=&quot;color: #AA22FF&quot;&gt;int&lt;/span&gt;}])
 &lt;span style=&quot;color: #666666&quot;&gt;-&lt;/span&gt; Spec: [{&lt;span style=&quot;color: #BB4444&quot;&gt;&#x27;email&#x27;&lt;/span&gt;: &lt;span style=&quot;color: #AA22FF&quot;&gt;str&lt;/span&gt;, &lt;span style=&quot;color: #BB4444&quot;&gt;&#x27;id&#x27;&lt;/span&gt;: &lt;span style=&quot;color: #AA22FF&quot;&gt;int&lt;/span&gt;}]
 &lt;span style=&quot;color: #666666&quot;&gt;-&lt;/span&gt; Target: {&lt;span style=&quot;color: #BB4444&quot;&gt;&#x27;email&#x27;&lt;/span&gt;: &lt;span style=&quot;color: #BB4444&quot;&gt;&#x27;charlie@example.com&#x27;&lt;/span&gt;, &lt;span style=&quot;color: #BB4444&quot;&gt;&#x27;id&#x27;&lt;/span&gt;: &lt;span style=&quot;color: #BB4444&quot;&gt;&#x27;3&#x27;&lt;/span&gt;}
 &lt;span style=&quot;color: #666666&quot;&gt;-&lt;/span&gt; Spec: {&lt;span style=&quot;color: #BB4444&quot;&gt;&#x27;email&#x27;&lt;/span&gt;: &lt;span style=&quot;color: #AA22FF&quot;&gt;str&lt;/span&gt;, &lt;span style=&quot;color: #BB4444&quot;&gt;&#x27;id&#x27;&lt;/span&gt;: &lt;span style=&quot;color: #AA22FF&quot;&gt;int&lt;/span&gt;}
 &lt;span style=&quot;color: #666666&quot;&gt;-&lt;/span&gt; Target: &lt;span style=&quot;color: #BB4444&quot;&gt;&#x27;id&#x27;&lt;/span&gt;
 &lt;span style=&quot;color: #666666&quot;&gt;-&lt;/span&gt; Spec: &lt;span style=&quot;color: #BB4444&quot;&gt;&#x27;id&#x27;&lt;/span&gt;
 &lt;span style=&quot;color: #666666&quot;&gt;-&lt;/span&gt; Target: &lt;span style=&quot;color: #BB4444&quot;&gt;&#x27;3&#x27;&lt;/span&gt;
 &lt;span style=&quot;color: #666666&quot;&gt;-&lt;/span&gt; Spec: &lt;span style=&quot;color: #AA22FF&quot;&gt;int&lt;/span&gt;
glom&lt;span style=&quot;color: #666666&quot;&gt;.&lt;/span&gt;matching&lt;span style=&quot;color: #666666&quot;&gt;.&lt;/span&gt;TypeMatchError: expected &lt;span style=&quot;color: #AA22FF&quot;&gt;type&lt;/span&gt; &lt;span style=&quot;color: #AA22FF&quot;&gt;int&lt;/span&gt;, &lt;span style=&quot;color: #AA22FF; font-weight: bold&quot;&gt;not&lt;/span&gt; &lt;span style=&quot;color: #AA22FF&quot;&gt;str&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;The data trace gets even sweeter when we introduce flow control with Switch. 
See the data trace in action in &lt;a href=&quot;https://yak.party/glompad/#spec=%23+let%27s+classify+vowels+vs+consonants+to+show+off+Switch%27s+error+handling%0AMatch%28Switch%28%5B%28Or%28%27a%27%2C+%27e%27%2C+%27i%27%2C+%27o%27%2C+%27u%27%29%2C+Val%28%27vowel%27%29%29%2C%0A++++++++++++++%28And%28str%2C+M%2C+M%28T%5B2%3A%5D%29+%3D%3D+%27%27%29%2C+Val%28%27consonant%27%29%29%5D%29%29&amp;amp;target=%23+An+integer+will+cause+the+expected+failure%0A3&amp;amp;v=1&quot;&gt;this example&lt;/a&gt;.
Users of shape-based typecheckers like &lt;a href=&quot;https://flow.org/&quot;&gt;Flow&lt;/a&gt; will especially appreciate 
the specificity of glom&#x27;s error messages in these validation cases.&lt;/p&gt;
&lt;!--

In mid-2020, some combination of PEG and Python 2&#x27;s deprecation lit a fire of innovation, one of the most ambitious of which is now captured in [PEP 634](https://peps.python.org/pep-0634/), and implemented in Python 3.10&#x27;s [Structural Pattern Matching](https://docs.python.org/3/whatsnew/3.10.html#pep-634-structural-pattern-matching).

--&gt;

&lt;h2 id=&quot;streaming&quot;&gt;&lt;a href=&quot;#streaming&quot; class=&quot;toclink&quot;&gt;Streaming&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;For datasets too large to fit in memory, glom grew an &lt;code&gt;Iter()&lt;/code&gt; specifier in 2019 (&lt;a href=&quot;https://yak.party/glompad/#spec=Iter%28%29.split%28%29.flatten%28%29.unique%28%29.all%28%29&amp;amp;target=%5B1%2C+2%2C+None%2C+None%2C+3%2C+None%2C+3%2C+None%2C+2%2C+4%5D&amp;amp;v=1&quot;&gt;example&lt;/a&gt;, &lt;a href=&quot;https://glom.readthedocs.io/en/latest/streaming.html#streaming-iteration&quot;&gt;docs&lt;/a&gt;). 
&lt;code&gt;Iter()&lt;/code&gt; offers a readable chaining API that lazily creates nesting generators.&lt;/p&gt;
&lt;div class=&quot;codehilite&quot; style=&quot;background: #f8f8f8&quot;&gt;&lt;pre style=&quot;line-height: 125%;&quot;&gt;&lt;span&gt;&lt;/span&gt;target &lt;span style=&quot;color: #666666&quot;&gt;=&lt;/span&gt; [&lt;span style=&quot;color: #666666&quot;&gt;1&lt;/span&gt;, &lt;span style=&quot;color: #666666&quot;&gt;2&lt;/span&gt;, &lt;span style=&quot;color: #AA22FF; font-weight: bold&quot;&gt;None&lt;/span&gt;, &lt;span style=&quot;color: #AA22FF; font-weight: bold&quot;&gt;None&lt;/span&gt;, &lt;span style=&quot;color: #666666&quot;&gt;3&lt;/span&gt;, &lt;span style=&quot;color: #AA22FF; font-weight: bold&quot;&gt;None&lt;/span&gt;, &lt;span style=&quot;color: #666666&quot;&gt;3&lt;/span&gt;, &lt;span style=&quot;color: #AA22FF; font-weight: bold&quot;&gt;None&lt;/span&gt;, &lt;span style=&quot;color: #666666&quot;&gt;2&lt;/span&gt;, &lt;span style=&quot;color: #666666&quot;&gt;4&lt;/span&gt;]

spec &lt;span style=&quot;color: #666666&quot;&gt;=&lt;/span&gt; Iter()&lt;span style=&quot;color: #666666&quot;&gt;.&lt;/span&gt;filter()&lt;span style=&quot;color: #666666&quot;&gt;.&lt;/span&gt;unique()  &lt;span style=&quot;color: #008800; font-style: italic&quot;&gt;# this gives a streaming generator when evaluated&lt;/span&gt;
glom(target, spec&lt;span style=&quot;color: #666666&quot;&gt;.&lt;/span&gt;all())  &lt;span style=&quot;color: #008800; font-style: italic&quot;&gt;# .all() converts the generator to a list&lt;/span&gt;
&lt;span style=&quot;color: #008800; font-style: italic&quot;&gt;# [1, 2, 3, 4]&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;&lt;code&gt;Iter()&lt;/code&gt;&#x27;s built-in methods also include &lt;a href=&quot;https://glom.readthedocs.io/en/latest/streaming.html#glom.Iter.split&quot;&gt;&lt;code&gt;.split()&lt;/code&gt;&lt;/a&gt;, &lt;a href=&quot;https://glom.readthedocs.io/en/latest/grouping.html#glom.flatten&quot;&gt;&lt;code&gt;.flatten()&lt;/code&gt;&lt;/a&gt;, &lt;a href=&quot;https://glom.readthedocs.io/en/latest/streaming.html#glom.Iter.chunked&quot;&gt;&lt;code&gt;.chunked()&lt;/code&gt;&lt;/a&gt;, &lt;a href=&quot;https://glom.readthedocs.io/en/latest/streaming.html#glom.Iter.slice&quot;&gt;&lt;code&gt;.slice()&lt;/code&gt;&lt;/a&gt;, &lt;a href=&quot;https://glom.readthedocs.io/en/latest/streaming.html#glom.Iter.limit&quot;&gt;&lt;code&gt;.limit()&lt;/code&gt;&lt;/a&gt; among others. 
In short, endless possibilities for endless data.&lt;/p&gt;
&lt;h2 id=&quot;flattening_and_merging&quot;&gt;&lt;a href=&quot;#flattening_and_merging&quot; class=&quot;toclink&quot;&gt;Flattening and Merging&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;So much data revolves around iterables that in 2019 glom introduced the ability to &quot;reduce&quot; those iterables to flatter values, with the introduction of &lt;code&gt;Flatten&lt;/code&gt; (&lt;a href=&quot;https://yak.party/glompad/#spec=Flatten%28%29&amp;amp;target=%5B%7B0%7D%2C+%5B1%2C+2%2C+3%5D%2C+%284%2C+5%29%5D&amp;amp;v=1)&quot;&gt;example&lt;/a&gt;, &lt;a href=&quot;https://glom.readthedocs.io/en/latest/grouping.html#glom.flatten&quot;&gt;docs&lt;/a&gt;):&lt;/p&gt;
&lt;div class=&quot;codehilite&quot; style=&quot;background: #f8f8f8&quot;&gt;&lt;pre style=&quot;line-height: 125%;&quot;&gt;&lt;span&gt;&lt;/span&gt;list_of_iterables &lt;span style=&quot;color: #666666&quot;&gt;=&lt;/span&gt; [{&lt;span style=&quot;color: #666666&quot;&gt;0&lt;/span&gt;}, [&lt;span style=&quot;color: #666666&quot;&gt;1&lt;/span&gt;, &lt;span style=&quot;color: #666666&quot;&gt;2&lt;/span&gt;, &lt;span style=&quot;color: #666666&quot;&gt;3&lt;/span&gt;], (&lt;span style=&quot;color: #666666&quot;&gt;4&lt;/span&gt;, &lt;span style=&quot;color: #666666&quot;&gt;5&lt;/span&gt;)]
flatten(list_of_iterables)
&lt;span style=&quot;color: #008800; font-style: italic&quot;&gt;# [0, 1, 2, 3, 4, 5]&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Even a mix of iterables (iterators, lists, tuples) combines nicely.&lt;/p&gt;
&lt;p&gt;With &lt;code&gt;Flatten&lt;/code&gt; came the numeric &lt;a href=&quot;https://glom.readthedocs.io/en/latest/grouping.html#glom.Sum&quot;&gt;&lt;code&gt;Sum&lt;/code&gt;&lt;/a&gt;, not unlike the builtin:&lt;/p&gt;
&lt;div class=&quot;codehilite&quot; style=&quot;background: #f8f8f8&quot;&gt;&lt;pre style=&quot;line-height: 125%;&quot;&gt;&lt;span&gt;&lt;/span&gt;glom(&lt;span style=&quot;color: #AA22FF&quot;&gt;range&lt;/span&gt;(&lt;span style=&quot;color: #666666&quot;&gt;5&lt;/span&gt;), Sum())
&lt;span style=&quot;color: #008800; font-style: italic&quot;&gt;# 15&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;And the generic &lt;a href=&quot;https://glom.readthedocs.io/en/latest/grouping.html#glom.Fold&quot;&gt;&lt;code&gt;Fold&lt;/code&gt;&lt;/a&gt;, useful for some rare cases:&lt;/p&gt;
&lt;div class=&quot;codehilite&quot; style=&quot;background: #f8f8f8&quot;&gt;&lt;pre style=&quot;line-height: 125%;&quot;&gt;&lt;span&gt;&lt;/span&gt;target &lt;span style=&quot;color: #666666&quot;&gt;=&lt;/span&gt; [&lt;span style=&quot;color: #AA22FF&quot;&gt;set&lt;/span&gt;([&lt;span style=&quot;color: #666666&quot;&gt;1&lt;/span&gt;, &lt;span style=&quot;color: #666666&quot;&gt;2&lt;/span&gt;]), &lt;span style=&quot;color: #AA22FF&quot;&gt;set&lt;/span&gt;([&lt;span style=&quot;color: #666666&quot;&gt;3&lt;/span&gt;]), &lt;span style=&quot;color: #AA22FF&quot;&gt;set&lt;/span&gt;([&lt;span style=&quot;color: #666666&quot;&gt;2&lt;/span&gt;, &lt;span style=&quot;color: #666666&quot;&gt;4&lt;/span&gt;])]
result &lt;span style=&quot;color: #666666&quot;&gt;=&lt;/span&gt; glom(target, Fold(T, init&lt;span style=&quot;color: #666666&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #AA22FF&quot;&gt;frozenset&lt;/span&gt;, op&lt;span style=&quot;color: #666666&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #AA22FF&quot;&gt;frozenset&lt;/span&gt;&lt;span style=&quot;color: #666666&quot;&gt;.&lt;/span&gt;union))
&lt;span style=&quot;color: #008800; font-style: italic&quot;&gt;# frozenset([1, 2, 3, 4])&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;A later release brought flattening to mappings, via &lt;code&gt;Merge&lt;/code&gt; (&lt;a href=&quot;https://yak.party/glompad/#spec=Merge%28%29&amp;amp;target=%5B%7B%27a%27%3A+%27alpha%27%7D%2C+%7B%27b%27%3A+%27B%27%7D%2C+%7B%27a%27%3A+%27A%27%7D%5D&amp;amp;v=1&quot;&gt;example&lt;/a&gt;, &lt;a href=&quot;https://glom.readthedocs.io/en/latest/grouping.html#glom.merge&quot;&gt;docs&lt;/a&gt;):&lt;/p&gt;
&lt;div class=&quot;codehilite&quot; style=&quot;background: #f8f8f8&quot;&gt;&lt;pre style=&quot;line-height: 125%;&quot;&gt;&lt;span&gt;&lt;/span&gt;target &lt;span style=&quot;color: #666666&quot;&gt;=&lt;/span&gt; [{&lt;span style=&quot;color: #BB4444&quot;&gt;&#x27;a&#x27;&lt;/span&gt;: &lt;span style=&quot;color: #BB4444&quot;&gt;&#x27;alpha&#x27;&lt;/span&gt;}, {&lt;span style=&quot;color: #BB4444&quot;&gt;&#x27;b&#x27;&lt;/span&gt;: &lt;span style=&quot;color: #BB4444&quot;&gt;&#x27;B&#x27;&lt;/span&gt;}, {&lt;span style=&quot;color: #BB4444&quot;&gt;&#x27;a&#x27;&lt;/span&gt;: &lt;span style=&quot;color: #BB4444&quot;&gt;&#x27;A&#x27;&lt;/span&gt;}]
merge(target)
&lt;span style=&quot;color: #008800; font-style: italic&quot;&gt;# {&#x27;a&#x27;: &#x27;A&#x27;, &#x27;b&#x27;: &#x27;B&#x27;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;&lt;code&gt;Merge()&lt;/code&gt; is great for deduping documents with a simple last-value-wins strategy.&lt;/p&gt;
&lt;h2 id=&quot;other_core_updates&quot;&gt;&lt;a href=&quot;#other_core_updates&quot; class=&quot;toclink&quot;&gt;Other core updates&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The features above, and myriad others from &lt;a href=&quot;https://github.com/mahmoud/glom/blob/master/CHANGELOG.md&quot;&gt;the changelog&lt;/a&gt;, required multiple evolutions of the glom core. 
Underneath glom&#x27;s hood is a loop that interprets the spec against the target. 
A simple, early version is preserved &lt;a href=&quot;https://glom.readthedocs.io/en/latest/faq.html#how-does-glom-work&quot;&gt;here in the docs&lt;/a&gt;. &lt;/p&gt;
&lt;p&gt;However, the inner workings of the core were not part of glom&#x27;s API, which limited extensibility. 
A lot of progress has been made in opening up glom internals for those use cases we couldn&#x27;t predict.&lt;/p&gt;
&lt;h3 id=&quot;scope&quot;&gt;&lt;a href=&quot;#scope&quot; class=&quot;toclink&quot;&gt;Scope&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Most transformations only requires a target and spec. Most... but not all.&lt;/p&gt;
&lt;p&gt;For cases that needed additional state, like aggregation and multi-target glomming, 
we added the glom &lt;code&gt;Scope&lt;/code&gt; (&lt;a href=&quot;https://yak.party/glompad/#spec=T.count%28S.search%29&amp;amp;target=%5B%27a%27%2C+%27c%27%2C+%27a%27%2C+%27b%27%5D&amp;amp;scope=%7B%27search%27%3A+%27a%27%7D&amp;amp;v=1&quot;&gt;example&lt;/a&gt;, &lt;a href=&quot;https://glom.readthedocs.io/en/latest/api.html#the-glom-scope&quot;&gt;docs&lt;/a&gt;):&lt;/p&gt;
&lt;div class=&quot;codehilite&quot; style=&quot;background: #f8f8f8&quot;&gt;&lt;pre style=&quot;line-height: 125%;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;span style=&quot;color: #008800; font-style: italic&quot;&gt;# Make a spec that uses the T singleton to call &lt;/span&gt;
&lt;span style=&quot;color: #008800; font-style: italic&quot;&gt;# the target&#x27;s count method using the search value in the scope (S)&lt;/span&gt;
count_spec &lt;span style=&quot;color: #666666&quot;&gt;=&lt;/span&gt; T&lt;span style=&quot;color: #666666&quot;&gt;.&lt;/span&gt;count(S&lt;span style=&quot;color: #666666&quot;&gt;.&lt;/span&gt;search) 
scope &lt;span style=&quot;color: #666666&quot;&gt;=&lt;/span&gt; {&lt;span style=&quot;color: #BB4444&quot;&gt;&#x27;search&#x27;&lt;/span&gt;: &lt;span style=&quot;color: #BB4444&quot;&gt;&#x27;a&#x27;&lt;/span&gt;}  &lt;span style=&quot;color: #008800; font-style: italic&quot;&gt;# additional context we&#x27;ll pass in&lt;/span&gt;
glom([&lt;span style=&quot;color: #BB4444&quot;&gt;&#x27;a&#x27;&lt;/span&gt;, &lt;span style=&quot;color: #BB4444&quot;&gt;&#x27;c&#x27;&lt;/span&gt;, &lt;span style=&quot;color: #BB4444&quot;&gt;&#x27;a&#x27;&lt;/span&gt;, &lt;span style=&quot;color: #BB4444&quot;&gt;&#x27;b&#x27;&lt;/span&gt;], count_spec, scope&lt;span style=&quot;color: #666666&quot;&gt;=&lt;/span&gt;scope)
&lt;span style=&quot;color: #008800; font-style: italic&quot;&gt;# 2&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Here, the scope is used to pass in a &lt;code&gt;search&lt;/code&gt; parameter which will be used against the target (&lt;a href=&quot;https://glom.readthedocs.io/en/latest/api.html#object-oriented-access-and-method-calls-with-t&quot;&gt;&lt;code&gt;T&lt;/code&gt;&lt;/a&gt;).
Usage can get quite advanced, including specs that write to the scope (&lt;a href=&quot;https://yak.party/glompad/#spec=%23+save+val+to+the+scope%2C+then+build+a+new+result+dict%0A%28S%28value%3DT%5B%27data%27%5D%5B%27val%27%5D%29%2C+%7B%27result%27%3A+S%5B%27value%27%5D%7D%29&amp;amp;target=%7B%27data%27%3A+%7B%27val%27%3A+9%7D%7D&amp;amp;v=1&quot;&gt;example&lt;/a&gt;):&lt;/p&gt;
&lt;div class=&quot;codehilite&quot; style=&quot;background: #f8f8f8&quot;&gt;&lt;pre style=&quot;line-height: 125%;&quot;&gt;&lt;span&gt;&lt;/span&gt;target &lt;span style=&quot;color: #666666&quot;&gt;=&lt;/span&gt; {&lt;span style=&quot;color: #BB4444&quot;&gt;&#x27;data&#x27;&lt;/span&gt;: {&lt;span style=&quot;color: #BB4444&quot;&gt;&#x27;val&#x27;&lt;/span&gt;: &lt;span style=&quot;color: #666666&quot;&gt;9&lt;/span&gt;}}

spec &lt;span style=&quot;color: #666666&quot;&gt;=&lt;/span&gt; (S(value&lt;span style=&quot;color: #666666&quot;&gt;=&lt;/span&gt;T[&lt;span style=&quot;color: #BB4444&quot;&gt;&#x27;data&#x27;&lt;/span&gt;][&lt;span style=&quot;color: #BB4444&quot;&gt;&#x27;val&#x27;&lt;/span&gt;]), 
        {&lt;span style=&quot;color: #BB4444&quot;&gt;&#x27;result&#x27;&lt;/span&gt;: S[&lt;span style=&quot;color: #BB4444&quot;&gt;&#x27;value&#x27;&lt;/span&gt;]})

glom(target, spec)
&lt;span style=&quot;color: #008800; font-style: italic&quot;&gt;# {&#x27;result&#x27;: 9}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Here we grab &lt;code&gt;&#x27;val&#x27;&lt;/code&gt;, save it to the scope as &lt;code&gt;&#x27;value&#x27;&lt;/code&gt;, then use it to build our new result.&lt;/p&gt;
&lt;h3 id=&quot;modes&quot;&gt;&lt;a href=&quot;#modes&quot; class=&quot;toclink&quot;&gt;Modes&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;As discussed in &lt;a href=&quot;http://sedimental.org/cruising_through_data.html#pattern-matching&quot;&gt;pattern matching&lt;/a&gt; above,&lt;br /&gt;
some applications outgrew glom&#x27;s initial data transformation behavior. 
To handle these diverging behaviors, glom introduced the concept of &lt;em&gt;modes&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;Glom specs stay succinct by using Python literals, and modes allow changing the interpretation of those objects. 
Glom comes with two documented modes, the default &lt;code&gt;Auto()&lt;/code&gt; and &lt;code&gt;Match()&lt;/code&gt; (&lt;a href=&quot;https://yak.party/glompad/#spec=Auto%28%5BMatch%28int%2C+default%3DSKIP%29%5D%29&amp;amp;target=%5B1%2C+%27a%27%2C+2%2C+%27c%27%2C+%27a%27%2C+%27b%27%5D&amp;amp;v=1&quot;&gt;example&lt;/a&gt;), which can be interleaved as necessary:&lt;/p&gt;
&lt;div class=&quot;codehilite&quot; style=&quot;background: #f8f8f8&quot;&gt;&lt;pre style=&quot;line-height: 125%;&quot;&gt;&lt;span&gt;&lt;/span&gt;spec = Auto([Match(int, default=SKIP)])
target = [1, &#x27;a&#x27;, 2, &#x27;c&#x27;, &#x27;a&#x27;, &#x27;b&#x27;]
glom(target, spec)
# [1, 2]
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;We&#x27;re working on adding more. You can easily &lt;a href=&quot;https://glom.readthedocs.io/en/latest/modes.html&quot;&gt;add your own&lt;/a&gt;, too.&lt;/p&gt;
&lt;h3 id=&quot;extensions&quot;&gt;&lt;a href=&quot;#extensions&quot; class=&quot;toclink&quot;&gt;Extensions&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;We strive to make glom as widely applicable as possible, but data takes too many forms to count.
We solve this by making glom extensible in several ways:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://glom.readthedocs.io/en/latest/api.html#setup-and-registration&quot;&gt;Registering&lt;/a&gt; new target types and new operations on the target&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://glom.readthedocs.io/en/latest/custom_spec_types.html&quot;&gt;Creating new Spec types&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://glom.readthedocs.io/en/latest/modes.html&quot;&gt;Adding new modes&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;By understanding glom&#x27;s scope and &lt;a href=&quot;https://glom.readthedocs.io/en/latest/custom_spec_types.html#the-glom-scope&quot;&gt;its internals&lt;/a&gt;, 
it becomes clear that most built-in glom functionality is implemented through these public interfaces.
So while glom can feel magical at times, now you can extend glom without touching the core, 
and be a part of the magic, too. ☄️&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;Not bad for five years, and we haven&#x27;t even scratched all the surfaces, yet.
Hopefully the next showcase won&#x27;t be quite so far out. &lt;p&gt;&lt;/p&gt;



&lt;hr /&gt;

</content>

  </entry>
  
  <entry>
    <id>http://sedimental.org/intentional_creation.html</id>
    <author>
      <name>Mahmoud Hashemi</name>
      <uri>http://sedimental.org/</uri>
    </author>
    <title>Intentional Creation</title>
    <link rel="alternate" type="text/html" href="http://sedimental.org/intentional_creation.html" />
    <published>2023-01-04T08:00:00Z</published>
    <updated>2023-01-04T08:00:00Z</updated>
    <category term="python"/><category term="code"/><category term="work"/><category term="hatnote"/><category term="life"/><category term="apa"/>
    

    <content type="html">&lt;p&gt;&lt;p&gt;&lt;em&gt;Reliably tap into your creativity with the 4 Cs: Consume, critique, curate, create.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;This is one of my oldest ideas, finally published on &lt;a href=&quot;https://github.com/readme/guides/intentional-creation&quot;&gt;the GitHub ReadME Project blog&lt;/a&gt;, along with &lt;a href=&quot;https://github.com/readme/stories/mahmoud-hashemi&quot;&gt;a profile&lt;/a&gt;, in June 2022. For more like this, follow me on &lt;a href=&quot;https://twitter.com/mhashemi&quot;&gt;Twitter&lt;/a&gt; or &lt;a href=&quot;https://qoto.org/@mahmoud&quot;&gt;Mastodon&lt;/a&gt;. (You can also read it &lt;a href=&quot;http://sedimental.org/intentional_creation_zh.html&quot;&gt;in 中文 here&lt;/a&gt;. Thanks Dominic Huang!)&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;We all have creative potential. Whether it gets you up in the morning or keeps you up at night, you&#x27;ve felt its gnaw. &lt;/p&gt;
&lt;p&gt;Turning that potential into productivity can prove challenging in an internet-connected environment that offers a constant stream of consumables. How do we pick a direction? &lt;/p&gt;
&lt;p&gt;In this guide, you&#x27;ll see how to distill the elements of creativity into four deliberate stages, and how to put the process to use: &lt;/p&gt;
&lt;div class=&quot;toc&quot;&gt;&lt;span class=&quot;toctitle&quot;&gt;Contents&lt;/span&gt;&lt;ul&gt;&lt;li&gt;&lt;a href=&quot;#consume&quot;&gt;Consume&lt;/a&gt;&lt;li&gt;&lt;a href=&quot;#critique&quot;&gt;Critique&lt;/a&gt;&lt;li&gt;&lt;a href=&quot;#curate&quot;&gt;Curate&lt;/a&gt;&lt;li&gt;&lt;a href=&quot;#create&quot;&gt;Create&lt;/a&gt;&lt;ul&gt;&lt;li&gt;&lt;a href=&quot;#debugging_the_process&quot;&gt;Debugging the process&lt;/a&gt;&lt;/ul&gt;&lt;li&gt;&lt;a href=&quot;#putting_it_into_practice&quot;&gt;Putting it into practice&lt;/a&gt;&lt;/ul&gt;&lt;/div&gt;&lt;p&gt;These 4 Cs comprise a straightforward, adaptable approach that works well in both group and solo settings. You&#x27;ve already started on step 1. Read on to find out what to do next.&lt;/p&gt;
&lt;p&gt;&lt;a target=&quot;_blank&quot; href=&quot;http://sedimental.org/uploads/cccc_2019.png&quot;&gt;&lt;img title=&quot;An image of the consumption-to-creation gradient, shaped as a pyramid. CC-BY-SA.&quot; width=&quot;100%&quot; src=&quot;http://sedimental.org/uploads/cccc_gh.png&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;consume&quot;&gt;&lt;a href=&quot;#consume&quot; class=&quot;toclink&quot;&gt;Consume&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Step 1: Turn passive consumption into active research.&lt;/strong&gt; &lt;/p&gt;
&lt;p&gt;From the moment you open your eyes in the morning, you&#x27;re accosted with calls to consume. Articles, videos, podcasts, the newest Wordle variant. When consumption is the default mode of our modern computing environment, how is a builder supposed to build?&lt;/p&gt;
&lt;p&gt;To create, we must first recognize its inverse: consumption. Consumption is a useful stage, but can be dangerous if it’s terminal. An infinite loop in this stage kills any chance of creation. &lt;/p&gt;
&lt;p&gt;Little is created in a vacuum. Creation still starts with consumption, albeit consumption disarmed with an intention. Turn pure consumption into active research, punctuated with critique.&lt;/p&gt;
&lt;h2 id=&quot;critique&quot;&gt;&lt;a href=&quot;#critique&quot; class=&quot;toclink&quot;&gt;Critique&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Step 2: Capture your reactions in critiques, and research no faster than you can react.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;As with so many software problems of our day, the answer is simple: React. No, not the JavaScript framework, but the human act of reaction. Intentional creation starts with giving yourself pause on new inputs. Seek a reaction from yourself. A semi-structured reaction, or critique, is a time-honored practice in creative fields, like architecture.&lt;/p&gt;
&lt;p&gt;Infinite scroll may prove challenging to overcome, but before turning your consideration to the next item in your feed, activate your critical senses. Draw some conclusions. Even unvetted, they&#x27;re yours. &lt;/p&gt;
&lt;p&gt;If you&#x27;re finding it hard to summon a critique, this is a clear sign you&#x27;re consuming faster than you can reflect. If you&#x27;re not reflecting, you&#x27;re not learning. You may need to go deeper on individual items, or just take a break.&lt;/p&gt;
&lt;p&gt;Your critiques have never been easier to capture, whether typed in markdown, dictated to automatic transcription, or written down in a notepad on your desk. Try opening your editor or critique tool before opening any new resources. Feel free to open one now. &lt;/p&gt;
&lt;p&gt;&lt;/p&gt;&lt;center&gt;&lt;big&gt;&lt;em&gt;If you&#x27;re not reflecting, you&#x27;re not learning.&lt;/em&gt;&lt;/big&gt;&lt;/center&gt;&lt;p&gt;&lt;/p&gt;
&lt;h2 id=&quot;curate&quot;&gt;&lt;a href=&quot;#curate&quot; class=&quot;toclink&quot;&gt;Curate&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Step 3: Curate critiques into collections that act as reservoirs of creative reference.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Critiques are only proto-creative output. Writing anything helps prime the creative pump, but criticism is raw reaction. You want a refined synthesis. Once you&#x27;ve got enough critiques under your belt, curate the positive examples into a collection. &lt;/p&gt;
&lt;p&gt;From interior designers to lab researchers to club DJs, creators recognize the value of a structured, referenceable collection. Sometimes a situation calls for urgency or direction, and an organized, well-researched collection can offer an existing solution. Sometimes, in the context of a comprehensive collection, the lack of a referenceable solution is itself a signal that it&#x27;s time to invent.&lt;/p&gt;
&lt;p&gt;Curated collections become artifacts unto themselves. I&#x27;ve helped create a few, including &lt;a href=&quot;https://0ver.org/&quot;&gt;0ver.org&lt;/a&gt;, &lt;a href=&quot;https://seealso.org/&quot;&gt;seealso.org&lt;/a&gt;, and &lt;a href=&quot;https://github.com/mahmoud/awesome-python-applications&quot;&gt;the Awesome Python Applications list&lt;/a&gt;. There’s more awesome out there beyond &lt;a href=&quot;https://github.com/sindresorhus/awesome&quot;&gt;Awesome Lists&lt;/a&gt;, like &lt;a href=&quot;https://explorabl.es/&quot;&gt;explorabl.es&lt;/a&gt;, the &lt;a href=&quot;https://cooperpress.com/publications/&quot;&gt;Cooperpress newsletters&lt;/a&gt;, or &lt;a href=&quot;https://en.wikipedia.org/wiki/Swipe_file&quot;&gt;the “swipe file” phenomenon&lt;/a&gt; used among designers and content creators. There&#x27;s respectable work in curation. Still, curation is more important as a stepping stone to our original higher calling. Less is more.&lt;/p&gt;
&lt;h2 id=&quot;create&quot;&gt;&lt;a href=&quot;#create&quot; class=&quot;toclink&quot;&gt;Create&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Step 4: Return to your curations regularly to discover your creative path forward.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Collections of a certain size tend to produce interesting findings. Patterns and gaps emerge that inspire creative next steps. As an example, while researching approaches to Python packaging, a pattern emerged that led to one of my most popular concepts/blog posts/talks, &lt;a href=&quot;https://sedimental.org/the_packaging_gradient.html&quot;&gt;The Packaging Gradient&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Whole projects can be born out of connections made with collections. My framework &lt;a href=&quot;http://github.com/mahmoud/clastic&quot;&gt;Clastic&lt;/a&gt;, which was eventually used by teams at PayPal and &lt;a href=&quot;https://www.wikilovesmonuments.org&quot;&gt;Wiki Loves Monuments&lt;/a&gt;, came out of the curated combination of &lt;a href=&quot;http://pytest.org/&quot;&gt;pytest&lt;/a&gt; dependency-injection semantics with &lt;a href=&quot;https://werkzeug.palletsprojects.com/&quot;&gt;werkzeug&lt;/a&gt; primitives.&lt;/p&gt;
&lt;p&gt;Realistically, the majority of creation happens below the threshold of standalone artifacts. For instance, when adding a feature to an existing system, a parallel approach in a different project serves as a useful guide. I&#x27;ve lost track of the number of times I&#x27;ve swiped techniques from Awesome Python Applications, including ones used to &lt;a href=&quot;http://sedimental.org/tech_refresh.html&quot;&gt;port my dayjob&#x27;s 300k SLOC codebase from Python 2 to 3&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Most creative outputs have a similar lineage. Only now we have an explicit process.&lt;/p&gt;
&lt;h3 id=&quot;debugging_the_process&quot;&gt;&lt;a href=&quot;#debugging_the_process&quot; class=&quot;toclink&quot;&gt;Debugging the process&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;It&#x27;s easy to see creations we appreciate as towering achievements that sprung fully-formed from their creators&#x27; genius. But creation comes in fits and starts. If creation comes slowly, here are a few strategies to consider: &lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Search for a natural split in an existing collection that&#x27;s getting too big, and explore what makes it interesting. &lt;/li&gt;
&lt;li&gt;Revisit an old, contentious critique and re-react. What did you get right/wrong?&lt;/li&gt;
&lt;li&gt;Pick a particular exemplar and turn it into a case study. One beautiful aspect of FOSS projects is that going deep can mean getting involved. There&#x27;s nothing like proximity to a problem to inspire creative thinking.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;More generally, be wary of one-size-fits-all solutions; while prescriptive techniques such as &lt;a href=&quot;https://zettelkasten.de/&quot;&gt;the Zettelkasten Method&lt;/a&gt; may work for some, creation is idiosyncratic. Embrace your own process.&lt;/p&gt;
&lt;h2 id=&quot;putting_it_into_practice&quot;&gt;&lt;a href=&quot;#putting_it_into_practice&quot; class=&quot;toclink&quot;&gt;Putting it into practice&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;When inspiration hits, connections can form so quickly that we take for granted what goes on. When inspiration proves less willing to strike, we can keep ourselves primed for creativity by ensuring all four activities continue in balance.&lt;/p&gt;
&lt;p&gt;There are a few notable benefits of intentional creation:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;When you&#x27;ve built something, the influences are well-documented. It can be easier to involve others when there&#x27;s a clear creative thread to pull on.&lt;/li&gt;
&lt;li&gt;Sharing your critiques and curations invites collaboration with other creators and curators. &lt;/li&gt;
&lt;li&gt;Self-awareness. If you&#x27;re not finding your critiques crystallizing into new thoughts and ideas for projects, that&#x27;s a sign you&#x27;re looking at the wrong stuff. Are you following your interests or passively consuming trending content?&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Practically, intentional creation means consciously spending less time on consumer sites, from Twitter to Hacker News, and more time taking notes, tagging bookmarks, and creating your own knowledge base. Attempt activities that are less entertainment and more you, ultimately closing the gap between you and your creative goals.&lt;/p&gt;
&lt;p&gt;If it sounds too simple, that&#x27;s because it is. You&#x27;re still accountable to you, that&#x27;s the hard part. But hopefully you&#x27;ll find some value in this simple hierarchy that lets you check in on your own activities and make adjustments toward a more creative end. Spend less time consuming, and more time on the other three Cs. Consume only enough to allow yourself to critique, curate, and create.&lt;/p&gt;
&lt;p&gt;If you made it this far, then start now. Step 2. Use any tool or service you like, from &lt;a href=&quot;https://docs.google.com/spreadsheets/d/1Vvrnp83PDkIGKq6pYJqPGf99xqRn8Cg4MJiTGOxgS0U/edit#gid=1010469400&quot;&gt;spreadsheets&lt;/a&gt; to &lt;a href=&quot;https://github.com/mahmoud/awesome-python-applications/blob/master/projects.yaml&quot;&gt;YAML&lt;/a&gt;, and answer this: What&#x27;s your critique? &lt;p&gt;&lt;/p&gt;



&lt;hr /&gt;

</content>

  </entry>
  
  <entry>
    <id>http://sedimental.org/tech_refresh.html</id>
    <author>
      <name>Mahmoud Hashemi</name>
      <uri>http://sedimental.org/</uri>
    </author>
    <title>Changing the Tires on a Moving Codebase</title>
    <link rel="alternate" type="text/html" href="http://sedimental.org/tech_refresh.html" />
    <published>2021-03-10T16:30:00Z</published>
    <updated>2021-03-10T16:30:00Z</updated>
    <category term="python"/><category term="code"/><category term="work"/>
    

    <content type="html">&lt;p&gt;&lt;p&gt;&lt;em&gt;2020 was a year of reckonings. And for all that was beyond one’s
control, as the year went on, I found myself pouring more and more
into the one thing that felt within reach: futureproofing of the large
enterprise web application I helped build,
&lt;a href=&quot;https://simplelegal.com&quot;&gt;SimpleLegal&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Now complete, this replatforming easily ranks in my most complex
projects, and right now, holds the top spot for the happiest
ending. That happiness comes at a cost, but with some the right
approach that cost may not be as high as you think.&lt;/em&gt;&lt;/p&gt;
&lt;div class=&quot;toc&quot;&gt;&lt;span class=&quot;toctitle&quot;&gt;Contents&lt;/span&gt;&lt;ul&gt;&lt;li&gt;&lt;a href=&quot;#the_bottom_line&quot;&gt;The Bottom Line&lt;/a&gt;&lt;li&gt;&lt;a href=&quot;#the_setup&quot;&gt;The Setup&lt;/a&gt;&lt;li&gt;&lt;a href=&quot;#the_outset&quot;&gt;The Outset&lt;/a&gt;&lt;li&gt;&lt;a href=&quot;#the_traction_issues&quot;&gt;The Traction Issues&lt;/a&gt;&lt;li&gt;&lt;a href=&quot;#the_sentry_pivot&quot;&gt;The Sentry Pivot&lt;/a&gt;&lt;li&gt;&lt;a href=&quot;#the_new_road&quot;&gt;The New Road&lt;/a&gt;&lt;ul&gt;&lt;li&gt;&lt;a href=&quot;#committing_to_transactions&quot;&gt;Committing to transactions&lt;/a&gt;&lt;ul&gt;&lt;li&gt;&lt;a href=&quot;#the_truly_atomic_request&quot;&gt;The truly atomic request&lt;/a&gt;&lt;li&gt;&lt;a href=&quot;#transactional_test_setup&quot;&gt;Transactional test setup&lt;/a&gt;&lt;/ul&gt;&lt;li&gt;&lt;a href=&quot;#better_than_best_practices&quot;&gt;Better than best practices&lt;/a&gt;&lt;ul&gt;&lt;li&gt;&lt;a href=&quot;#the_utility_of_namespaces&quot;&gt;The utility of namespaces&lt;/a&gt;&lt;li&gt;&lt;a href=&quot;#coverage_tools&quot;&gt;Coverage tools&lt;/a&gt;&lt;li&gt;&lt;a href=&quot;#flattening_database_migrations&quot;&gt;Flattening database migrations&lt;/a&gt;&lt;/ul&gt;&lt;li&gt;&lt;a href=&quot;#easing_onto_the_stack&quot;&gt;Easing onto the stack&lt;/a&gt;&lt;/ul&gt;&lt;li&gt;&lt;a href=&quot;#the_rollout&quot;&gt;The Rollout&lt;/a&gt;&lt;li&gt;&lt;a href=&quot;#the_aftermath&quot;&gt;The Aftermath&lt;/a&gt;&lt;/ul&gt;&lt;/div&gt;&lt;h2 id=&quot;the_bottom_line&quot;&gt;&lt;a href=&quot;#the_bottom_line&quot; class=&quot;toclink&quot;&gt;The Bottom Line&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;We took &lt;a href=&quot;https://simplelegal.com&quot;&gt;SimpleLegal&lt;/a&gt;’s primary product, a
300,000 line Django-1.11-Python 2.7-Redis-Postgres-10 codebase, to a
Django 2.2-Python 3.8-Postgres-12 stack, on-schedule and without major
site incidents. And it feels amazing.&lt;/p&gt;
&lt;p&gt;Speaking as tech lead on the project, what did it look like? For me,
something like this:&lt;/p&gt;
&lt;p&gt;&lt;img width=&quot;100%&quot; src=&quot;http://sedimental.org/uploads/tr_img/2020_commit_graph.png&quot; title=&quot;You can see the last vestiges of normal all the way on the left.&quot; /&gt;&lt;/p&gt;
&lt;p&gt;But as Director of Engineering, what did it cost? &lt;strong&gt;3.5 dev years&lt;/strong&gt;
and just about &lt;strong&gt;$2 per line of code&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;And I&#x27;m especially proud of that result, because along the way, we
also substantially improved the speed and reliability of both the site
and development process itself. The product now has a bright future
ahead, ready to shine in sales RFPs and compliance
questionnaires. Most importantly, there’ll be no worrying about when
to delicately break it to a candidate that they’ll be working with
unsupported technology.&lt;/p&gt;
&lt;p&gt;In short, a large, solid investment that’s already paying for
itself. If you just came here for the estimate we wish we had, you&#x27;ve
got it. This post is all about how your team can achieve the same
result, if not better.&lt;/p&gt;
&lt;h2 id=&quot;the_setup&quot;&gt;&lt;a href=&quot;#the_setup&quot; class=&quot;toclink&quot;&gt;The Setup&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The story begins in 2013, when a freshly YC-incubated SimpleLegal made
all the right decisions for a new SaaS LegalTech company: Python,
Django, Postgres, Redis. In classic startup fashion, features came
first, unless technology was a blocker. Packages were only upgraded
incidentally.&lt;/p&gt;
&lt;p&gt;&lt;img width=&quot;40%&quot; src=&quot;http://sedimental.org/uploads/tr_img/tech_debt.png&quot; align=&quot;right&quot; title=&quot;Masks are effective, except when it comes to dusty code.&quot; /&gt;&lt;/p&gt;
&lt;p&gt;By 2019, the end of this technical runway had drawn near. While Python
2 may be getting extended support from various vendors, there were
precious few volunteers in sight to do Django 1 CVE patches in 2021. A
web framework’s a riskier attack surface, so we finally had our
compliance forcing function, and it was time to pay off our tech debt.&lt;/p&gt;
&lt;h2 id=&quot;the_outset&quot;&gt;&lt;a href=&quot;#the_outset&quot; class=&quot;toclink&quot;&gt;The Outset&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;So began our Tech Refresh replatforming initiative, in Q4 2019. The
goal: Upgrade the stack while still shipping features, like changing
the tires of a moving car. We wanted to do it carefully, and that
would take time. Here are some helpful ground rules for long-running
projects:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Any project that gets worked on 10+ hours per week deserves a
   30-minute weekly sync.&lt;/li&gt;
&lt;li&gt;Every recurring meeting deserves a log. Put it in the invite. Use
   that Project Log to record progress, blockers, and decisions.&lt;/li&gt;
&lt;li&gt;It’s a marathon, not a sprint. Avoid relying on working nights,
   weekends, and holidays.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;We started with a sketch of a plan that, generously interpreted, ended
up being about halfway correct. Some early guesses that turned into
successes:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Move to &lt;a href=&quot;https://github.com/jazzband/pip-tools&quot;&gt;pip-tools&lt;/a&gt; and
   unpin dependencies based on extensive changelog analysis. Identify
   packages without py23 compatible versions. (Though we’ve since
   moved to &lt;a href=&quot;https://github.com/python-poetry/poetry&quot;&gt;poetry&lt;/a&gt;.)&lt;/li&gt;
&lt;li&gt;Add line coverage reporting to CI&lt;/li&gt;
&lt;li&gt;Revamp internal testing framework to allow devs to quickly write tests&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;More on these below. Other plans weren’t so realistic:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Take our CI from ~60% to 95% line coverage in 6 months&lt;/li&gt;
&lt;li&gt;Parallelized conversion of app packages over the course of 3 months&lt;/li&gt;
&lt;li&gt;Use low traffic times around USA holidays (Thanksgiving, Christmas,
   New Years) to gradually roll onto the new app before 2021.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;We were young! As naïve as we were, at least we knew it would be a lot
of work. To help shoulder the burden, we scouted, hired, and trained
three dedicated off-shore developers.&lt;/p&gt;
&lt;h2 id=&quot;the_traction_issues&quot;&gt;&lt;a href=&quot;#the_traction_issues&quot; class=&quot;toclink&quot;&gt;The Traction Issues&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Even with added developers, by mid-2020 it was becoming obvious we
were dreaming about 95% coverage, let alone 100%. Total coverage may
be best practice, but 3.5 developers couldn’t cover enough ground. We
were getting valuable tests, and even finding old bugs, but if we
stuck with the letter of the plan, Django 2 would end up being a 2022
project. At 70%, we decided it was time to pivot.&lt;/p&gt;
&lt;p&gt;We realized that CI is more sensitive than most users for most of the
site. So we focused in on testing the highest impact code. What’s
high-impact? 1) the code that fails most visibly and 2) the code
that’s hardest to retry. You can build an inventory of high-impact
code in under a week by looking at traffic stats, batch job schedules,
and asking your support staff.&lt;/p&gt;
&lt;p&gt;Around 80% of the codebase falls outside that high-traffic/high-impact
list. What to do about that 80%? Lean in on error detection and fast
time-to-fix.&lt;/p&gt;
&lt;h2 id=&quot;the_sentry_pivot&quot;&gt;&lt;a href=&quot;#the_sentry_pivot&quot; class=&quot;toclink&quot;&gt;The Sentry Pivot&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;img width=&quot;25%&quot; src=&quot;http://sedimental.org/uploads/tr_img/magnifyingglass.png&quot; align=&quot;right&quot; title=&quot;You haven&#x27;t seen your code until you&#x27;ve seen it in a stack trace.&quot; /&gt;&lt;/p&gt;
&lt;p&gt;One nice thing about startup life is that it’s easy to try new
tools. One practice we’ve embraced at SimpleLegal is to reserve every
5th week for developers to work on the development process itself,
like a coordinated 20% time. Even the best chef can’t cook five-star
food in a messy kitchen. This was our way of cleaning up the shop and
ultimately speeding up the ship.&lt;/p&gt;
&lt;p&gt;During one such period, someone had the genius idea to add dedicated
error reporting to the system, using
&lt;a href=&quot;https://sentry.io/&quot;&gt;Sentry&lt;/a&gt;. Within a day or two, we had a site you
could visit and get stack traces. It was pretty magical, and it wasn’t
until Tech Refresh that we realized that while integration takes one
dev-day, full adoption can take a team months.&lt;/p&gt;
&lt;p&gt;You see, adding Sentry to a mature-but-fast-moving system means one
thing: noise. Our live site was erroring all the time. Most errors
weren’t visible or didn’t block users, who in some cases had quietly
learned to work around longstanding site quirks. Pretty quickly, our
developers learned to treat Sentry as a repository of debugging
information. A Sentry event on its own wasn’t something to be taken
seriously in 2019. That changed in 2020, with the team responsible for
delivering a seamless replatform needing Sentry to be something else:
a responsive site quality tool.&lt;/p&gt;
&lt;p&gt;How did we get there? First step, enhance the data flowing into Sentry
by following &lt;a href=&quot;https://docs.sentry.io/product/sentry-basics/guides/getting-started/#-how-many-projects-should-i-create&quot;&gt;these best
practices&lt;/a&gt;:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Split up your products into
   &lt;a href=&quot;https://docs.sentry.io/product/sentry-basics/guides/getting-started/#-how-many-projects-should-i-create&quot;&gt;separate Sentry projects&lt;/a&gt;. This includes your frontend and backend.&lt;/li&gt;
&lt;li&gt;Tag your releases. Don’t tag dev env deployments with the branch,
   it clutters up the Releases UI. Add a separate branch tag for
   searches.&lt;/li&gt;
&lt;li&gt;Split up your environments. This is critical for directing
   alerts. Our Sentry client environment is configured by domain
   conventions and Django’s &lt;a href=&quot;https://docs.djangoproject.com/en/3.1/ref/contrib/sites/&quot;&gt;sites
   framework&lt;/a&gt;. If it helps, here&#x27;s
   a baseline, we use these environments:&lt;ul&gt;
&lt;li&gt;Production: Current official release. DevOps monitored.&lt;/li&gt;
&lt;li&gt;Sandbox: Current official release (some companies do next
  release). Used by customers to test changes. DevOps monitored.&lt;/li&gt;
&lt;li&gt;Demo/Sales: Previous official release. Mostly internal traffic,
  but external visibility at prospect demo time. DevOps monitored.&lt;/li&gt;
&lt;li&gt;Canary: Next official release. Otherwise known as
  staging. Internal traffic. Dev monitored.&lt;/li&gt;
&lt;li&gt;ProdQA: Current official release. Used internally to reproduce
  support issues. Dev monitored.&lt;/li&gt;
&lt;li&gt;QA: Dev branches, dev release, internal traffic. Unmonitored
  debugging data.&lt;/li&gt;
&lt;li&gt;Local test/CI: Not published to Sentry by default.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;With issues finally properly tagged and searchable, we used Sentry’s
new &lt;a href=&quot;https://docs.sentry.io/product/discover-queries/&quot;&gt;Discover tool&lt;/a&gt;
to export issues weekly, and prioritize legacy errors. To start, we
focused on high-visibility production errors with non-internal human
users. Our specific query: &lt;code&gt;has:user !transaction:/api/*
event.type:error !user.username:*@simplelegal.*&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;We triaged into 4 categories: Quick fix (minor bug), Quick error (turn
an opaque 500 error into a actionable 400 of some form),
&lt;a href=&quot;http://agiledictionary.com/209/spike/&quot;&gt;Spike&lt;/a&gt; (larger bug, requires
research), and Silence (using Sentry’s ignore feature). Over 6 weeks
we went from over 2500 weekly events down to less than 500.&lt;/p&gt;
&lt;p&gt;Further efforts have gotten us under 100 events per week, spread
across a handful of issues, which is more than manageable for even a
lean team. While &quot;Sentry Zero&quot; remains the ideal, we achieved and
maintained the real goal of a responsive flow, in large part thanks to
&lt;a href=&quot;https://sentry.io/integrations/slack/&quot;&gt;the Slack integration&lt;/a&gt;. Our
team no longer hears about server errors from our Support team. In
fact, these days, we let them know when a client is having trouble and
we’ve got a ticket underway.&lt;/p&gt;
&lt;p&gt;And it really is important to develop close ties with your support
team. Embedded in our strategy above was that CI is much more
sensitive than a real user. While perfection is tempting, it’s not
unrealistic to ask a bit of patience from an enterprise user, provided
your support team is prepared. Sync with them weekly so surprise is
minimized. If they’re feeling ambitious, you can teach them some
Sentry basics, too.&lt;/p&gt;
&lt;h2 id=&quot;the_new_road&quot;&gt;&lt;a href=&quot;#the_new_road&quot; class=&quot;toclink&quot;&gt;The New Road&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;img width=&quot;28%&quot; src=&quot;http://sedimental.org/uploads/tr_img/tachometer.png&quot; align=&quot;right&quot; title=&quot;Pedal to the metal.&quot; /&gt;&lt;/p&gt;
&lt;p&gt;With noise virtually eliminated, we were ready to move fast. While the
lean-in on fast-fixing Sentry issues was necessary, a strong reactive
game is only useful if there are proactive changes being
pushed. Here are some highlights we learned when making those changes:&lt;/p&gt;
&lt;h3 id=&quot;committing_to_transactions&quot;&gt;&lt;a href=&quot;#committing_to_transactions&quot; class=&quot;toclink&quot;&gt;Committing to transactions&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Used properly, rollbacks can make it like errors never happened, the
perfect complement to a fast-fix strategy.&lt;/p&gt;
&lt;h4 id=&quot;the_truly_atomic_request&quot;&gt;&lt;a href=&quot;#the_truly_atomic_request&quot; class=&quot;toclink&quot;&gt;The truly atomic request&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;Get as much as possible into the transactions. Turn on
&lt;a href=&quot;https://docs.djangoproject.com/en/3.1/topics/db/transactions/#tying-transactions-to-http-requests&quot;&gt;ATOMIC_REQUESTS&lt;/a&gt;,
if you haven’t already. Some requests do more than change the
database, though, like sending notifications and enqueuing background
tasks.&lt;/p&gt;
&lt;p&gt;At SimpleLegal, we rearchitected to defer all side effects (except
logging) until a successful response was being returned. Middleware
can help, but mainly we achieved this by getting rid of our Redis
queue, and switching to a PostgreSQL-backed task queue/broker. This
arrangement ensures that if an error occurs, the transaction is rolled
back, no tasks are enqueued, and the user gets a clean failure. We
spot the breakage in Sentry, toggle over to the old site to unblock,
and their next retry succeeds.&lt;/p&gt;
&lt;h4 id=&quot;transactional_test_setup&quot;&gt;&lt;a href=&quot;#transactional_test_setup&quot; class=&quot;toclink&quot;&gt;Transactional test setup&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;Transactionality also proved key to our testing strategy. SimpleLegal
had long outgrown Django’s primitive fixture system. Most tests
required complex Python to set up, making tests slow to write and slow
to run. To speed up both writing and running, we wrapped the whole
test session in a transaction, then, before any test cases run, we set
up exemplary base states. Test cases used these base states as
&lt;a href=&quot;https://docs.pytest.org/en/stable/fixture.html&quot;&gt;fixtures&lt;/a&gt;, and rolled
back to the base state after every test case. See &lt;a href=&quot;https://gist.github.com/mahmoud/10f6b6b0a9c5860030693357124131df&quot;&gt;this conftest.py
excerpt&lt;/a&gt;
for details.&lt;/p&gt;
&lt;h3 id=&quot;better_than_best_practices&quot;&gt;&lt;a href=&quot;#better_than_best_practices&quot; class=&quot;toclink&quot;&gt;Better than best practices&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Software scenarios vary so widely, there’s an art to knowing which
advice isn’t for you. Here’s an assortment of cul de sacs we learned
about firsthand.&lt;/p&gt;
&lt;h4 id=&quot;the_utility_of_namespaces&quot;&gt;&lt;a href=&quot;#the_utility_of_namespaces&quot; class=&quot;toclink&quot;&gt;The utility of namespaces&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;Given how code is divided into modules, packages, Django apps, etc.,
it may be tempting to treat those as units of work. Don’t start
there. Code divisions can be pretty arbitrary, and it’s hard to know
when you’ve pulled on a risky thread.&lt;/p&gt;
&lt;p&gt;Assuming there are automated refactorings, as in &lt;a href=&quot;https://portingguide.readthedocs.io/en/latest/&quot;&gt;a 2to3
conversion&lt;/a&gt;, start by
porting by type of transformation. That way, one need only review a
command and a list of paths affected. Plus, automated fixes
necessarily follow a pattern, meaning more people can fix bugs arising
from the refactor.&lt;/p&gt;
&lt;h4 id=&quot;coverage_tools&quot;&gt;&lt;a href=&quot;#coverage_tools&quot; class=&quot;toclink&quot;&gt;Coverage tools&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;&lt;img width=&quot;25%&quot; src=&quot;http://sedimental.org/uploads/tr_img/scantron.png&quot; align=&quot;right&quot; title=&quot;Grade those tests carefully.&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Coverage was a mixed bag for us. Obviously our coverage-first strategy
wasn’t tenable, but it was still useful for prioritization and status
checks. On a per-change basis, we found coverage tools to be somewhat
unreliable. We never got to the bottom of why coverage acted
nondeterministically, and we left the conclusion at, “off-the-shelf
tools like codecov are probably not targeted at monorepos of our
scale.”&lt;/p&gt;
&lt;p&gt;In running into coverage walls, we ended up exploring many other
interpretations of coverage. For us, much higher-priority than line
coverage were “route coverage” (i.e., every URL has at least one
integration test) and “model repr coverage” (i.e., every model object
had a useful text representation, useful for debugging in
Sentry). With more time, we would have liked to build tools around
those, and even around online-profiling based coverage statistics, to
prioritize the highest traffic lines, not just the highest traffic
routes. If you’ve heard of approaches to these ends, we’d love to
discuss them with you.&lt;/p&gt;
&lt;h4 id=&quot;flattening_database_migrations&quot;&gt;&lt;a href=&quot;#flattening_database_migrations&quot; class=&quot;toclink&quot;&gt;Flattening database migrations&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;On the surface, reducing the number of files we needed to upgrade
seems logical. Turns out, flattening
&lt;a href=&quot;https://docs.djangoproject.com/en/3.1/topics/migrations/&quot;&gt;migrations&lt;/a&gt;
is a low-payoff strategy to get rid of files. Changing historical
migration file structure complicated our rollout, while upgrading
migrations we didn’t flatten was straightforward. Not to mention, if
you just wanted the CI speedup, you can take the same page from &lt;a href=&quot;https://openedx.atlassian.net/wiki/spaces/AC/pages/23003228/Everything+About+Database+Migrations#EverythingAboutDatabaseMigrations-SquashingMigrations&quot;&gt;the
Open EdX
Platform&lt;/a&gt;
that we did: &lt;a href=&quot;https://github.com/edx/edx-platform/blob/66f0f9891f00994f77604a51dbb29736aa605fa8/scripts/reset-test-db.sh#L75&quot;&gt;build a base DB cache that you check in every couple
months&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Turns out, &lt;a href=&quot;https://sedimental.org/awesome_python_applications.html#goal-1-a-better-development-cycle&quot;&gt;you can learn a lot from open-source
applications&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&quot;easing_onto_the_stack&quot;&gt;&lt;a href=&quot;#easing_onto_the_stack&quot; class=&quot;toclink&quot;&gt;Easing onto the stack&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;If you have more than one application, use the smaller, simpler
application to pilot changes. We were lucky enough to have a separate
app whose tests ran faster, making for a tighter development loop we
coul learn from. Likewise, if you have more than one production
environment, start rollouts with the one with the least impact.&lt;/p&gt;
&lt;p&gt;Clone your CI jobs for the new stack, too. They’ll all fail, but
resist the urge to mark them as optional. Instead, build a single-file
inventory of all tests and their current testing state. We built a
small extension for our test runner,
&lt;a href=&quot;https://docs.pytest.org/en/stable/&quot;&gt;pytest&lt;/a&gt;, which bulk skipped tests
based on a status inventory file. Then, ratchet: unskip and fix a
test, update the file, check that tests pass, and repeat. Much more
convenient and scannable than &lt;a href=&quot;https://docs.pytest.org/en/latest/skipping.html#skipping-test-functions&quot;&gt;pytest
mark&lt;/a&gt;
decorators spread throughout the codebase. See &lt;a href=&quot;https://gist.github.com/mahmoud/10f6b6b0a9c5860030693357124131df&quot;&gt;this conftest.py
excerpt&lt;/a&gt;
for details.&lt;/p&gt;
&lt;h2 id=&quot;the_rollout&quot;&gt;&lt;a href=&quot;#the_rollout&quot; class=&quot;toclink&quot;&gt;The Rollout&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;In Q4 2020, we doubled up on infrastructure to run the old and new
sites in parallel, backed by the same database. We got into a loop of
enabling traffic to the new stack, building a queue of Sentry issues
to fix, and switching it back off, while tracking the time. After
around 120 hours of new stack, strategically spread around the clock
and week, enough organizational confidence had been built that we
could leave the site on during our most critical hours: Mondays and
Tuesdays at the beginning of the month.&lt;/p&gt;
&lt;p&gt;The sole hiccup was &lt;a href=&quot;https://www.zdnet.com/article/aws-outage-impacts-thousands-of-online-services/&quot;&gt;an AWS
outage&lt;/a&gt;
Thanksgiving week. At this point we were ahead of schedule, and enough
confidence had been built in our fast-fix workflow that we didn’t need
our original holiday testing windows. And for that, many thanks were given.&lt;/p&gt;
&lt;p&gt;We kept at the fast-fix crank until we were done. Done isn&#x27;t when the
new system has no errors, it&#x27;s when traffic on the new system has
fewer events than the old system. Then, fix forward, and start
scheduling time to delete the scaffolding.&lt;/p&gt;
&lt;p&gt;&lt;img width=&quot;60%&quot; src=&quot;http://sedimental.org/uploads/tr_img/baton.png&quot; title=&quot;Finally, that tired old stack can rest.&quot; /&gt;&lt;/p&gt;
&lt;h2 id=&quot;the_aftermath&quot;&gt;&lt;a href=&quot;#the_aftermath&quot; class=&quot;toclink&quot;&gt;The Aftermath&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;So, once you’re on current LTS versions of Django, Python, Linux, and
Postgres, job complete, right?&lt;/p&gt;
&lt;p&gt;Thankfully, tech debt never quite hits 0. While updating and replacing
core technologies on a schedule is no small feat, replacing a rusty
part with a shiny one doesn’t change a design. Architectural tech debt
-- mistakes in abstractions, including the lack thereof -- can present
an even greater challenge. Solutions to those problems don’t
generalize between projects as cleanly, but they do benefit from
up-to-date and error-free foundations.&lt;/p&gt;
&lt;p&gt;For all the projects looking to add tread to their technical tires, we
hope this retrospective helps you confidently and pragmatically
retrofit your stack for years to come.&lt;/p&gt;
&lt;p&gt;Finally, big thanks to &lt;a href=&quot;https://uvik.net/&quot;&gt;Uvik&lt;/a&gt; for the talent
connection, and the talent: &lt;a href=&quot;https://github.com/ypankovych&quot;&gt;Yaroslav&lt;/a&gt;,
&lt;a href=&quot;https://github.com/skhortiuk&quot;&gt;Serhii&lt;/a&gt;, and Oleh. Shoutouts to
&lt;a href=&quot;https://github.com/kurtbrose/&quot;&gt;Kurt&lt;/a&gt;,
&lt;a href=&quot;https://github.com/justinvanwinkle&quot;&gt;Justin&lt;/a&gt;, and Chris, my fellow
leads. And the cheers to business leadership at SimpleLegal and
everywhere, for seeing the value in maintainability.&lt;p&gt;&lt;/p&gt;



&lt;hr /&gt;

</content>

  </entry>
  
  <entry>
    <id>http://sedimental.org/thanks_201x.html</id>
    <author>
      <name>Mahmoud Hashemi</name>
      <uri>http://sedimental.org/</uri>
    </author>
    <title>Thanks, 201X!</title>
    <link rel="alternate" type="text/html" href="http://sedimental.org/thanks_201x.html" />
    <published>2019-12-02T18:00:00Z</published>
    <updated>2019-12-02T18:00:00Z</updated>
    <category term="life"/><category term="work"/><category term="python"/>
    

    <content type="html">&lt;p&gt;&lt;p&gt;&lt;em&gt;Thought I&#x27;d take a Sunday afternoon to reflect on, oh I don&#x27;t know, a decade.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;img align=&quot;right&quot; width=&quot;40%&quot; src=&quot;http://sedimental.org/uploads/illo/legatree_med.png&quot; /&gt;
Been a long ten years, but it&#x27;s flown past. This particular decade
happens to coincide with my first years of full-time professional
software engineering.&lt;/p&gt;
&lt;h2 id=&quot;the_quantity&quot;&gt;&lt;a href=&quot;#the_quantity&quot; class=&quot;toclink&quot;&gt;The Quantity&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;I can&#x27;t possibly summarize it all, and if I tried, it&#x27;d still be
colored by what&#x27;s on my mind right now. But I can point to the
artifacts I tried to leave along the way:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://twitter.com/mhashemi&quot;&gt;Twitter&lt;/a&gt; FWIW&lt;sup id=&quot;fnref:1&quot;&gt;&lt;a class=&quot;footnote-ref&quot; href=&quot;http://sedimental.org/thanks_201x.html#fn:1&quot;&gt;1&lt;/a&gt;&lt;/sup&gt; (2008+)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;~20&lt;/strong&gt; &lt;a href=&quot;http://sedimental.org/open_source_projects.html&quot;&gt;Open-Source Projects&lt;/a&gt; (2012+)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;~15&lt;/strong&gt; &lt;a href=&quot;http://sedimental.org/hatnote_projects.html&quot;&gt;Hatnote Projects&lt;/a&gt; (2013+, &lt;a href=&quot;https://twitter.com/hatnotable&quot;&gt;follow us&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;~25&lt;/strong&gt; entries on this blog (2015+)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;+7&lt;/strong&gt; &lt;a href=&quot;https://medium.com/paypal-tech/search?q=python&quot;&gt;here&lt;/a&gt; (2014-2016)&lt;/li&gt;
&lt;li&gt;Not including &lt;a href=&quot;https://www.pythondoeswhat.com/&quot;&gt;pythondoeswhat.com&lt;/a&gt; or &lt;a href=&quot;https://blog.hatnote.com/&quot;&gt;blog.hatnote.com&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;(or other posts on the blogs only real heads know)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;~10&lt;/strong&gt; &lt;a href=&quot;http://sedimental.org/talks.html&quot;&gt;Talks&lt;/a&gt; (2016+)&lt;/li&gt;
&lt;li&gt;Lest I forget: &lt;a href=&quot;http://shop.oreilly.com/product/0636920047346.do?code=authd&quot;&gt;O&#x27;Reilly&#x27;s Enterprise Software with Python&lt;/a&gt; (2016)&lt;/li&gt;
&lt;li&gt;And &lt;a href=&quot;http://sedimental.org/appearances.html&quot;&gt;several podcast/media appearances&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://calver.org/&quot;&gt;calver.org&lt;/a&gt; (2016) and &lt;a href=&quot;https://0ver.org/&quot;&gt;0ver.org&lt;/a&gt; (2018) (Versioning is a fun pastime)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://pyninsula.org/&quot;&gt;Pyninsula&lt;/a&gt; (2017+) - &lt;a href=&quot;https://www.youtube.com/c/Pyninsula&quot;&gt;YouTube&lt;/a&gt;, &lt;a href=&quot;https://www.meetup.com/Pyninsula-Python-Peninsula-Meetup/&quot;&gt;Meetup&lt;/a&gt;, &lt;a href=&quot;https://mail.python.org/mailman3/lists/pyninsula-announce.python.org/&quot;&gt;Email Announce&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Taking a chronological look at each of the above, I&#x27;m relieved to see
obvious growth.&lt;/p&gt;
&lt;p&gt;If I were to highlight one resource, it would probably be the
&lt;a href=&quot;http://sedimental.org/talks.html&quot;&gt;talks&lt;/a&gt;. Despite the stress of preparation and delivery, I&#x27;m least
concerned with having a massive miscommunication when we&#x27;re all in the
room and I can see the points hitting home. It&#x27;s impossible to pick a
favorite, but &lt;a href=&quot;http://sedimental.org/talks.html#ask-the-ecosystem-lessons-from-350-foss-python-applications&quot;&gt;Ask the
Ecosystem&lt;/a&gt;
(2019), the &lt;a href=&quot;http://sedimental.org/talks.html#restructuring-data-in-python&quot;&gt;Restructuring
Data&lt;/a&gt; lightning talk (2018),
and &lt;a href=&quot;https://www.youtube.com/watch?v=iLVNWfPWAC8&quot;&gt;The Packaging
Gradient&lt;/a&gt; (2017) seem
like audience faves from where I&#x27;m sitting.&lt;/p&gt;
&lt;h2 id=&quot;the_quality&quot;&gt;&lt;a href=&quot;#the_quality&quot; class=&quot;toclink&quot;&gt;The Quality&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Each project, post, and talk had its own reward, but I guess I&#x27;ve got
more than just those to show for the decade.&lt;/p&gt;
&lt;p&gt;On the more profit-driven side, I built tools and teams at PayPal, but
once I could manage the risk, I got to dip into startups for the last
few years. Lucky for me, it wasn&#x27;t a total bust, and the wife and I
bought a place in &lt;a href=&quot;https://en.wikipedia.org/wiki/Japantown,_San_Jose&quot;&gt;my favorite neighborhood (in the
USA)&lt;/a&gt;. Not a
millionaire, but I&#x27;m hoping and working for a world where no one has
to be.&lt;/p&gt;
&lt;p&gt;More recently, the Python Software Foundation &lt;a href=&quot;http://pyfound.blogspot.com/2019/11/python-software-foundation-fellow.html&quot;&gt;made me a
Fellow&lt;/a&gt;. This
isn&#x27;t something I can be nonchalant about, and I&#x27;m not going to
understate how much this means, to me, working in a field like
software, where concrete symbols of progress are alternatingly elusive
and vanishing. Plus it&#x27;s Python, and reciprocated love is nice. I have
hundreds of people to thank for helping me reach this point, and I
have to thank the PSF for dedicating the time to ramping up these
awards. They&#x27;ve convinced me more than ever that we need more
institutions to build this sort of advancement.&lt;/p&gt;
&lt;p&gt;To all of you, thank you.&lt;/p&gt;
&lt;h2 id=&quot;the_struggle&quot;&gt;&lt;a href=&quot;#the_struggle&quot; class=&quot;toclink&quot;&gt;The Struggle&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;I like to think I managed to do all of the above while staying away
from industry hype, on the principle that massive speculative capital
influx isn&#x27;t where real value is added to society, and doesn&#x27;t
generate the kind of innovation that excites me.&lt;/p&gt;
&lt;p&gt;I may have been naïve, but I came to Silicon Valley with an idea
about the transformative power of software. Changing times may
illustrate a grittier interpretation than the one I had and have, but
I continue to hold dear software&#x27;s potential for positive impact. If
you&#x27;ve felt that vision waver, let me tell you, you&#x27;re not alone.&lt;/p&gt;
&lt;p&gt;In the past decade, I&#x27;ve seen too many engineers sucked in by new
technologies and ventures, only to find themselves alienated from
their work. Episodes ranging from an afternoon lost to debugging
Docker/k8s clusters, to years of work disappearing at the end of a VC
runway. Nothing has been harder to watch than those
bedraggled-but-persistent idealists regroup, each time a bit more
cynical than the last.&lt;/p&gt;
&lt;p&gt;Even if its seeming intractibility has taken it from the center stage,
the burnout conversation continues to smolder, because there&#x27;s no
issue realer. I know; I released more ceramics than software &lt;a href=&quot;https://www.flickr.com/photos/mahmoudhashemi/albums/72157648555341327&quot;&gt;back in
2014&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Some problems can be solved by &lt;a href=&quot;https://opensource.com/article/18/9/its-time-pay-maintainers&quot;&gt;paying the
maintainers&lt;/a&gt;,
but I think the vastly bigger issue is around losing the human
connection between the real effort software takes and the real
benefits it brings, combined with FOSS&#x27;s dearth of collaborators in
supporting roles (QA, product/project/release management).&lt;/p&gt;
&lt;p&gt;That&#x27;s why I&#x27;m incredibly thankful for the Wikimedia community for
always being there, patient with schedules and issues, as long as the
software got the job done. It can be a challenge to juggle projects,
but I tell every budding engineer: find that direct connection to
people who will appreciate your work, and avoid cynicism at all costs.&lt;/p&gt;
&lt;p&gt;&lt;img width=&quot;34%&quot; align=&quot;right&quot; src=&quot;http://sedimental.org/uploads/illo/green_field_med.png&quot; /&gt;&lt;/p&gt;
&lt;p&gt;There are some interesting prospects in the works, but I&#x27;m keeping
this post retro. Besides, if 2029 rolls around and all I did was break
even with 2009-19, I don&#x27;t see how I can be disappointed.&lt;/p&gt;
&lt;p&gt;Thanks again for everything in 201X, and for sticking with me in 202X.&lt;/p&gt;
&lt;div class=&quot;footnote&quot;&gt;
&lt;hr /&gt;
&lt;ol&gt;
&lt;li id=&quot;fn:1&quot;&gt;
&lt;p&gt;Despite using &lt;a href=&quot;https://twitter.com/mhashemi&quot;&gt;Twitter&lt;/a&gt; for over a
decade, the process of tweeting feels so perfunctory, and the
service itself so tenuous, that I still can&#x27;t bring myself to
invest the time. I mostly use it to crosspost my blog posts or
help friends promote their posts/projects.&lt;/p&gt;
&lt;p&gt;But until I start an email newsletter, or really get on top of
&lt;a href=&quot;https://yak.party&quot;&gt;yak.party&lt;/a&gt;, it&#x27;s still the best I got for
announcing where I&#x27;m speaking next. &lt;a class=&quot;footnote-backref&quot; href=&quot;http://sedimental.org/thanks_201x.html#fnref:1&quot; title=&quot;Jump back to footnote 1 in the text&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;&lt;p&gt;&lt;/p&gt;



&lt;hr /&gt;

</content>

  </entry>
  
  <entry>
    <id>http://sedimental.org/awesome_python_applications.html</id>
    <author>
      <name>Mahmoud Hashemi</name>
      <uri>http://sedimental.org/</uri>
    </author>
    <title>Awesome Python Applications</title>
    <link rel="alternate" type="text/html" href="http://sedimental.org/awesome_python_applications.html" />
    <published>2018-12-20T19:20:00Z</published>
    <updated>2018-12-20T19:20:00Z</updated>
    <category term="python"/><category term="code"/><category term="apa"/>
    

    <content type="html">&lt;p&gt;&lt;p&gt;&lt;em&gt;What we can learn from 180+ case studies on successfully shipping Python software.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;If you&#x27;re reading this (or hearing
&lt;a href=&quot;https://testandcode.com/55&quot;&gt;this&lt;/a&gt;), you read and write code, probably
Python. And for all the code you&#x27;ve shipped, you&#x27;ve probably had your
share of missed requirements. Somehere in the excitement of software
abstraction, we can lose sight of what really matters, what makes our
well-factored modules and packages and frameworks turn into real-world
applications.&lt;/p&gt;
&lt;p&gt;That&#x27;s why I&#x27;m announcing &lt;a href=&quot;https://github.com/mahmoud/awesome-python-applications&quot;&gt;&lt;strong&gt;&lt;em&gt;Awesome Python
Applications&lt;/em&gt;&lt;/strong&gt;&lt;/a&gt;,
a hand-curated list of 180+ projects, all of which are:
&lt;img align=&quot;right&quot; width=&quot;40%&quot; src=&quot;http://sedimental.org/uploads/illo/snake_cd.png&quot; /&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Free software with an online source repository.&lt;/li&gt;
&lt;li&gt;Using Python for a considerable part of their functionality.&lt;/li&gt;
&lt;li&gt;Well-known, or at least prominently used in an identifiable niche.&lt;/li&gt;
&lt;li&gt;Maintained or otherwise demonstrably still functional on relevant platforms.&lt;/li&gt;
&lt;li&gt;Shipped applications, not libraries or frameworks.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The result is a list of predominantly focused on software that
installs without &lt;code&gt;pip&lt;/code&gt; or PyPI, and whose audience is mostly &lt;em&gt;not&lt;/em&gt;
developers. There&#x27;s still plenty of that in there, too, with other
exceptions, but the breadth of the list &lt;a href=&quot;https://github.com/mahmoud/awesome-python-applications#awesome-python-applications&quot;&gt;speaks for
itself&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;So why spend weeks cataloguing open-source Python applications?&lt;/p&gt;
&lt;p&gt;Aside from holiday cheer, three big reasons.&lt;/p&gt;
&lt;div class=&quot;toc&quot;&gt;&lt;span class=&quot;toctitle&quot;&gt;Contents&lt;/span&gt;&lt;ul&gt;&lt;li&gt;&lt;a href=&quot;#goal_1_a_better_development_cycle&quot;&gt;Goal #1: A Better Development Cycle&lt;/a&gt;&lt;li&gt;&lt;a href=&quot;#goal_2_a_complete_python_production_loop&quot;&gt;Goal #2: A Complete Python Production Loop&lt;/a&gt;&lt;li&gt;&lt;a href=&quot;#goal_3_grounding_for_the_python_ecosystem&quot;&gt;Goal #3: Grounding for the Python Ecosystem&lt;/a&gt;&lt;li&gt;&lt;a href=&quot;#next_steps&quot;&gt;Next steps&lt;/a&gt;&lt;/ul&gt;&lt;/div&gt;&lt;h2 id=&quot;goal_1_a_better_development_cycle&quot;&gt;&lt;a href=&quot;#goal_1_a_better_development_cycle&quot; class=&quot;toclink&quot;&gt;Goal #1: A Better Development Cycle&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Ever since I started
&lt;a href=&quot;https://www.youtube.com/watch?v=iLVNWfPWAC8&quot;&gt;talking&lt;/a&gt;
&lt;a href=&quot;https://www.youtube.com/watch?v=tfI2hdK6vVY&quot;&gt;about&lt;/a&gt; &lt;a href=&quot;http://sedimental.org/the_packaging_gradient.html&quot;&gt;Python
packaging&lt;/a&gt;, people
have been asking me questions about which packaging technique is best
for their software. I was struck, over and over again, how far people
can get in developing an application before reaching the fundamental
question of delivery. Exploring this, I landed on a more basic
question:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Why are so many people building applications from first
principles (blog posts and Stack Overflow)?&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Isn&#x27;t Python one of the biggest names in the software world?  Aren&#x27;t
there dozens of successful, real-world applications written in Python?
What are the chances your application is totally unique?&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Awesome Python Applications&lt;/em&gt; attempts to open up a new
flow for answering the toughest development questions.&lt;/p&gt;
&lt;p&gt;When building an application, scan the list to find projects which
most closely match your project&#x27;s requirements. Then, use that
application as a guide for answering your own questions. This works
especially well for abstract questions surrounding architecture,
deployment, and testing.&lt;/p&gt;
&lt;p&gt;Back in school, I learned more about architecture and software
development from &lt;a href=&quot;https://github.com/wikimedia/mediawiki&quot;&gt;the MediaWiki source
code&lt;/a&gt; than I did from any
class. It continues to inspire me &lt;a href=&quot;http://sedimental.org/hatnote_projects.html&quot;&gt;to this
day&lt;/a&gt;. APA is the next
step in enabling the holistic education of a working application with
real users.&lt;/p&gt;
&lt;p&gt;In short, while we may lack the time &lt;a href=&quot;http://aosabook.org/en/index.html&quot;&gt;to write
them&lt;/a&gt;, each production application
is worth a thousand blog posts.&lt;/p&gt;
&lt;h2 id=&quot;goal_2_a_complete_python_production_loop&quot;&gt;&lt;a href=&quot;#goal_2_a_complete_python_production_loop&quot; class=&quot;toclink&quot;&gt;Goal #2: A Complete Python Production Loop&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;We Python programmers are also software &lt;em&gt;users&lt;/em&gt;. But unlike other
software users, we know how to file issues and may even make
significant contributions back to our applications of choice.&lt;/p&gt;
&lt;p&gt;&lt;img align=&quot;right&quot; width=&quot;30%&quot; src=&quot;http://sedimental.org/uploads/illo/network_sm.png&quot; /&gt;&lt;/p&gt;
&lt;p&gt;By choosing Python software when possible, we take one step closer to
pitching in. What better way for a future application developer to get
started?&lt;/p&gt;
&lt;p&gt;I would love to see more developers connect with software they didn&#x27;t
realize was Python. My (minor) contributions to the
&lt;a href=&quot;https://github.com/twisted/twisted&quot;&gt;Twisted&lt;/a&gt; were greatly energized
by the knowledge that one of my favorite applications,
&lt;a href=&quot;https://github.com/deluge-torrent/deluge&quot;&gt;Deluge&lt;/a&gt;, heavily used the
library. Using free software leads to creating more free software.&lt;/p&gt;
&lt;h2 id=&quot;goal_3_grounding_for_the_python_ecosystem&quot;&gt;&lt;a href=&quot;#goal_3_grounding_for_the_python_ecosystem&quot; class=&quot;toclink&quot;&gt;Goal #3: Grounding for the Python Ecosystem&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;With the pace and cerebrality of technology, it can be easy to get
ahead of ourselves and our end users. Infrastructure devs get
disconnected from application devs, and that makes for worse software
over time. This problem is compounded when applications get less
developer attention. Most APA entries have three- and even two-digit
starcounts, unless users are highly technical. Few major Python
applications are distributed with PyPI, so &lt;a href=&quot;https://pypistats.org&quot;&gt;download
statistics&lt;/a&gt; can&#x27;t help us either. Even if they
did, lower-level libraries have way more fanout. And of course free
software projects can&#x27;t lay down big donations or conference
sponsorships, so representation tends to be pretty sparse all around.&lt;/p&gt;
&lt;p&gt;These applications represent the best of the free and living portion of
Python. Not only are they a source of utility and pride, but they need
our support, in spirit and in practice. It is my sincere hope that the
APA will help to anchor the Python community in its real-world
applications.&lt;/p&gt;
&lt;p&gt;What does this mean, concretely? A keen eye will
notice &lt;a href=&quot;https://github.com/mahmoud/awesome-python-applications/blob/master/projects.yaml&quot;&gt;how the list is
structured&lt;/a&gt;. This
isn&#x27;t just for consistent rendering, but an attempt at an API for the
dataset. We must explore our ecosystem with the relzationship between
libraries and applications in mind.&lt;/p&gt;
&lt;p&gt;I know I&#x27;m going out on a limb here, and metrics aren&#x27;t everything,
but it would be very interesting to see the Python FOSS ecosystem
explored as an analogue of the scientific publishing framework. Can we
get some sort of developer
&lt;a href=&quot;https://en.wikipedia.org/wiki/H-index&quot;&gt;&lt;em&gt;h&lt;/em&gt;-index&lt;/a&gt; by treating
libraries as
&quot;&lt;a href=&quot;https://en.wikipedia.org/wiki/Article-level_metrics&quot;&gt;articles&lt;/a&gt;&quot; and
applications as
&quot;&lt;a href=&quot;https://en.wikipedia.org/wiki/Journal-level_metrics&quot;&gt;journals&lt;/a&gt;&quot;?
Adding in some application userbase approximations (via social
&lt;a href=&quot;https://en.wikipedia.org/wiki/Altmetrics&quot;&gt;altmetrics&lt;/a&gt; and other
means) can give us much deeper insight into real-world impact.&lt;/p&gt;
&lt;h2 id=&quot;next_steps&quot;&gt;&lt;a href=&quot;#next_steps&quot; class=&quot;toclink&quot;&gt;Next steps&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;If this essay seems shorter than &lt;a href=&quot;http://sedimental.org/archive.html&quot;&gt;my usual&lt;/a&gt;, that&#x27;s
because it&#x27;s really an introduction to &lt;a href=&quot;https://github.com/mahmoud/awesome-python-applications&quot;&gt;the list
itself&lt;/a&gt;. I got
caught up in several projects&#x27; codebases while doing the research, and
you will, too.&lt;/p&gt;
&lt;p&gt;If we&#x27;ve missed a project, please open &lt;a href=&quot;https://github.com/mahmoud/awesome-python-applications/issues/new&quot;&gt;an
issue&lt;/a&gt;
or PR. If you&#x27;re as excited about this as I am, consider helping with
some of &lt;a href=&quot;https://github.com/mahmoud/awesome-python-applications/issues&quot;&gt;the open
issues&lt;/a&gt;. There
are still a lot of application features to survey: licenses,
Python versions, frameworks, and more. And as always, watch this space
(and the repo) for updates as we make more discoveries!&lt;p&gt;&lt;/p&gt;



&lt;hr /&gt;

</content>

  </entry>
  
  <entry>
    <id>http://sedimental.org/glom_restructured_data.html</id>
    <author>
      <name>Mahmoud Hashemi</name>
      <uri>http://sedimental.org/</uri>
    </author>
    <title>Announcing glom: Restructured Data for Python</title>
    <link rel="alternate" type="text/html" href="http://sedimental.org/glom_restructured_data.html" />
    <published>2018-05-09T17:00:00Z</published>
    <updated>2018-05-09T17:00:00Z</updated>
    <category term="python"/><category term="data"/><category term="glom"/><category term="software"/><category term="boltons"/>
    

    <content type="html">&lt;p&gt;&lt;p&gt;&lt;em&gt;This post introduces &lt;a href=&quot;https://github.com/mahmoud/glom&quot;&gt;&lt;strong&gt;glom&lt;/strong&gt;&lt;/a&gt;,
Python&#x27;s missing operator for nested objects and data.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;If you&#x27;re an easy sell, &lt;a href=&quot;http://glom.readthedocs.io/en/latest/api.html&quot;&gt;full API docs&lt;/a&gt; and
&lt;a href=&quot;http://glom.readthedocs.io/en/latest/tutorial.html&quot;&gt;tutorial&lt;/a&gt; are already available at
&lt;a href=&quot;https://glom.readthedocs.io/&quot;&gt;glom.readthedocs.io&lt;/a&gt;. &lt;br /&gt;
Harder sells, this 5-minute post is for you.&lt;br /&gt;
Really hard sells &lt;a href=&quot;https://twitter.com/mhashemi/status/994111054702522369&quot;&gt;met me at PyCon&lt;/a&gt;,&lt;br /&gt;
where I gave &lt;a href=&quot;https://www.youtube.com/watch?v=3aREXkfeWek&quot;&gt;this 5-minute talk&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;http://sedimental.org/uploads/illo/comet.png&quot; align=&quot;right&quot; width=&quot;30%&quot; /&gt;&lt;/p&gt;
&lt;h2 id=&quot;the_spectre_of_structure&quot;&gt;&lt;a href=&quot;#the_spectre_of_structure&quot; class=&quot;toclink&quot;&gt;The Spectre of Structure&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;In the Python world, there&#x27;s a saying: &lt;em&gt;&quot;Flat is better than nested.&quot;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Maybe times have changed or maybe that adage just applies more to code
than data. In spite of the warning, nested data continues to grow,
from document stores to RPC systems to structured logs to plain ol&#x27;
JSON web services.&lt;/p&gt;
&lt;p&gt;After all, if &quot;flat&quot; was the be-all-end-all, why would namespaces be
&lt;a href=&quot;https://en.wikipedia.org/wiki/Zen_of_Python&quot;&gt;one honking great idea&lt;/a&gt;? Nobody likes artificial flatness, nobody wants
to call a function with 40 arguments.&lt;/p&gt;
&lt;p&gt;Nested data is tricky though. Reaching into deeply structured data can
get you some ugly errors. Consider this simple line:&lt;/p&gt;
&lt;div class=&quot;codehilite&quot; style=&quot;background: #f8f8f8&quot;&gt;&lt;pre style=&quot;line-height: 125%;&quot;&gt;&lt;span&gt;&lt;/span&gt;value &lt;span style=&quot;color: #666666&quot;&gt;=&lt;/span&gt; target&lt;span style=&quot;color: #666666&quot;&gt;.&lt;/span&gt;a[&lt;span style=&quot;color: #BB4444&quot;&gt;&#x27;b&#x27;&lt;/span&gt;][&lt;span style=&quot;color: #BB4444&quot;&gt;&#x27;c&#x27;&lt;/span&gt;]
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;That single line can result in at least four different exceptions,
each less helpful than the last:&lt;/p&gt;
&lt;div class=&quot;codehilite&quot; style=&quot;background: #f8f8f8&quot;&gt;&lt;pre style=&quot;line-height: 125%;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;span style=&quot;color: #D2413A; font-weight: bold&quot;&gt;AttributeError&lt;/span&gt;: &lt;span style=&quot;color: #BB4444&quot;&gt;&#x27;TargetType&#x27;&lt;/span&gt; &lt;span style=&quot;color: #AA22FF&quot;&gt;object&lt;/span&gt; has no attribute &lt;span style=&quot;color: #BB4444&quot;&gt;&#x27;a&#x27;&lt;/span&gt;
&lt;span style=&quot;color: #D2413A; font-weight: bold&quot;&gt;KeyError&lt;/span&gt;: &lt;span style=&quot;color: #BB4444&quot;&gt;&#x27;b&#x27;&lt;/span&gt;
&lt;span style=&quot;color: #D2413A; font-weight: bold&quot;&gt;TypeError&lt;/span&gt;: &lt;span style=&quot;color: #BB4444&quot;&gt;&#x27;NoneType&#x27;&lt;/span&gt; &lt;span style=&quot;color: #AA22FF&quot;&gt;object&lt;/span&gt; has no attribute &lt;span style=&quot;color: #BB4444&quot;&gt;&#x27;__getitem__&#x27;&lt;/span&gt;
&lt;span style=&quot;color: #D2413A; font-weight: bold&quot;&gt;TypeError&lt;/span&gt;: &lt;span style=&quot;color: #AA22FF&quot;&gt;list&lt;/span&gt; indices must be integers, &lt;span style=&quot;color: #AA22FF; font-weight: bold&quot;&gt;not&lt;/span&gt; &lt;span style=&quot;color: #AA22FF&quot;&gt;str&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Clearly, we need our tools to catch up to our nested data.&lt;/p&gt;
&lt;p&gt;Enter &lt;strong&gt;glom&lt;/strong&gt;.&lt;/p&gt;
&lt;h2 id=&quot;restructuring_data&quot;&gt;&lt;a href=&quot;#restructuring_data&quot; class=&quot;toclink&quot;&gt;Restructuring Data&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/mahmoud/glom&quot;&gt;glom&lt;/a&gt; is a new approach to working with data in Python, featuring:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;http://glom.readthedocs.io/en/latest/tutorial.html#access-granted&quot;&gt;Path-based access&lt;/a&gt; for nested structures&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://glom.readthedocs.io/en/latest/api.html#glom-func&quot;&gt;Declarative data transformation&lt;/a&gt; using lightweight, Pythonic specifications&lt;/li&gt;
&lt;li&gt;Readable, meaningful &lt;a href=&quot;http://glom.readthedocs.io/en/latest/api.html#exceptions&quot;&gt;error messages&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Built-in &lt;a href=&quot;http://glom.readthedocs.io/en/latest/api.html#debugging&quot;&gt;data exploration and debugging features&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;A tool as simple and powerful as glom &lt;a href=&quot;http://glom.readthedocs.io/en/latest/by_analogy.html&quot;&gt;attracts many
comparisons&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;While similarities exist, and are often intentional, glom differs from
other offerings in a few ways:&lt;/p&gt;
&lt;h3 id=&quot;going_beyond_access&quot;&gt;&lt;a href=&quot;#going_beyond_access&quot; class=&quot;toclink&quot;&gt;Going Beyond Access&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Many nested data tools simply perform deep gets and searches, stopping
short after solving the problem posed above. Realizing that access
almost always precedes assignment, glom takes the paradigm further,
enabling total declarative transformation of the data.&lt;/p&gt;
&lt;p&gt;By way of introduction, let&#x27;s start off with space-age access, the
classic &quot;deep-get&quot;:&lt;/p&gt;
&lt;div class=&quot;codehilite&quot; style=&quot;background: #f8f8f8&quot;&gt;&lt;pre style=&quot;line-height: 125%;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;span style=&quot;color: #AA22FF; font-weight: bold&quot;&gt;from&lt;/span&gt; &lt;span style=&quot;color: #0000FF; font-weight: bold&quot;&gt;glom&lt;/span&gt; &lt;span style=&quot;color: #AA22FF; font-weight: bold&quot;&gt;import&lt;/span&gt; glom

target &lt;span style=&quot;color: #666666&quot;&gt;=&lt;/span&gt; {&lt;span style=&quot;color: #BB4444&quot;&gt;&#x27;galaxy&#x27;&lt;/span&gt;: {&lt;span style=&quot;color: #BB4444&quot;&gt;&#x27;system&#x27;&lt;/span&gt;: {&lt;span style=&quot;color: #BB4444&quot;&gt;&#x27;planet&#x27;&lt;/span&gt;: &lt;span style=&quot;color: #BB4444&quot;&gt;&#x27;jupiter&#x27;&lt;/span&gt;}}}
spec &lt;span style=&quot;color: #666666&quot;&gt;=&lt;/span&gt; &lt;span style=&quot;color: #BB4444&quot;&gt;&#x27;galaxy.system.planet&#x27;&lt;/span&gt;

output &lt;span style=&quot;color: #666666&quot;&gt;=&lt;/span&gt; glom(target, spec)
&lt;span style=&quot;color: #008800; font-style: italic&quot;&gt;# output = &#x27;jupiter&#x27;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;&lt;img src=&quot;http://sedimental.org/uploads/illo/mjc/jupiter_med.png&quot; align=&quot;right&quot; width=&quot;30%&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Some quick terminology:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;em&gt;target&lt;/em&gt; is our data, be it dict, list, or any other object&lt;/li&gt;
&lt;li&gt;&lt;em&gt;spec&lt;/em&gt; is what we want &lt;em&gt;output&lt;/em&gt; to be&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;With &lt;code&gt;output = glom(target, spec)&lt;/code&gt; committed to memory, we&#x27;re ready
for some new requirements.&lt;/p&gt;
&lt;p&gt;Our astronomers want to focus in on the Solar system, and represent
planets as a list. Let&#x27;s restructure the data to make a list of names:&lt;/p&gt;
&lt;div class=&quot;codehilite&quot; style=&quot;background: #f8f8f8&quot;&gt;&lt;pre style=&quot;line-height: 125%;&quot;&gt;&lt;span&gt;&lt;/span&gt;target &lt;span style=&quot;color: #666666&quot;&gt;=&lt;/span&gt; {&lt;span style=&quot;color: #BB4444&quot;&gt;&#x27;system&#x27;&lt;/span&gt;: {&lt;span style=&quot;color: #BB4444&quot;&gt;&#x27;planets&#x27;&lt;/span&gt;: [{&lt;span style=&quot;color: #BB4444&quot;&gt;&#x27;name&#x27;&lt;/span&gt;: &lt;span style=&quot;color: #BB4444&quot;&gt;&#x27;earth&#x27;&lt;/span&gt;}, {&lt;span style=&quot;color: #BB4444&quot;&gt;&#x27;name&#x27;&lt;/span&gt;: &lt;span style=&quot;color: #BB4444&quot;&gt;&#x27;jupiter&#x27;&lt;/span&gt;}]}}

glom(target, (&lt;span style=&quot;color: #BB4444&quot;&gt;&#x27;system.planets&#x27;&lt;/span&gt;, [&lt;span style=&quot;color: #BB4444&quot;&gt;&#x27;name&#x27;&lt;/span&gt;]))
&lt;span style=&quot;color: #008800; font-style: italic&quot;&gt;# [&#x27;earth&#x27;, &#x27;jupiter&#x27;]&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;And let&#x27;s say we want to capture a parallel list of moon counts with
the names as well:&lt;/p&gt;
&lt;div class=&quot;codehilite&quot; style=&quot;background: #f8f8f8&quot;&gt;&lt;pre style=&quot;line-height: 125%;&quot;&gt;&lt;span&gt;&lt;/span&gt;target &lt;span style=&quot;color: #666666&quot;&gt;=&lt;/span&gt; {&lt;span style=&quot;color: #BB4444&quot;&gt;&#x27;system&#x27;&lt;/span&gt;: {&lt;span style=&quot;color: #BB4444&quot;&gt;&#x27;planets&#x27;&lt;/span&gt;: [{&lt;span style=&quot;color: #BB4444&quot;&gt;&#x27;name&#x27;&lt;/span&gt;: &lt;span style=&quot;color: #BB4444&quot;&gt;&#x27;earth&#x27;&lt;/span&gt;, &lt;span style=&quot;color: #BB4444&quot;&gt;&#x27;moons&#x27;&lt;/span&gt;: &lt;span style=&quot;color: #666666&quot;&gt;1&lt;/span&gt;},
                                 {&lt;span style=&quot;color: #BB4444&quot;&gt;&#x27;name&#x27;&lt;/span&gt;: &lt;span style=&quot;color: #BB4444&quot;&gt;&#x27;jupiter&#x27;&lt;/span&gt;, &lt;span style=&quot;color: #BB4444&quot;&gt;&#x27;moons&#x27;&lt;/span&gt;: &lt;span style=&quot;color: #666666&quot;&gt;69&lt;/span&gt;}]}}

spec &lt;span style=&quot;color: #666666&quot;&gt;=&lt;/span&gt; {&lt;span style=&quot;color: #BB4444&quot;&gt;&#x27;names&#x27;&lt;/span&gt;: (&lt;span style=&quot;color: #BB4444&quot;&gt;&#x27;system.planets&#x27;&lt;/span&gt;, [&lt;span style=&quot;color: #BB4444&quot;&gt;&#x27;name&#x27;&lt;/span&gt;]),
        &lt;span style=&quot;color: #BB4444&quot;&gt;&#x27;moons&#x27;&lt;/span&gt;: (&lt;span style=&quot;color: #BB4444&quot;&gt;&#x27;system.planets&#x27;&lt;/span&gt;, [&lt;span style=&quot;color: #BB4444&quot;&gt;&#x27;moons&#x27;&lt;/span&gt;])}

glom(target, spec)
&lt;span style=&quot;color: #008800; font-style: italic&quot;&gt;# {&#x27;names&#x27;: [&#x27;earth&#x27;, &#x27;jupiter&#x27;], &#x27;moons&#x27;: [1, 69]}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;We can react to changing data requirements as fast as the data itself
can change, naturally restructuring our results, despite the input&#x27;s
nested nature. Like a list comprehension, but for nested data, our
code mirrors our output.&lt;/p&gt;
&lt;p&gt;And we&#x27;re just getting started.&lt;/p&gt;
&lt;h3 id=&quot;true_python_native&quot;&gt;&lt;a href=&quot;#true_python_native&quot; class=&quot;toclink&quot;&gt;True Python-Native&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Most other implementations are limited to a particular data format or
pure model, be it &lt;a href=&quot;http://jmespath.org/&quot;&gt;jmespath&lt;/a&gt; or
&lt;a href=&quot;https://en.wikipedia.org/wiki/XPath&quot;&gt;XPath&lt;/a&gt;/&lt;a href=&quot;https://en.wikipedia.org/wiki/XSLT&quot;&gt;XSLT&lt;/a&gt;. glom makes no such sacrifices of
practicality, harnessing the full power of Python itself.&lt;/p&gt;
&lt;p&gt;Going back to our example, let&#x27;s say we wanted to get an aggregate
moon count:&lt;/p&gt;
&lt;div class=&quot;codehilite&quot; style=&quot;background: #f8f8f8&quot;&gt;&lt;pre style=&quot;line-height: 125%;&quot;&gt;&lt;span&gt;&lt;/span&gt;target &lt;span style=&quot;color: #666666&quot;&gt;=&lt;/span&gt; {&lt;span style=&quot;color: #BB4444&quot;&gt;&#x27;system&#x27;&lt;/span&gt;: {&lt;span style=&quot;color: #BB4444&quot;&gt;&#x27;planets&#x27;&lt;/span&gt;: [{&lt;span style=&quot;color: #BB4444&quot;&gt;&#x27;name&#x27;&lt;/span&gt;: &lt;span style=&quot;color: #BB4444&quot;&gt;&#x27;earth&#x27;&lt;/span&gt;, &lt;span style=&quot;color: #BB4444&quot;&gt;&#x27;moons&#x27;&lt;/span&gt;: &lt;span style=&quot;color: #666666&quot;&gt;1&lt;/span&gt;},
                                 {&lt;span style=&quot;color: #BB4444&quot;&gt;&#x27;name&#x27;&lt;/span&gt;: &lt;span style=&quot;color: #BB4444&quot;&gt;&#x27;jupiter&#x27;&lt;/span&gt;, &lt;span style=&quot;color: #BB4444&quot;&gt;&#x27;moons&#x27;&lt;/span&gt;: &lt;span style=&quot;color: #666666&quot;&gt;69&lt;/span&gt;}]}}


glom(target, {&lt;span style=&quot;color: #BB4444&quot;&gt;&#x27;moon_count&#x27;&lt;/span&gt;: (&lt;span style=&quot;color: #BB4444&quot;&gt;&#x27;system.planets&#x27;&lt;/span&gt;, [&lt;span style=&quot;color: #BB4444&quot;&gt;&#x27;moons&#x27;&lt;/span&gt;], &lt;span style=&quot;color: #AA22FF&quot;&gt;sum&lt;/span&gt;)})
&lt;span style=&quot;color: #008800; font-style: italic&quot;&gt;# {&#x27;moon_count&#x27;: 70}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;With glom, you have full access to Python at any given moment. Pass
values to functions, whether built-in, imported, or defined inline
with &lt;code&gt;lambda&lt;/code&gt;. But &lt;code&gt;glom&lt;/code&gt; doesn&#x27;t stop there.&lt;/p&gt;
&lt;p&gt;Now we get to one of my favorite features by far. Leaning into
Python&#x27;s power, we unlock the following syntax:&lt;/p&gt;
&lt;div class=&quot;codehilite&quot; style=&quot;background: #f8f8f8&quot;&gt;&lt;pre style=&quot;line-height: 125%;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;span style=&quot;color: #AA22FF; font-weight: bold&quot;&gt;from&lt;/span&gt; &lt;span style=&quot;color: #0000FF; font-weight: bold&quot;&gt;glom&lt;/span&gt; &lt;span style=&quot;color: #AA22FF; font-weight: bold&quot;&gt;import&lt;/span&gt; T

spec &lt;span style=&quot;color: #666666&quot;&gt;=&lt;/span&gt; T[&lt;span style=&quot;color: #BB4444&quot;&gt;&#x27;system&#x27;&lt;/span&gt;][&lt;span style=&quot;color: #BB4444&quot;&gt;&#x27;planets&#x27;&lt;/span&gt;][&lt;span style=&quot;color: #666666&quot;&gt;-1&lt;/span&gt;]&lt;span style=&quot;color: #666666&quot;&gt;.&lt;/span&gt;values()

glom(target, spec)
&lt;span style=&quot;color: #008800; font-style: italic&quot;&gt;# [&#x27;jupiter&#x27;, 69]&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;What just happened?&lt;/p&gt;
&lt;p&gt;&lt;code&gt;T&lt;/code&gt; stands for &lt;em&gt;target&lt;/em&gt;, and &lt;a href=&quot;http://glom.readthedocs.io/en/latest/api.html#object-oriented-access-and-method-calls-with-t&quot;&gt;it acts as your data&#x27;s stunt
double&lt;/a&gt;. &lt;code&gt;T&lt;/code&gt; records every key you get, every attribute you
access, every index you index, and every method you call. And out
comes a spec that&#x27;s usable like any other.&lt;/p&gt;
&lt;p&gt;No more worrying if an attribute is &lt;code&gt;None&lt;/code&gt; or a key isn&#x27;t set. Take
that leap with &lt;code&gt;T&lt;/code&gt;. &lt;code&gt;T&lt;/code&gt; never raises an exception, so worst case you
get a &lt;a href=&quot;http://glom.readthedocs.io/en/latest/api.html#exceptions&quot;&gt;meaningful error message&lt;/a&gt; when you run &lt;code&gt;glom()&lt;/code&gt; on it.&lt;/p&gt;
&lt;p&gt;And if you&#x27;re ok with the data not being there, just set a default:&lt;/p&gt;
&lt;div class=&quot;codehilite&quot; style=&quot;background: #f8f8f8&quot;&gt;&lt;pre style=&quot;line-height: 125%;&quot;&gt;&lt;span&gt;&lt;/span&gt;glom(target, T[&lt;span style=&quot;color: #BB4444&quot;&gt;&#x27;system&#x27;&lt;/span&gt;][&lt;span style=&quot;color: #BB4444&quot;&gt;&#x27;comets&#x27;&lt;/span&gt;][&lt;span style=&quot;color: #666666&quot;&gt;-1&lt;/span&gt;], default&lt;span style=&quot;color: #666666&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #AA22FF; font-weight: bold&quot;&gt;None&lt;/span&gt;)
&lt;span style=&quot;color: #008800; font-style: italic&quot;&gt;# None&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Finally, &lt;a href=&quot;https://en.wikipedia.org/wiki/Null_coalescing_operator&quot;&gt;null-coalescing operators&lt;/a&gt; for Python!&lt;/p&gt;
&lt;p&gt;But so much more. This kind of dynamism is what made me fall in love
with Python. No other language could do it quite like this.&lt;/p&gt;
&lt;p&gt;That&#x27;s why glom will always be a Python library first and a CLI
second. Oh, didn&#x27;t I mention there was a CLI?&lt;/p&gt;
&lt;h3 id=&quot;library_first_then_cli&quot;&gt;&lt;a href=&quot;#library_first_then_cli&quot; class=&quot;toclink&quot;&gt;Library first, then CLI&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Tools like &lt;a href=&quot;https://stedolan.github.io/jq/&quot;&gt;jq&lt;/a&gt; provide a lot of value on the console, but leave a
dubious path forward for further integration. glom&#x27;s full-featured
command-line interface is only a stepping stone to using it more
extensively inside application logic.&lt;/p&gt;
&lt;div class=&quot;codehilite&quot; style=&quot;background: #f8f8f8&quot;&gt;&lt;pre style=&quot;line-height: 125%;&quot;&gt;&lt;span&gt;&lt;/span&gt;$&lt;span style=&quot;color: #bbbbbb&quot;&gt; &lt;/span&gt;pip&lt;span style=&quot;color: #bbbbbb&quot;&gt; &lt;/span&gt;install&lt;span style=&quot;color: #bbbbbb&quot;&gt; &lt;/span&gt;glom
$&lt;span style=&quot;color: #bbbbbb&quot;&gt; &lt;/span&gt;curl&lt;span style=&quot;color: #bbbbbb&quot;&gt; &lt;/span&gt;-s&lt;span style=&quot;color: #bbbbbb&quot;&gt; &lt;/span&gt;https://api.github.com/repos/mahmoud/glom/events&lt;span style=&quot;color: #bbbbbb&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #BB6622; font-weight: bold&quot;&gt;\&lt;/span&gt;
&lt;span style=&quot;color: #bbbbbb&quot;&gt;  &lt;/span&gt;|&lt;span style=&quot;color: #bbbbbb&quot;&gt; &lt;/span&gt;glom&lt;span style=&quot;color: #bbbbbb&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #BB4444&quot;&gt;&#x27;[{&quot;type&quot;: &quot;type&quot;, &quot;date&quot;: &quot;created_at&quot;, &quot;user&quot;: &quot;actor.login&quot;}]&#x27;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Which gets us:&lt;/p&gt;
&lt;div class=&quot;codehilite&quot; style=&quot;background: #f8f8f8&quot;&gt;&lt;pre style=&quot;line-height: 125%;&quot;&gt;&lt;span&gt;&lt;/span&gt;[
&lt;span style=&quot;color: #bbbbbb&quot;&gt;  &lt;/span&gt;{
&lt;span style=&quot;color: #bbbbbb&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;color: #008000; font-weight: bold&quot;&gt;&quot;date&quot;&lt;/span&gt;:&lt;span style=&quot;color: #bbbbbb&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #BB4444&quot;&gt;&quot;2018-05-09T03:39:44Z&quot;&lt;/span&gt;,
&lt;span style=&quot;color: #bbbbbb&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;color: #008000; font-weight: bold&quot;&gt;&quot;type&quot;&lt;/span&gt;:&lt;span style=&quot;color: #bbbbbb&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #BB4444&quot;&gt;&quot;WatchEvent&quot;&lt;/span&gt;,
&lt;span style=&quot;color: #bbbbbb&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;color: #008000; font-weight: bold&quot;&gt;&quot;user&quot;&lt;/span&gt;:&lt;span style=&quot;color: #bbbbbb&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #BB4444&quot;&gt;&quot;asapzacy&quot;&lt;/span&gt;
&lt;span style=&quot;color: #bbbbbb&quot;&gt;  &lt;/span&gt;},
&lt;span style=&quot;color: #bbbbbb&quot;&gt;  &lt;/span&gt;{
&lt;span style=&quot;color: #bbbbbb&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;color: #008000; font-weight: bold&quot;&gt;&quot;date&quot;&lt;/span&gt;:&lt;span style=&quot;color: #bbbbbb&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #BB4444&quot;&gt;&quot;2018-05-08T22:51:46Z&quot;&lt;/span&gt;,
&lt;span style=&quot;color: #bbbbbb&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;color: #008000; font-weight: bold&quot;&gt;&quot;type&quot;&lt;/span&gt;:&lt;span style=&quot;color: #bbbbbb&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #BB4444&quot;&gt;&quot;WatchEvent&quot;&lt;/span&gt;,
&lt;span style=&quot;color: #bbbbbb&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;color: #008000; font-weight: bold&quot;&gt;&quot;user&quot;&lt;/span&gt;:&lt;span style=&quot;color: #bbbbbb&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #BB4444&quot;&gt;&quot;CameronCairns&quot;&lt;/span&gt;
&lt;span style=&quot;color: #bbbbbb&quot;&gt;  &lt;/span&gt;},
&lt;span style=&quot;color: #bbbbbb&quot;&gt;  &lt;/span&gt;{
&lt;span style=&quot;color: #bbbbbb&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;color: #008000; font-weight: bold&quot;&gt;&quot;date&quot;&lt;/span&gt;:&lt;span style=&quot;color: #bbbbbb&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #BB4444&quot;&gt;&quot;2018-05-08T03:27:27Z&quot;&lt;/span&gt;,
&lt;span style=&quot;color: #bbbbbb&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;color: #008000; font-weight: bold&quot;&gt;&quot;type&quot;&lt;/span&gt;:&lt;span style=&quot;color: #bbbbbb&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #BB4444&quot;&gt;&quot;PushEvent&quot;&lt;/span&gt;,
&lt;span style=&quot;color: #bbbbbb&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;color: #008000; font-weight: bold&quot;&gt;&quot;user&quot;&lt;/span&gt;:&lt;span style=&quot;color: #bbbbbb&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #BB4444&quot;&gt;&quot;mahmoud&quot;&lt;/span&gt;
&lt;span style=&quot;color: #bbbbbb&quot;&gt;  &lt;/span&gt;},
&lt;span style=&quot;color: #bbbbbb&quot;&gt;  &lt;/span&gt;{
&lt;span style=&quot;color: #bbbbbb&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;color: #008000; font-weight: bold&quot;&gt;&quot;date&quot;&lt;/span&gt;:&lt;span style=&quot;color: #bbbbbb&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #BB4444&quot;&gt;&quot;2018-05-08T03:27:27Z&quot;&lt;/span&gt;,
&lt;span style=&quot;color: #bbbbbb&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;color: #008000; font-weight: bold&quot;&gt;&quot;type&quot;&lt;/span&gt;:&lt;span style=&quot;color: #bbbbbb&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #BB4444&quot;&gt;&quot;PullRequestEvent&quot;&lt;/span&gt;,
&lt;span style=&quot;color: #bbbbbb&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;color: #008000; font-weight: bold&quot;&gt;&quot;user&quot;&lt;/span&gt;:&lt;span style=&quot;color: #bbbbbb&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #BB4444&quot;&gt;&quot;mahmoud&quot;&lt;/span&gt;
&lt;span style=&quot;color: #bbbbbb&quot;&gt;  &lt;/span&gt;}
&lt;span style=&quot;border: 1px solid #FF0000&quot;&gt;...&lt;/span&gt;
]
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Piping hot JSON into &lt;code&gt;glom&lt;/code&gt; with a cool Python literal spec, with
pretty-printed JSON out. A great way to process and filter API calls,
and explore some data. Something genuinely enjoyable, because you know
you won&#x27;t be stuck in a pipe dream.&lt;/p&gt;
&lt;p&gt;Everything on the command line ports directly into production-grade
Python, complete with better error handling and limitless integration
possibilities.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;http://sedimental.org/uploads/illo/comet_multi.png&quot; align=&quot;right&quot; width=&quot;40%&quot; /&gt;&lt;/p&gt;
&lt;h2 id=&quot;next_steps&quot;&gt;&lt;a href=&quot;#next_steps&quot; class=&quot;toclink&quot;&gt;Next steps&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Never before glom have I put a piece of code into production so quickly.&lt;/p&gt;
&lt;p&gt;Within two weeks of the first commit, glom has paid its weight in
gold, with glom specs replacing &lt;a href=&quot;http://www.django-rest-framework.org/&quot;&gt;Django Rest Framework&lt;/a&gt; code 2x
to 5x their size, making the codebase faster and more
readable. Meanwhile, glom&#x27;s core is so tight that we&#x27;re on pace to
have more docs and tests than code very soon.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;glom()&lt;/code&gt; function is stable, along with the rest of the API,
unless otherwise specified.&lt;/p&gt;
&lt;p&gt;A lot of other features are baking or in the works. For now, we&#x27;ll
be focusing on the following growth areas:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/mahmoud/glom/issues/7&quot;&gt;Validation functionality&lt;/a&gt;, in the vein of schema and cerberus&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/mahmoud/glom/issues/8&quot;&gt;CLI robustness&lt;/a&gt;, better error messages, etc.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/mahmoud/glom/issues/9&quot;&gt;Extension API&lt;/a&gt;, clean up some internal code, open up extensions&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/mahmoud/glom/issues/10&quot;&gt;Automatic default registration&lt;/a&gt; of default behaviors for co-installed packages (e.g., Django)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;We&#x27;ll be talking about all of this and more &lt;a href=&quot;https://twitter.com/mhashemi/status/994111054702522369&quot;&gt;at PyCon&lt;/a&gt;, so
swing by if you can. In either case, I hope you&#x27;ll try glom out and
let us know how it goes!&lt;/p&gt;
&lt;!--

# The Story of glom

* A couple years ago I built `remap`, a `map()` function for trees of Python objects
* It didn&#x27;t solve all my problems because it&#x27;s mostly for cases where
  you don&#x27;t know much about the structure of data
* While building Montage, we tried using the &quot;fat model&quot; approach of
  teaching objects to serialize themselves, but this didn&#x27;t compose
  well. Every API endpoint needed slightly different data
* Then it dawned on me, what we needed was templating, but for basic
  objects like dicts, lists, etc., so that we could declaratively
  create JSON-serializable API responses.
* Taking inspiration from lightweight templating languages like
  `gofmt` and `ashes`, we built the first version of glom.

--&gt;&lt;p&gt;&lt;/p&gt;



&lt;hr /&gt;

</content>

  </entry>
  
  <entry>
    <id>http://sedimental.org/maintainerati_2017_github_design.html</id>
    <author>
      <name>Mahmoud Hashemi</name>
      <uri>http://sedimental.org/</uri>
    </author>
    <title>Maintainerati 2017: GitHub Design</title>
    <link rel="alternate" type="text/html" href="http://sedimental.org/maintainerati_2017_github_design.html" />
    <published>2017-10-18T05:00:00Z</published>
    <updated>2017-10-18T05:00:00Z</updated>
    <category term="code"/><category term="python"/><category term="events"/>
    

    <content type="html">&lt;p&gt;&lt;p&gt;Last week I attended a &lt;a href=&quot;https://twitter.com/maintainerati&quot;&gt;Maintainerati&lt;/a&gt; event, an
unconference/mini-summit for maintainers of popular software, run as a
prelude to the &lt;a href=&quot;https://githubuniverse.com/&quot;&gt;GitHub Universe&lt;/a&gt; conference. After being
brought up to speed on this year&#x27;s secret handshake of the software elite,
I had a great time in the documentation breakout group, as well as
moderating a lively discussion on diversity in open-source, both of
which deserve their own write-ups at some point.&lt;/p&gt;
&lt;p&gt;&lt;img title=&quot;One of about a dozen minitalks summarizing one of the
breakout groups&#x27; discussions.&quot; width=&quot;100%&quot; src=&quot;http://sedimental.org/uploads/maintainerati_2017_summaries.jpg&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Once those were through and coffee breaks were had, what I consider
the main event was upon us: An opportunity to discuss with GitHub
designers and developers all the different ways projects use
&lt;a href=&quot;https://en.wikipedia.org/wiki/GitHub&quot;&gt;GitHub&lt;/a&gt;, and how GitHub might improve to match those use
cases. I think these interactions have the most direct potential to
bear fruit, so in my excitement I wrote a bunch of the proceedings
down:&lt;/p&gt;
&lt;div class=&quot;toc&quot;&gt;&lt;span class=&quot;toctitle&quot;&gt;Contents&lt;/span&gt;&lt;ul&gt;&lt;li&gt;&lt;a href=&quot;#digested_emails&quot;&gt;Digested emails&lt;/a&gt;&lt;ul&gt;&lt;li&gt;&lt;a href=&quot;#star_spectrum&quot;&gt;Star spectrum&lt;/a&gt;&lt;/ul&gt;&lt;li&gt;&lt;a href=&quot;#code_review_permissions&quot;&gt;Code review permissions&lt;/a&gt;&lt;li&gt;&lt;a href=&quot;#dashboard_improvements&quot;&gt;Dashboard improvements&lt;/a&gt;&lt;li&gt;&lt;a href=&quot;#thanks&quot;&gt;Thanks!&lt;/a&gt;&lt;/ul&gt;&lt;/div&gt;&lt;h2 id=&quot;digested_emails&quot;&gt;&lt;a href=&quot;#digested_emails&quot; class=&quot;toclink&quot;&gt;Digested emails&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Discussion is one of the greatest things about GitHub, but as Jupyter
developer &lt;a href=&quot;https://github.com/ian-r-rose&quot;&gt;Ian Rose&lt;/a&gt; brought up, an email for every comment
can be overwhelming. Daily or weekly digests for issues, or even for
all your GitHub activity would be a huge improvement, especially for
more lightweight users of GitHub. This may not strike subscribers of
&lt;a href=&quot;http://weekly.hatnote.com/&quot;&gt;The Weeklypedia&lt;/a&gt; as a surprise, but I am a big fan of
email digests.&lt;/p&gt;
&lt;p&gt;More control over engagement levels could open a great new avenue for
driving traffic for GitHub, too.&lt;/p&gt;
&lt;h3 id=&quot;star_spectrum&quot;&gt;&lt;a href=&quot;#star_spectrum&quot; class=&quot;toclink&quot;&gt;Star spectrum&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Right now you can either &lt;a href=&quot;https://help.github.com/articles/about-stars/&quot;&gt;star&lt;/a&gt; repos or &lt;a href=&quot;https://help.github.com/articles/watching-and-unwatching-repositories/&quot;&gt;watch&lt;/a&gt; them, effectively getting
no notifications or &lt;em&gt;all&lt;/em&gt; of them.&lt;/p&gt;
&lt;p&gt;I&#x27;d estimate about a third of the repos I star look interesting, but
haven&#x27;t yet reached the point where I&#x27;d use or contribute to them. So
they mostly get starred and forgotten.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://starminder.xyz&quot;&gt;&lt;img title=&quot;A screenshot of the
simple but useful Starminder&quot; align=&quot;right&quot; width=&quot;40%&quot; src=&quot;http://sedimental.org/uploads/starminder_20171017.png&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;A friend of mine started a little project called
&lt;a href=&quot;https://starminder.xyz/&quot;&gt;&lt;em&gt;Starminder&lt;/em&gt;&lt;/a&gt;, which emails a nightly selection of five
of my starred repos. I&#x27;ve been having a grand time revisiting these
old stars and seeing how far they&#x27;ve come, even reminding me of
features I was waiting to build.&lt;/p&gt;
&lt;p&gt;And while I love &lt;a href=&quot;https://github.com/nkantar&quot;&gt;Nik&#x27;s work&lt;/a&gt;, instead of relying on
Starminder, it would be way better if I could tell GitHub roughly how
often I&#x27;d like updates on a project, and then get &lt;a href=&quot;https://github.com/twisted/twisted/pulse/monthly&quot;&gt;Pulse-like info&lt;/a&gt;
delivered to my inbox on a weekly or monthly basis.&lt;/p&gt;
&lt;p&gt;Commit activity, high-traffic issues, and especially new tags/releases
are all things I&#x27;d be very excited to get personalized, periodic
updates on, without having to get every single notification as a
separate email.&lt;/p&gt;
&lt;p&gt;One off-the-cuff idea I had was to establish some sort of star
gradient, with the basic star without notifications being an option on
one end of the opt-in engagement spectrum, and full-blown,
every-notification &quot;Watching&quot; on the other. Could there be one Star
dropdown to rule them all?&lt;/p&gt;
&lt;h2 id=&quot;code_review_permissions&quot;&gt;&lt;a href=&quot;#code_review_permissions&quot; class=&quot;toclink&quot;&gt;Code review permissions&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Requiring code review before merging is a pretty smart idea for any
rigorous project, and &lt;a href=&quot;https://help.github.com/articles/enabling-required-reviews-for-pull-requests/&quot;&gt;now GitHub supports it natively&lt;/a&gt;.
However, only developers with write permissions can actually perform a
code review. Here are some real-life use cases that demonstrate why this
is less than ideal:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;A senior developer not involved with the project files an issue
  requesting a feature. I would like them to review the implementation
  to ensure it does what they want. The senior developer has a busy
  schedule and doesn&#x27;t want to join the project and get a bunch of
  notifications, but would be qualified to review the code.&lt;/li&gt;
&lt;li&gt;A novice developer finds an problem in the documentation, they could
  review the new documentation for clarity. Their lack of experience
  makes them best qualified to review.&lt;/li&gt;
&lt;li&gt;The core maintainer implements a feature, but is actually the only
  developer on the project. Requesting a code review from
  non-project-member peers is a great way to get them to look at the
  code and become more involved with the project going forward.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;For bonus points all permissions could have an option to be
time-limited. Designated reviewr and expiration possibilities
notwithstanding, I think the best flow would include the ability to
add someone to a specific PR as reviewer, without giving them any
project-wide permissions.&lt;/p&gt;
&lt;h2 id=&quot;dashboard_improvements&quot;&gt;&lt;a href=&quot;#dashboard_improvements&quot; class=&quot;toclink&quot;&gt;Dashboard improvements&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;I&#x27;m probably weird for doing this, but I habitually visit the normal
&lt;a href=&quot;https://github.com/&quot;&gt;github.com&lt;/a&gt; logged-in landing page, aka the dashboard, several times a
day. Now, for the few of you who share my habit probably noticed,
there&#x27;s a new Discover tab, offering personalized
suggestions of repos to star.&lt;/p&gt;
&lt;p&gt;The event stream stayed mostly the same, however, as it has for many
years. But despite its maturity there are a couple events that
surprisingly don&#x27;t show up anywhere, even when the dashboard seems
like a natural fit:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Follows&lt;/strong&gt; - I have the better part of a thousand followers, but I can&#x27;t remember
  if I&#x27;ve ever seen a notification about this. &lt;a href=&quot;https://github.com/mahmoud?tab=followers&quot;&gt;They seem like nice folks!&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Stars on org-owned repos&lt;/strong&gt; - &lt;a href=&quot;https://github.com/python-attrs/attrs&quot;&gt;There&lt;/a&gt; &lt;a href=&quot;https://github.com/hatnote/montage&quot;&gt;are&lt;/a&gt;
  &lt;a href=&quot;https://github.com/python-hyper/hyperlink&quot;&gt;several&lt;/a&gt; &lt;a href=&quot;https://github.com/kurtbrose/pyjks&quot;&gt;repos&lt;/a&gt; I maintain and watch, but for
  which I&#x27;ve never seen on-dash notifications. What do they all have
  in common? They&#x27;re all owned by organizations (e.g.,
  &lt;a href=&quot;http://github.com/python-hyper&quot;&gt;python-hyper&lt;/a&gt;). Other types of
  notifications show up, but not stars.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Watches&lt;/strong&gt; - Not sure I&#x27;ve ever gotten a notification for someone
  watching one of my repos, even though they&#x27;re probably more
  interested in collaboration than the average stargazer.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Any or all of these would certainly make my &lt;a href=&quot;https://github.com/&quot;&gt;github.com&lt;/a&gt; itch
yield more interesting results, and I&#x27;m sure there are some
enhancements I&#x27;ve missed, too!&lt;/p&gt;
&lt;h2 id=&quot;thanks&quot;&gt;&lt;a href=&quot;#thanks&quot; class=&quot;toclink&quot;&gt;Thanks!&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Just wanted to say thanks to GitHub for putting together such a great
event. Whether or not any of these features materializes in the near
future, it was so nice to meet up with old friends and make some new
ones, too.&lt;/p&gt;
&lt;p&gt;Focused, cross-technology encounters like these are all too rare. For
my Python readers, let this serve as a reminder to get out and
interact with other stacks. Python&#x27;s strength is its integrative
nature, and I think that can be a strength for us Pythonists as well.&lt;/p&gt;
&lt;p&gt;In any case, thanks for the event, GitHub! Hope to see you again next
year!&lt;p&gt;&lt;/p&gt;



&lt;hr /&gt;

</content>

  </entry>
  
  <entry>
    <id>http://sedimental.org/plugin_systems.html</id>
    <author>
      <name>Mahmoud Hashemi</name>
      <uri>http://sedimental.org/</uri>
    </author>
    <title>Plugin Systems</title>
    <link rel="alternate" type="text/html" href="http://sedimental.org/plugin_systems.html" />
    <published>2017-07-11T18:00:00Z</published>
    <updated>2017-07-11T18:00:00Z</updated>
    <category term="code"/><category term="pycon"/><category term="python"/><category term="plugins"/>
    

    <content type="html">&lt;p&gt;&lt;p&gt;&lt;em&gt;&quot;What are plugins?&quot; and other proceedings of the inaugural PyCon
Comparative Plugin Systems &lt;a href=&quot;https://en.wikipedia.org/wiki/Birds_of_a_feather_(computing)&quot;&gt;BoF&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Update: This BoF and post inspired [a talk I gave at PyGotham 2017][pygotham2017].&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Within the programming world, and the Python ecosystem in particular,
there are a lot of presumptions around plugins. Specifically, we take
them for granted. &quot;It&#x27;s &lt;em&gt;just&lt;/em&gt; a plugin.&quot; &quot;Oh, &lt;em&gt;another&lt;/em&gt; plugin library?&quot;&lt;/p&gt;
&lt;p&gt;So for PyCon 2017, I resolved to dismiss the dismissals by revisiting
plugins, and it may have been the best programming decision I&#x27;ve made
all year.&lt;/p&gt;
&lt;p&gt;&lt;img align=&quot;right&quot; width=&quot;40%&quot; src=&quot;http://sedimental.org/uploads/illo/snake_plugin_sm.png&quot; /&gt;&lt;/p&gt;
&lt;div class=&quot;toc&quot;&gt;&lt;span class=&quot;toctitle&quot;&gt;Contents&lt;/span&gt;&lt;ul&gt;&lt;li&gt;&lt;a href=&quot;#why_plugins&quot;&gt;Why plugins?&lt;/a&gt;&lt;li&gt;&lt;a href=&quot;#setting_examples&quot;&gt;Setting examples&lt;/a&gt;&lt;li&gt;&lt;a href=&quot;#taxonomizing&quot;&gt;Taxonomizing&lt;/a&gt;&lt;ul&gt;&lt;li&gt;&lt;a href=&quot;#generalizability&quot;&gt;Generalizability&lt;/a&gt;&lt;li&gt;&lt;a href=&quot;#discovery&quot;&gt;Discovery&lt;/a&gt;&lt;li&gt;&lt;a href=&quot;#install_location&quot;&gt;Install location&lt;/a&gt;&lt;li&gt;&lt;a href=&quot;#plugin_independence&quot;&gt;Plugin independence&lt;/a&gt;&lt;li&gt;&lt;a href=&quot;#dependency_registration&quot;&gt;Dependency registration&lt;/a&gt;&lt;/ul&gt;&lt;li&gt;&lt;a href=&quot;#drawing_a_line&quot;&gt;Drawing a line&lt;/a&gt;&lt;li&gt;&lt;a href=&quot;#a_definition&quot;&gt;A definition&lt;/a&gt;&lt;li&gt;&lt;a href=&quot;#motivation&quot;&gt;Motivation&lt;/a&gt;&lt;li&gt;&lt;a href=&quot;#in_conclusion&quot;&gt;In conclusion&lt;/a&gt;&lt;/ul&gt;&lt;/div&gt;&lt;h2 id=&quot;why_plugins&quot;&gt;&lt;a href=&quot;#why_plugins&quot; class=&quot;toclink&quot;&gt;Why plugins?&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;For all types of software, open-source or otherwise, the scalability
of development poses a problem long before scalability of performance
and other technical challenges. Engaging more developers creates code
contention and bugs. Too many cooks is all it takes to spoil the
broth.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;All growing projects need an API for code integration.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Call them plugins, modules, or extensions, from your browser to your
kernel, they are &lt;em&gt;the&lt;/em&gt; widely successful solution. Tellingly, the only
thing wider than the success of plugin-based architecture is the
variety of implementations.&lt;/p&gt;
&lt;p&gt;Python&#x27;s dynamic nature in particular seems to encourage
inventiveness. The more the merrier, usually, but at some point we
cloud a tricky space. How different could these plugin systems be? How
wide is the range of functionalities, really? How does a developer
choose the right plugin system for a given project? For that matter,
what is a plugin system anyway? No one I talked to had clear answers.&lt;/p&gt;
&lt;p&gt;So when &lt;a href=&quot;https://us.pycon.org/2017/about/&quot;&gt;PyCon 2017&lt;/a&gt; rolled around, I knew exactly what I
wanted to do: call together a team of developers to get to the bottom
of the above, or at the very least, answer the question,&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;&quot;What happens when you ask a dozen veteran Python programmers
to spill their guts about plugins?&quot;&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;img title=&quot;Our fearless band of extensionists&quot; width=&quot;100%&quot; src=&quot;http://sedimental.org/uploads/pycon_2017_plugin_bof_crop.jpg&quot; /&gt;&lt;/p&gt;
&lt;h2 id=&quot;setting_examples&quot;&gt;&lt;a href=&quot;#setting_examples&quot; class=&quot;toclink&quot;&gt;Setting examples&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Our group leapt into action by listing off plugin systems as fast as we could:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.openstack.org/stevedore/latest/&quot;&gt;stevedore&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.twisted.org/en/stable/core/howto/plugin.html&quot;&gt;twisted.plugin&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.mercurial-scm.org/wiki/WritingExtensions&quot;&gt;Mercurial extensions&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.pytest.org/en/latest/plugins.html&quot;&gt;pytest plugins&lt;/a&gt; (&lt;a href=&quot;https://github.com/pytest-dev/pluggy&quot;&gt;pluggy&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://gather.readthedocs.io/en/latest/&quot;&gt;gather&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.pylonsproject.org/projects/venusian/en/latest/&quot;&gt;venusian&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://pluginbase.pocoo.org/&quot;&gt;pluginbase&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://straightplugin.readthedocs.io/en/latest/&quot;&gt;straight.plugin&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.pylint.org/en/1.6.0/plugins.html&quot;&gt;pylint plugins&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://flake8.pycqa.org/en/latest/plugin-development/&quot;&gt;flake8 plugins&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://setuptools.readthedocs.io/en/latest/setuptools.html#dynamic-discovery-of-services-and-plugins&quot;&gt;raw setuptools entrypoints&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://zopecomponent.readthedocs.io/en/latest/&quot;&gt;zope.component&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://django-extensions.readthedocs.io/en/latest/&quot;&gt;Django command extensions&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://docs.sqlalchemy.org/en/latest/dialects/index.html&quot;&gt;SQLAlchemy dialects/DBAPIs&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://www.sphinx-doc.org/en/stable/extdev/index.html#dev-extensions&quot;&gt;Sphinx extensions&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://docs.buildout.org/en/latest/topics/extensions.html&quot;&gt;Buildout extensions&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://pyarmory-pike.readthedocs.io/en/latest/&quot;&gt;Pike&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://dectate.readthedocs.io/en/latest/&quot;&gt;Dectate&lt;/a&gt; and &lt;a href=&quot;http://reg.readthedocs.io/en/latest/index.html&quot;&gt;Reg&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Others that came and went a little too fast to jot down&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;With our plate heaping with examples like these, we all felt ready to
dig into our big questions.&lt;/p&gt;
&lt;h2 id=&quot;taxonomizing&quot;&gt;&lt;a href=&quot;#taxonomizing&quot; class=&quot;toclink&quot;&gt;Taxonomizing&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;For our first bit of analysis, we asked: What practical and
fundamental attributes differentiate these approaches? If we had to
create a taxonomy, what characteristics would we look for?&lt;/p&gt;
&lt;h3 id=&quot;generalizability&quot;&gt;&lt;a href=&quot;#generalizability&quot; class=&quot;toclink&quot;&gt;Generalizability&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;You&#x27;ll notice our list of example plugin systems included several very
specialized examples, from pylint to SQLAlchemy. Many projects even
use totally internal plugin systems to achieve better
factoring.&lt;/p&gt;
&lt;p&gt;Bespoke plugin systems like pylint&#x27;s are a valuable reference for
anyone looking to account for patterns in their own system, especially
generic systems like &lt;a href=&quot;http://www.giantflyingsaucer.com/blog/?p=5858&quot;&gt;pike and stevedore&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&quot;discovery&quot;&gt;&lt;a href=&quot;#discovery&quot; class=&quot;toclink&quot;&gt;Discovery&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;A plugin system&#x27;s first job is locating the plugins to load. The split
here is whether plugins are individually specified, or automatically
discovered based on paths and patterns.&lt;/p&gt;
&lt;p&gt;In either case, we need paths. Some systems provide search
functionality, exchanging explicitness for convenience. This can be a
good trade, especially when plugins number in the double digits, or
whenever less technical users are concerned.&lt;/p&gt;
&lt;h3 id=&quot;install_location&quot;&gt;&lt;a href=&quot;#install_location&quot; class=&quot;toclink&quot;&gt;Install location&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Closely related to discovery, our next differentiator was the degree
to which the plugin system leveraged Python&#x27;s own package management
facilities. Some systems, like &lt;a href=&quot;https://docs.pylonsproject.org/projects/venusian/en/latest/&quot;&gt;venusian&lt;/a&gt;, were designed to encourage
&lt;code&gt;pip install&lt;/code&gt;-ing plugins, searching for them in &lt;code&gt;site-packages&lt;/code&gt;,
alongside the application itself.&lt;/p&gt;
&lt;p&gt;Other systems have their own search paths, locating plugins in the
user directory and elsewhere on the filesystem. Still other systems
are designed for plugins inside the application tree, as is the case
with &lt;a href=&quot;https://docs.djangoproject.com/en/1.11/ref/applications/&quot;&gt;Django apps&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&quot;plugin_independence&quot;&gt;&lt;a href=&quot;#plugin_independence&quot; class=&quot;toclink&quot;&gt;Plugin independence&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;One of the most challenging parts of plugin development is finding
ways of independently reusing and testing code, while keeping in mind
the code&#x27;s role as an optional component of another application.&lt;/p&gt;
&lt;p&gt;In some systems, like Django&#x27;s, the tailoring is so tightly coupled
that reusability doesn&#x27;t make sense. But other approaches, like
&lt;a href=&quot;http://gather.readthedocs.io/en/latest/&quot;&gt;gather&lt;/a&gt;&#x27;s, keeps plugin code independently usable.&lt;/p&gt;
&lt;h3 id=&quot;dependency_registration&quot;&gt;&lt;a href=&quot;#dependency_registration&quot; class=&quot;toclink&quot;&gt;Dependency registration&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Almost all plugins work by providing some set of &lt;em&gt;hooks&lt;/em&gt; which are
findable and callable by the core. We found another differentiator in
whether and how plugins could gain access to resources from the core,
and even other plugins.&lt;/p&gt;
&lt;p&gt;Not all systems support this, preferring to keep plugins as leaf
participants in the application. Those simplistic setups hit limits
fast. The next best, and most common, solution is to simply pass the
whole core state at the time of hook invocation, providing plugins
with the same access as the core. It works, but the API becomes the
whole system state.&lt;/p&gt;
&lt;p&gt;More advanced systems allow plugins to publish an inventory of
dependencies, which the core then injects. Higher granularity enables
lazier evaluation for a performance boost, and more explicit structure
helps create a more maintainable application overall.&lt;/p&gt;
&lt;h2 id=&quot;drawing_a_line&quot;&gt;&lt;a href=&quot;#drawing_a_line&quot; class=&quot;toclink&quot;&gt;Drawing a line&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;With our group feeling like we were approaching the nature of things,
we reversed direction, asking instead: What &lt;em&gt;isn&#x27;t&lt;/em&gt; a plugin system?&lt;/p&gt;
&lt;p&gt;Establishing explicit boundaries and specific counterexamples proved
instrumental to producing a final definition.&lt;/p&gt;
&lt;p&gt;Is &lt;a href=&quot;https://docs.python.org/2/library/functions.html#eval&quot;&gt;&lt;code&gt;eval()&lt;/code&gt;&lt;/a&gt; a plugin system? We thought maybe, at first. But
the more we thought about it, no, because the code itself was not
sufficiently abstracted through a loading or namespacing system.&lt;/p&gt;
&lt;p&gt;Is &lt;a href=&quot;https://en.wikipedia.org/wiki/Domain_Name_System&quot;&gt;DNS&lt;/a&gt; a plugin system? It has names and namespaces galore. But
no, because code is not being loaded &lt;em&gt;in&lt;/em&gt;. Remote services in general
are beyond the boundary of what a plugin can be. They exist out there,
and we call out to them. They&#x27;re callouts, not plugins.&lt;/p&gt;
&lt;h2 id=&quot;a_definition&quot;&gt;&lt;a href=&quot;#a_definition&quot; class=&quot;toclink&quot;&gt;A definition&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;So with our boundaries established, we were ready to offer a
definition:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;A plugin system is a software facility used by a running program to
discover and load code, often containing hooks called by the host
application&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;But, by this definition, isn&#x27;t Python&#x27;s built-in &lt;code&gt;import&lt;/code&gt;
functionality a plugin system? Mostly, yes! Python&#x27;s import system is
a plugin system.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;For discovery it uses &lt;a href=&quot;https://docs.python.org/2/library/sys.html#sys.path&quot;&gt;&lt;code&gt;sys.path&lt;/code&gt;&lt;/a&gt;, various &quot;site&quot;
  directories and &quot;.pth&quot; files, and &lt;a href=&quot;https://docs.python.org/2/library/sys.html#sys.path_hooks&quot;&gt;much more&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;For installation, it uses &lt;code&gt;site-packages&lt;/code&gt;,
  &lt;a href=&quot;https://pip.readthedocs.io/en/latest/user_guide/#user-installs&quot;&gt;user &lt;code&gt;.local&lt;/code&gt; directories&lt;/a&gt;, and more.&lt;/li&gt;
&lt;li&gt;As far as independent reusability, virtually every module
  &lt;a href=&quot;https://docs.python.org/2/using/cmdline.html#cmdoption-m&quot;&gt;can be made its own entrypoint&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;As for dependency registration, every module is tossed into
  &lt;a href=&quot;https://docs.python.org/2/library/sys.html#sys.modules&quot;&gt;&lt;code&gt;sys.modules&lt;/code&gt;&lt;/a&gt; with the others, but also has access to
  &lt;code&gt;import&lt;/code&gt; and &lt;code&gt;sys&lt;/code&gt;, making roughly every module an equal partner in
  application state.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Python&#x27;s import system is a powerful one, with a
&lt;a href=&quot;https://docs.python.org/3/reference/import.html#finders-and-loaders&quot;&gt;plugin system&lt;/a&gt; of its own. But finders, loaders, and
import hooks aren&#x27;t &lt;em&gt;Python&#x27;s&lt;/em&gt; plugin system. For that, you need to
look to &lt;a href=&quot;https://docs.python.org/2/library/site.html&quot;&gt;the &lt;code&gt;site&lt;/code&gt; module&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;motivation&quot;&gt;&lt;a href=&quot;#motivation&quot; class=&quot;toclink&quot;&gt;Motivation&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;With our hour nearly up, all these proximate details still
needed to be distilled into an ultimate motivation behind plugins. To
this end, we returned to one of software engineering&#x27;s fundamental
principles: &lt;a href=&quot;https://en.wikipedia.org/wiki/Separation_of_concerns&quot;&gt;Separation of concerns&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;We want to reason about our software. We want to know what state it is
in. What we all want is the ability to say, &quot;the core is ready,
proceeding to load modules/extensions/plugins.&quot; We want to defer
loading &lt;em&gt;some&lt;/em&gt; code so that we can add extra instrumentation, checks,
resiliency, and error messages to that loading process. If something
misbehaves, we can do better than a stack trace and an &lt;code&gt;ImportError&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Python&#x27;s import system is a plugin system of sorts, but because
we use it all the time, we&#x27;ve already used up most of the concern
separation potential of &lt;code&gt;import&lt;/code&gt;. Hence, all the creativity around
plugin systems, seeking a balance between feeling native to Python,
while not still successfully separating concerns.&lt;/p&gt;
&lt;h2 id=&quot;in_conclusion&quot;&gt;&lt;a href=&quot;#in_conclusion&quot; class=&quot;toclink&quot;&gt;In conclusion&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;So now we have achieved a complete view of the Python plugin system
ecosystem, from motivation to manifestation.&lt;/p&gt;
&lt;p&gt;By numbers alone, it may seem on the face like there are more than
enough Python plugin solutions. But looking at the motivation and
taxonomy above, it&#x27;s clear that there are still several gaps waiting
to be filled.&lt;/p&gt;
&lt;p&gt;By taking a holistic look at the implementations and motivations, the
PyCon 2017 Plugins Open Session ended with the conclusion that even
&lt;a href=&quot;http://sedimental.org/plugin_systems.html#setting_examples&quot;&gt;Python&#x27;s wide selection&lt;/a&gt; could use expansion.&lt;/p&gt;
&lt;p&gt;So, until next year, go forth and continue to build! The future of
well-factored code depends on it.&lt;sup id=&quot;fnref:further&quot;&gt;&lt;a class=&quot;footnote-ref&quot; href=&quot;http://sedimental.org/plugin_systems.html#fn:further&quot;&gt;1&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;
&lt;p&gt;&lt;img width=&quot;50%&quot; src=&quot;http://sedimental.org/uploads/illo/snake_puzzle_sm.png&quot; /&gt;&lt;/p&gt;
&lt;div class=&quot;footnote&quot;&gt;
&lt;hr /&gt;
&lt;ol&gt;
&lt;li id=&quot;fn:further&quot;&gt;
&lt;p&gt;For additional reading, I recommend doing what we did
after our discussion, finding and reading
&lt;a href=&quot;http://eli.thegreenplace.net/2012/08/07/fundamental-concepts-of-plugin-infrastructures&quot;&gt;this post from Eli Bendersky&lt;/a&gt;. While it
focuses more on specific implementations and less about
generalized systems, Eli&#x27;s post overlaps in many very
reaffirming ways, much to our relief and
gratification. The worked example of building
ReStructured Text plugins is a perfect complement to the
post above. &lt;a class=&quot;footnote-backref&quot; href=&quot;http://sedimental.org/plugin_systems.html#fnref:further&quot; title=&quot;Jump back to footnote 1 in the text&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;&lt;p&gt;&lt;/p&gt;



&lt;hr /&gt;

</content>

  </entry>
  
  <entry>
    <id>http://sedimental.org/the_packaging_gradient.html</id>
    <author>
      <name>Mahmoud Hashemi</name>
      <uri>http://sedimental.org/</uri>
    </author>
    <title>The Many Layers of Packaging</title>
    <link rel="alternate" type="text/html" href="http://sedimental.org/the_packaging_gradient.html" />
    <published>2017-05-09T20:47:00Z</published>
    <updated>2017-05-09T20:47:00Z</updated>
    <category term="python"/><category term="packaging"/><category term="boltons"/>
    

    <content type="html">&lt;p&gt;&lt;p&gt;&lt;em&gt;The packaging gradient, and why PyPI isn&#x27;t an app store.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Update: I turned this post into a talk. The &lt;a href=&quot;https://www.youtube.com/watch?v=iLVNWfPWAC8&quot;&gt;video from PyBay is
here&lt;/a&gt;, the &lt;a href=&quot;https://speakerdeck.com/mhashemi/the-packaging-gradient&quot;&gt;slides are available here&lt;/a&gt;. The
long-cut video from &lt;a href=&quot;https://www.meetup.com/BAyPIGgies/events/242072266/&quot;&gt;BayPiggies&lt;/a&gt; is coming, but &lt;a href=&quot;https://speakerdeck.com/mhashemi/the-packaging-gradient-extended-edition&quot;&gt;the
&quot;Extended Edition&quot; slides are here&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;One lesson threaded throughout
&lt;a href=&quot;https://www.oreilly.com/library/view/enterprise-software-with/9781491943755/&quot;&gt;&lt;em&gt;Enterprise Software with Python&lt;/em&gt;&lt;/a&gt; is that deployment is not the
last step of development. The mark of an experienced engineer is to
work backwards from deployment, planning and designing for the reality
of production environments.&lt;/p&gt;
&lt;p&gt;You could learn this the hard way. Or you could come on a journey into
what I call &lt;em&gt;the packaging gradient&lt;/em&gt;. It&#x27;s a quick and easy decision
tree to figure out what you need to ship. You&#x27;ll gain a trained eye,
and an understanding as to why there seem to be so many conflicting
opinions about how to package code.&lt;/p&gt;
&lt;p&gt;The first lesson on our adventure is:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;Implementation language does not define packaging solutions.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;img align=&quot;right&quot; width=&quot;40%&quot; src=&quot;http://sedimental.org/uploads/illo/snake_box_sm.png&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Packaging is all about target environment and deployment
experience. Python will be used in examples, but the same decision
tree applies to most general-purpose languages.&lt;/p&gt;
&lt;p&gt;Python was designed to be cross-platform and runs in countless
environments. But don&#x27;t take this to mean that Python&#x27;s built-in tools
will carry you anywhere you want to go. I can
&lt;a href=&quot;https://kivy.org/docs/guide/android.html&quot;&gt;write a mobile app in Python&lt;/a&gt;, does it make sense to
install it on my phone with &lt;a href=&quot;https://en.wikipedia.org/wiki/Pip_(package_manager)&quot;&gt;pip&lt;/a&gt;? As you&#x27;ll see, a language&#x27;s
built-in tools only scratch the surface.&lt;/p&gt;
&lt;p&gt;So, one by one, I&#x27;m going to describe some code you want to ship,
followed by the simplest acceptable packaging process that provides
that repeatable deployment process we crave. We save the most involved
solutions for last, right before &lt;a href=&quot;http://sedimental.org/the_packaging_gradient.html#closing&quot;&gt;the short version&lt;/a&gt;. Ready?
Let&#x27;s go!&lt;/p&gt;
&lt;div class=&quot;toc&quot;&gt;&lt;span class=&quot;toctitle&quot;&gt;Contents&lt;/span&gt;&lt;ul&gt;&lt;li&gt;&lt;a href=&quot;#prelude_the_humble_script&quot;&gt;Prelude: The Humble Script&lt;/a&gt;&lt;li&gt;&lt;a href=&quot;#the_python_module&quot;&gt;The Python Module&lt;/a&gt;&lt;li&gt;&lt;a href=&quot;#the_pure_python_package&quot;&gt;The pure-Python Package&lt;/a&gt;&lt;li&gt;&lt;a href=&quot;#the_python_package&quot;&gt;The Python Package&lt;/a&gt;&lt;li&gt;&lt;a href=&quot;#milestone_outgrowing_our_roots&quot;&gt;Milestone: Outgrowing our roots&lt;/a&gt;&lt;li&gt;&lt;a href=&quot;#depending_on_pre_installed_python&quot;&gt;Depending on pre-installed Python&lt;/a&gt;&lt;li&gt;&lt;a href=&quot;#depending_on_a_new_python_ecosystem&quot;&gt;Depending on a new Python/ecosystem&lt;/a&gt;&lt;li&gt;&lt;a href=&quot;#bringing_your_own_python&quot;&gt;Bringing your own Python&lt;/a&gt;&lt;ul&gt;&lt;li&gt;&lt;a href=&quot;#servers_ride_the_bus&quot;&gt;Servers ride the bus&lt;/a&gt;&lt;/ul&gt;&lt;li&gt;&lt;a href=&quot;#bringing_your_own_userspace&quot;&gt;Bringing your own userspace&lt;/a&gt;&lt;ul&gt;&lt;li&gt;&lt;a href=&quot;#in_our_own_image&quot;&gt;In our own image&lt;/a&gt;&lt;li&gt;&lt;a href=&quot;#an_image_by_any_other_name&quot;&gt;An image by any other name&lt;/a&gt;&lt;li&gt;&lt;a href=&quot;#the_whale_in_the_room&quot;&gt;The whale in the room&lt;/a&gt;&lt;/ul&gt;&lt;li&gt;&lt;a href=&quot;#bringing_your_own_kernel&quot;&gt;Bringing your own kernel&lt;/a&gt;&lt;li&gt;&lt;a href=&quot;#bringing_your_own_hardware&quot;&gt;Bringing your own hardware&lt;/a&gt;&lt;li&gt;&lt;a href=&quot;#but_what_about&quot;&gt;But what about...&lt;/a&gt;&lt;ul&gt;&lt;li&gt;&lt;a href=&quot;#os_packages&quot;&gt;OS packages&lt;/a&gt;&lt;li&gt;&lt;a href=&quot;#virtualenv&quot;&gt;virtualenv&lt;/a&gt;&lt;li&gt;&lt;a href=&quot;#security&quot;&gt;Security&lt;/a&gt;&lt;/ul&gt;&lt;li&gt;&lt;a href=&quot;#closing&quot;&gt;Closing&lt;/a&gt;&lt;/ul&gt;&lt;/div&gt;&lt;h2 id=&quot;prelude_the_humble_script&quot;&gt;&lt;a href=&quot;#prelude_the_humble_script&quot; class=&quot;toclink&quot;&gt;Prelude: The Humble Script&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Everyone&#x27;s first exposure to Python deployment was something so
innocuous you probably wouldn&#x27;t remember. You copied a script from
point &lt;em&gt;A&lt;/em&gt; to point &lt;em&gt;B&lt;/em&gt;. Chances are, whether &lt;em&gt;A&lt;/em&gt; and &lt;em&gt;B&lt;/em&gt; were separate
directories or computers, your days of &quot;just use &lt;code&gt;cp&lt;/code&gt;&quot; didn&#x27;t last
long.&lt;/p&gt;
&lt;p&gt;Because while a single file is the ideal format for copying, it
doesn&#x27;t work when that file has unmet dependencies at the destination.&lt;/p&gt;
&lt;p&gt;Even simple scripts end up depending on:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Python libraries - &lt;a href=&quot;https://github.com/mahmoud/boltons&quot;&gt;boltons&lt;/a&gt;, &lt;a href=&quot;https://github.com/kennethreitz/requests&quot;&gt;requests&lt;/a&gt;, &lt;a href=&quot;https://github.com/numpy/numpy&quot;&gt;NumPy&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Python, the runtime - &lt;a href=&quot;https://en.wikipedia.org/wiki/CPython&quot;&gt;CPython&lt;/a&gt;, &lt;a href=&quot;https://en.wikipedia.org/wiki/PyPy&quot;&gt;PyPy&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;System libraries - &lt;a href=&quot;https://en.wikipedia.org/wiki/GNU_C_Library&quot;&gt;glibc&lt;/a&gt;, &lt;a href=&quot;http://zlib.net/&quot;&gt;zlib&lt;/a&gt;, &lt;a href=&quot;https://anaconda.org/anaconda/libxml2&quot;&gt;libxml2&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Operating system - &lt;a href=&quot;https://en.wikipedia.org/wiki/Ubuntu_(operating_system)&quot;&gt;Ubuntu&lt;/a&gt;, &lt;a href=&quot;https://www.freebsd.org/&quot;&gt;FreeBSD&lt;/a&gt;, &lt;a href=&quot;http://68.media.tumblr.com/e846f7ed786ead5cee6e4097b254b181/tumblr_mqfh4b0rV61sydj82o1_250.gif&quot;&gt;Windows&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;So every good packaging adventure always starts with the question:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Where is your code going, and what can we depend on being there?&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;First, let&#x27;s look at libraries. Virtually every project these days
begins with library package management, a little &lt;code&gt;pip install&lt;/code&gt;. It&#x27;s
worth a closer look!&lt;/p&gt;
&lt;h2 id=&quot;the_python_module&quot;&gt;&lt;a href=&quot;#the_python_module&quot; class=&quot;toclink&quot;&gt;The Python Module&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Python library code comes in two sizes, &lt;a href=&quot;https://docs.python.org/2/tutorial/modules.html&quot;&gt;module&lt;/a&gt; and package,
practically corresponding to files and directories on disk. Packages
can contain modules and packages, and in some cases can grow to be
quite sprawling. The module, being a single file, is much easier to
redistribute.&lt;/p&gt;
&lt;p&gt;In fact, if a pure-Python module imports nothing but the standard
library itself, you have the unique option of being able to distribute
it by simply copying the single file into your codebase.&lt;/p&gt;
&lt;p&gt;This type of inclusion, known as vendoring, is often glossed over, but
bears many advantages. &lt;a href=&quot;https://www.python.org/dev/peps/pep-0020/&quot;&gt;Simple is better than complex&lt;/a&gt;. No extra
commands or formats, no build, no install. Just copy the
code&lt;sup id=&quot;fnref:licenses&quot;&gt;&lt;a class=&quot;footnote-ref&quot; href=&quot;http://sedimental.org/the_packaging_gradient.html#fn:licenses&quot;&gt;1&lt;/a&gt;&lt;/sup&gt; and roll.&lt;/p&gt;
&lt;p&gt;For examples of libraries doing this, see &lt;a href=&quot;https://bottlepy.org/docs/dev/&quot;&gt;bottle.py&lt;/a&gt;,
&lt;a href=&quot;https://github.com/mahmoud/ashes&quot;&gt;ashes&lt;/a&gt;, &lt;a href=&quot;https://github.com/keleshev/schema&quot;&gt;schema&lt;/a&gt;, and, of course,
&lt;a href=&quot;https://github.com/mahmoud/boltons&quot;&gt;boltons&lt;/a&gt;, which also has
&lt;a href=&quot;http://boltons.readthedocs.io/en/latest/architecture.html&quot;&gt;an architectural statement&lt;/a&gt; on the topic.&lt;/p&gt;
&lt;h2 id=&quot;the_pure_python_package&quot;&gt;&lt;a href=&quot;#the_pure_python_package&quot; class=&quot;toclink&quot;&gt;The pure-Python Package&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Packages are the larger unit of redistributable Python. Packages are
directories of code containing an &lt;code&gt;__init__.py&lt;/code&gt;. Provided they contain
only pure-Python modules, they can also be vendored, similar to the
module above. Even very popular packages
&lt;a href=&quot;https://github.com/pypa/pip/#TODO&quot;&gt;like pip itself&lt;/a&gt; can be found with &lt;code&gt;vendor&lt;/code&gt;, &lt;code&gt;lib&lt;/code&gt;,
and &lt;code&gt;packages&lt;/code&gt; directories.&lt;/p&gt;
&lt;p&gt;Because these packages nest and sprawl, vendoring can lead to
codebases that feel unwieldy. While it may seem awkward to have &lt;code&gt;lib&lt;/code&gt;
directories many times larger than your application, it&#x27;s more common
than some less-experienced devs might expect. That said, having worked
on some very large codebases, I can definitely understand why core
Python developers created other options for distributing Python
libraries.&lt;/p&gt;
&lt;p&gt;For libraries that only contain Python code, whether single-file or
multi-file, Python&#x27;s original built-in solution still works today:
&lt;a href=&quot;https://docs.python.org/2/distutils/sourcedist.html&quot;&gt;sdists&lt;/a&gt;, or &quot;source distributions&quot;. This early format has
worked for well over a decade and is still supported by &lt;code&gt;pip&lt;/code&gt; and the
&lt;a href=&quot;https://pypi.python.org/pypi&quot;&gt;Python Package Index&lt;/a&gt; (PyPI)&lt;sup id=&quot;fnref:pypi&quot;&gt;&lt;a class=&quot;footnote-ref&quot; href=&quot;http://sedimental.org/the_packaging_gradient.html#fn:pypi&quot;&gt;2&lt;/a&gt;&lt;/sup&gt;.&lt;/p&gt;
&lt;h2 id=&quot;the_python_package&quot;&gt;&lt;a href=&quot;#the_python_package&quot; class=&quot;toclink&quot;&gt;The Python Package&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Python is a great language, and one which is made all the greater
by its power to integrate.&lt;/p&gt;
&lt;p&gt;Many libraries contain &lt;a href=&quot;http://sedimental.org/python_by_the_c_side.html&quot;&gt;C&lt;/a&gt;, &lt;a href=&quot;https://en.wikipedia.org/wiki/Cython&quot;&gt;Cython&lt;/a&gt;, and other
statically-compiled languages that need build tools. If we distribute
such code using sdists, installation will trigger a build that will
fail without the tools, will take time and resources if it succeeds,
and generally involve more intermediary languages and four-letter
keywords than Python devs thought should be necessary.&lt;/p&gt;
&lt;p&gt;When you have a library that requires compilation, then it&#x27;s
definitely time to look into &lt;a href=&quot;http://pythonwheels.com/&quot;&gt;the wheel format&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Wheels are named after wheels of cheese, found in
&lt;a href=&quot;https://wiki.python.org/moin/CheeseShop&quot;&gt;the proverbial cheese shop&lt;/a&gt;. Aptly named, wheels really
help get development rolling. Unlike source distributions like sdists,
the publisher does all the building, resulting in a system-specific
binary.&lt;/p&gt;
&lt;p&gt;The install process just decompresses and copies files into
place. It&#x27;s so simple that even pure-Python code gets installed &lt;a href=&quot;https://hynek.me/articles/sharing-your-labor-of-love-pypi-quick-and-dirty/&quot;&gt;faster&lt;/a&gt;
when packaged as a wheel instead of an sdist.&lt;/p&gt;
&lt;p&gt;Now even when you upload wheels, I still recommend uploading sdists as
a fallback solution for those occasions when a wheel won&#x27;t work. It&#x27;s
simply not possible to prebuild wheels for all configurations in all
environments. If you&#x27;re curious what that means, check out
&lt;a href=&quot;https://github.com/pypa/manylinux/blob/master/pep-513.rst#rationale&quot;&gt;the design rationale behind manylinux1 wheels&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;milestone_outgrowing_our_roots&quot;&gt;&lt;a href=&quot;#milestone_outgrowing_our_roots&quot; class=&quot;toclink&quot;&gt;Milestone: Outgrowing our roots&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;img align=&quot;right&quot; width=&quot;40%&quot; src=&quot;http://sedimental.org/uploads/illo/legatree_med.png&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Now, three approaches in, we&#x27;ve hit our first milestone. So far,
everything has relied on built-in Python tools. pip, PyPI, the wheel
and sdist formats, all of these were designed &lt;em&gt;by&lt;/em&gt; developers, &lt;em&gt;for&lt;/em&gt;
developers, to distribute code and tools &lt;em&gt;to&lt;/em&gt; other developers.&lt;/p&gt;
&lt;p&gt;In other words:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;PyPI is not an app store.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;PyPI, pip, wheels, and the underlying setuptools machinations are all
designed for &lt;em&gt;libraries&lt;/em&gt;. Code for developer reuse.&lt;/p&gt;
&lt;p&gt;Going back to our first example, a &quot;script&quot; is more accurately
described as a command-line &lt;em&gt;application&lt;/em&gt;. Command-line applications
can have a Python-savvy audience, so it&#x27;s not totally unreasonable to
host them on PyPI and install them with pip (or &lt;a href=&quot;https://github.com/mitsuhiko/pipsi&quot;&gt;pipsi&lt;/a&gt;). But
understand that we&#x27;re approaching the limit for a good production and
user-facing experience.&lt;/p&gt;
&lt;p&gt;So let&#x27;s get explicit. By default, the built-in packaging tools are
designed to depend on:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;A working Python installation&lt;/li&gt;
&lt;li&gt;A network connection, probably to the Internet&lt;/li&gt;
&lt;li&gt;Pre-installed system libraries&lt;/li&gt;
&lt;li&gt;A developer who is willing to sit and watch dependencies
  recursively download at install-time, and debug version conflicts,
  build errors, and myriad other issues.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;These are fine, and expected for development environments.
Professionals are paid to do it, students pay to learn it, and there
are even a few oddballs who enjoy this sort of thing.&lt;/p&gt;
&lt;p&gt;Going into our next options, notice how we have shifted gears to
support &lt;em&gt;applications&lt;/em&gt;. Remember that distributing applications is
more a function of target platform than of implementation
language. This is harder than library distribution because we stop
depending on layers of the stack, and the developer who would be there
to ensure the setup works.&lt;/p&gt;
&lt;h2 id=&quot;depending_on_pre_installed_python&quot;&gt;&lt;a href=&quot;#depending_on_pre_installed_python&quot; class=&quot;toclink&quot;&gt;Depending on pre-installed Python&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;For our first foray into application distribution, we&#x27;re going to
maintain the assumption that Python exists in the target
environment. This isn&#x27;t the wildest assumption, CPython 2 is available
on virtually every Linux and Mac machine.&lt;/p&gt;
&lt;p&gt;Taking Python for granted, we can turn to bundling up all of the
Python libraries on which our code depends. We want a single
executable file, the kind that you can double click or run by
prefixing with a &lt;code&gt;./&lt;/code&gt;, anywhere on a Python-enabled
host. &lt;a href=&quot;https://pex.readthedocs.io/en/latest/&quot;&gt;The PEX format&lt;/a&gt; gets us exactly this.&lt;/p&gt;
&lt;p&gt;The PEX, or Python EXecutable, is a carefully-constructed ZIP archive,
with just a hint of bootstrapping. PEXs can be built for Linux, Mac,
and Windows. Artifacts rely on the system Python, but unlike pip, a
PEX does not install itself or otherwise affect system state. It uses
mature, &lt;a href=&quot;https://www.python.org/dev/peps/pep-0273/&quot;&gt;standard features&lt;/a&gt; of Python, successfully
iterating on a &lt;a href=&quot;https://docs.python.org/3/library/zipapp.html&quot;&gt;broadly&lt;/a&gt;-&lt;a href=&quot;https://github.com/brownhead/superzippy&quot;&gt;used&lt;/a&gt; approach.&lt;/p&gt;
&lt;p&gt;A lot can be done with Python and Python libraries alone. If your
project follows this approach, PEX is an easy
choice. &lt;a href=&quot;https://www.youtube.com/watch?v=NmpnGhRwsu0&quot;&gt;See this 15-minute video for a solid introduction&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;depending_on_a_new_python_ecosystem&quot;&gt;&lt;a href=&quot;#depending_on_a_new_python_ecosystem&quot; class=&quot;toclink&quot;&gt;Depending on a new Python/ecosystem&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Plain old vanilla Python leaving you wanting? That factory-installed
system software can leave a lot to be desired. Lucky for us there&#x27;s an
upgrade well within grasp.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.anaconda.com/download&quot;&gt;Anaconda&lt;/a&gt; is a Python distribution with expanded support
for distributing libraries and applications. It&#x27;s cross-platform, and
has supported binary packages since before the wheel. Anaconda
packages and ships system libraries like &lt;a href=&quot;https://anaconda.org/anaconda/libxml2&quot;&gt;libxml2&lt;/a&gt;, as well
as applications like &lt;a href=&quot;https://anaconda.org/anaconda/postgresql&quot;&gt;PostgreSQL&lt;/a&gt;, which fall outside the
purview of default Python packaging tools. That&#x27;s because while
Anaconda might seem like an innocent Python distribution from the
outside, internally Anaconda blends in characteristics of a full-blown
operating system, complete with its own package manager, &lt;a href=&quot;https://conda.io/docs/&quot;&gt;conda&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;If you look inside of an Anaconda installation, or at the screenshot
below, you&#x27;ll find something that looks a lot like
&lt;a href=&quot;https://en.wikipedia.org/wiki/Unix_File_System&quot;&gt;a root Linux filesystem&lt;/a&gt; (&lt;code&gt;lib&lt;/code&gt;, &lt;code&gt;bin&lt;/code&gt;, &lt;code&gt;include&lt;/code&gt;,
&lt;code&gt;etc&lt;/code&gt;), with some extra Anaconda-specific directories.&lt;/p&gt;
&lt;p&gt;&lt;img width=&quot;75%&quot; src=&quot;http://sedimental.org/uploads/anaconda_internals.png&quot; /&gt;&lt;/p&gt;
&lt;p&gt;What&#x27;s remarkable is that the underlying operating system can be
Windows, Mac, or basically any flavor of Linux. Just like that,
Anaconda unassumingly blends Python libraries and system libraries,
convenience and power, development and data science. And it does it
all by using features built into Python and target operating
systems.&lt;/p&gt;
&lt;p&gt;Consider that the list of cross-platform and language-agnostic package
managers includes only &lt;a href=&quot;https://en.wikipedia.org/wiki/Steam_(software)&quot;&gt;Steam&lt;/a&gt;, &lt;a href=&quot;https://en.wikipedia.org/wiki/Nix_package_manager&quot;&gt;Nix&lt;/a&gt;, and
&lt;a href=&quot;https://en.wikipedia.org/wiki/Pkgsrc&quot;&gt;pkgsrc&lt;/a&gt;, and you can start to understand why conda is
&lt;a href=&quot;https://jakevdp.github.io/blog/2016/08/25/conda-myths-and-misconceptions/&quot;&gt;often misunderstood&lt;/a&gt;. Adding onto that, conda is adding
features fast. For instance, conda is the first Python-centric package
manager to do its dependency resolution up front (using
&lt;a href=&quot;https://github.com/ContinuumIO/pycosat&quot;&gt;a SAT solver&lt;/a&gt;), &lt;a href=&quot;https://github.com/pypa/pip/issues/988&quot;&gt;unlike pip&lt;/a&gt;. More recently,
&lt;a href=&quot;https://github.com/conda/conda/blob/master/CHANGELOG.md#430-2016-12-14--safety&quot;&gt;conda 4.3&lt;/a&gt; fulfilled the wishes of many by matching
&lt;a href=&quot;https://en.wikipedia.org/wiki/Advanced_Packaging_Tool&quot;&gt;apt&lt;/a&gt; and &lt;a href=&quot;https://en.wikipedia.org/wiki/Yellowdog_Updater,_Modified&quot;&gt;yum&lt;/a&gt; with transactional package installation. Now
conda matches operating system package managers in critical technical
respects, except the wide-open social components of
&lt;a href=&quot;https://anaconda.org/&quot;&gt;anaconda.org&lt;/a&gt; make it even easier to use than, say
&lt;a href=&quot;https://askubuntu.com/questions/4983/what-are-ppas-and-how-do-i-use-them/4990#4990&quot;&gt;PPAs&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;In short, Anaconda makes a compelling and effective case, both as a
development environment
&lt;a href=&quot;https://docs.conda.io/projects/conda/en/latest/commands/index.html#conda-vs-pip-vs-virtualenv-commands&quot;&gt;comparable to pip + virtualenv&lt;/a&gt;, and even as part
of the equation
&lt;a href=&quot;https://medium.com/paypal-tech/python-packaging-at-paypal-4a90352a7ca2&quot;&gt;in production server environments&lt;/a&gt;. Python is lucky to
host to such a rare breed.&lt;/p&gt;
&lt;h2 id=&quot;bringing_your_own_python&quot;&gt;&lt;a href=&quot;#bringing_your_own_python&quot; class=&quot;toclink&quot;&gt;Bringing your own Python&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;img align=&quot;right&quot; width=&quot;40%&quot; src=&quot;http://sedimental.org/uploads/illo/snake_freeze_sm.png&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Can you imagine deploying to an environment without Python? It&#x27;s a
hellish scenario, I know. Luckily, your code can still bring your own,
and it&#x27;s ice cold. Freezing, in fact.&lt;/p&gt;
&lt;p&gt;When I wrote my first Python program, I naturally shared news of the
accomplishment with my parents, who naturally wanted to experience
this taste of &lt;em&gt;The Future&lt;/em&gt; firsthand.&lt;/p&gt;
&lt;p&gt;Of course all I had a .py file I wrote on &lt;a href=&quot;https://en.wikipedia.org/wiki/Knoppix&quot;&gt;Knoppix&lt;/a&gt;, and they
were halfway around the world on a Windows 2000 machine. Luckily, this
new software called &lt;a href=&quot;https://github.com/marcelotduarte/cx_Freeze&quot;&gt;cx_Freeze&lt;/a&gt; was
&lt;a href=&quot;https://mail.python.org/pipermail/python-announce-list/2002-November/001824.html&quot;&gt;just announced a couple months earlier&lt;/a&gt;. Unluckily,
no one told me, and the better part of a decade would pass before I
learned how to use it.&lt;/p&gt;
&lt;p&gt;Fifteen years later, the process has evolved, but retained the same
general shape. &lt;a href=&quot;http://www.openwall.com/presentations/WOOT13-Security-Analysis-of-Dropbox/&quot;&gt;Dropbox&lt;/a&gt;, &lt;a href=&quot;https://en.wikipedia.org/wiki/Eve_Online&quot;&gt;EVE Online&lt;/a&gt;,
&lt;a href=&quot;https://en.wikipedia.org/wiki/Civilization_IV&quot;&gt;Civilization IV&lt;/a&gt;, &lt;a href=&quot;https://kivy.org/&quot;&gt;kivy&lt;/a&gt;, and countless other
applications and frameworks rely on freezing to ship applications,
generally to personal computing devices. Interpreter, libraries, and
application logic, all rolled into an independent artifact.&lt;/p&gt;
&lt;p&gt;These days the list of open-source tools has expanded beyond
&lt;a href=&quot;https://github.com/marcelotduarte/cx_Freeze&quot;&gt;cx_Freeze&lt;/a&gt; to include &lt;a href=&quot;http://www.pyinstaller.org/&quot;&gt;PyInstaller&lt;/a&gt;,
&lt;a href=&quot;https://github.com/jamesabel/osnap&quot;&gt;osnap&lt;/a&gt;, &lt;a href=&quot;https://pypi.python.org/pypi/bbfreeze&quot;&gt;bbFreeze&lt;/a&gt;, &lt;a href=&quot;http://www.py2exe.org/&quot;&gt;py2exe&lt;/a&gt;,
&lt;a href=&quot;https://py2app.readthedocs.io/en/latest/&quot;&gt;py2app&lt;/a&gt;, &lt;a href=&quot;https://pypi.python.org/pypi/pynsist&quot;&gt;pynsist&lt;/a&gt;, &lt;a href=&quot;http://nuitka.net/pages/overview.html&quot;&gt;nuitka&lt;/a&gt;, and
more. There is even a conda-native option called
&lt;a href=&quot;https://github.com/conda/constructor&quot;&gt;constructor&lt;/a&gt;. A partial feature matrix can be found
&lt;a href=&quot;http://python-guide.readthedocs.io/en/latest/shipping/freezing/&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Most of these systems give you some latitude to determine exactly how
independent an executable to generate. Frozen artifacts almost always
ends up depending somewhat on the host operating system. See
&lt;a href=&quot;http://www.py2exe.org/index.cgi/Tutorial#Step5&quot;&gt;this py2exe tutorial discussion of Windows system libraries&lt;/a&gt;
for a taste of the fun.&lt;/p&gt;
&lt;p&gt;If you&#x27;re wondering about the chilly moniker, freezers owe their name
to their reliance on the &quot;frozen module&quot; functionality built into
Python. It&#x27;s
&lt;a href=&quot;https://docs.python.org/2/c-api/import.html#c.PyImport_ImportFrozenModule&quot;&gt;sparsely&lt;/a&gt;
&lt;a href=&quot;https://docs.python.org/2/library/imp.html#imp.init_frozen&quot;&gt;documented&lt;/a&gt;,
but basically Python code is precompiled into bytecode and frozen into
the interpreter.
&lt;a href=&quot;https://docs.python.org/3/whatsnew/3.3.html&quot;&gt;As of Python 3.3&lt;/a&gt;,
Python&#x27;s import system
&lt;a href=&quot;http://sayspy.blogspot.com/2012/02/how-i-bootstrapped-importlib.html&quot;&gt;was ported&lt;/a&gt;
from C to a frozen pure-Python implementation.&lt;/p&gt;
&lt;h3 id=&quot;servers_ride_the_bus&quot;&gt;&lt;a href=&quot;#servers_ride_the_bus&quot; class=&quot;toclink&quot;&gt;Servers ride the bus&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;&lt;img align=&quot;right&quot; width=&quot;40%&quot; src=&quot;http://sedimental.org/uploads/illo/omnibus_med.jpg&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Freezing tends to be targeted more toward client software. They&#x27;re
great for GUIs and CLI applications run by a single user on a single
machine at a time. When it comes to deploying server software bundled
with its own Python, there is a very notable alternative: the
&lt;a href=&quot;https://github.com/chef/omnibus&quot;&gt;Omnibus&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Omnibus builds &quot;full-stack&quot; installers designed to deploy applications
to servers. It supports RedHat and Debian-based Linux distros, as well
as Mac and Windows. A few years back, DataDog saw the light and
&lt;a href=&quot;https://www.datadoghq.com/blog/new-datadog-agent-omnibus-ticket-dependency-hell/&quot;&gt;made the switch&lt;/a&gt; for their Python-based
agent. &lt;a href=&quot;https://about.gitlab.com/&quot;&gt;GitLab&lt;/a&gt;&#x27;s &lt;a href=&quot;https://about.gitlab.com/downloads/&quot;&gt;on-premise solution&lt;/a&gt; is perhaps the
largest open-source usage, and has been a joy to install and upgrade.&lt;/p&gt;
&lt;p&gt;Unlike our multitude of freezers, Omnibus is uniquely elegant and
mature. No other system has natively shipped
multi-component/multi-service packages as sleekly for as long.&lt;/p&gt;
&lt;h2 id=&quot;bringing_your_own_userspace&quot;&gt;&lt;a href=&quot;#bringing_your_own_userspace&quot; class=&quot;toclink&quot;&gt;Bringing your own userspace&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Probably the newest and fastest-growing class of solution has actually
been a long time coming. You may have heard it referenced by its
buzzword: containerization, sometimes crudely described as
&quot;lightweight virtualization&quot;.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://blog.jessfraz.com/post/containers-zones-jails-vms/&quot;&gt;Better descriptions exist&lt;/a&gt;, but the important part is
this: Unlike other options so far, these packages establish a firm
border between their dependencies and the libraries on the host
system. This is a huge win for environmental independence and
deployment repeatability.&lt;/p&gt;
&lt;h3 id=&quot;in_our_own_image&quot;&gt;&lt;a href=&quot;#in_our_own_image&quot; class=&quot;toclink&quot;&gt;In our own image&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Let&#x27;s illustrate with one of the simplest and most mature
implementations, &lt;a href=&quot;https://en.wikipedia.org/wiki/AppImage&quot;&gt;AppImage&lt;/a&gt;.&lt;/p&gt;
&lt;div style=&quot;text-align:center;&quot;&gt;&lt;img width=&quot;60%&quot; src=&quot;http://sedimental.org/uploads/illo/snake_image_sm.png&quot; /&gt;&lt;/div&gt;

&lt;p&gt;Since 2004, the aptly-named AppImage (and its predecessor
&lt;a href=&quot;https://en.wikipedia.org/wiki/AppImage#klik&quot;&gt;klik&lt;/a&gt;) have been providing distro-agnostic, installation-free
application distribution to Linux end users, without requiring root or
touching the underlying operating system. AppImages only rely on the
kernel and CPU architecture.&lt;/p&gt;
&lt;p&gt;An AppImage is perhaps the most aptly-named solution in this whole
post. It is literally an &lt;a href=&quot;https://en.wikipedia.org/wiki/ISO_9660&quot;&gt;ISO9660&lt;/a&gt; image containing an
entrypoint executable, plus a snapshot of a filesystem comprising a
userspace, full of support libraries and other dependencies. Looking
inside a mounted &lt;a href=&quot;https://kdenlive.org/&quot;&gt;Kdenlive&lt;/a&gt; image, it&#x27;s easy to recognize
the familiar structure of a Unix filesystem:&lt;/p&gt;
&lt;p&gt;&lt;img width=&quot;75%&quot; src=&quot;http://sedimental.org/uploads/kdenlive_appimage_internals.png&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Dozens of headlining Linux applications ship like this now. Download
the AppImage, make it executable, double-click, and voila.&lt;/p&gt;
&lt;p&gt;If you&#x27;re reading this on a Mac, you&#x27;ve probably had a similar
experience. This is one of those rare cases where there&#x27;s some
consensus: Apple was one of the pioneers in image-based deployments,
with &lt;a href=&quot;https://en.wikipedia.org/wiki/Apple_Disk_Image&quot;&gt;DMGs&lt;/a&gt; and &lt;a href=&quot;https://en.wikipedia.org/wiki/Bundle_(macOS)&quot;&gt;Bundles&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&quot;an_image_by_any_other_name&quot;&gt;&lt;a href=&quot;#an_image_by_any_other_name&quot; class=&quot;toclink&quot;&gt;An image by any other name&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;No class of formats would be complete without
&lt;a href=&quot;https://en.wikipedia.org/wiki/Format_war&quot;&gt;a war&lt;/a&gt;. AppImage &lt;a href=&quot;https://en.wikipedia.org/wiki/AppImage#Reception_and_usage&quot;&gt;inspired&lt;/a&gt; the
&lt;a href=&quot;https://en.wikipedia.org/wiki/Flatpak&quot;&gt;Flatpak&lt;/a&gt; format, which was adopted by RedHat/Fedora, but was
of course insufficient for Canonical/Ubuntu, who were also targeting
mobile, and created &lt;a href=&quot;https://en.wikipedia.org/wiki/Snappy_(package_manager)&quot;&gt;Snappy&lt;/a&gt;. A shiny update to our deb-rpm
split tradition.&lt;/p&gt;
&lt;p&gt;Both of these formats introduce more features, as well as more
complexity and dependence on the operating system. Both Snaps and
Flatpaks expect the host to support their runtime, which can include
&lt;a href=&quot;https://flatpak.org/faq/#Can_Flatpak_be_used_on_servers_too_&quot;&gt;dbus, a systemd user session, and more&lt;/a&gt;. A lot of
work is put into increased &lt;a href=&quot;https://en.wikipedia.org/wiki/Linux_namespaces#Mount_.28mnt.29&quot;&gt;namespacing&lt;/a&gt; to isolate
running applications into separate &lt;a href=&quot;https://blog.jessfraz.com/post/getting-towards-real-sandbox-containers/&quot;&gt;sandboxes&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;I haven&#x27;t actually seen these formats used for deploying server
software. Flatpak might never support servers, Snappy is trying, but
personally, I would really like to hear about or experiment with
server-oriented AppImages.&lt;/p&gt;
&lt;h3 id=&quot;the_whale_in_the_room&quot;&gt;&lt;a href=&quot;#the_whale_in_the_room&quot; class=&quot;toclink&quot;&gt;The whale in the room&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Some call the technology sphere a marketplace of ideas, and that
metaphor is certainly felt in this case. Whether you&#x27;ve heard good
things or bad, we can all agree &lt;a href=&quot;https://en.wikipedia.org/wiki/Docker_(software)&quot;&gt;Docker&lt;/a&gt; is the format sold
the hardest. What else would you do when you&#x27;ve got
&lt;a href=&quot;https://www.crunchbase.com/organization/docker&quot;&gt;$180 million of VC&lt;/a&gt; breathing down your neck.&lt;/p&gt;
&lt;p&gt;Docker lets you make an application as self-contained as AppImage, but
exceeds even Snapcraft and Flatpak in the assumptions it makes. Images
are managed and run by &lt;a href=&quot;https://docs.docker.com/engine/reference/commandline/dockerd/&quot;&gt;yet another service&lt;/a&gt; with a lot of
capabilities and tightly coupled components.&lt;/p&gt;
&lt;p&gt;Docker&#x27;s packaging abstraction reflects this complexity. Take for
instance how Docker applications default to running as &lt;code&gt;root&lt;/code&gt;, despite
&lt;a href=&quot;https://docs.docker.com/engine/userguide/eng-image/dockerfile_best-practices/#user&quot;&gt;their documentation&lt;/a&gt; recommending against this. Default
&lt;code&gt;root&lt;/code&gt; is particularly unfriendly because namespacing is still not a
reliable guard against malicious actors attacking the host
system. &lt;a href=&quot;http://blog.dscpl.com.au/2015/12/don-run-as-root-inside-of-docker.html&quot;&gt;Root inside the container is root outside the container&lt;/a&gt;. Always
check the &lt;a href=&quot;https://www.google.com/search?q=namespace+site:cve.mitre.org&amp;amp;client=ubuntu&amp;amp;hs=55V&amp;amp;channel=fs&amp;amp;source=lnt&amp;amp;tbs=qdr:y&amp;amp;sa=X&quot;&gt;CVEs&lt;/a&gt;. The Docker
&lt;a href=&quot;https://docs.docker.com/engine/security/security/#docker-daemon-attack-surface&quot;&gt;security documentation&lt;/a&gt; also includes some good,
frank discussion of what one is getting into.&lt;/p&gt;
&lt;p&gt;Checking in with our trendline, so far we have been shipping larger
larger, more-inclusive artifacts for more independent, reliable
deployments. Some container systems present us with our first clear
departure from this pattern. We no longer have a single executable
that runs or installs our code. Technically we have a self-contained
application, but we&#x27;re also back to requiring an interpreter other
than the OS and CPU.&lt;/p&gt;
&lt;p&gt;It&#x27;s not hard to imagine instances where the complexity of a runtime
can overrun the advantages of self-containment. To quote Jessie
Frazelle&#x27;s &lt;a href=&quot;https://blog.jessfraz.com/post/containers-zones-jails-vms/&quot;&gt;blog post&lt;/a&gt; again, &lt;strong&gt;&quot;Complexity ==
Bugs&quot;&lt;/strong&gt;. This dynamic leads some to skip straight to our next option,
but as AppImage simply demonstrates, this is not an impeachment of all
image-based approaches.&lt;/p&gt;
&lt;!-- If I have time: 2D scatterplot of relative inclusivity and
execution dependability. --&gt;

&lt;h2 id=&quot;bringing_your_own_kernel&quot;&gt;&lt;a href=&quot;#bringing_your_own_kernel&quot; class=&quot;toclink&quot;&gt;Bringing your own kernel&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Now we&#x27;re really packing heavy. If having your Python code, libraries,
runtime, and necessary system libraries isn&#x27;t enough, you can add one
more piece of machinery: the operating system &lt;a href=&quot;https://en.wikipedia.org/wiki/Kernel_(operating_system)&quot;&gt;kernel&lt;/a&gt; itself.&lt;/p&gt;
&lt;p&gt;While this type of distribution never really caught on for consumers,
there is a rich ecosystem of tools and formats for VM-based server
deployment, from &lt;a href=&quot;https://en.wikipedia.org/wiki/Vagrant_(software)&quot;&gt;Vagrant&lt;/a&gt; to &lt;a href=&quot;https://en.wikipedia.org/wiki/Amazon_Machine_Image&quot;&gt;AMIs&lt;/a&gt; to
&lt;a href=&quot;https://en.wikipedia.org/wiki/OpenStack&quot;&gt;OpenStack&lt;/a&gt;. The whole dang cloud.&lt;/p&gt;
&lt;p&gt;Like our more complex container examples above, the images used to run
virtual machines are not runnable executables, and require a mediating
runtime, called a &lt;a href=&quot;https://en.wikipedia.org/wiki/Hypervisor&quot;&gt;hypervisor&lt;/a&gt;. These days hypervisor
machinery is very mature, and may even come standard with the
operating system, as is the case with &lt;a href=&quot;https://en.wikipedia.org/wiki/Hyper-V&quot;&gt;Windows&lt;/a&gt; and
&lt;a href=&quot;https://developer.apple.com/reference/hypervisor&quot;&gt;Mac&lt;/a&gt;. The images themselves come in a &lt;a href=&quot;https://en.wikipedia.org/wiki/VMDK&quot;&gt;few&lt;/a&gt;
&lt;a href=&quot;https://en.wikipedia.org/wiki/Open_Virtualization_Format&quot;&gt;formats&lt;/a&gt;, all of which are mature and dependable, if large. Size
and build time may be the only deterrent for smaller projects
prioritizing development time. Thanks to years of kernel and
&lt;a href=&quot;https://en.wikipedia.org/wiki/Hardware-assisted_virtualization&quot;&gt;processor advancement&lt;/a&gt;, virtualization is not as slow as many
developers would assume. If you can get your software shipped faster
on images, then I say go for it.&lt;/p&gt;
&lt;p&gt;Larger organizations save a lot from even small reductions to
deployment and runtime overhead, but have to balance that against half
a dozen other concerns worthy of
&lt;a href=&quot;https://www.oreilly.com/library/view/enterprise-software-with/9781491943755/&quot;&gt;a much longer discussion elsewhere&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;bringing_your_own_hardware&quot;&gt;&lt;a href=&quot;#bringing_your_own_hardware&quot; class=&quot;toclink&quot;&gt;Bringing your own hardware&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;In a software-driven Internet obsessed with lighter and lighter weight
solutions, it can be easy to forget that a lot of software is
&lt;a href=&quot;https://en.wikipedia.org/wiki/Computer_appliance&quot;&gt;literally packaged&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;If your application calls for it, you can absolutely slap it on a
rackable server, &lt;a href=&quot;https://www.raspberrypi.org/&quot;&gt;Raspberry Pi&lt;/a&gt;, or even a
&lt;a href=&quot;https://micropython.org/&quot;&gt;micropython&lt;/a&gt; and physically ship it. It may seem absurd
at first, but hardware is the most sensible option for countless
cases. And not limited to just consumer and IoT use cases,
either. Especially where infrastructure and security are concerned,
hardware is made to fit software like a glove, and can minimize
exposure for all parties.&lt;/p&gt;
&lt;div style=&quot;text-align:center;&quot;&gt;&lt;img width=&quot;40%&quot; src=&quot;http://sedimental.org/uploads/illo/snake_esc_sm.png&quot; /&gt;&lt;/div&gt;

&lt;h2 id=&quot;but_what_about&quot;&gt;&lt;a href=&quot;#but_what_about&quot; class=&quot;toclink&quot;&gt;But what about...&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Before concluding, there are some usual suspects that may be
conspicuously absent, depending on how long you&#x27;ve been packaging
code.&lt;/p&gt;
&lt;h3 id=&quot;os_packages&quot;&gt;&lt;a href=&quot;#os_packages&quot; class=&quot;toclink&quot;&gt;OS packages&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Where do OS packages like &lt;a href=&quot;https://en.wikipedia.org/wiki/Deb_(file_format)&quot;&gt;deb&lt;/a&gt; and &lt;a href=&quot;https://en.wikipedia.org/wiki/RPM_Package_Manager&quot;&gt;RPM&lt;/a&gt; fit into all of
this? They can fit anywhere, really. If you are very sure what
operating system(s) you&#x27;re targeting, these packaging systems can be
powerful tools for distributing and installing code. There are reasons
beyond popularity that almost all production container and VM
workflows rely on OS package managers. They are mature, robust, and
capable of doing dependency resolution, transactional installs, and
custom uninstall logic. Even systems as powerful as
&lt;a href=&quot;http://sedimental.org/the_packaging_gradient.html#servers_ride_the_bus&quot;&gt;Omnibus&lt;/a&gt; target OS packages.&lt;/p&gt;
&lt;p&gt;In &lt;a href=&quot;https://www.oreilly.com/library/view/enterprise-software-with/9781491943755/&quot;&gt;ESP&lt;/a&gt;&#x27;s packaging segment, I touch on how we leveraged RPMs as
a delivery mechanism for Python services in PayPal&#x27;s production RHEL
environment. One detail, that would have been minor and confusing in
that context, but should make sense to readers now, is that PayPal
didn&#x27;t use the vanilla operating system setup. Instead, all machines
used a separate rpmdb and install path for PayPal-specific packages,
maintaining a clear divide between application and base system.&lt;/p&gt;
&lt;h3 id=&quot;virtualenv&quot;&gt;&lt;a href=&quot;#virtualenv&quot; class=&quot;toclink&quot;&gt;virtualenv&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Where do &lt;a href=&quot;http://python-guide.readthedocs.io/en/latest/dev/virtualenvs/&quot;&gt;virtualenvs&lt;/a&gt; fit into all of this? Virtualenvs
are indispensible for many Python development workflows, but I
discourage direct use of virtualenvs for deployment. Virtualenvs can
be a useful packaging primitive, but they need additional machinery to
become a complete solution. The &lt;a href=&quot;http://dh-virtualenv.readthedocs.io/en/1.0/tutorial.html&quot;&gt;dh-virtualenv package&lt;/a&gt;
demonstrates this well for deb packaging, but you can also make a
virtualenv in an RPM post-install step, or by virtue of using an
installer like &lt;a href=&quot;https://github.com/jamesabel/osnap&quot;&gt;osnap&lt;/a&gt;. The key is that the artifact and its
install process should be self-contained, minimizing the risk of
partial installs.&lt;/p&gt;
&lt;p&gt;This isn&#x27;t virtualenv-specific, but lest it go unsaid, do not
pip-install things, especially from the Internet, during production
deploys. &lt;a href=&quot;http://sedimental.org/the_packaging_gradient.html#depending_on_pre_installed_python&quot;&gt;Scroll up and read about PEX&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&quot;security&quot;&gt;&lt;a href=&quot;#security&quot; class=&quot;toclink&quot;&gt;Security&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The further down the gradient you come, the harder it gets to update
components of your package. Everything is more tightly bound
together. This doesn&#x27;t necessarily mean that it&#x27;s harder to update in
general, but it is still a consideration, when for years the approach
has been to have system administrators and other technicians handle
certain kinds of infrastructure updates.&lt;/p&gt;
&lt;p&gt;For example, if a kernel security issue emerges, and you&#x27;re deploying
containers, the host system&#x27;s kernel can be updated without requiring
a new build on behalf of the application. If you deploy VM images,
you&#x27;ll need a new build. Whether or not this dynamic makes one option
more secure is still a bit of an old debate, going back to the
still-unsettled matter of
&lt;a href=&quot;https://www.google.com/search?channel=fs&amp;amp;q=static+vs+dynamic+linking&quot;&gt;static versus dynamic linking&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;closing&quot;&gt;&lt;a href=&quot;#closing&quot; class=&quot;toclink&quot;&gt;Closing&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Packaging in Python has a bit of a reputation for being a bumpy
ride. This is mostly a confused side effect of Python&#x27;s
versatility. Once you understand the natural boundaries between each
packaging solution, you begin to realize that the varied landscape is
a small price Python programmers pay for using the most balanced,
flexible language available.&lt;/p&gt;
&lt;p&gt;A summary of our lessons along the way:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Language does not define packaging, environment does. Python is
   general-purpose, PyPI is not.&lt;/li&gt;
&lt;li&gt;Application packaging must not be confused with library
   packaging. Python is for both, but pip is for libraries.&lt;/li&gt;
&lt;li&gt;Self-contained artifacts are the key to repeatable deploys.&lt;/li&gt;
&lt;li&gt;Containment is a spectrum, from executable to installer to userspace
   image to virtual machine image to hardware. &quot;Containers&quot; are not
   just one thing, let alone the only option.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Now, with map in hand, you can safely navigate the rich terrain. The
Python packaging landscape is converging, but don&#x27;t let that narrow
your focus. Every year seems to open new frontiers, challenging
existing practices for shipping Python.&lt;/p&gt;
&lt;div style=&quot;text-align:center;&quot;&gt;&lt;img width=&quot;60%&quot; src=&quot;http://sedimental.org/uploads/illo/snake_c_med.png&quot; /&gt;&lt;/div&gt;

&lt;div class=&quot;footnote&quot;&gt;
&lt;hr /&gt;
&lt;ol&gt;
&lt;li id=&quot;fn:licenses&quot;&gt;
&lt;p&gt;Don&#x27;t forget to include respective free software licenses, where applicable. &lt;a class=&quot;footnote-backref&quot; href=&quot;http://sedimental.org/the_packaging_gradient.html#fnref:licenses&quot; title=&quot;Jump back to footnote 1 in the text&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;fn:pypi&quot;&gt;
&lt;p&gt;Despite being called the Python Package Index, PyPI does not
index packages. PyPI indexes distributions, which can contain
one or more packages. For instance, pip installing &lt;a href=&quot;https://pillow.readthedocs.io/en/stable/&quot;&gt;Pillow&lt;/a&gt;
allows you to import PIL. Pillow is the distribution, PIL is
the package. The Pillow-PIL example also demonstrates how the
distribution-package separation enables multiple
implementations of the same API. Pillow is a fork of &lt;a href=&quot;https://pypi.python.org/pypi/PIL&quot;&gt;the
original PIL package&lt;/a&gt;. Still, as most distributions only
provide one package, please name your distribution after the
package for consistency&#x27;s sake. &lt;a class=&quot;footnote-backref&quot; href=&quot;http://sedimental.org/the_packaging_gradient.html#fnref:pypi&quot; title=&quot;Jump back to footnote 2 in the text&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;&lt;p&gt;&lt;/p&gt;



&lt;hr /&gt;

</content>

  </entry>
  
  <entry>
    <id>http://sedimental.org/developer_variants.html</id>
    <author>
      <name>Mahmoud Hashemi</name>
      <uri>http://sedimental.org/</uri>
    </author>
    <title>Developer variants</title>
    <link rel="alternate" type="text/html" href="http://sedimental.org/developer_variants.html" />
    <published>2016-08-09T10:00:00Z</published>
    <updated>2016-08-09T10:00:00Z</updated>
    <category term="python"/><category term="code"/><category term="work"/>
    

    <content type="html">&lt;p&gt;&lt;p&gt;&lt;img width=&quot;34%&quot; src=&quot;http://sedimental.org/uploads/illo/snowflake_med.png&quot; align=&quot;right&quot; /&gt;
Software development takes all kinds. I&#x27;m not talking about appearances or job
titles. I&#x27;m talking about motivations and fulfillment.&lt;/p&gt;
&lt;p&gt;In my years of writing code and leading projects, I&#x27;ve come to learn a
bit about how my teammates, and I, experience success, through a few
manifest archetypes.&lt;/p&gt;
&lt;h2 id=&quot;the_developer_mathematician&quot;&gt;&lt;a href=&quot;#the_developer_mathematician&quot; class=&quot;toclink&quot;&gt;The Developer-Mathematician&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Always a source of conversation, the Developer-Mathematician, seeks
truth, pure and provable. They don&#x27;t want to create software. They
want to unearth timeless, universal absolutes that happen to be in the
neighborhood of computers.&lt;/p&gt;
&lt;p&gt;Catch them crafting functional code, writing property-based tests, or
exhaustively searching their bookmarks for that one paper on arXiv.&lt;/p&gt;
&lt;p&gt;To be honest, purity and formalism can chafe when building most
software. Proofs are still more suited to dissertations than
development. Still, it&#x27;s good to strike a healthy balance between
research and development. Make time to try new testing strategies,
start a weekly paper club, and keep those fundamentals sharp.&lt;/p&gt;
&lt;h2 id=&quot;the_developer_architect&quot;&gt;&lt;a href=&quot;#the_developer_architect&quot; class=&quot;toclink&quot;&gt;The Developer-Architect&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Less formal than the mathematician, but not always more practical, the
Developer-Architect is brimming with potential. They want to create
something original, important, and particularly elegant. They want to
create something that outlasts them, something worthy of use,
maintenance, and study. The creation need not be immortal or
universal; the more of their mark that is left on it the better.&lt;/p&gt;
&lt;p&gt;Find them making high-concept pitches in response to clear gaps in the
open-source ecosystem, or discussing best practices that are
suspiciously similar to their own practices. If your
Developer-Architect is low on ideas or recently saw one of their ideas
superseded or implemented without them, they may become despondent.&lt;/p&gt;
&lt;p&gt;Software designers derive a lot of pleasure from the design process,
but need to be reminded that architecture is far from the hardest
part. To avoid turmoil and despondency, Developer-Architects must code
their own implementations and design only a few steps ahead. Creative
code can be very good code, and may well be worth the risk and wait.&lt;/p&gt;
&lt;h2 id=&quot;the_developer_engineer&quot;&gt;&lt;a href=&quot;#the_developer_engineer&quot; class=&quot;toclink&quot;&gt;The Developer-Engineer&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Least formal, but no less professional, the Developer Engineer is the
workhorse of the software industry. Engineers build for the sake of
building. Recognize them by their willingness to experiment with code,
and their lack of attachment to code. If it doesn&#x27;t work, the engineer
has confidence: Toss it, we can build it better again.&lt;/p&gt;
&lt;p&gt;For motivation, the engineer needs clear requirements and a modicum of
appreciation for a spec well-met. For fulfillment, the build itself
often suffices, so avoid process and interruptions.&lt;/p&gt;
&lt;p&gt;Proofs and designs aside, I still believe when we channel the
Developer Engineer, we channel our best selves. A sense of confident
understanding of the problem, married with unbounded pragmatism,
leading to working, shippable code. It will have bugs, and it may not
be abstracted quite right for future extensibility, but it will work.&lt;/p&gt;
&lt;h2 id=&quot;a_winning_combination&quot;&gt;&lt;a href=&quot;#a_winning_combination&quot; class=&quot;toclink&quot;&gt;A Winning Combination&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;We all go through phases, play different roles, and work with all
sorts. Embracing the mathematician, architect, and engineer, as well
as others, from tinkerers to hustlers, has taught me more than I could
have learned by my undifferentiated self.&lt;/p&gt;
&lt;p&gt;The key is recognizing your current motivations and finding alignment
of these angles within a company, within a team, and within oneself.&lt;p&gt;&lt;/p&gt;



&lt;hr /&gt;

</content>

  </entry>
  
  <entry>
    <id>http://sedimental.org/calver.html</id>
    <author>
      <name>Mahmoud Hashemi</name>
      <uri>http://sedimental.org/</uri>
    </author>
    <title>Announcing CalVer</title>
    <link rel="alternate" type="text/html" href="http://sedimental.org/calver.html" />
    <published>2016-06-22T17:30:00Z</published>
    <updated>2016-06-22T17:30:00Z</updated>
    <category term="python"/><category term="versioning"/><category term="code"/><category term="boltons"/><category term="ashes"/>
    

    <content type="html">&lt;p&gt;&lt;p&gt;&lt;img align=&quot;right&quot; width=&quot;20%&quot; src=&quot;http://sedimental.org/uploads/illo/caltree_med.png&quot; /&gt;
&lt;em&gt;It&#x27;s about time.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Technologists expect things to get better with time. Your current
laptop has more RAM than the last, your current car is safer than its
predecessor, and the latest version of your code is certainly the best
ever.&lt;/p&gt;
&lt;p&gt;What if the same be said of versioning systems?&lt;/p&gt;
&lt;p&gt;Software versioning systems also get better with time. That&#x27;s why
today I&#x27;m pleased to announce &lt;strong&gt;CalVer&lt;/strong&gt;, a calendar versioning
convention based on project release dates, formally hosted on
&lt;strong&gt;&lt;a href=&quot;http://calver.org&quot;&gt;calver.org&lt;/a&gt;&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Calendar versioning represents a powerful alternative to Semantic
Versioning (&lt;a href=&quot;http://semver.org&quot;&gt;SemVer&lt;/a&gt;). CalVer combines with or even replaces
SemVer versioning systems, based on the needs of the project.&lt;/p&gt;
&lt;h2 id=&quot;features&quot;&gt;&lt;a href=&quot;#features&quot; class=&quot;toclink&quot;&gt;Features&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The &lt;a href=&quot;http://calver.org&quot;&gt;calver.org&lt;/a&gt; site speaks for itself, but there you&#x27;ll
find:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;http://calver.org/#scheme&quot;&gt;Terms and definitions&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Case studies, including &lt;a href=&quot;http://calver.org/#ubuntu&quot;&gt;Ubuntu&lt;/a&gt;,
    &lt;a href=&quot;http://calver.org/#twisted&quot;&gt;Twisted&lt;/a&gt;, &lt;a href=&quot;http://calver.org/#teradata&quot;&gt;Teradata&lt;/a&gt;, and
    &lt;a href=&quot;http://calver.org/#other_notable_projects&quot;&gt;more&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;And &lt;a href=&quot;http://calver.org/#when_to_use_calver&quot;&gt;a short guide&lt;/a&gt; on when to use CalVer for your future projects&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Case studies feature badges like this one, for &lt;a href=&quot;http://calver.org/#ubuntu&quot;&gt;Ubuntu&lt;/a&gt;&#x27;s
versioning scheme:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;img src=&quot;https://img.shields.io/badge/calver-YY.0M.MICRO-22bfda.svg&quot; /&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;You&#x27;ll also find &lt;a href=&quot;http://calver.org/users.html&quot;&gt;a project list&lt;/a&gt;, always seeking new additions.&lt;/p&gt;
&lt;h2 id=&quot;rationale&quot;&gt;&lt;a href=&quot;#rationale&quot; class=&quot;toclink&quot;&gt;Rationale&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Many projects have designed their version schemes to better
match the needs of their developers and customers. CalVer formalizes
those practices. &lt;a href=&quot;http://calver.org&quot;&gt;calver.org&lt;/a&gt; began as a resource to help
maintainers communicate the design choices in their versioning scheme.&lt;/p&gt;
&lt;p&gt;CalVer has grown to showcase prominent uses and provide a way for more
projects to adopt calendar versioning in their projects. It even hosts
a community-curated &lt;a href=&quot;http://calver.org/users.html&quot;&gt;list of projects&lt;/a&gt; using calendar versioning.&lt;/p&gt;
&lt;p&gt;Even more background on the project can be found on the
&lt;a href=&quot;http://calver.org/about.html&quot;&gt;calver.org About page&lt;/a&gt;, as well as my previous
versioning essay, &lt;em&gt;&lt;a href=&quot;http://sedimental.org/designing_a_version.html&quot;&gt;Designing a version&lt;/a&gt;&lt;/em&gt;.&lt;/p&gt;
&lt;h2 id=&quot;compared_to_semver&quot;&gt;&lt;a href=&quot;#compared_to_semver&quot; class=&quot;toclink&quot;&gt;Compared to SemVer&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Some comparisons are inevitable. SemVer, hosted at
&lt;a href=&quot;http://semver.org&quot;&gt;semver.org&lt;/a&gt;, is a big name in software versioning
conventions. CalVer combines well with incremental-number schemes, so
it&#x27;s not strictly a competition. That said, here is how CalVer
outshines SemVer.&lt;/p&gt;
&lt;p&gt;🕐  CalVer integrates objective, intuitive calendar dates. &lt;br /&gt;
⊠  SemVer subjectively increments numbers.&lt;/p&gt;
&lt;p&gt;🕑  CalVer encompasses real-world usage through a formal
vocabulary. &lt;br /&gt;
⊠  SemVer imitates the form of a specification, albeit a
confrontational one. Unlike real specifications, SemVer lacks
objective verifiability, exemplars, or reference implementations.&lt;/p&gt;
&lt;p&gt;🕒  CalVer makes maintenance easier through powerful, objective
semantics. Look at a library&#x27;s version number, immediately know how
recent your copy. Compare across libraries, checking that dependencies
are in sync. Deprecate versions based on time. &lt;br /&gt;
⊠  SemVer has Tom Preston-Werner&#x27;s semantics.&lt;/p&gt;
&lt;p&gt;🕓  CalVer&#x27;s use of release dates allows for automatable, immutable
versions on which everyone can agree.  &lt;br /&gt;
⊠  SemVer introduces one more place a bug can enter a projects. Versions
only go up, and a release which violates SemVer guidelines cannot be
undone. That pressure means more projects &lt;a href=&quot;http://sedimental.org/designing_a_version.html#semver_and_release_blockage&quot;&gt;perpetually stuck in 0.x&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The &lt;a href=&quot;http://sedimental.org/designing_a_version.html&quot;&gt;list goes on&lt;/a&gt;, but the message is clear. There is an
alternative to SemVer, and it&#x27;s about time!&lt;/p&gt;
&lt;h2 id=&quot;next_steps&quot;&gt;&lt;a href=&quot;#next_steps&quot; class=&quot;toclink&quot;&gt;Next steps&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Have a look at the &lt;a href=&quot;http://calver.org/users.html&quot;&gt;Users&lt;/a&gt; list and help add any projects I may
have missed. It&#x27;s a big ecosystem out there, and the initial list
reflects my own Linux and Python tendencies.&lt;/p&gt;
&lt;p&gt;&lt;img align=&quot;right&quot; width=&quot;25%&quot; src=&quot;http://sedimental.org/uploads/illo/calver_cal_med.png&quot; /&gt;&lt;/p&gt;
&lt;p&gt;For current maintainers using calendar versioning, next time you get a
raised eyebrow, just let them know: It&#x27;s CalVer. Or save yourself a
step and add one of &lt;a href=&quot;http://calver.org/overview.html#case_studies&quot;&gt;the badges&lt;/a&gt;, linking to &lt;a href=&quot;http://calver.org&quot;&gt;calver.org&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;For developers of new libraries, CalVer is here to stay, and
&lt;a href=&quot;http://calver.org&quot;&gt;calver.org&lt;/a&gt; will be there next time you&#x27;re designing your
versioning scheme. It&#x27;s a big ecosystem out there, and once you try
CalVer, I think you&#x27;ll agree. Software versioning get better with
time.&lt;p&gt;&lt;/p&gt;



&lt;hr /&gt;

</content>

  </entry>
  
  <entry>
    <id>http://sedimental.org/running_from_software.html</id>
    <author>
      <name>Mahmoud Hashemi</name>
      <uri>http://sedimental.org/</uri>
    </author>
    <title>Running from software</title>
    <link rel="alternate" type="text/html" href="http://sedimental.org/running_from_software.html" />
    <published>2016-05-27T11:11:00Z</published>
    <updated>2016-05-27T11:11:00Z</updated>
    <category term="python"/><category term="code"/><category term="work"/>
    

    <content type="html">&lt;p&gt;&lt;p&gt;So while PyCon 2016 starts in less than 48 hours, some kind of
anticipation compelled me to polish off the last of
&lt;a href=&quot;https://www.youtube.com/channel/UCgxzjK6GuOHVKR_08TT4hJQ&quot;&gt;the talks from last year&lt;/a&gt;. For some reason I went for a
keynote. I&#x27;m not typically a keynote attendee, and this time I&#x27;d missed
something big.&lt;sup id=&quot;fnref:pycon2016&quot;&gt;&lt;a class=&quot;footnote-ref&quot; href=&quot;http://sedimental.org/running_from_software.html#fn:pycon2016&quot;&gt;1&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://twitter.com/jacobian&quot;&gt;Jacob Kaplan-Moss&lt;/a&gt;, the herald of &lt;a href=&quot;https://www.djangoproject.com/&quot;&gt;Django&lt;/a&gt;, really
laid something out. I&#x27;ll give you the short version, but here&#x27;s a
video in case you want a look:&lt;/p&gt;
&lt;iframe width=&quot;560&quot; height=&quot;315&quot; src=&quot;https://www.youtube.com/embed/hIJdFxYlEKE&quot; frameborder=&quot;0&quot; allowfullscreen=&quot;&quot;&gt;&lt;/iframe&gt;

&lt;p&gt;To summarize, Jacob sets out to explain why mediocrity is acceptable.
Bell curves rule everything around us. He holds up his record as a
middling ultramarathon runner as proof. He surmises that lack of
passion for work is leading people to feel untalented. This, combined
with &quot;brilliant asshole&quot; programmers, is shaming people out of the
industry. He wraps up with a message of inclusivity, especially toward
women. Now, you can probably make sense of any other details with
&lt;a href=&quot;http://sedimental.org/uploads/jacobian_pycon2015.pdf&quot;&gt;the slides&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Above all, Jacob and I are in complete agreement with his opening and
closing. If you consider yourself an average programmer, that is fine
and probably better than the alternatives. Also, as a field, software
must continue reaching out to and integrating more underrepresented
groups, especially women.&lt;/p&gt;
&lt;p&gt;That said, I&#x27;m not sure how one could have put more missteps between
those two points.&lt;sup id=&quot;fnref:1&quot;&gt;&lt;a class=&quot;footnote-ref&quot; href=&quot;http://sedimental.org/running_from_software.html#fn:1&quot;&gt;2&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;
&lt;h2 id=&quot;the_10x_programmer&quot;&gt;&lt;a href=&quot;#the_10x_programmer&quot; class=&quot;toclink&quot;&gt;The 10x Programmer&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;If Jacob makes one thing clear from the keynote, it&#x27;s that years of
being called a 10x programmer has made him very uncomfortable. He
rejects the concept, as many have. Now I, too, have at various points
been called a rockstar, ninja, and 10xer, and even though I also don&#x27;t
identify with those labels, I will tell you that the 10x programmer is
very real.&lt;sup id=&quot;fnref:tptm&quot;&gt;&lt;a class=&quot;footnote-ref&quot; href=&quot;http://sedimental.org/running_from_software.html#fn:tptm&quot;&gt;3&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;
&lt;p&gt;Every 10x programmer I know spends most days as a 1x something
else. Most 10x code is the result of observing and accumulating 10x
more domain knowledge, then being in the right place at the right
time. You do what ten developers off the street could never. I&#x27;ve been
there, and I have the commits to prove it. And when other aspects of
my life take priority, I&#x27;m an average programmer, focusing on my job
and its share of 1x work.&lt;/p&gt;
&lt;p&gt;10x programming is a matter of insight and inspiration, confidence and
autonomy. This is a circumstance so unique that it creates an
obligation to teach software to the world. You never know when the
right 1x programmer is going to be in the right place to transform
their surroundings with a 10x moment. Many of the most creative people
I know understand very little about programming, and one can&#x27;t help
but wonder what programming skills or insight might bring to their
process.&lt;/p&gt;
&lt;p&gt;The great thing about Python is that you can teach so much programming
with so little overhead. You give those highly creative people even a
taste of programming and it opens up vast opportunities. Even just the
shared vocabulary is a huge boost to cross-pollination of ideas
between disciplines.&lt;/p&gt;
&lt;p&gt;Look at Python use among biologists, neuroscientists, and other
academics and analysts. Their amazing results speak volumes. Yet by
strict accounts their engineering skill wilts next to experienced
Python systems engineers working at YouTube, PayPal, Dropbox,
Continuum Analytics, etc.&lt;/p&gt;
&lt;p&gt;It&#x27;s inexcusable to put such a diverse group on this single bell curve
when their goals and disciplines are so different. Our language is the
same and our cultures are mutually beneficial. Seeing people measured
along this single dimension keeps me up at night.&lt;/p&gt;
&lt;p&gt;Putting it all in terms of employment is harmful. Maximizing employee
utilization only creates more 1x programming. Software is more than
the industry of churning out code. A programmer is more than someone
who is paid to write software. A person is more than their profession.&lt;/p&gt;
&lt;!-- * Physical tasks like labor and exercise are infinitely more
  quantifiable than programming tasks. --&gt;

&lt;h2 id=&quot;the_privilege&quot;&gt;&lt;a href=&quot;#the_privilege&quot; class=&quot;toclink&quot;&gt;The Privilege&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;It&#x27;s said that the most sure sign of privilege is ignorance. Jacob
drives this all the way home, but not for lack of trying&lt;/p&gt;
&lt;p&gt;From the beginning of the talk, he considers the immediate
situation. He disclaims most of his reputation, describes his origins
as unremarkable, and points out that his biggest contributions weren&#x27;t
actually his. Later on in the talk, while showcasing the face of the
privileged programmer, the 10x archetype, the person most likely to be
able to ride on their identity, he shares a chuckle at his own
resemblance.&lt;/p&gt;
&lt;p&gt;Moving into Jacob&#x27;s running-programming analogy, the anecdote got off
to a false start, but just kept going. Nobody stopped him to point out
that by virtue of simply &lt;em&gt;being&lt;/em&gt; an ultra-runner, he &lt;em&gt;is&lt;/em&gt; the top
tier. If you&#x27;re in the 68th percentile of ultrarunners, then you&#x27;re in
the top 1% of people who run, period. Even finishing a normal marathon
faster than the median time demonstrates talent and tremendous
physical gifts.&lt;/p&gt;
&lt;p&gt;Jacob trimmed the y-axis, measured himself among the top tier, and
found himself only slightly better than mediocre. The sort of
guilt-inducing behavior that he claims leads people to leave the
field, unfolding right on stage.&lt;/p&gt;
&lt;h2 id=&quot;the_corporatism&quot;&gt;&lt;a href=&quot;#the_corporatism&quot; class=&quot;toclink&quot;&gt;The Corporatism&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Throughout the talk, Jacob cites some statistics. The one that stuck
with me was about an impending employment deficit. The U.S. government
projects 1.5 million unfilled programming jobs in the year 2020. This
becomes a central motivation for Jacob encouraging people to go into
software&lt;sup id=&quot;fnref:3&quot;&gt;&lt;a class=&quot;footnote-ref&quot; href=&quot;http://sedimental.org/running_from_software.html#fn:3&quot;&gt;4&lt;/a&gt;&lt;/sup&gt;. Programming is immediately linked to coding for money.&lt;/p&gt;
&lt;p&gt;Jacob says software is a skill, like any other. Programming is like
running marathons. Individuals are responsible for their own
training. But Jacob bears a message of hope: bosses will pay you to
run, even if you&#x27;re not the fastest.&lt;/p&gt;
&lt;p&gt;Too many managers are like Jacob, subtly redirecting the creative
potential of software into commodity labor. &quot;We&quot; need as many people
as possible to learn and teach programming because some a small
portion of society has decided to gamble money on software eating
everything in a very particular way.&lt;/p&gt;
&lt;p&gt;On the contrary, people need exposure to programming for its
fundamental concepts. Software offers new ways of decomposing problems and
creating solutions, new approaches that are necessary to understand an
increasingly fast-paced and connected world. That is totally
irrespective of employment. Software design is a new way of thinking,
for all people, employed as programmers or not.&lt;/p&gt;
&lt;h2 id=&quot;in_short&quot;&gt;&lt;a href=&quot;#in_short&quot; class=&quot;toclink&quot;&gt;In short&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Jacob is a much better runner than he gives himself credit for, but
programming is not running.&lt;/p&gt;
&lt;p&gt;Software is much more than an industry. You don&#x27;t need a programming
job to be a good programmmer.&lt;/p&gt;
&lt;p&gt;This brings me back to reiterate the central thought we share: One
doesn&#x27;t need to compare favorably to other programmers in order to
make a difference with software. So, we must accept and support
programmers of all walks and skill levels.&lt;/p&gt;
&lt;div class=&quot;footnote&quot;&gt;
&lt;hr /&gt;
&lt;ol&gt;
&lt;li id=&quot;fn:pycon2016&quot;&gt;
&lt;p&gt;Suffice to say, I&#x27;m already subscribed to &lt;a href=&quot;https://www.youtube.com/channel/UCwTD5zJbsQGJN75MwbykYNw&quot;&gt;PyCon 2016&lt;/a&gt; &lt;a class=&quot;footnote-backref&quot; href=&quot;http://sedimental.org/running_from_software.html#fnref:pycon2016&quot; title=&quot;Jump back to footnote 1 in the text&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;fn:1&quot;&gt;
&lt;p&gt;Dear Jacob, if you are reading this, I just wanted to say no
  harsh feelings. It was a moving talk and I&#x27;m sure that most
  people got the good messages that bookended the talk. I hope you
  don&#x27;t mind the criticism and still find it as interesting as you
  mentioned on stage. Hope it helps with future keynotes, and I&#x27;ll
  be &lt;a href=&quot;https://twitter.com/mhashemi&quot;&gt;right here&lt;/a&gt; if you have any
  followups. &lt;a class=&quot;footnote-backref&quot; href=&quot;http://sedimental.org/running_from_software.html#fnref:1&quot; title=&quot;Jump back to footnote 2 in the text&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;fn:tptm&quot;&gt;
&lt;p&gt;This also came up in &lt;a href=&quot;https://talkpython.fm/episodes/show/54/enterprise-software-with-python&quot;&gt;Episode #54 of Talk Python to Me&lt;/a&gt;, while
     discussing my course, &lt;a href=&quot;http://sedimental.orgshop.oreilly.com/product/0636920047346.do&quot;&gt;Enterprise Software with Python&lt;/a&gt;. &lt;a class=&quot;footnote-backref&quot; href=&quot;http://sedimental.org/running_from_software.html#fnref:tptm&quot; title=&quot;Jump back to footnote 3 in the text&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;fn:3&quot;&gt;
&lt;p&gt;&quot;The US Bureau of Labor Statistics estimates that by 2020 there
  will be a 1.5 million programming job gap, which means there
  will be that many jobs unfilled. That&#x27;s in five years. The EU
  has published similar numbers, 1.2 million in 2018—three
  years. That means we need to be doing something to get more
  people into our industry.&quot; &lt;a class=&quot;footnote-backref&quot; href=&quot;http://sedimental.org/running_from_software.html#fnref:3&quot; title=&quot;Jump back to footnote 4 in the text&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;&lt;p&gt;&lt;/p&gt;



&lt;hr /&gt;

</content>

  </entry>
  
  <entry>
    <id>http://sedimental.org/managing_python_ecosystems.html</id>
    <author>
      <name>Mahmoud Hashemi</name>
      <uri>http://sedimental.org/</uri>
    </author>
    <title>Managing Python Ecosystems</title>
    <link rel="alternate" type="text/html" href="http://sedimental.org/managing_python_ecosystems.html" />
    <published>2016-05-24T17:00:00Z</published>
    <updated>2016-05-24T17:00:00Z</updated>
    <category term="python"/><category term="work"/><category term="code"/><category term="esp"/><category term="boltons"/>
    

    <content type="html">&lt;p&gt;&lt;p&gt;&lt;img width=&quot;40%&quot; align=&quot;right&quot; src=&quot;http://sedimental.org/uploads/illo/koi_fish_med.png&quot; title=&quot;Ecosystems as shimmery, shiny, scaley, and fishy as a koi.&quot; /&gt;&lt;/p&gt;
&lt;p&gt;You know that old quote:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;The wider the net you cast, the wider the variety you catch.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Was it a wise old fisherman? Or a dogged Python programmer? Either
way, words don&#x27;t come much truer than those.&lt;/p&gt;
&lt;p&gt;Few, if any, programming languages have embodied the description
&quot;general-purpose&quot; as wholly as Python. And with the wide net of that
applicability comes a wide variety in use -- and environments.&lt;/p&gt;
&lt;p&gt;Library and framework developers rarely get to control how their code
is used, and thus have to think about how their code fits into the
whole ecosystem. From writing hybrid code for Python 2 &lt;em&gt;and&lt;/em&gt; 3 to
inserting shims for Pythons without threading support, there&#x27;s no rest
for the rigorous. Until now.&lt;/p&gt;
&lt;h3 id=&quot;announcing_ecoutils&quot;&gt;&lt;a href=&quot;#announcing_ecoutils&quot; class=&quot;toclink&quot;&gt;Announcing &lt;code&gt;ecoutils&lt;/code&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Ecosystems differ. Widely. Academic Python tends to be more
Windows-heavy, corporate Python will probably forever be entrenched in
Python 2, and one can never predict the arrival of that oddball user
with the super old version of Python on &lt;a href=&quot;https://en.wikipedia.org/wiki/Cygwin&quot;&gt;Cygwin&lt;/a&gt;. But these
are generalities and we can do better.&lt;/p&gt;
&lt;p&gt;Enter &lt;a href=&quot;http://boltons.readthedocs.io/en/latest/ecoutils.html&quot;&gt;&lt;code&gt;ecoutils&lt;/code&gt;&lt;/a&gt;. &lt;code&gt;ecoutils&lt;/code&gt; is a pure-Python module
that, using nothing but builtins, generates a semantic, Python-centric
profile of the environment that&#x27;s running it. This includes:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Host operating system&lt;/strong&gt;: Windows, OS X, Ubuntu, Debian, CentOS, RHEL, etc.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Language version&lt;/strong&gt;: 2.5, 2.6, 2.7, ..., 3.4, 3.5, ..., etc.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Executable runtime&lt;/strong&gt;: CPython, PyPy, Jython, etc., (plus build date and compiler)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Features&lt;/strong&gt;: 64-bit, IPv6, Unicode character support (UCS-2/UCS-4)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Built-in library support&lt;/strong&gt;: OpenSSL, threading, SQLite, zlib, and more&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;User environment&lt;/strong&gt;: umask, ulimit, working directory&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Machine info&lt;/strong&gt;: CPU count, hostname, filesystem encoding&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img width=&quot;40%&quot; align=&quot;right&quot; src=&quot;http://sedimental.org/uploads/illo/green_field_med.png&quot; title=&quot;If only all fields were so green in software ecosystems.&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Now, instead of crossing platform support bridges when users bring
them to you, you can be proactive. Now, instead of guessing how
developers are using the code, you can design for their needs and
watch those needs change.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;ecoutils&lt;/code&gt; only gets more valuable when code goes to production. If you
manage your own machines, you know the risk of version drift and
missed boxes only goes up with machine number and time. If you don&#x27;t
manage your machines, it&#x27;s just a matter of time until someone is
being trained on your boxes.&lt;/p&gt;
&lt;p&gt;So what does a profile look like?&lt;/p&gt;
&lt;h3 id=&quot;generating_a_profile&quot;&gt;&lt;a href=&quot;#generating_a_profile&quot; class=&quot;toclink&quot;&gt;Generating a profile&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Profiles are generated by &lt;a href=&quot;http://boltons.readthedocs.io/en/latest/ecoutils.html#boltons.ecoutils.get_profile&quot;&gt;&lt;code&gt;ecoutils.get_profile()&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;When run as a module, &lt;code&gt;ecoutils&lt;/code&gt; calls &lt;code&gt;get_profile()&lt;/code&gt; and prints a
JSON-formatted profile. On my fully-updated Ubuntu 14.04LTS machine,
&lt;code&gt;python -m boltons.ecoutils&lt;/code&gt; yields:&lt;/p&gt;
&lt;div class=&quot;codehilite&quot; style=&quot;background: #f8f8f8&quot;&gt;&lt;pre style=&quot;line-height: 125%;&quot;&gt;&lt;span&gt;&lt;/span&gt;{
&lt;span style=&quot;color: #bbbbbb&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;color: #008000; font-weight: bold&quot;&gt;&quot;_eco_version&quot;&lt;/span&gt;:&lt;span style=&quot;color: #bbbbbb&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #BB4444&quot;&gt;&quot;1.0.0&quot;&lt;/span&gt;,
&lt;span style=&quot;color: #bbbbbb&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;color: #008000; font-weight: bold&quot;&gt;&quot;cpu_count&quot;&lt;/span&gt;:&lt;span style=&quot;color: #bbbbbb&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #666666&quot;&gt;4&lt;/span&gt;,
&lt;span style=&quot;color: #bbbbbb&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;color: #008000; font-weight: bold&quot;&gt;&quot;cwd&quot;&lt;/span&gt;:&lt;span style=&quot;color: #bbbbbb&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #BB4444&quot;&gt;&quot;/home/mahmoud/projects/boltons&quot;&lt;/span&gt;,
&lt;span style=&quot;color: #bbbbbb&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;color: #008000; font-weight: bold&quot;&gt;&quot;fs_encoding&quot;&lt;/span&gt;:&lt;span style=&quot;color: #bbbbbb&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #BB4444&quot;&gt;&quot;UTF-8&quot;&lt;/span&gt;,
&lt;span style=&quot;color: #bbbbbb&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;color: #008000; font-weight: bold&quot;&gt;&quot;guid&quot;&lt;/span&gt;:&lt;span style=&quot;color: #bbbbbb&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #BB4444&quot;&gt;&quot;6b139e7bbf5ad4ed8d4063bf6235b4d2&quot;&lt;/span&gt;,
&lt;span style=&quot;color: #bbbbbb&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;color: #008000; font-weight: bold&quot;&gt;&quot;hostfqdn&quot;&lt;/span&gt;:&lt;span style=&quot;color: #bbbbbb&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #BB4444&quot;&gt;&quot;mahmoud-host&quot;&lt;/span&gt;,
&lt;span style=&quot;color: #bbbbbb&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;color: #008000; font-weight: bold&quot;&gt;&quot;hostname&quot;&lt;/span&gt;:&lt;span style=&quot;color: #bbbbbb&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #BB4444&quot;&gt;&quot;mahmoud-host&quot;&lt;/span&gt;,
&lt;span style=&quot;color: #bbbbbb&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;color: #008000; font-weight: bold&quot;&gt;&quot;linux_dist_name&quot;&lt;/span&gt;:&lt;span style=&quot;color: #bbbbbb&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #BB4444&quot;&gt;&quot;Ubuntu&quot;&lt;/span&gt;,
&lt;span style=&quot;color: #bbbbbb&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;color: #008000; font-weight: bold&quot;&gt;&quot;linux_dist_version&quot;&lt;/span&gt;:&lt;span style=&quot;color: #bbbbbb&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #BB4444&quot;&gt;&quot;14.04&quot;&lt;/span&gt;,
&lt;span style=&quot;color: #bbbbbb&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;color: #008000; font-weight: bold&quot;&gt;&quot;python&quot;&lt;/span&gt;:&lt;span style=&quot;color: #bbbbbb&quot;&gt; &lt;/span&gt;{
&lt;span style=&quot;color: #bbbbbb&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;color: #008000; font-weight: bold&quot;&gt;&quot;argv&quot;&lt;/span&gt;:&lt;span style=&quot;color: #bbbbbb&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #BB4444&quot;&gt;&quot;boltons/ecoutils.py&quot;&lt;/span&gt;,
&lt;span style=&quot;color: #bbbbbb&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;color: #008000; font-weight: bold&quot;&gt;&quot;bin&quot;&lt;/span&gt;:&lt;span style=&quot;color: #bbbbbb&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #BB4444&quot;&gt;&quot;/usr/bin/python&quot;&lt;/span&gt;,
&lt;span style=&quot;color: #bbbbbb&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;color: #008000; font-weight: bold&quot;&gt;&quot;build_date&quot;&lt;/span&gt;:&lt;span style=&quot;color: #bbbbbb&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #BB4444&quot;&gt;&quot;Jun 22 2015 17:58:13&quot;&lt;/span&gt;,
&lt;span style=&quot;color: #bbbbbb&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;color: #008000; font-weight: bold&quot;&gt;&quot;compiler&quot;&lt;/span&gt;:&lt;span style=&quot;color: #bbbbbb&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #BB4444&quot;&gt;&quot;GCC 4.8.2&quot;&lt;/span&gt;,
&lt;span style=&quot;color: #bbbbbb&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;color: #008000; font-weight: bold&quot;&gt;&quot;features&quot;&lt;/span&gt;:&lt;span style=&quot;color: #bbbbbb&quot;&gt; &lt;/span&gt;{
&lt;span style=&quot;color: #bbbbbb&quot;&gt;      &lt;/span&gt;&lt;span style=&quot;color: #008000; font-weight: bold&quot;&gt;&quot;64bit&quot;&lt;/span&gt;:&lt;span style=&quot;color: #bbbbbb&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #AA22FF; font-weight: bold&quot;&gt;true&lt;/span&gt;,
&lt;span style=&quot;color: #bbbbbb&quot;&gt;      &lt;/span&gt;&lt;span style=&quot;color: #008000; font-weight: bold&quot;&gt;&quot;expat&quot;&lt;/span&gt;:&lt;span style=&quot;color: #bbbbbb&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #BB4444&quot;&gt;&quot;expat_2.1.0&quot;&lt;/span&gt;,
&lt;span style=&quot;color: #bbbbbb&quot;&gt;      &lt;/span&gt;&lt;span style=&quot;color: #008000; font-weight: bold&quot;&gt;&quot;ipv6&quot;&lt;/span&gt;:&lt;span style=&quot;color: #bbbbbb&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #AA22FF; font-weight: bold&quot;&gt;true&lt;/span&gt;,
&lt;span style=&quot;color: #bbbbbb&quot;&gt;      &lt;/span&gt;&lt;span style=&quot;color: #008000; font-weight: bold&quot;&gt;&quot;openssl&quot;&lt;/span&gt;:&lt;span style=&quot;color: #bbbbbb&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #BB4444&quot;&gt;&quot;OpenSSL 1.0.1f 6 Jan 2014&quot;&lt;/span&gt;,
&lt;span style=&quot;color: #bbbbbb&quot;&gt;      &lt;/span&gt;&lt;span style=&quot;color: #008000; font-weight: bold&quot;&gt;&quot;readline&quot;&lt;/span&gt;:&lt;span style=&quot;color: #bbbbbb&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #AA22FF; font-weight: bold&quot;&gt;true&lt;/span&gt;,
&lt;span style=&quot;color: #bbbbbb&quot;&gt;      &lt;/span&gt;&lt;span style=&quot;color: #008000; font-weight: bold&quot;&gt;&quot;sqlite&quot;&lt;/span&gt;:&lt;span style=&quot;color: #bbbbbb&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #BB4444&quot;&gt;&quot;3.8.2&quot;&lt;/span&gt;,
&lt;span style=&quot;color: #bbbbbb&quot;&gt;      &lt;/span&gt;&lt;span style=&quot;color: #008000; font-weight: bold&quot;&gt;&quot;threading&quot;&lt;/span&gt;:&lt;span style=&quot;color: #bbbbbb&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #AA22FF; font-weight: bold&quot;&gt;true&lt;/span&gt;,
&lt;span style=&quot;color: #bbbbbb&quot;&gt;      &lt;/span&gt;&lt;span style=&quot;color: #008000; font-weight: bold&quot;&gt;&quot;tkinter&quot;&lt;/span&gt;:&lt;span style=&quot;color: #bbbbbb&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #BB4444&quot;&gt;&quot;8.6&quot;&lt;/span&gt;,
&lt;span style=&quot;color: #bbbbbb&quot;&gt;      &lt;/span&gt;&lt;span style=&quot;color: #008000; font-weight: bold&quot;&gt;&quot;unicode_wide&quot;&lt;/span&gt;:&lt;span style=&quot;color: #bbbbbb&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #AA22FF; font-weight: bold&quot;&gt;true&lt;/span&gt;,
&lt;span style=&quot;color: #bbbbbb&quot;&gt;      &lt;/span&gt;&lt;span style=&quot;color: #008000; font-weight: bold&quot;&gt;&quot;zlib&quot;&lt;/span&gt;:&lt;span style=&quot;color: #bbbbbb&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #BB4444&quot;&gt;&quot;1.2.8&quot;&lt;/span&gt;
&lt;span style=&quot;color: #bbbbbb&quot;&gt;    &lt;/span&gt;},
&lt;span style=&quot;color: #bbbbbb&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;color: #008000; font-weight: bold&quot;&gt;&quot;version&quot;&lt;/span&gt;:&lt;span style=&quot;color: #bbbbbb&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #BB4444&quot;&gt;&quot;2.7.6 (default, Jun 22 2015, 17:58:13) [GCC 4.8.2]&quot;&lt;/span&gt;,
&lt;span style=&quot;color: #bbbbbb&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;color: #008000; font-weight: bold&quot;&gt;&quot;version_info&quot;&lt;/span&gt;:&lt;span style=&quot;color: #bbbbbb&quot;&gt; &lt;/span&gt;[&lt;span style=&quot;color: #666666&quot;&gt;2&lt;/span&gt;,&lt;span style=&quot;color: #bbbbbb&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #666666&quot;&gt;7&lt;/span&gt;,&lt;span style=&quot;color: #bbbbbb&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #666666&quot;&gt;6&lt;/span&gt;,&lt;span style=&quot;color: #bbbbbb&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #BB4444&quot;&gt;&quot;final&quot;&lt;/span&gt;,&lt;span style=&quot;color: #bbbbbb&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #666666&quot;&gt;0&lt;/span&gt;]
&lt;span style=&quot;color: #bbbbbb&quot;&gt;  &lt;/span&gt;},
&lt;span style=&quot;color: #bbbbbb&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;color: #008000; font-weight: bold&quot;&gt;&quot;time_utc&quot;&lt;/span&gt;:&lt;span style=&quot;color: #bbbbbb&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #BB4444&quot;&gt;&quot;2016-05-24 07:59:40.473140&quot;&lt;/span&gt;,
&lt;span style=&quot;color: #bbbbbb&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;color: #008000; font-weight: bold&quot;&gt;&quot;time_utc_offset&quot;&lt;/span&gt;:&lt;span style=&quot;color: #bbbbbb&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #666666&quot;&gt;-8.0&lt;/span&gt;,
&lt;span style=&quot;color: #bbbbbb&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;color: #008000; font-weight: bold&quot;&gt;&quot;ulimit_hard&quot;&lt;/span&gt;:&lt;span style=&quot;color: #bbbbbb&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #666666&quot;&gt;4096&lt;/span&gt;,
&lt;span style=&quot;color: #bbbbbb&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;color: #008000; font-weight: bold&quot;&gt;&quot;ulimit_soft&quot;&lt;/span&gt;:&lt;span style=&quot;color: #bbbbbb&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #666666&quot;&gt;1024&lt;/span&gt;,
&lt;span style=&quot;color: #bbbbbb&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;color: #008000; font-weight: bold&quot;&gt;&quot;umask&quot;&lt;/span&gt;:&lt;span style=&quot;color: #bbbbbb&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #BB4444&quot;&gt;&quot;002&quot;&lt;/span&gt;,
&lt;span style=&quot;color: #bbbbbb&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;color: #008000; font-weight: bold&quot;&gt;&quot;uname&quot;&lt;/span&gt;:&lt;span style=&quot;color: #bbbbbb&quot;&gt; &lt;/span&gt;{
&lt;span style=&quot;color: #bbbbbb&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;color: #008000; font-weight: bold&quot;&gt;&quot;machine&quot;&lt;/span&gt;:&lt;span style=&quot;color: #bbbbbb&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #BB4444&quot;&gt;&quot;x86_64&quot;&lt;/span&gt;,
&lt;span style=&quot;color: #bbbbbb&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;color: #008000; font-weight: bold&quot;&gt;&quot;node&quot;&lt;/span&gt;:&lt;span style=&quot;color: #bbbbbb&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #BB4444&quot;&gt;&quot;mahmoud-host&quot;&lt;/span&gt;,
&lt;span style=&quot;color: #bbbbbb&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;color: #008000; font-weight: bold&quot;&gt;&quot;processor&quot;&lt;/span&gt;:&lt;span style=&quot;color: #bbbbbb&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #BB4444&quot;&gt;&quot;x86_64&quot;&lt;/span&gt;,
&lt;span style=&quot;color: #bbbbbb&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;color: #008000; font-weight: bold&quot;&gt;&quot;release&quot;&lt;/span&gt;:&lt;span style=&quot;color: #bbbbbb&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #BB4444&quot;&gt;&quot;3.13.0-85-generic&quot;&lt;/span&gt;,
&lt;span style=&quot;color: #bbbbbb&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;color: #008000; font-weight: bold&quot;&gt;&quot;system&quot;&lt;/span&gt;:&lt;span style=&quot;color: #bbbbbb&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #BB4444&quot;&gt;&quot;Linux&quot;&lt;/span&gt;,
&lt;span style=&quot;color: #bbbbbb&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;color: #008000; font-weight: bold&quot;&gt;&quot;version&quot;&lt;/span&gt;:&lt;span style=&quot;color: #bbbbbb&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #BB4444&quot;&gt;&quot;#129-Ubuntu SMP Thu Mar 17 20:50:15 UTC 2016&quot;&lt;/span&gt;
&lt;span style=&quot;color: #bbbbbb&quot;&gt;  &lt;/span&gt;},
&lt;span style=&quot;color: #bbbbbb&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;color: #008000; font-weight: bold&quot;&gt;&quot;username&quot;&lt;/span&gt;:&lt;span style=&quot;color: #bbbbbb&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #BB4444&quot;&gt;&quot;mahmoud&quot;&lt;/span&gt;
}
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Weighing in at just over 1KB, it&#x27;s not too daunting! ecoutils is part
of &lt;a href=&quot;http://boltons.readthedocs.io/en/latest/&quot;&gt;the boltons package&lt;/a&gt;, so &lt;code&gt;pip install boltons&lt;/code&gt; and
see how yours compares.&lt;/p&gt;
&lt;p&gt;By virtue of being in boltons, the &lt;code&gt;ecoutils&lt;/code&gt; module is also fully
standalone, and can be used without the rest of the boltons
package. ecoutils has been tested with Python 2.6, 2.7, 3.4, 3.5, and
PyPy on Ubuntu, Debian, RHEL, OS X, FreeBSD, and
Windows. &lt;a href=&quot;https://github.com/mahmoud/boltons/issues&quot;&gt;File an issue&lt;/a&gt; if something seems to be
broken. Compatibility is the goal.&lt;/p&gt;
&lt;h3 id=&quot;transmission_and_collection&quot;&gt;&lt;a href=&quot;#transmission_and_collection&quot; class=&quot;toclink&quot;&gt;Transmission and collection&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Now, ecoutils is really just part of the solution. Sure you can write
out a quick profile it at the top of every log file, and you won&#x27;t
regret it. However, real ecosystem management means running a sort of
Python analytics shop.&lt;/p&gt;
&lt;p&gt;For those familiar with browsing the Internet, your browser is a
virtual machine that has likely been participating in a similar
arrangement all day today. Like Google Analytics or &lt;a href=&quot;http://piwik.org/&quot;&gt;Piwik&lt;/a&gt;,
the setup involves collecting relevant data, and then sending it to a
central server for storage and querying.&lt;/p&gt;
&lt;p&gt;Collection is handled by &lt;code&gt;ecoutils&lt;/code&gt;. As far as transmission is
concerned, in development environments, we have a dead-simple,
side-effect-minimizing, single-file HTTP client that sends &lt;code&gt;ecoutils&lt;/code&gt;
profiles to a central analytics server on application startup.&lt;/p&gt;
&lt;p&gt;In production environments, our framework serves this information for
queries on a special port, through &lt;a href=&quot;https://github.com/paypal/support&quot;&gt;SuPPort&lt;/a&gt;&#x27;s MetaService,
through &lt;a href=&quot;https://github.com/mahmoud/clastic#clastic&quot;&gt;clastic&lt;/a&gt;&#x27;s &lt;a href=&quot;https://github.com/mahmoud/clastic/blob/master/clastic/meta.py&quot;&gt;MetaApplication&lt;/a&gt;, where this
all started. Here&#x27;s &lt;a href=&quot;http://tools.wmflabs.org/hashtags/meta/&quot;&gt;an example of it&lt;/a&gt; running in
&lt;a href=&quot;http://tools.wmflabs.org/hashtags/&quot;&gt;Wikipedia Hashtags Search&lt;/a&gt;, on a
&lt;a href=&quot;https://www.mediawiki.org/wiki/Wikimedia_Labs&quot;&gt;managed Wikimedia environment&lt;/a&gt;, over which I have minimal
control, and need maximum information.&lt;sup id=&quot;fnref:1&quot;&gt;&lt;a class=&quot;footnote-ref&quot; href=&quot;http://sedimental.org/managing_python_ecosystems.html#fn:1&quot;&gt;1&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;
&lt;p&gt;Push or pull, all the data is stored in a simple SQL (or JSONL)
format, as demonstrated by &lt;a href=&quot;https://github.com/mahmoud/espymetrics/&quot;&gt;espymetrics&lt;/a&gt;, the example
project for my &lt;a href=&quot;https://www.oreilly.com/library/view/enterprise-software-with/9781491943755/&quot;&gt;Enterprise Software with Python&lt;/a&gt; course. Nothing
more enterprise than having literally dozens of environments by
design, and even more than that by debt.&lt;/p&gt;
&lt;p&gt;One last note, data management is all about audience and context. If
you&#x27;re an administrator in a professional setting, the data above is
great. But there are understandably some cases where you might want
something less identifiable. &lt;code&gt;get_profile&lt;/code&gt; has a &lt;code&gt;scrub&lt;/code&gt; flag that
handles that. See &lt;a href=&quot;http://boltons.readthedocs.io/en/latest/ecoutils.html#boltons.ecoutils.get_profile&quot;&gt;the docs&lt;/a&gt; for details.&lt;/p&gt;
&lt;h3 id=&quot;success_stories&quot;&gt;&lt;a href=&quot;#success_stories&quot; class=&quot;toclink&quot;&gt;Success stories&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Originally designed for easier remote administration across multiple
environments, a little bit of info has had far-reaching impacts. For a
few examples from my work at PayPal, this approach enabled us to:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Deprecate and remove production Python 2.6 support from our
  framework, simplifying our build matrix without customer impact.&lt;/li&gt;
&lt;li&gt;Actively engage new users attempting to use our framework with
  unsupported Pythons or OSes.&lt;/li&gt;
&lt;li&gt;Improve utilization through designing for observed CPU counts.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In practice, &lt;code&gt;ecoutils&lt;/code&gt; combines well with &lt;a href=&quot;https://github.com/giampaolo/psutil&quot;&gt;psutil&lt;/a&gt; data to
go even further in utilization.&lt;/p&gt;
&lt;h3 id=&quot;building_for_variation&quot;&gt;&lt;a href=&quot;#building_for_variation&quot; class=&quot;toclink&quot;&gt;Building for variation&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Some of you probably came here expecting to read yet another great
post about &lt;a href=&quot;https://virtualenv.pypa.io/en/stable/&quot;&gt;virtualenv&lt;/a&gt;, &lt;a href=&quot;https://tox.readthedocs.io/en/latest/&quot;&gt;tox&lt;/a&gt;, and maybe even
&lt;a href=&quot;http://conda.pydata.org/docs/using/envs.html&quot;&gt;conda envs&lt;/a&gt;. I&#x27;m glad you&#x27;ve already heard of them,
because they&#x27;re a big part of the story. If you haven&#x27;t yet explored
these tools, check them out, because they are invaluable for
cross-version Python testing and packaging.&lt;/p&gt;
&lt;p&gt;Also, if you&#x27;re working on an open-source library, I can vouch for
&lt;a href=&quot;https://travis-ci.org/&quot;&gt;Travis CI&lt;/a&gt; (Linux) and &lt;a href=&quot;https://www.appveyor.com/&quot;&gt;Appveyor&lt;/a&gt; (Windows) as
very valuable providers for cross-platform testing. I use both of them
on &lt;a href=&quot;https://github.com/mahmoud/boltons&quot;&gt;boltons&lt;/a&gt;, and it makes it easier, not harder, for
contributors to submit pull requests with confidence. Most outfits
can&#x27;t afford to have a team member leading support for each platform,
like we do at PayPal.&lt;/p&gt;
&lt;h3 id=&quot;conclusion&quot;&gt;&lt;a href=&quot;#conclusion&quot; class=&quot;toclink&quot;&gt;Conclusion&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Python is more than just an expressive, succinct programming
language. In a diverse world, Python is a tremendous force, made so by
its wide deployment, cross-platform support, and external library
integrations. Python gives you SQLite, JSON, SSL, Unicode, and much
more, but with many necessary strings attached to Python version,
build, or environment. &lt;code&gt;ecoutils&lt;/code&gt; offers an experienced look at the
real features that affect the value of Python components and teams.&lt;/p&gt;
&lt;p&gt;Don&#x27;t leave ecosystems and their constituents to chance, whim, or
fad. Collect the data that makes your ecosystem unique, and make
measured decisions based on the realest demand: actual usage.&lt;/p&gt;
&lt;div class=&quot;footnote&quot;&gt;
&lt;hr /&gt;
&lt;ol&gt;
&lt;li id=&quot;fn:1&quot;&gt;
&lt;p&gt;When that server seems slow, remember to
&lt;a href=&quot;https://donate.wikimedia.org/wiki/Ways_to_Give&quot;&gt;donate to Wikipedia&lt;/a&gt;. And maybe volunteer, because
money alone does not make servers run fast. &lt;a class=&quot;footnote-backref&quot; href=&quot;http://sedimental.org/managing_python_ecosystems.html#fnref:1&quot; title=&quot;Jump back to footnote 1 in the text&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;&lt;p&gt;&lt;/p&gt;



&lt;hr /&gt;

</content>

  </entry>
  
  <entry>
    <id>http://sedimental.org/esp.html</id>
    <author>
      <name>Mahmoud Hashemi</name>
      <uri>http://sedimental.org/</uri>
    </author>
    <title>Enterprise Software with Python</title>
    <link rel="alternate" type="text/html" href="http://sedimental.org/esp.html" />
    <published>2016-03-22T11:04:00Z</published>
    <updated>2016-03-22T11:04:00Z</updated>
    <category term="python"/><category term="work"/><category term="code"/><category term="education"/><category term="esp"/>
    

    <content type="html">&lt;p&gt;&lt;p&gt;When I first published &lt;a href=&quot;http://sedimental.org/10_myths_of_enterprise_python.html&quot;&gt;10 Myths of Enterprise Python&lt;/a&gt; on
&lt;a href=&quot;https://medium.com/paypal-tech/10-myths-of-enterprise-python-8302b8f21f82&quot;&gt;the PayPal Engineering blog&lt;/a&gt;, there were a lot of
reactions. Some I expected:&lt;/p&gt;
&lt;p&gt;&lt;img width=&quot;40%&quot; align=&quot;right&quot; src=&quot;http://sedimental.org/uploads/illo/ncc_1701d_med.png&quot; title=&quot;The NCC-1701D, one of many illustrations from Enterprise
Software with Python&quot; /&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;a href=&quot;https://twitter.com/michahell/status/544109301401661440&quot;&gt;Surprise&lt;/a&gt; at Python in the enterprise space.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://twitter.com/jpheasly/status/543882786419908611&quot;&gt;Relief&lt;/a&gt; at more attestation of Python&#x27;s use in the enterprise.&lt;/li&gt;
&lt;li&gt;And, as with all the best, &lt;a href=&quot;https://news.ycombinator.com/item?id=9256082&quot;&gt;a few flamewars&lt;/a&gt;.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;But there was one I missed: new developers interested in professional
software development.&lt;/p&gt;
&lt;p&gt;Really I should have seen it coming. For the better part of a decade,
Python has provided me the best vocabulary for answering questions
from motivated individuals looking for programming productivity. It&#x27;s
only logical that once they got the basics down, they&#x27;d want to take
it to the next level.&lt;/p&gt;
&lt;p&gt;With this end in mind, I&#x27;m pleased to announce
&lt;strong&gt;&lt;a href=&quot;https://www.oreilly.com/library/view/enterprise-software-with/9781491943755/&quot;&gt;Enterprise Software with Python&lt;/a&gt;&lt;/strong&gt; (ESP), a bridging class
from beginner to pro&lt;sup id=&quot;fnref:1&quot;&gt;&lt;a class=&quot;footnote-ref&quot; href=&quot;http://sedimental.org/esp.html#fn:1&quot;&gt;1&lt;/a&gt;&lt;/sup&gt;, brought to you by
&lt;a href=&quot;http://www.oreilly.com/&quot;&gt;O&#x27;Reilly Media&lt;/a&gt; and yours truly.&lt;/p&gt;
&lt;p&gt;It&#x27;s got something for everyone, but really it&#x27;s designed with three
groups in mind:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Recently-graduated and self-taught developers&lt;/strong&gt;, looking for a holistic
  introduction to enterprise software.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Experienced developers at large organizations&lt;/strong&gt;, looking for a relatable
  orientation to Python industry standards.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Technical team leaders with priorities&lt;/strong&gt;, looking to quickly get
  groups on the same page of vocabulary, expectations, and practice.&lt;sup id=&quot;fnref:4me&quot;&gt;&lt;a class=&quot;footnote-ref&quot; href=&quot;http://sedimental.org/esp.html#fn:4me&quot;&gt;2&lt;/a&gt;&lt;/sup&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;As the title suggests, ESP is more than a Python class. While the
perspective is Pythonic and there are several examples in Python, this
is a full software development course. You will find a serious effort
has been made to set expectations and develop the soft skills large
organizations demand. You need architectural skills to form a
technical opinion, engineering skills to implement and maintain it,
and managerial skills to defend it all along the way. I can&#x27;t resist a
good table of contents, so this is how the course is factored to
address all of these:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Introductions and definitions&lt;/strong&gt; - A bit about me, a bunch about the course.&lt;/li&gt;
&lt;li&gt;Overview&lt;/li&gt;
&lt;li&gt;Prerequisites and viewing guide&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Definitions and foundations&lt;/strong&gt; - Know your domain, know your platform.&lt;/li&gt;
&lt;li&gt;What is Enterprise Software? - 9 Hallmarks of the Enterprise&lt;/li&gt;
&lt;li&gt;What is Python? 3 Perspectives for the Organization&lt;/li&gt;
&lt;li&gt;What is Python &lt;em&gt;Not&lt;/em&gt;? 4 Common Misconceptions&lt;/li&gt;
&lt;li&gt;When to Use Python? Motivations and Applications&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Architecture and design&lt;/strong&gt; - Do your research, present your findings.&lt;/li&gt;
&lt;li&gt;Designing Architectures: Professional Planning&lt;/li&gt;
&lt;li&gt;Gathering Requirements: Understanding the 6 Aspects of Software&lt;/li&gt;
&lt;li&gt;Researching Environments: From Production to Development&lt;/li&gt;
&lt;li&gt;Choosing Dependencies: Evaluating Building Blocks&lt;/li&gt;
&lt;li&gt;Getting Assistance: Finding Help in the Software World&lt;/li&gt;
&lt;li&gt;Presenting Designs: Navigating the Organizational and Interpersonal&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Engineering practices&lt;/strong&gt; - Execution and delivery with minimal regret.&lt;/li&gt;
&lt;li&gt;Development Environments: Editors and Dev Tools&lt;/li&gt;
&lt;li&gt;Source Control, Issue Tracking, and Continuous Integration&lt;/li&gt;
&lt;li&gt;Workflow: Starting a Python Project&lt;/li&gt;
&lt;li&gt;Design Patterns: Idioms for Python Projects&lt;/li&gt;
&lt;li&gt;Debugging: Solving Problems in Python projects&lt;/li&gt;
&lt;li&gt;Security: Software Risk Management Fundamentals&lt;/li&gt;
&lt;li&gt;Code Review: Python Antipatterns and Collaboration&lt;/li&gt;
&lt;li&gt;Testing: Practical Python Quality Engineering&lt;/li&gt;
&lt;li&gt;Logging and Monitoring: Introspectable Python Projects&lt;/li&gt;
&lt;li&gt;Profiling and Performance: Strategies for High-Speed Python&lt;/li&gt;
&lt;li&gt;Documentation: Preserving the Legacy&lt;/li&gt;
&lt;li&gt;Packaging and Deployment: Going Live&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Career development and further study&lt;/strong&gt; - A good end offers a dozen new beginnings.&lt;/li&gt;
&lt;li&gt;Project Ideas: Building Experience&lt;/li&gt;
&lt;li&gt;Technology Evangelism: Building a Community&lt;/li&gt;
&lt;li&gt;Other Resources: Building Skills&lt;/li&gt;
&lt;li&gt;Closing&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Yes, it is a lot. I never pass on an opportunity to give a
comprehensive treatment, but I&#x27;ll save the whole motivation and process
essay for later. For now, keep in mind that most segments are under 20
minutes, and the longest, &lt;em&gt;Profiling and Performance&lt;/em&gt;, is only 45
minutes — shorter than most orgs&#x27; tech talks. It&#x27;s all compact and
practical, right down to &lt;a href=&quot;https://github.com/mahmoud/espymetrics/&quot;&gt;the example repo&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;/p&gt;&lt;center&gt;
&lt;a href=&quot;http://shop.oreilly.com/product/0636920047346.do?code=authd&quot;&gt;
&lt;img width=&quot;70%&quot; src=&quot;http://sedimental.org/uploads/esp_01.jpg&quot; /&gt;
&lt;/a&gt;&lt;br /&gt;
&lt;em&gt;Actual footage from the intro. Not a prerelease render.&lt;/em&gt;
&lt;/center&gt;&lt;p&gt;&lt;/p&gt;
&lt;p&gt;The first three parts are free, and will give you a good sense of the
format, tone, and content. I kept it pretty light and approachable,
complete with dozens of illustrations. Purchasers can stream the rest,
and download DRM-free copies whenever you want (my personal
favorite). If you have any questions or concerns, don&#x27;t hesitate to
reach out &lt;a href=&quot;https://twitter.com/mhashemi&quot;&gt;to me&lt;/a&gt;, &lt;a href=&quot;http://sedimental.org/about.html&quot;&gt;personally&lt;/a&gt;, or
&lt;a href=&quot;https://twitter.com/OReillyMedia&quot;&gt;O&#x27;Reilly Media&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.oreilly.com/library/view/enterprise-software-with/9781491943755/&quot;&gt;I hope you&#x27;ll take a look&lt;/a&gt;! It&#x27;s already making waves at PayPal,
and chances are there&#x27;s someone you know who could use it, too.&lt;/p&gt;
&lt;!--

Various primary-source clippings I wrote related to the class. Don&#x27;t
mind these.

I&#x27;ve found even many experienced developers have a lot of skill gaps
that leech at their development confidence and effectiveness in a
corporate setting. This course seeks to address that.

I&#x27;m exactly designing it to be an enterprise followup to courses like
Jess&#x27;s. The largest contingent of Python programmers I&#x27;ve worked with
are those who know the basics of Python as a programming language, but
don&#x27;t know how to apply it day-to-day. Enterprise is indeed about
scaling, but much more about scaling development than scaling
performance (though I intend to cover both).

This will appeal to all developers looking to turn professional with
Python. Most instructive programming videos don&#x27;t cover the
expectations and best practices used within companies. Examples would
be when and how to add tests, automation, source control,
etc. Enterprise development is all about meetings, priorities,
budgets, and compromises, and reaching scale is a matter of earning
trust and proving approaches.

As for the topic feedback, I wholeheartedly agree. Enterprise
development is all about risk management, so my #1 priority is
avoiding failure. If new developers fail, they may blame Python, or
worse, their managers might blame them (and Python)! The TL;DR on my
opinion of when _not_ to use Python is for web frontend development,
and possibly for mobile (Kivy is really coming along,
though). Python&#x27;s web frontend offerings would be very hard for a new
developer to sell against JavaScript unfortunately.

My overarching message of when to use Python is one of positivity: we
have used Python for positively everything, high performance, high
reliability, high security, high accuracy (i.e., data science), you
name it. There&#x27;ll be a bit about Python 2 and 3, too. It&#x27;s a key
architectural decision, after all. :)

## Description

What&#x27;s makes the difference between a casual coder and a professional
software engineer? How do beginner Pythonists become intermediate
developers?

One part masterclass, one part crash course, Enterprise Software with
Python answers this question by touching on every element of the
enterprise software development. PayPal&#x27;s Lead Developer of Python
Infrastructure Mahmoud Hashemi busts myths and offers guidance, using
Python to demonstrate standard patterns and practices that apply
across the software industry.

Python is renowned for making it easy to get started with programming,
but a lot of Python programmers are set adrift after learning the
language basics. Enterprise Software with Python gives you an
insider&#x27;s introduction to:

    Defining software and software requirements for professional practice
    Fortifying your corporate environments with the power of open source
    Implementing, debugging, and reviewing project implementations
    Measuring, optimizing, and scaling applications at the enterprise level
    Preventing availability and security disasters with simple, practical changes
    Testing and documenting codebases for long-term maintenance
    Packaging and deploying optimally within your organization
    Winning autonomy by earning the confidence of your management and teammates

Whether you are currently at a large organization, hope to work in the
enterprise, or are just looking to further develop your skills,
Enterprise Software with Python will help you take your craft to the
next level.

## Proposal

### Who is this for?

Budding Python developers looking to turn pro. Beginners who know the
language and need direction in applying it in an organization.

### How does this help solve a problem or group of problems?

Python itself is very easy to learn in a hobby or academic setting,
but a lot of Python developers are set adrift after learning the
language. If they’re lucky they have some professional development
experience in other languages, but even then many of the paradigms
don’t translate well. Scaling, both development practices and
application architectures, is specific to every language. Illuminating
that dark art starts with teaching best practices that move a beginner
Pythonist to an intermediate Python engineer.

--&gt;

&lt;div class=&quot;footnote&quot;&gt;
&lt;hr /&gt;
&lt;ol&gt;
&lt;li id=&quot;fn:1&quot;&gt;
&lt;p&gt;This link has a 50% off coupon code, applied at checkout. Check
if your organization has Safari, first. If not, use
&lt;a href=&quot;http://shop.oreilly.com/product/0636920047346.do&quot;&gt;this coupon-less link&lt;/a&gt; and expense it! :) Safari
users, try &lt;a href=&quot;https://www.safaribooksonline.com/library/view/enterprise-software-with/9781491943755/&quot;&gt;the SBO site&lt;/a&gt;. If you&#x27;re not
sure if you have Safari access, contact your technology
education and training department. &lt;a class=&quot;footnote-backref&quot; href=&quot;http://sedimental.org/esp.html#fnref:1&quot; title=&quot;Jump back to footnote 1 in the text&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;fn:4me&quot;&gt;
&lt;p&gt;This target audience is me, but I know there are others out
there. &lt;em&gt;Send me your tiring, huddled masses yearning to learn
Python.&lt;/em&gt; Seriously though, I can&#x27;t fully quantify how much
time it saves me to send a new Python initiate to a video,
then have them come back with the foundations necessary to
have a productive conversation. &lt;a class=&quot;footnote-backref&quot; href=&quot;http://sedimental.org/esp.html#fnref:4me&quot; title=&quot;Jump back to footnote 2 in the text&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;&lt;p&gt;&lt;/p&gt;



&lt;hr /&gt;

</content>

  </entry>
  
  <entry>
    <id>http://sedimental.org/designing_a_version.html</id>
    <author>
      <name>Mahmoud Hashemi</name>
      <uri>http://sedimental.org/</uri>
    </author>
    <title>Designing a version</title>
    <link rel="alternate" type="text/html" href="http://sedimental.org/designing_a_version.html" />
    <published>2016-02-23T18:27:00Z</published>
    <updated>2016-02-23T18:27:00Z</updated>
    <category term="python"/><category term="code"/><category term="versioning"/><category term="boltons"/><category term="ashes"/><category term="work"/>
    

    <content type="html">&lt;p&gt;&lt;p&gt;In modern software development, a project isn&#x27;t a project without a
proper versioning scheme.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;The legatree&quot; align=&quot;right&quot; width=&quot;150px&quot; src=&quot;http://sedimental.org/uploads/illo/legatree_med.png&quot; /&gt;
Weak version management neglects clients like lack of source control
neglects collaborators. Dependency management and migration rely on
versions. Beyond the technical, a project&#x27;s version bears a huge
impact on the perception of the project. It informs adoption and
entices users to upgrade. The version is attached to the name of the
project — appearing closer and more often than the names of the
maintainers. Versions are how a project builds a legacy.&lt;/p&gt;
&lt;p&gt;So why do projects leave versioning to afterthought? What do clients
expect and what do projects need?&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Followup: This post culminated in the
&lt;a href=&quot;http://sedimental.org/calver.html&quot;&gt;announcing CalVer&lt;/a&gt; and launching
&lt;a href=&quot;http://calver.org&quot;&gt;calver.org&lt;/a&gt;. This page provides a thorough background to the
CalVer best practices.&lt;/em&gt;&lt;/p&gt;
&lt;div class=&quot;toc&quot;&gt;&lt;span class=&quot;toctitle&quot;&gt;Contents&lt;/span&gt;&lt;ul&gt;&lt;li&gt;&lt;a href=&quot;#semantic_versioning&quot;&gt;Semantic Versioning&lt;/a&gt;&lt;ul&gt;&lt;li&gt;&lt;a href=&quot;#semver_and_code_breakage&quot;&gt;SemVer and code breakage&lt;/a&gt;&lt;li&gt;&lt;a href=&quot;#semver_and_release_blockage&quot;&gt;SemVer and release blockage&lt;/a&gt;&lt;li&gt;&lt;a href=&quot;#semver_and_certifiability&quot;&gt;SemVer and certifiability&lt;/a&gt;&lt;/ul&gt;&lt;li&gt;&lt;a href=&quot;#collective_expectations&quot;&gt;Collective Expectations&lt;/a&gt;&lt;ul&gt;&lt;li&gt;&lt;a href=&quot;#1_versions_go_up&quot;&gt;#1 Versions go up&lt;/a&gt;&lt;li&gt;&lt;a href=&quot;#2_versions_correlate_to_software_quality&quot;&gt;#2 Versions correlate to software quality&lt;/a&gt;&lt;li&gt;&lt;a href=&quot;#3_versions_are_numeric_except_when_they_re_not&quot;&gt;#3 Versions are numeric, except when they&#x27;re not&lt;/a&gt;&lt;/ul&gt;&lt;li&gt;&lt;a href=&quot;#case_study_chrome_vs_firefox&quot;&gt;Case Study: Chrome vs. Firefox&lt;/a&gt;&lt;li&gt;&lt;a href=&quot;#calendar_versioning&quot;&gt;Calendar Versioning&lt;/a&gt;&lt;ul&gt;&lt;li&gt;&lt;a href=&quot;#calver_leverages_natural_understanding&quot;&gt;CalVer leverages natural understanding&lt;/a&gt;&lt;li&gt;&lt;a href=&quot;#calver_has_better_semantics&quot;&gt;CalVer has better semantics&lt;/a&gt;&lt;li&gt;&lt;a href=&quot;#calver_protects_projects&quot;&gt;CalVer protects projects&lt;/a&gt;&lt;/ul&gt;&lt;li&gt;&lt;a href=&quot;#summary&quot;&gt;Summary&lt;/a&gt;&lt;/ul&gt;&lt;/div&gt;&lt;h2 id=&quot;semantic_versioning&quot;&gt;&lt;a href=&quot;#semantic_versioning&quot; class=&quot;toclink&quot;&gt;Semantic Versioning&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Currently, the go-to versioning system for open-source software is
referred to as &lt;em&gt;Semantic Versioning&lt;/em&gt;, or &lt;a href=&quot;http://semver.org/&quot;&gt;SemVer&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Take a quick look at the
&lt;a href=&quot;https://pypi.python.org/pypi?%3Aaction=rss&quot;&gt;40 most recent updates on the Python Package Index&lt;/a&gt;
(&lt;a href=&quot;https://pypi.python.org/pypi&quot;&gt;PyPI&lt;/a&gt;). My glance showed all but &lt;em&gt;six&lt;/em&gt; packages had the
comfortable three-part versioning scheme, &lt;code&gt;major.minor.micro&lt;/code&gt;. Among
those packages the highest minor version was 108. The highest micro
version was all the way up to 595.&lt;/p&gt;
&lt;!--
# PyPI recent 40

* Highest minor: 108
* Highest micro: 595
* Five 4-part versions
* One calendar version
--&gt;

&lt;p&gt;So, if SemVer is so popular, it must be easy, right? Follow
&lt;a href=&quot;http://semver.org/#semantic-versioning-specification-semver&quot;&gt;a couple straightforward steps&lt;/a&gt;. Pick a number, add
one to it. With arithmetic that simple, what could go wrong?&lt;/p&gt;
&lt;h4 id=&quot;semver_and_code_breakage&quot;&gt;&lt;a href=&quot;#semver_and_code_breakage&quot; class=&quot;toclink&quot;&gt;SemVer and code breakage&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;Everyone knows it&#x27;s more exciting to announce 2.0 than 1.7.0, even if
there&#x27;s more user demand for the latter than the former. This is
especially true with SemVer, because a SemVer major
version change implies breaking the API.&lt;/p&gt;
&lt;p&gt;As we will see, there are consequences to this. People judge value
based on version number. SemVer supports this opaque
apples-and-oranges comparison, punishing libraries that get it right
on the first try, and encouraging libraries to break APIs to appear
more mature and get that coveted 2.0.&lt;/p&gt;
&lt;h4 id=&quot;semver_and_release_blockage&quot;&gt;&lt;a href=&quot;#semver_and_release_blockage&quot; class=&quot;toclink&quot;&gt;SemVer and release blockage&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;More damaging than the fatuous 2.0 is the epidemic of
&lt;strong&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/Zeno&#x27;s_paradoxes#Dichotomy_paradox&quot;&gt;Zeno&#x27;s 1.0&lt;/a&gt;&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img width=&quot;99%&quot; src=&quot;http://sedimental.org/uploads/illo/zeno_one_dot_oh.png&quot; /&gt;&lt;br /&gt; &lt;em&gt;Witness the version, racing to numeric motionlessness. (Image based
on &lt;a href=&quot;https://commons.wikimedia.org/wiki/File:Zeno_Dichotomy_Paradox.png&quot;&gt;Martin Grandjean&#x27;s&lt;/a&gt;.)&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;To quote the &lt;a href=&quot;http://semver.org/#how-do-i-know-when-to-release-100&quot;&gt;second answer in SemVer&#x27;s own FAQ&lt;/a&gt;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;If your software is being used in production, it should probably
already be 1.0.0. If you have a stable API on which users have come
to depend, you should be 1.0.0. If you’re worrying a lot about
backwards compatibility, you should probably already be 1.0.0.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;On this count, SemVer might be found not guilty.&lt;sup id=&quot;fnref:2&quot;&gt;&lt;a class=&quot;footnote-ref&quot; href=&quot;http://sedimental.org/designing_a_version.html#fn:2&quot;&gt;2&lt;/a&gt;&lt;/sup&gt; If so, it&#x27;s the
SemVer users that didn&#x27;t get the memo — myself included. Maybe if it
had been in the spec itself.&lt;/p&gt;
&lt;p&gt;The problem is the heavy emphasis on &quot;public API&quot;
breakage. Conservative library authors end up indefinitely preferring
the &lt;em&gt;semantic power&lt;/em&gt; of 0.x: &lt;a href=&quot;http://semver.org/#spec-item-4&quot;&gt;The ability to break APIs&lt;/a&gt;. Whether
the cause is conservatism, humility, or misunderstanding, the effect
is misrepresenting the release state of many major libraries.&lt;/p&gt;
&lt;p&gt;A more practical scheme might help represent accurate versions for
mature, production libraries like &lt;a href=&quot;http://cython.org/&quot;&gt;Cython&lt;/a&gt; (0.23) and
&lt;a href=&quot;http://www.scipy.org/&quot;&gt;SciPy&lt;/a&gt; (0.17), both of which &lt;a href=&quot;http://shop.oreilly.com/product/0636920033431.do&quot;&gt;have&lt;/a&gt;
&lt;a href=&quot;http://shop.oreilly.com/product/9781783984749.do&quot;&gt;books&lt;/a&gt; and nearly a &lt;em&gt;decade&lt;/em&gt; of release history still on
PyPI.&lt;/p&gt;
&lt;h4 id=&quot;semver_and_certifiability&quot;&gt;&lt;a href=&quot;#semver_and_certifiability&quot; class=&quot;toclink&quot;&gt;SemVer and certifiability&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;Appealing to engineering aesthetics, SemVer is presented as a
&quot;specification&quot;. But, unlike the vast majority of successful
&lt;a href=&quot;https://en.wikipedia.org/wiki/Request_for_Comments&quot;&gt;RFCs&lt;/a&gt;, there is no validation or certification that can
determine whether a project has a correct implementation. Yes, if a
project API changes, but the major version is not incremented, the
SemVer specification has been violated. But there&#x27;s no way to test
that generally, and no one does it specifically.&lt;/p&gt;
&lt;p&gt;SemVer is a detailed suggestion. Software breaks as quickly as
SemVer&#x27;s promise. The &lt;a href=&quot;http://semver.org/#what-do-i-do-if-i-accidentally-release-a-backwards-incompatible-change-as-a-minor-version&quot;&gt;remediations&lt;/a&gt; do &lt;em&gt;not&lt;/em&gt;
happen. Better to embrace the realities of versioning, rather than
argue over the MUSTs and MUST NOTs of an unenforceable specification.&lt;/p&gt;
&lt;h2 id=&quot;collective_expectations&quot;&gt;&lt;a href=&quot;#collective_expectations&quot; class=&quot;toclink&quot;&gt;Collective Expectations&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Let&#x27;s take a brief moment to reconsider the humble version.&lt;/p&gt;
&lt;p&gt;We encounter far more software than we write. Few, if any, expect
compliance with all the suggestions in SemVer. So what do we expect
from our versions?&lt;/p&gt;
&lt;p&gt;There are three main expectations driving modern software versioning:&lt;/p&gt;
&lt;h3 id=&quot;1_versions_go_up&quot;&gt;&lt;a href=&quot;#1_versions_go_up&quot; class=&quot;toclink&quot;&gt;#1 Versions go up&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The later the release, the greater the version. Sofware should not
change without a version change, and the version must go up, and never
come down.&lt;/p&gt;
&lt;h3 id=&quot;2_versions_correlate_to_software_quality&quot;&gt;&lt;a href=&quot;#2_versions_correlate_to_software_quality&quot; class=&quot;toclink&quot;&gt;#2 Versions correlate to software quality&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;A project name communicates an ideal. The project version communicates
current progress toward that ideal. Vision pursued by version: The
greater the version, the greater the software.&lt;/p&gt;
&lt;h3 id=&quot;3_versions_are_numeric_except_when_they_re_not&quot;&gt;&lt;a href=&quot;#3_versions_are_numeric_except_when_they_re_not&quot; class=&quot;toclink&quot;&gt;#3 Versions are numeric, except when they&#x27;re not&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Here&#x27;s where things get hairy. Numeric versions are the default, but
non-numeric versions and version components abound.&lt;/p&gt;
&lt;p&gt;Version vernacular is now thoroughly mainstream: &quot;alpha&quot;, &quot;beta&quot;,
&quot;dev&quot;, &quot;nightly&quot;, &quot;stable&quot;, and so on. There are also named project
versions, like those used in Linux distributions, such as Debian&#x27;s
&quot;jessie&quot;, Ubuntu&#x27;s &quot;trusty&quot;, and Windows&#x27; &quot;longhorn&quot;. Non-numeric
versions are often hijacked for branding purposes. Numerical versions&#x27;
technical utility is much more important to preserve.&lt;/p&gt;
&lt;h2 id=&quot;case_study_chrome_vs_firefox&quot;&gt;&lt;a href=&quot;#case_study_chrome_vs_firefox&quot; class=&quot;toclink&quot;&gt;Case Study: Chrome vs. Firefox&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;We take our version expectations for granted, but a convention this
fundamental has profound effects at scale. As mentioned above, higher
versions are expected to be better, especially within a project. But
there is at least one case where this impact very publically spilled
out across projects: &lt;em&gt;The Chrome-Firefox Version Wars&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;When &lt;a href=&quot;https://en.wikipedia.org/wiki/Google_Chrome&quot;&gt;Google Chrome&lt;/a&gt; entered the browser race, it brought with
it a fast feature release schedule and a versioning system to
match. This versioning system had Chrome see a dozen major releases
while &lt;a href=&quot;https://en.wikipedia.org/wiki/Firefox&quot;&gt;Firefox&lt;/a&gt; was still 3.x. Firefox looked like it was
being left in the dust, despite the fact that Chrome was less mature
and, as anyone who used it at the time can attest, Chrome 4 wasn&#x27;t
half the browser Firefox 4 ended up being.&lt;/p&gt;
&lt;p&gt;After a couple years of &lt;a href=&quot;http://lowendmac.com/musings/11mm/version-numbers.html&quot;&gt;this onslaught&lt;/a&gt;, Firefox switched its
versioning system to match. Now, despite browsing for hours a day, few
users or even developers &lt;a href=&quot;http://www.extremetech.com/internet/92792-mozilla-takes-firefox-version-number-removal-a-step-further&quot;&gt;could tell you&lt;/a&gt; off the top of their heads
what version of Firefox/Chrome they use.&lt;sup id=&quot;fnref:3&quot;&gt;&lt;a class=&quot;footnote-ref&quot; href=&quot;http://sedimental.org/designing_a_version.html#fn:3&quot;&gt;3&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;
&lt;p&gt;SemVer ignored this huge precedent,
&lt;a href=&quot;http://semver.org/#if-even-the-tiniest-backwards-incompatible-changes-to-the-public-api-require-a-major-version-bump-wont-i-end-up-at-version-4200-very-rapidly&quot;&gt;harshly judging fast-moving projects&lt;/a&gt;. Let&#x27;s call that
our last straw and look at an alternative.&lt;/p&gt;
&lt;h2 id=&quot;calendar_versioning&quot;&gt;&lt;a href=&quot;#calendar_versioning&quot; class=&quot;toclink&quot;&gt;Calendar Versioning&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;img align=&quot;right&quot; width=&quot;110px&quot; src=&quot;http://sedimental.org/uploads/illo/caltree_med.png&quot; /&gt;
If you&#x27;re an earnest engineer with honest intents of creating,
releasing, and maintaining a project, then calendar versioning may be
for you. &lt;a href=&quot;http://calver.org&quot;&gt;CalVer&lt;/a&gt; fulfills all of
&lt;a href=&quot;http://sedimental.org/designing_a_version.html#collective_expectations&quot;&gt;the versioning expectations&lt;/a&gt;, so what
advantages does it bring?&lt;/p&gt;
&lt;h3 id=&quot;calver_leverages_natural_understanding&quot;&gt;&lt;a href=&quot;#calver_leverages_natural_understanding&quot; class=&quot;toclink&quot;&gt;CalVer leverages natural understanding&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;People are calendar-oriented. Practically, it&#x27;s just easier to
remember that a library was causing a live issue back in 2013 than it
is to remember that up until version 1.6.18 that library had a lot of
bugs.&lt;/p&gt;
&lt;p&gt;Furthermore, in long-term development, releases pile up and
increasingly large major versions blur together. Browser versions have
been rendered meaningless. But the calendar is one construct where
numbers increase and cycle regularly. Leveraging that natural
understanding anchors otherwise arbitrary versions.&lt;/p&gt;
&lt;h3 id=&quot;calver_has_better_semantics&quot;&gt;&lt;a href=&quot;#calver_has_better_semantics&quot; class=&quot;toclink&quot;&gt;CalVer has better semantics&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Ironically yes.&lt;/p&gt;
&lt;p&gt;&quot;Semantic&quot; Versioning is all relative. One developer&#x27;s 1.0.0 is
another&#x27;s 0.0.1alpha. As authors, we try to ignore this and write
others off as wrong. But as clients, we make snap judgments, and
SemVer lets us forget and pretend. Calendar versioning is absolute and
neutral, with practical advantages to boot.&lt;/p&gt;
&lt;p&gt;As application developers adding functionality, evaluating a new
library means ascertaining maintenance status, usually by looking at
the most recent release date. CalVer puts us in the ballpark right
away. As maintainers depending on many libraries, calendar versioning
allows us to look at the dependency list and quickly ascertain which
libraries are good candidates for updating. CalVer even lets us take
that a step further, with date-based deprecation.&lt;/p&gt;
&lt;p&gt;Many might not realize it, but the oh-so ubiquitous &lt;a href=&quot;http://www.ubuntu.com/&quot;&gt;Ubuntu&lt;/a&gt;
is in fact calendar versioned. For example, version 15.04 came out in
April, 2015.  It gets better when you remember Long-Term
Support. Ubuntu&#x27;s LTS support lasts for five years. So, &lt;code&gt;14 + 5&lt;/code&gt;:
Ubuntu 14.04&#x27;s end of life will be in 2019. You don&#x27;t have to look
anything up. It&#x27;s all right there in the CalVer semantics.&lt;sup id=&quot;fnref:4&quot;&gt;&lt;a class=&quot;footnote-ref&quot; href=&quot;http://sedimental.org/designing_a_version.html#fn:4&quot;&gt;4&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;
&lt;h3 id=&quot;calver_protects_projects&quot;&gt;&lt;a href=&quot;#calver_protects_projects&quot; class=&quot;toclink&quot;&gt;CalVer protects projects&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;If you care about the future of the project, then guard it against one
of the worst fates: the fatuous 2.0. Give your project a
future. Guard against the learned expectation of 2.0 or death.&lt;/p&gt;
&lt;p&gt;A 1.x &lt;em&gt;always&lt;/em&gt; carries one advantage over a 2.0: the code is deployed
and working. Avoid contempt for past decisions and current users. In
engineering, utility is half of correctness.&lt;/p&gt;
&lt;p&gt;SemVer is set up so that every major release implies a minimum
threshold of change. If the project is founded on and aiming for
correctness, fewer and fewer changes are
required. &lt;a href=&quot;https://en.wikipedia.org/wiki/Donald_Knuth&quot;&gt;Donald Knuth&lt;/a&gt; embraced this in the extreme by having
&lt;a href=&quot;https://en.wikipedia.org/wiki/TeX#History&quot;&gt;TeX&#x27;s version approach π asymptotically&lt;/a&gt;. Suffice to
say with CalVer, you are safe to add as much or as little
functionality as needed.&lt;/p&gt;
&lt;p&gt;&lt;a id=&quot;successors&quot;&gt;&lt;/a&gt;
Too often projects become a victim of versioning. New projects end up
masquerading as new versions. &lt;a href=&quot;https://d3js.org/&quot;&gt;D3&lt;/a&gt; could have been
&lt;a href=&quot;http://mbostock.github.io/protovis/&quot;&gt;Protovis&lt;/a&gt; 2.0, but instead, a successor was created.
Both projects coexisted and we are all the better for it. Same with
&lt;a href=&quot;https://attrs.readthedocs.org/en/stable/why.html#characteristic&quot;&gt;characteristic and attrs&lt;/a&gt;. Successors and CalVer protect projects and
do justice by clients and code.&lt;/p&gt;
&lt;h2 id=&quot;summary&quot;&gt;&lt;a href=&quot;#summary&quot; class=&quot;toclink&quot;&gt;Summary&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Consider adding a calendar component to your next library&#x27;s versioning
schemes. As for my opinion, I&#x27;ve joined &lt;a href=&quot;https://twitter.com/hynek&quot;&gt;other&lt;/a&gt;
&lt;a href=&quot;https://twitter.com/glyph&quot;&gt;maintainers&lt;/a&gt; in doing so for &lt;a href=&quot;https://github.com/mahmoud/boltons/blob/master/CHANGELOG.md&quot;&gt;boltons&lt;/a&gt; and
&lt;a href=&quot;https://github.com/mahmoud/ashes/&quot;&gt;ashes&lt;/a&gt;. I&#x27;ve found it makes a lot of sense for libraries, and
a little less sense for protocols and services.&lt;sup id=&quot;fnref:5&quot;&gt;&lt;a class=&quot;footnote-ref&quot; href=&quot;http://sedimental.org/designing_a_version.html#fn:5&quot;&gt;5&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;
&lt;p&gt;Either way, think about project versions. The version is part of your
project&#x27;s face and your clients&#x27; integration. After spending days,
weeks, and months on a project, it&#x27;s worthwhile to spend a few minutes
or hours designing a versioning system tailored to the needs of
project users and maintainers.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;If you&#x27;re into enterprise software considerations like these,
 &lt;a href=&quot;http://sedimental.org/atom.xml&quot;&gt;subscribe&lt;/a&gt; or
 &lt;a href=&quot;https://twitter.com/mhashemi&quot;&gt;follow me on Twitter&lt;/a&gt; for some
 details about my upcoming O&#x27;Reilly project.&lt;/em&gt;&lt;/p&gt;
&lt;!--
If you don&#x27;t have time to think about the version of the library
you are writing or including, then maybe you shouldn&#x27;t be writing
including it.
--&gt;

&lt;!-- ============== !--&gt;

&lt;div class=&quot;footnote&quot;&gt;
&lt;hr /&gt;
&lt;ol&gt;
&lt;li id=&quot;fn:1&quot;&gt;
&lt;p&gt;Astute readers will note that it&#x27;s Semantic Versioning 2.0.0.
  &lt;em&gt;&quot;Oh, cute, Tom used his own scheme for the document.&quot;&lt;/em&gt; But did you
  wonder what public API changed to trigger that major version bump?
  SemVer&#x27;s public API has been semver.org &lt;strong&gt;&lt;a href=&quot;https://web.archive.org/web/20111207065319/http://semver.org/&quot;&gt;since before 1.0&lt;/a&gt;&lt;/strong&gt;.
  How about those semantics? &lt;a class=&quot;footnote-backref&quot; href=&quot;http://sedimental.org/designing_a_version.html#fnref:1&quot; title=&quot;Jump back to footnote 1 in the text&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;fn:2&quot;&gt;
&lt;p&gt;I&#x27;ve actually been saying something similar, but more practical, for a long time:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;If both you (or your team) &lt;strong&gt;and&lt;/strong&gt; a stranger (someone not
directly advised) are both using a library in a production
environment, the time for a major version has come.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;If it&#x27;s just you and yours, that&#x27;s understandable. Many great
  scientists took &lt;a href=&quot;https://en.wikipedia.org/wiki/Self-experimentation_in_medicine&quot;&gt;great risks with themselves&lt;/a&gt; for the
  sake of progress. If it&#x27;s just a stranger going against your
  explicit advice, then there&#x27;s no accounting for such
  wildcards. But, if both of groups are using something in
  production, then it&#x27;s time to face the facts. Tie up the loosest
  of ends and give it a major version. &lt;a class=&quot;footnote-backref&quot; href=&quot;http://sedimental.org/designing_a_version.html#fnref:2&quot; title=&quot;Jump back to footnote 2 in the text&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;fn:3&quot;&gt;
&lt;p&gt;Here are some more resources for those interested in the
  Firefox release switch up:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://support.mozilla.org/en-US/questions/896705&quot;&gt;Support forum discussion on FF major releases&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://www.pcworld.com/article/224842/why_firefox_rapid_release_schedule_is_a_bad_idea.html&quot;&gt;Firefox Rapid Release Criticized&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://www.theverge.com/2012/7/9/3147445/mozilla-jono-dicarlo-rapid-releases-firefox&quot;&gt;Former Mozilla dev Jono DiCarlo on Firefox Rapid Release&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=678775&quot;&gt;The Bugzilla bug for hiding the version number&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;At the very least this should illustrate that versions
  matter. They&#x27;re part of your project&#x27;s identity. Design them to
  help your user. &lt;a class=&quot;footnote-backref&quot; href=&quot;http://sedimental.org/designing_a_version.html#fnref:3&quot; title=&quot;Jump back to footnote 3 in the text&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;fn:4&quot;&gt;
&lt;p&gt;To illustrate the prevalence, there are actually many other
  examples of calendar versioning we take for granted. Off the top
  of my head I could think of Twisted, Windows 95/98/2000, and
  probably most ubiquitous: every mainstream car in
  circulation. &lt;a href=&quot;http://sedimental.org/about.html&quot; target=&quot;_blank&quot;&gt;Email me&lt;/a&gt; with more examples and I&#x27;ll compile
  them somewhere. &lt;a class=&quot;footnote-backref&quot; href=&quot;http://sedimental.org/designing_a_version.html#fnref:4&quot; title=&quot;Jump back to footnote 4 in the text&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;fn:5&quot;&gt;
&lt;p&gt;To illustrate, if I could have it my way, we&#x27;d have OpenSSL
  16.x.x. That way I can easily complain if I find someone using
  10.x.x in production. That said, TLS/1.3 seems better than
  TLS/16.0.&lt;/p&gt;
&lt;p&gt;My current thought is that protocols live outside of time,
  because I believe it&#x27;s possible to complete a protocol, but an
  implementation is never done. &lt;a class=&quot;footnote-backref&quot; href=&quot;http://sedimental.org/designing_a_version.html#fnref:5&quot; title=&quot;Jump back to footnote 5 in the text&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;&lt;p&gt;&lt;/p&gt;



&lt;hr /&gt;

</content>

  </entry>
  
  <entry>
    <id>http://sedimental.org/getting_a_python_job.html</id>
    <author>
      <name>Mahmoud Hashemi</name>
      <uri>http://sedimental.org/</uri>
    </author>
    <title>Getting a Python job</title>
    <link rel="alternate" type="text/html" href="http://sedimental.org/getting_a_python_job.html" />
    <published>2016-01-25T21:02:00Z</published>
    <updated>2016-01-25T21:02:00Z</updated>
    <category term="work"/><category term="python"/>
    

    <content type="html">&lt;p&gt;&lt;p&gt;Every day, Python is the primary programming language for tens if not
hundreds of thousands of professional engineers, analysts, and
researchers, including yours truly. Given Python&#x27;s &quot;language of
choice&quot; status, what can you do to join those lucky ranks?&lt;/p&gt;
&lt;p&gt;It&#x27;s a good question, and one I get often. Recently I was asked more
publically than
usual. &lt;a href=&quot;https://twitter.com/mkennedy&quot;&gt;Michael Kennedy&lt;/a&gt;, host of the
&lt;a href=&quot;https://talkpython.fm/&quot;&gt;Talk Python to Me podcast&lt;/a&gt;, asked me five
questions on behalf of people early in their Python/programming
careers:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;What kind of Python devs do you work with and interview?&lt;/li&gt;
&lt;li&gt;What is the most important piece of experience that you look for in a candidate?&lt;/li&gt;
&lt;li&gt;If someone is applying for their first job with you, what can they
   present to show they have the right skillset/education?&lt;/li&gt;
&lt;li&gt;Open-source contributions&lt;/li&gt;
&lt;li&gt;Side projects&lt;/li&gt;
&lt;li&gt;Mobile phone apps&lt;/li&gt;
&lt;li&gt;Websites&lt;/li&gt;
&lt;li&gt;Code competitions&lt;/li&gt;
&lt;li&gt;If you are presented with two candidates, one with a solid CS
   degree, and the other with 1-2 years of experience, which would
   you value more?&lt;/li&gt;
&lt;li&gt;Why did you hire the last person you hired?&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Here are my answers, the enterprise hiring perspective, as transcribed
from my parts of &lt;a href=&quot;https://talkpython.fm/episodes/show/41/getting-your-first-dev-job-as-a-python-developer-part-2&quot;&gt;the panel discussion&lt;/a&gt;.&lt;/p&gt;
&lt;div class=&quot;toc&quot;&gt;&lt;span class=&quot;toctitle&quot;&gt;Contents&lt;/span&gt;&lt;ul&gt;&lt;li&gt;&lt;a href=&quot;#intro&quot;&gt;Intro&lt;/a&gt;&lt;li&gt;&lt;a href=&quot;#my_type_of_hiring&quot;&gt;My type of hiring&lt;/a&gt;&lt;li&gt;&lt;a href=&quot;#the_most_important_experience&quot;&gt;The most important experience&lt;/a&gt;&lt;li&gt;&lt;a href=&quot;#side_experience&quot;&gt;Side experience&lt;/a&gt;&lt;li&gt;&lt;a href=&quot;#formal_education&quot;&gt;Formal education&lt;/a&gt;&lt;li&gt;&lt;a href=&quot;#last_hire&quot;&gt;Last hire&lt;/a&gt;&lt;li&gt;&lt;a href=&quot;#takeaways&quot;&gt;Takeaways&lt;/a&gt;&lt;/ul&gt;&lt;/div&gt;&lt;h2 id=&quot;intro&quot;&gt;&lt;a href=&quot;#intro&quot; class=&quot;toclink&quot;&gt;Intro&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Hi my name is Mahmoud Hashemi. I&#x27;m lead developer of Python
Infrastructure
&lt;a href=&quot;https://medium.com/paypal-tech/search?q=python&quot;&gt;at PayPal&lt;/a&gt;, and I&#x27;m
also the presenter of Enterprise Software with Python, coming soon
&lt;a href=&quot;http://www.oreilly.com/pub/au/6849&quot;&gt;from O&#x27;Reilly&lt;/a&gt;. Dedicated listeners may recognize my voice from
&lt;a href=&quot;https://talkpython.fm/episodes/show/4/enterprise-python-and-large-scale-projects&quot;&gt;episode #4 of Talk Python to Me&lt;/a&gt;,
and it&#x27;s great to be back on the show.&lt;/p&gt;
&lt;h2 id=&quot;my_type_of_hiring&quot;&gt;&lt;a href=&quot;#my_type_of_hiring&quot; class=&quot;toclink&quot;&gt;My type of hiring&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;&lt;em&gt;What kind of Python devs do you work with and interview?&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;I work with Python infrastructure engineers. Software infrastructure
is the foundation of all sorts of software development, from web to
backend to batch to automation and tools. To do it well you have to
have personal experience developing in two or more of those
categories. For the past year or so, my team has been adjunct to the
PayPal application security team, and that&#x27;s who I&#x27;m hiring for right
now. So a little plug, if you have at least five years of industry
experience and want to get into some ultrahigh performance Python
security work, shoot me an email at &lt;a href=&quot;http://sedimental.orgmailto:mahmoud@paypal.com&quot;&gt;mahmoud@paypal.com&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;All that said, one of the services the Python infrastructure team also
performs is to do phone and in-person interviews for PayPal teams
looking to expand their Python talent through hiring.&lt;/p&gt;
&lt;h2 id=&quot;the_most_important_experience&quot;&gt;&lt;a href=&quot;#the_most_important_experience&quot; class=&quot;toclink&quot;&gt;The most important experience&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;&lt;em&gt;What is the most important piece of experience that you look for in a candidate?&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;The most important fundamental skills I look for are closely related
to experience: environmental fluidity and personal learning abilty.&lt;/p&gt;
&lt;p&gt;Wait, not Python? That&#x27;s right. The fact is, for more junior jobs, the
Python is going to be the easiest part of the job, and new hires have
plenty of time to learn, plus the team is there to help. New
developers will come up to speed quickly provided they&#x27;re comfortable
learning in the environment.&lt;/p&gt;
&lt;p&gt;As for environmental fluidity, specifically, PayPal uses a lot of
Linux, so I look for candidates that can demonstrate familiarity at
the console, interacting with the operating system. So while I don&#x27;t
usually give candidates complex algorithmic questions on the spot, I
&lt;em&gt;do&lt;/em&gt; log them into one of PayPal&#x27;s test servers and have them do some
basic debugging. For the experienced, you can almost feel them
relaxing into a familiar environment. For the inexperienced, the
terminal can be an aptly named dark and scary place. Either way, the
command line is a foundational technology critical to enterprise work,
and is not going away anytime soon. Lack of command line comfort is a
big yellow flag, especially when Linux is so widespread and easy to
experiment with on your own.&lt;/p&gt;
&lt;p&gt;The other characteristic I look for is learning ability. The skills
to read and research naturally, absorbing and arranging information
automatically. I&#x27;ve been burned once or twice by talented people who
were too lazy to read the docs, or too intimidated to read the source
code. You don&#x27;t have to do it in big gulps, but you do need to do it
consistently. So I usually look at what candidates have done to learn
lately, and the sources they&#x27;ve been consulting. Show me some code
you&#x27;ve written and what you learned during the process. Tell me about
a project that sounds much simpler than it was. What sites taught you
the web? Seen any noteworthy source code lately?&lt;/p&gt;
&lt;p&gt;On the other hand, I watch out for HackerNewsy types. My projects have
topped HN several times in the last couple years, and some lurking is
fine, but I want someone ready to outgrow that consumption and
commodification of creative work interleaved with press
releases. Someone ready to dedicate time to actually create the sorts
of things that others will upvote.&lt;/p&gt;
&lt;h2 id=&quot;side_experience&quot;&gt;&lt;a href=&quot;#side_experience&quot; class=&quot;toclink&quot;&gt;Side experience&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;&lt;em&gt;If someone is applying for their first job with you, what can they
present to show they have the right skillset/education?&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;When it comes to first jobs and concrete projects, I&#x27;ll look at
anything and everything. With new developers it&#x27;s just so rare to get
someone with anything interesting in their GitHub or Bitbucket
account, but that is definitely my first stop. Software is
increasingly portfolio driven, and I do get a bit discouraged when I
see a developer who doesn&#x27;t have a GitHub, or a site, or even a
blog. You can cram for an interview, and you can exaggerate on a
resume, but you can&#x27;t really fake a meaningful commit timeline going
back a year or two. Even if it&#x27;s just school projects, at least I
could see you&#x27;ve tried and you have some basic git
skills. Contributions to other projects tell a good story, too. You
were probably using the project for something, being productive. You
took the time to understand how it worked, you were able to
communicate, and lived up to someone else&#x27;s standards. That&#x27;s
stressful for a lot of people, but that&#x27;s got a lot in common with
enterprise development, too.&lt;/p&gt;
&lt;p&gt;Side projects and apps that run in environments similar to our own are
very interesting. Mobile phone apps not as much. Code competitions and
scores from reddit/stackoverflow/HN are OK, but honestly those skills
don&#x27;t apply that well internally. This may make me unpopular, but
people who have high scores on all those sites are playing games that
can lead them to be impatient and unhelpful with internal people and
processes. That said, if you&#x27;re someone who helps out with mentorship
or even get on IRC and answer questions, that could be great!&lt;/p&gt;
&lt;h2 id=&quot;formal_education&quot;&gt;&lt;a href=&quot;#formal_education&quot; class=&quot;toclink&quot;&gt;Formal education&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;&lt;em&gt;If you are presented with two candidates, one with a solid CS
degree, and the other with 1-2 years of experience, which would
you value more?&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Of the three hires I&#x27;d truly consider my &quot;star&quot; hires, none of them
had a CS degree. Electrical engineering, math, and comparative
literature. The things they had in common were voracious reading and
extensive hours spent in some Python or POSIX environment.&lt;/p&gt;
&lt;p&gt;Computer science degrees aren&#x27;t really necessary for the majority of
enterprise work. Like I said before, environmental fluidity and
willingness to read docs are far more important. A couple of CS
classes get you some useful vocabulary and teach you time
complexity.&lt;/p&gt;
&lt;p&gt;As for the concept of a degree in general, if you want to work at a
big company, it&#x27;s a lot easier to get in with a bachelors. You don&#x27;t
need much more than that. The right two years of experience can go a
long way in terms of skills development, but in terms of management
marketability, no degree raises eyebrows in many cases. So, in short,
for enterprise software, my observation is that a computer science
degree is about as good as a non-CS degree plus 2 years experience
which is about as good as no degree plus 4-5 years experience, at least.&lt;/p&gt;
&lt;p&gt;Most professors and academic programs don&#x27;t give you all that much
pragmatic knowledge, even if it&#x27;s pretty old stuff like emacs and
terminal usage. Basically everything is about how you approach your
assignments and free time. If you push beyond the requirements, you
will learn much more.&lt;/p&gt;
&lt;p&gt;So, if you&#x27;re in school, take an operating systems class. Take a
networking class. Maybe a crypto class. You&#x27;ll learn almost as much as
running a shared server in your dorm. No, those are different types of
knowledge, so consider doing both. If you&#x27;re not in school, Coursera
and other options are far better than nothing, and I&#x27;d like to hear
about those experiences in interviews.&lt;/p&gt;
&lt;h2 id=&quot;last_hire&quot;&gt;&lt;a href=&quot;#last_hire&quot; class=&quot;toclink&quot;&gt;Last hire&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;&lt;em&gt;Why did you hire the last person you hired?&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;I gave my most recent thumbs up to a developer who knew Django and was
willing to continue working with it, but most importantly he could
start on-site before the req closed. In large companies, empty seats
have expiration dates, and everyone is willing to gamble. Because
somebody is better than nobody, and even if they&#x27;re worse than nobody,
then you still get a backfill when they leave or are pushed out. But
this developer seems to be working out, but I only helped hire him for
another team.&lt;/p&gt;
&lt;p&gt;The last engineer I hired onto my team was recruited over the course
of two years. I met him at PyCon 2012 and we collaborated on a few
open-source projects. Real recruiting can be a long process, not the
least of which is due to weird budgeting and bureaucracy. So please
don&#x27;t get frustrated if you&#x27;re still waiting on an email reply from
me! :)&lt;/p&gt;
&lt;h2 id=&quot;takeaways&quot;&gt;&lt;a href=&quot;#takeaways&quot; class=&quot;toclink&quot;&gt;Takeaways&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Reduced to a few bullet points, here are the key characteristics:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Environmental fluidity&lt;/li&gt;
&lt;li&gt;Reading ability and conceptual familiarity&lt;/li&gt;
&lt;li&gt;Command line comfort&lt;/li&gt;
&lt;li&gt;Not HackerNewsy&lt;/li&gt;
&lt;li&gt;Dedication. No technical butterflies here, please.&lt;/li&gt;
&lt;li&gt;Pragmatism, lack of frustration&lt;/li&gt;
&lt;li&gt;Management marketability&lt;/li&gt;
&lt;li&gt;Ability/willingness to work/train/visit onsite&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The other interviewees had some interesting things to say, as well. I
recommend checking out &lt;a href=&quot;https://talkpython.fm/episodes/show/41/getting-your-first-dev-job-as-a-python-developer-part-2&quot;&gt;the full podcast&lt;/a&gt;, now featuring
&lt;a href=&quot;https://talkpython.fm/episodes/transcript/41/getting-your-first-dev-job-as-a-python-developer-part-2&quot;&gt;transcripts for everyone, not just me&lt;/a&gt;. Thanks again
to Michael for having me back!&lt;p&gt;&lt;/p&gt;



&lt;hr /&gt;

</content>

  </entry>
  
  <entry>
    <id>http://sedimental.org/rwc_2016_lightning_talk.html</id>
    <author>
      <name>Mahmoud Hashemi</name>
      <uri>http://sedimental.org/</uri>
    </author>
    <title>RWC 2016 Lightning Talk</title>
    <link rel="alternate" type="text/html" href="http://sedimental.org/rwc_2016_lightning_talk.html" />
    <published>2016-01-07T20:20:00Z</published>
    <updated>2016-01-07T20:20:00Z</updated>
    <category term="code"/><category term="work"/><category term="python"/><category term="security"/>
    

    <content type="html">&lt;p&gt;&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;Today I had the pleasure of talking on stage for ~2 minutes at the
&lt;a href=&quot;http://www.realworldcrypto.com/&quot;&gt;Real World Crypto 2016 conference&lt;/a&gt; in Stanford, CA. This
is a pseudotranscript of that lightning talk.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;I&#x27;m Mahmoud Hashemi and I work as a Lead Developer at PayPal. I mostly
focus on &lt;a href=&quot;https://medium.com/paypal-tech/search?q=python&quot;&gt;Python frameworks and software infrastructure&lt;/a&gt;, but
for the last couple years I&#x27;ve been working on Application
Security. In fact, my first assignment, back in late 2012, was reverse
engineering and reimplementing Max Levchin&#x27;s Certicom elliptic curve
integration, in Python.&lt;/p&gt;
&lt;p&gt;These days I work on PayPal&#x27;s comprehensive key management (and HSM
integration) system. Suffice to say, we work a lot with encryption and
secure sockets. &lt;em&gt;Also&lt;/em&gt; suffice to say, we&#x27;re a bit nervous about
&lt;a href=&quot;https://www.openssl.org/&quot;&gt;OpenSSL&lt;/a&gt;. With all the news lately we&#x27;ve started design
discussions with regard to how we can hedge our OpenSSL bets.&lt;/p&gt;
&lt;p&gt;In Python, this translates to a &lt;a href=&quot;https://www.python.org/dev/peps/pep-0249/&quot;&gt;DBAPI 2.0&lt;/a&gt;-like abstraction
layer to enable swapping out security implementations. Like many
&lt;a href=&quot;https://en.wikipedia.org/wiki/Object-relational_mapping&quot;&gt;ORMs&lt;/a&gt; (e.g., &lt;a href=&quot;http://www.sqlalchemy.org/&quot;&gt;SQLAlchemy&lt;/a&gt;), but for security. Honestly,
there are usually better/more reasons to switch SSL implementations
than relational databases. We want an API that allows us to leverage
other great SSL implementations, including OpenSSL-derivatives like
&lt;a href=&quot;http://www.libressl.org/&quot;&gt;LibreSSL&lt;/a&gt;, as well as other implementations like
&lt;a href=&quot;https://www.wolfssl.com/wolfSSL/Home.html&quot;&gt;WolfSSL&lt;/a&gt;. PayPal already has a diverse SSL ecosystem, with
multiple versions of OpenSSL and tons of JVM-based implementations,
making it a great testbed ecosystem.&lt;/p&gt;
&lt;p&gt;To achieve this we&#x27;re hoping to have some productive discussions with
the experienced engineers and cryptographers that attend RWC. It&#x27;s
still very early days, and there are a lot of corner cases, so we&#x27;ll
need all the advice we can get. Help us invest in the algorithms, not
the implementations. Design for replaceability, to avoid having
17-year-old libraries serving today&#x27;s security-hungry Internet. You
can contact me at &lt;a href=&quot;https://github.com/mhamoud&quot;&gt;github.com/mahmoud&lt;/a&gt;,
&lt;a href=&quot;https://twitter.com/mhashemi&quot;&gt;twitter.com/mhashemi&lt;/a&gt;, or &lt;a href=&quot;http://sedimental.orgmailto:mahmoud@paypal.com&quot;&gt;mahmoud@paypal.com&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img title=&quot;A partially obfuscated view from the stage of RWC2016&quot; width=&quot;70%&quot; src=&quot;http://sedimental.org/uploads/rwc2016_stage.jpg&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;A partially obfuscated view from the stage of RWC2016&lt;/em&gt;&lt;p&gt;&lt;/p&gt;



&lt;hr /&gt;

</content>

  </entry>
  
  <entry>
    <id>http://sedimental.org/enterprise_overhaul_resolving_dns.html</id>
    <author>
      <name>Mahmoud Hashemi</name>
      <uri>http://sedimental.org/</uri>
    </author>
    <title>Enterprise Overhaul: Resolving DNS</title>
    <link rel="alternate" type="text/html" href="http://sedimental.org/enterprise_overhaul_resolving_dns.html" />
    <published>2015-12-21T11:13:00Z</published>
    <updated>2015-12-21T11:13:00Z</updated>
    <category term="python"/><category term="code"/><category term="work"/>
    

    <content type="html">&lt;p&gt;&lt;!-- Enterprise Overhaul: Resolving DNS --&gt;

&lt;!-- Overhaul your DNS Resolution, Enterprise-style --&gt;

&lt;!-- Overhauling DNS Resolutions for Enterprise Environments --&gt;

&lt;!-- aka Using DNS in Enterprise Environments --&gt;

&lt;!-- aka &quot;In With The Old: Enterprise DNS Considerations&quot; --&gt;

&lt;p&gt;&lt;em&gt;Originally published on
&lt;a href=&quot;https://medium.com/paypal-tech/enterprise-overhaul-resolving-dns-521dac3ab601&quot;&gt;the PayPal Engineering blog&lt;/a&gt;. Republished here with
minor modifications and updates.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Everyone assumes all software engineers are great with numbers. If
only they knew the truth. How many people&#x27;s phone numbers can you
recite? No peeking and emergency numbers don&#x27;t count! Don&#x27;t worry if
you couldn&#x27;t name that many. Here&#x27;s the real embarrassing test of the
day: How many sites&#x27; IP addresses can you name? No pinging and local
subnets don&#x27;t count!&lt;/p&gt;
&lt;p&gt;&lt;img width=&quot;50%&quot; title=&quot;Most telephones still looked like this when
DNS was invented.&quot; src=&quot;http://sedimental.org/uploads/illo/mjc/telephone.png&quot; /&gt;&lt;br /&gt;&lt;em&gt;Most
telephones still looked like this when DNS was invented. Not pictured:
the phonebook.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Back in the mid-1980s, the first Domain Name System (&lt;a href=&quot;https://en.wikipedia.org/wiki/Domain_Name_System&quot;&gt;DNS&lt;/a&gt;)
implementations started putting our IP addresses into server-based
contact lists and the Internet has never looked the same since. These
days, we may associate DNS with large-scale networks, but it&#x27;s
important to remember that DNS really came from a very human distaste
for numbers. Thirty years later, we engineers use it so much in normal
Internet usage that it&#x27;s easy to take for granted.&lt;/p&gt;
&lt;p&gt;DNS may be a mature, but the fact of networks is that it always takes
at least two to tango. As new technologies and deployments emerge, the
implications of integrating with DNS must still be revisited. Your
datacenter is not the Internet, even if it&#x27;s in the cloud. This post
looks at how to resolve a few of the DNS pitfalls preying on precious
reliability and performance.&lt;/p&gt;
&lt;!-- prevent potential pitfalls that prey on projects&#x27; precious
  performance and predictability. --&gt;

&lt;h3 id=&quot;a_protocol_precaution&quot;&gt;&lt;a href=&quot;#a_protocol_precaution&quot; class=&quot;toclink&quot;&gt;A protocol precaution&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The client side of DNS, &lt;em&gt;resolution&lt;/em&gt;, is virtually all
&lt;a href=&quot;https://en.wikipedia.org/wiki/User_Datagram_Protocol&quot;&gt;UDP&lt;/a&gt;. This is interesting because UDP is designed as a
lightweight, &lt;a href=&quot;https://en.wikipedia.org/wiki/Reliability_%28computer_networking%29&quot;&gt;unreliable&lt;/a&gt; transport. However, in many
of the most common use cases, DNS calls precede &lt;a href=&quot;https://en.wikipedia.org/wiki/Transmission_Control_Protocol&quot;&gt;TCP&lt;/a&gt;-backed
&lt;a href=&quot;https://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol&quot;&gt;HTTP&lt;/a&gt; and other protocols based on reliable transports. This
fundamental difference changes many things. Looking upstream, UDP does
not load-balance like TCP. Because UDP is not connection-oriented or
congestion-controlled, DNS traffic will act very differently at scale.&lt;/p&gt;
&lt;p&gt;So our first lesson is to stay true to the stateless nature of UDP and
avoid putting &lt;a href=&quot;https://www.f5.com/pdf/deployment-guides/dns-load-balancing-dg.pdf&quot;&gt;stateful load balancers&lt;/a&gt; in front of DNS
infrastructure. Instead, configure clients and servers to conform to
the built-in load-handling architecture of DNS. The Internet&#x27;s DNS
&quot;deployment&quot; is load balanced via its
&lt;a href=&quot;https://www.novell.com/documentation/dns_dhcp/?page=/documentation/dns_dhcp/dhcp_enu/data/behdbhhj.html&quot;&gt;inherent hierarchy&lt;/a&gt; and &lt;a href=&quot;https://en.wikipedia.org/wiki/Anycast&quot;&gt;IP Anycast&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&quot;client_integration&quot;&gt;&lt;a href=&quot;#client_integration&quot; class=&quot;toclink&quot;&gt;Client integration&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Back on the client side, you can do a lot to optimize and robustify your
application&#x27;s DNS integration. The first step is to take a hard look
at your stack. Whether you&#x27;re running Python, Java, JavaScript, or C++, the
defaults may not be for you, especially when working with traffic within the
datacenter.&lt;/p&gt;
&lt;p&gt;For example, while not supported here at PayPal, it&#x27;s safe to say
&lt;a href=&quot;https://github.com/tornadoweb/tornado&quot;&gt;Tornado&lt;/a&gt; is a popular Python web framework, with many
asynchronous networking features. But, silently and subtly,
&lt;a href=&quot;https://twitter.com/etrepum/status/585544395006550016&quot;&gt;DNS is not one of them&lt;/a&gt;. Tornado&#x27;s
&lt;a href=&quot;http://tornado.readthedocs.org/en/latest/netutil.html#tornado.netutil.BlockingResolver&quot;&gt;default DNS resolution behavior&lt;/a&gt; will block the
entire IO event loop, leading to big issues at scale.&lt;/p&gt;
&lt;p&gt;And that&#x27;s just one example of library DNS defaults jeopardizing
application reliability. Third-party packages and sometimes even
builtins in Java, Node.js, Python, and other stacks are full of hidden
DNS faux pas.&lt;/p&gt;
&lt;p&gt;For instance, the average off-the-shelf HTTP client seems like a
neutral-enough component. Where would we be without reliable standbys
like &lt;a href=&quot;https://en.wikipedia.org/wiki/Wget&quot;&gt;wget&lt;/a&gt;? And that is how the trouble starts. The DNS
defaults in most tools are designed to make for good Internet
citizens, not reliable and performant enterprise foundations.&lt;/p&gt;
&lt;p&gt;&lt;a target=&quot;_blank&quot; href=&quot;https://en.wikipedia.org/wiki/Domain_Name_System#Client_lookup&quot;&gt;&lt;img width=&quot;50%&quot; title=&quot;The hops Internet applications make for you.&quot; src=&quot;http://sedimental.org/uploads/DNS_in_the_real_world.svg.png&quot; /&gt;&lt;/a&gt;&lt;br /&gt;&lt;em&gt;The hops Internet-connected
applications make for you. It&#x27;s no wonder the default timeout is 5000
milliseconds.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;The first difference is name resolution timeouts. By default,
&lt;a href=&quot;http://linux.die.net/man/5/resolv.conf&quot;&gt;resolve.conf&lt;/a&gt;, &lt;a href=&quot;https://github.com/netty/netty/blob/1b8086a6c16319c93724d65af1c805363c03b6d0/resolver-dns/src/main/java/io/netty/resolver/dns/DnsNameResolver.java#L310&quot;&gt;netty&lt;/a&gt;, and
&lt;a href=&quot;http://c-ares.haxx.se/ares_init.html&quot;&gt;c-ares&lt;/a&gt; (gevent, node.js, curl) are all configured to a
whopping &lt;strong&gt;5 seconds&lt;/strong&gt;. But this is your enterprise, your service, and
your datacenter. Look at the &lt;a href=&quot;https://en.wikipedia.org/wiki/Service-level_agreement&quot; title=&quot;Service-Level Agreement&quot;&gt;SLA&lt;/a&gt; of your service and the
reliability of your DNS. If your service can&#x27;t take an extra 5000
milliseconds some percentage of the time, then you should lower that
timeout. I&#x27;ve usually recommended 200 milliseconds or less. If your
infrastructure can&#x27;t resolve DNS faster than that, do one or more of
the following:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Put the authoritative DNS servers topologically closer.&lt;/li&gt;
&lt;li&gt;Add caching DNS servers, maybe even on the same machine.&lt;/li&gt;
&lt;li&gt;Build application-level DNS caching.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Option #1 is purely a network issue, and a matter for network
operations to discuss. For brevity&#x27;s sake, option #2
&lt;a href=&quot;https://www.digitalocean.com/community/tutorials/how-to-configure-bind-as-a-caching-or-forwarding-dns-server-on-ubuntu-14-04&quot;&gt;is outside&lt;/a&gt; &lt;a href=&quot;https://help.ubuntu.com/community/Dnsmasq&quot;&gt;the scope&lt;/a&gt; &lt;a href=&quot;http://cr.yp.to/djbdns/dnscache.html&quot;&gt;of&lt;/a&gt;
&lt;a href=&quot;https://www.unbound.net/&quot;&gt;this article&lt;/a&gt;. But option #3 is the one we recommend most,
because it is bureaucracy-free and relatively easy to implement, even
with enterprise considerations.&lt;/p&gt;
&lt;h4 id=&quot;application_level_dns_caching&quot;&gt;&lt;a href=&quot;#application_level_dns_caching&quot; class=&quot;toclink&quot;&gt;Application-level DNS caching&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;When designing an enterprise application-level DNS cache, we must
recognize that we are not discussing standard-issue web components
like scrapers and browsers. Most enterprise services talk to a fixed
set of relatively few machines. Even the most powerful and complex
production PayPal services communicate with fewer than 200 addresses,
partly due to the prevalence of load balancing LTMs in our architecture.&lt;/p&gt;
&lt;p&gt;For our &lt;a href=&quot;https://medium.com/paypal-tech/introducing-support-98945f023a8e&quot;&gt;gevent-based Python stack&lt;/a&gt;, we use an asynchronous
DNS cache that refreshes those addresses every five minutes. Plus, the stack
warms up our application&#x27;s DNS cache by kicking off preresolution of
many known DNS-addressed hosts at startup, ensuring that the first
requests are as fast as later ones.&lt;/p&gt;
&lt;!-- Linux&#x27;s DNS behavior is provided via glibc. The same library that
brought you string formatting and basic time functions, also
nonchalantly provides DNS capabilities, with all its nuances. (TODO:
how well does this resolver/cache play with TTLs?)--&gt;

&lt;p&gt;Some may be asking, why use a custom, application-level DNS cache when
virtually every operating system caches DNS automatically? In short,
when the OS cache expires, the next DNS resolution will block, causing
stacks without this asynchronous DNS cache to block on the next
resolution. Our DNS cache allows us to use mildly stale
addresses while the cache is refreshing, making us robust to many DNS
issues. For our use cases both the chances and consequences of
connecting to the wrong server are so minute that it&#x27;s not worth
inflating outlier response times by inlining DNS. This arrangement
also makes services much more robust to network glitches and DNS
outages, as well as allowing for more logging and instrumentation
around the explicit DNS resolution so you can see when DNS is
performing badly.&lt;/p&gt;
&lt;h3 id=&quot;denecessitizing_dns&quot;&gt;&lt;a href=&quot;#denecessitizing_dns&quot; class=&quot;toclink&quot;&gt;Denecessitizing DNS&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The overhaul wouldn&#x27;t be complete without exploring one final
scenario. What&#x27;s it like to not use DNS at all? It may sound odd,
given the number of technologies built on DNS in the last 30
years. But even today, PayPal production services still communicate to
each other using a statically generated IP-address-based system, like
a souped-up &lt;a href=&quot;https://en.wikipedia.org/wiki/Hosts_%28file%29&quot;&gt;hosts file&lt;/a&gt;. This design decision long
predates my tenure here, and for a long time I considered it technical
debt. But after collaborating with architects here and at other
enterprise datacenters, I&#x27;ve come to appreciate the advantages of
skipping DNS. DNS was designed for multi-authority, federated,
eventually-consistent networks, like the Internet. Even the biggest
datacenters are not the Internet. A datacenter is topologically
smaller, has only one operational authority, and must meet much
tighter reliability requirements.&lt;/p&gt;
&lt;p&gt;&lt;img title=&quot;A little peek at PayPal&#x27;s midtier-to-midtier traffic.&quot; width=&quot;50%&quot; src=&quot;http://sedimental.org/uploads/pp_midtier.png&quot; /&gt;&lt;br /&gt; &lt;em&gt;A little peek at
PayPal&#x27;s midtier-to-midtier traffic. Each shrunken line of text is a
service endpoint. It looks like a lot, but each endpoint only talks to
a few others.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Whether or not your system uses DNS, when you own the entire network
it&#x27;s still best practice to maintain a central, version-controlled,
&quot;single source of truth&quot; repository for networking
configurations. After all, even DNS server configurations have to come
from somewhere. If it were possible to efficiently and reliably push
that same information to every client, would you? Explicit
preresolution of all service names reduces the window of inconsistency
while saving the datacenter billions of network requests. If you
already have a scalable deployment system, could it also fill the
network topology gap, saving you the trouble of overhauling, scaling,
and maintaining an Internet system for enterprise use? There&#x27;s a lot
packed in a question like that, but it&#x27;s something to consider when
designing your service ecosystem.&lt;/p&gt;
&lt;h3 id=&quot;in_short&quot;&gt;&lt;a href=&quot;#in_short&quot; class=&quot;toclink&quot;&gt;In short&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;So, to sum it all up, here are the key takeaways:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Beware the pitfalls of stateful load-balancing for DNS and UDP.&lt;/li&gt;
&lt;li&gt;Tighten up your timeouts according to your SLAs.&lt;/li&gt;
&lt;li&gt;Consider an in-application DNS cache with explicit resolution.&lt;/li&gt;
&lt;li&gt;The fastest and most reliable request is the request you don&#x27;t have to make.&lt;/li&gt;
&lt;li&gt;A datacenter is not the Internet.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If you&#x27;re not careful, out-of-box solutions will fill your inbox with
avoidable problems. Quality enterprise engineering means taking a
microscope to libraries, with deliberate overhauling for your
organization&#x27;s needs.&lt;/p&gt;
&lt;!-- &quot;DNS + HTTP: The Reliability and Performance of the Internet,
Inside the Datacenter!&quot; - Too many might not get the joke. --&gt;&lt;p&gt;&lt;/p&gt;



&lt;hr /&gt;

</content>

  </entry>
  
  <entry>
    <id>http://sedimental.org/announcing_the_hatnote_top_100.html</id>
    <author>
      <name>Mahmoud Hashemi</name>
      <uri>http://sedimental.org/</uri>
    </author>
    <title>Announcing the Hatnote Top 100</title>
    <link rel="alternate" type="text/html" href="http://sedimental.org/announcing_the_hatnote_top_100.html" />
    <published>2015-12-14T13:00:00Z</published>
    <updated>2015-12-14T13:00:00Z</updated>
    <category term="wikipedia"/><category term="hatnote"/><category term="python"/>
    

    <content type="html">&lt;p&gt;&lt;p&gt;&lt;em&gt;Originally published on &lt;a href=&quot;http://blog.hatnote.com/post/135182048397/announcing-the-hatnote-top-100&quot;&gt;the Hatnote blog&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Moreso than any other major site, &lt;a href=&quot;http://wikipedia.org/&quot;&gt;Wikipedia&lt;/a&gt; is centered around
knowledge, always growing, and brimming with information. It&#x27;s
important to remember that the insight of our favorite community-run
encyclopedia often follows the focus of its massive readership. Here
at Hatnote, we&#x27;ve often wondered, what great new topics is the
community learning about now?&lt;/p&gt;
&lt;p&gt;To shed more light on Wikipedia&#x27;s reading habits, we&#x27;re pleased to
announce the newest addition to the Hatnote family: &lt;strong&gt;The Hatnote Top
100&lt;/strong&gt;, available at &lt;strong&gt;&lt;a href=&quot;http://top.hatnote.com&quot;&gt;top.hatnote.com&lt;/a&gt;&lt;/strong&gt;. Because we can&#x27;t pass
up a good headwear-based pun.&lt;/p&gt;
&lt;p&gt;Updated daily, the Top 100 is a chart of the most-visited articles on
Wikipedia. Unlike the edit-oriented &lt;a href=&quot;http://listen.hatnote.com&quot;&gt;Listen to Wikipedia&lt;/a&gt; and
&lt;a href=&quot;http://weekly.hatnote.com&quot;&gt;Weeklypedia&lt;/a&gt;, Top 100 focuses on the biggest group of
Wikipedia users: the readers. Nearly 20 billion times per month,
&lt;a href=&quot;http://blog.wikimedia.org/2013/04/19/wikimedia-projects-500-million/&quot;&gt;around 500 million people&lt;/a&gt; read articles in over 200
languages. Top 100&#x27;s daily statistics offer a window into where
Wikipedia readers are focusing their attention. It also makes for a
great way to discover great chapters of Wikipedia one wouldn&#x27;t
normally read or edit.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://top.hatnote.com&quot; target=&quot;_blank&quot;&gt;&lt;img width=&quot;40%&quot; title=&quot;A screenshot of the Hatnote Top 100 from December 10, 2015&quot; src=&quot;https://41.media.tumblr.com/85ece35a58888f09b20733d6f0f3d0c2/tumblr_nzclixxtTV1s4aev9o1_1280.png&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Clear rankings, day-to-day differences, social media integration,
permalinks, and other familiar simple-but-critical features were
designed to make popular Wikipedia articles as relatable as albums on
a pop music chart. In practice, popular news stories and celebrities
definitely make the Top 100, but it is satisfying to see interesting
corners of history and other educational topic sharing, if not
dominating, the spotlight.&lt;/p&gt;
&lt;p&gt;In addition to a clear and readable report, Top 100 is also a
machine-readable archive, with reports dating back to November 2015,
including JSON versions of the metrics, as well as
&lt;a href=&quot;http://top.hatnote.com/about.html#feeds&quot;&gt;RSS feeds for all supported languages and projects&lt;/a&gt;. It&#x27;s all
available in over a dozen languages (and we
&lt;a href=&quot;https://github.com/hatnote/top/issues&quot;&gt;take requests for more&lt;/a&gt;). The data comes from a variety of
sources, most direct from Wikimedia, including
&lt;a href=&quot;https://wikimedia.org/api/rest_v1/?doc#!/Pageviews_data/get_metrics_pageviews&quot;&gt;a new pageview statistics API endpoint&lt;/a&gt; that we&#x27;ve been
proud to pilot and continue to use. And yes, as with all our projects
&lt;a href=&quot;https://github.com/hatnote/top/&quot;&gt;the code is open-source&lt;/a&gt;, too.&lt;/p&gt;
&lt;p&gt;For those of you looking to dig deeper than Wikipedia chart toppers,
there are several other activity-based projects worth mentioning:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;http://stats.grok.se&quot;&gt;stats.grok.se&lt;/a&gt; - The original, venerable pageview grapher and API&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://reportcard.wmflabs.org/&quot;&gt;Wikimedia Report Card&lt;/a&gt; - Advanced metrics and data used by the Wikimedia Foundation&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://wikirank.di.unimi.it/&quot;&gt;The Open Wikipedia Ranking&lt;/a&gt; - Traffic stats and more&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://twitter.com/WikipediaTrends&quot;&gt;@WikipediaTrends&lt;/a&gt; - A bot posting notable upward traffic spikes&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/Wikipedia:Top_25_Report&quot;&gt;The Top 25 Report&lt;/a&gt; - A manually-compiled weekly report of views and likely reasons&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://weekly.hatnote.com&quot;&gt;The Weeklypedia&lt;/a&gt; - Weekly edit statistics, emailed and archived by Hatnote&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;And there are other visualizations on &lt;a href=&quot;http://seealso.org&quot;&gt;seealso.org&lt;/a&gt; as
well. But for those who like to keep it simple, hit up the
&lt;a href=&quot;http://top.hatnote.com&quot;&gt;Hatnote Top 100&lt;/a&gt;, &lt;a href=&quot;http://top.hatnote.com/about.html#feeds&quot;&gt;subscribe to a feed&lt;/a&gt;, and/or
&lt;a href=&quot;https://twitter.com/hatnotable&quot;&gt;follow us on Twitter&lt;/a&gt;. See you there!&lt;p&gt;&lt;/p&gt;



&lt;hr /&gt;

</content>

  </entry>
  
  <entry>
    <id>http://sedimental.org/repeat_the_obvious.html</id>
    <author>
      <name>Mahmoud Hashemi</name>
      <uri>http://sedimental.org/</uri>
    </author>
    <title>Repeat the obvious</title>
    <link rel="alternate" type="text/html" href="http://sedimental.org/repeat_the_obvious.html" />
    <published>2015-11-09T08:05:00Z</published>
    <updated>2015-11-09T08:05:00Z</updated>
    <category term="disclaimer"/><category term="python"/><category term="life"/><category term="meta"/>
    

    <content type="html">&lt;p&gt;&lt;!-- aka &quot;Disclaimer: You may have read this before&quot;--&gt;

&lt;p&gt;Bad things happen when we don&#x27;t repeat the obvious.&lt;/p&gt;
&lt;!-- &lt;a href=&quot;http://sedimental.org&quot;&gt;&lt;img height=&quot;300px&quot; src=&quot;http://sedimental.org/uploads/repetition/blocks.jpg&quot;&gt;&lt;/a&gt; --&gt;

&lt;p&gt;It&#x27;s 9pm and I&#x27;m writing a post for &lt;a href=&quot;https://medium.com/paypal-tech/search?q=python&quot;&gt;the company engineering
blog&lt;/a&gt;. Every sentence is a slog. Not because I&#x27;m exacting and
conciseness isn&#x27;t my strong suit. My writing is slow because every
word is obvious, almost patronizing.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/Sierpinski_triangle&quot;&gt;&lt;img width=&quot;80%&quot; src=&quot;http://sedimental.org/uploads/repetition/800px-Sierpinski_triangle_evolution.svg.png&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Obvious realities bear repetition, and so must you. Common sense is
not so common. The majority of ideas floating around try too
hard. They&#x27;re designed to confuse, seduce, and sell. Press releases
and ads push to the forefront, while reviewed articles and texts sit
on shelves and in queues.&lt;/p&gt;
&lt;!--&lt;a href=&quot;https://en.wikipedia.org/wiki/Repeat_sign&quot;&gt;&lt;img
height=&quot;50px&quot;src=&quot;http://sedimental.org/uploads/repetition/YB0340_Repetition_reprise_debut.png&quot;&gt;&lt;/a&gt; --&gt;

&lt;p&gt;Repeat the obvious, so we stay on the same page. &lt;a href=&quot;http://learncodethehardway.org/&quot;&gt;The ways&lt;/a&gt;
we &lt;a href=&quot;http://recode.net/2015/02/14/obama-everybodys-got-to-learn-how-to-code/&quot;&gt;rush people&lt;/a&gt; into technology leaves
&lt;a href=&quot;http://lifehacker.com/how-i-taught-myself-to-code-in-eight-weeks-511615189&quot;&gt;little time&lt;/a&gt; for foundations. Software is so new and
developers so in-demand, every wave brings more fresh minds than the
last. Developers are arriving faster than knowledge can diffuse.&lt;/p&gt;
&lt;p&gt;Repeat the obvious, to keep perspective. Technology may favor the new,
but fundamentals do exist. Without reminders, time buries working
technologies in the dust of silence.&lt;/p&gt;
&lt;p&gt;Repeat the obvious, to avoid bizarre dark ages. Take functional
programming&#x27;s disappearance in the 1990s/2000s, cast aside in favor of
object orientated hype. Or that one time when not enough programmers
talked about and taught &lt;a href=&quot;https://en.wikipedia.org/wiki/Event_loop&quot;&gt;event-driven servers&lt;/a&gt; programming
and &lt;a href=&quot;https://en.wikipedia.org/wiki/Node.js&quot;&gt;Frankenstein&lt;/a&gt; was cast as revolutionary.&lt;/p&gt;
&lt;!-- &lt;a href=&quot;https://en.wikipedia.org/wiki/Da_capo&quot;&gt;&lt;img height=&quot;75px&quot;src=&quot;http://sedimental.org/uploads/repetition/YB0335_Repetition_dacapo.png&quot;&gt;&lt;/a&gt; --&gt;

&lt;p&gt;So I hope you&#x27;ll forgive the repetition. It hurts me more than it
hurts you, and believe me when I say it helps many. Documentation does
not equal disussion. The modern media landscape demands a technology
have both docs and discourse to remain useful.&lt;/p&gt;
&lt;p&gt;Until we live in a world where reference rules over repetition, you
can help by writing about something painfully obvious to you. Bad
things happen when we don&#x27;t repeat the obvious.&lt;/p&gt;
&lt;!-- https://www.flickr.com/photos/ryan_orr/467847865 --&gt;

&lt;!-- TODO: --&gt;&lt;p&gt;&lt;/p&gt;



&lt;hr /&gt;

</content>

  </entry>
  
  <entry>
    <id>http://sedimental.org/remap.html</id>
    <author>
      <name>Mahmoud Hashemi</name>
      <uri>http://sedimental.org/</uri>
    </author>
    <title>Remap: Nested Data Multitool for Python</title>
    <link rel="alternate" type="text/html" href="http://sedimental.org/remap.html" />
    <published>2015-09-24T19:25:00Z</published>
    <updated>2015-09-24T19:25:00Z</updated>
    <category term="python"/><category term="data"/><category term="boltons"/>
    

    <content type="html">&lt;p&gt;&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;This entry is the first in a series of &quot;cookbooklets&quot; showcasing
more advanced &lt;a href=&quot;https://boltons.readthedocs.org&quot;&gt;Boltons&lt;/a&gt;. If all goes well, the next 5
minutes will literally save you 5 hours.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;div class=&quot;toc&quot;&gt;&lt;span class=&quot;toctitle&quot;&gt;Contents&lt;/span&gt;&lt;ul&gt;&lt;li&gt;&lt;a href=&quot;#intro&quot;&gt;Intro&lt;/a&gt;&lt;li&gt;&lt;a href=&quot;#normalize_keys_and_values&quot;&gt;Normalize keys and values&lt;/a&gt;&lt;li&gt;&lt;a href=&quot;#drop_empty_values&quot;&gt;Drop empty values&lt;/a&gt;&lt;li&gt;&lt;a href=&quot;#convert_dictionaries_to_ordereddicts&quot;&gt;Convert dictionaries to OrderedDicts&lt;/a&gt;&lt;li&gt;&lt;a href=&quot;#sort_all_lists&quot;&gt;Sort all lists&lt;/a&gt;&lt;li&gt;&lt;a href=&quot;#collect_interesting_values&quot;&gt;Collect interesting values&lt;/a&gt;&lt;li&gt;&lt;a href=&quot;#add_common_keys&quot;&gt;Add common keys&lt;/a&gt;&lt;li&gt;&lt;a href=&quot;#corner_cases&quot;&gt;Corner cases&lt;/a&gt;&lt;li&gt;&lt;a href=&quot;#wrap_up&quot;&gt;Wrap-up&lt;/a&gt;&lt;/ul&gt;&lt;/div&gt;&lt;h2 id=&quot;intro&quot;&gt;&lt;a href=&quot;#intro&quot; class=&quot;toclink&quot;&gt;Intro&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Data is everywhere, especially within itself. That&#x27;s right, whether
it&#x27;s public APIs, document stores, or plain old configuration files,
data &lt;em&gt;will&lt;/em&gt; nest. And that nested data will find you.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/Flat_design&quot;&gt;UI fads&lt;/a&gt; aside, developers have always liked
&quot;flat&quot;. Even Python, so often turned to for data wrangling, only has
succinct built-in constructs for dealing with flat
data. &lt;a href=&quot;https://docs.python.org/2/tutorial/datastructures.html#list-comprehensions&quot;&gt;List comprehensions&lt;/a&gt;,
&lt;a href=&quot;https://docs.python.org/2/reference/expressions.html#generator-expressions&quot;&gt;generator expressions&lt;/a&gt;, &lt;a href=&quot;https://docs.python.org/2/library/functions.html#map&quot;&gt;map&lt;/a&gt;/&lt;a href=&quot;https://docs.python.org/2/library/functions.html#filter&quot;&gt;filter&lt;/a&gt;, and
&lt;a href=&quot;https://docs.python.org/2/library/itertools.html&quot;&gt;itertools&lt;/a&gt; are all built for flat work. In fact, the
allure of flat data is likely a direct result of this common gap in
most programming languages.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://commons.wikimedia.org/wiki/File:Russian-Matroshka2.jpg&quot;&gt;
&lt;img width=&quot;45%&quot; src=&quot;http://sedimental.org/uploads/Russian-Matroshka2.jpg&quot; /&gt;
&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Let&#x27;s change that.&lt;/strong&gt; First, let&#x27;s meet this nested
adversary. Provided you overlook my taste in media, it&#x27;s hard to fault
nested data when it reads as well as this &lt;a href=&quot;https://en.wikipedia.org/wiki/YAML&quot;&gt;YAML&lt;/a&gt;:&lt;/p&gt;
&lt;div class=&quot;codehilite&quot; style=&quot;background: #f8f8f8&quot;&gt;&lt;pre style=&quot;line-height: 125%;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;span style=&quot;color: #008000; font-weight: bold&quot;&gt;reviews&lt;/span&gt;:
&lt;span style=&quot;color: #bbbbbb&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;color: #008000; font-weight: bold&quot;&gt;shows&lt;/span&gt;:
&lt;span style=&quot;color: #bbbbbb&quot;&gt;    &lt;/span&gt;-&lt;span style=&quot;color: #bbbbbb&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #008000; font-weight: bold&quot;&gt;title&lt;/span&gt;:&lt;span style=&quot;color: #bbbbbb&quot;&gt; &lt;/span&gt;Star Trek - The Next Generation
&lt;span style=&quot;color: #bbbbbb&quot;&gt;      &lt;/span&gt;&lt;span style=&quot;color: #008000; font-weight: bold&quot;&gt;rating&lt;/span&gt;:&lt;span style=&quot;color: #bbbbbb&quot;&gt; &lt;/span&gt;10
&lt;span style=&quot;color: #bbbbbb&quot;&gt;      &lt;/span&gt;&lt;span style=&quot;color: #008000; font-weight: bold&quot;&gt;review&lt;/span&gt;:&lt;span style=&quot;color: #bbbbbb&quot;&gt; &lt;/span&gt;Episodic AND deep. &amp;lt;3 Data.
&lt;span style=&quot;color: #bbbbbb&quot;&gt;      &lt;/span&gt;&lt;span style=&quot;color: #008000; font-weight: bold&quot;&gt;tags&lt;/span&gt;:&lt;span style=&quot;color: #bbbbbb&quot;&gt; &lt;/span&gt;[&lt;span style=&quot;color: #BB4444&quot;&gt;&#x27;space&#x27;&lt;/span&gt;]
&lt;span style=&quot;color: #bbbbbb&quot;&gt;    &lt;/span&gt;-&lt;span style=&quot;color: #bbbbbb&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #008000; font-weight: bold&quot;&gt;title&lt;/span&gt;:&lt;span style=&quot;color: #bbbbbb&quot;&gt; &lt;/span&gt;Monty Python&#x27;s Flying Circus
&lt;span style=&quot;color: #bbbbbb&quot;&gt;      &lt;/span&gt;&lt;span style=&quot;color: #008000; font-weight: bold&quot;&gt;rating&lt;/span&gt;:&lt;span style=&quot;color: #bbbbbb&quot;&gt; &lt;/span&gt;10
&lt;span style=&quot;color: #bbbbbb&quot;&gt;      &lt;/span&gt;&lt;span style=&quot;color: #008000; font-weight: bold&quot;&gt;tags&lt;/span&gt;:&lt;span style=&quot;color: #bbbbbb&quot;&gt; &lt;/span&gt;[&lt;span style=&quot;color: #BB4444&quot;&gt;&#x27;comedy&#x27;&lt;/span&gt;]
&lt;span style=&quot;color: #bbbbbb&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;color: #008000; font-weight: bold&quot;&gt;movies&lt;/span&gt;:
&lt;span style=&quot;color: #bbbbbb&quot;&gt;    &lt;/span&gt;-&lt;span style=&quot;color: #bbbbbb&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #008000; font-weight: bold&quot;&gt;title&lt;/span&gt;:&lt;span style=&quot;color: #bbbbbb&quot;&gt; &lt;/span&gt;The Hitchiker&#x27;s Guide to the Galaxy
&lt;span style=&quot;color: #bbbbbb&quot;&gt;      &lt;/span&gt;&lt;span style=&quot;color: #008000; font-weight: bold&quot;&gt;rating&lt;/span&gt;:&lt;span style=&quot;color: #bbbbbb&quot;&gt; &lt;/span&gt;6
&lt;span style=&quot;color: #bbbbbb&quot;&gt;      &lt;/span&gt;&lt;span style=&quot;color: #008000; font-weight: bold&quot;&gt;review&lt;/span&gt;:&lt;span style=&quot;color: #bbbbbb&quot;&gt; &lt;/span&gt;So great to see Mos Def getting good work.
&lt;span style=&quot;color: #bbbbbb&quot;&gt;      &lt;/span&gt;&lt;span style=&quot;color: #008000; font-weight: bold&quot;&gt;tags&lt;/span&gt;:&lt;span style=&quot;color: #bbbbbb&quot;&gt; &lt;/span&gt;[&lt;span style=&quot;color: #BB4444&quot;&gt;&#x27;comedy&#x27;&lt;/span&gt;,&lt;span style=&quot;color: #bbbbbb&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #BB4444&quot;&gt;&#x27;space&#x27;&lt;/span&gt;,&lt;span style=&quot;color: #bbbbbb&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #BB4444&quot;&gt;&#x27;life&#x27;&lt;/span&gt;]
&lt;span style=&quot;color: #bbbbbb&quot;&gt;    &lt;/span&gt;-&lt;span style=&quot;color: #bbbbbb&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #008000; font-weight: bold&quot;&gt;title&lt;/span&gt;:&lt;span style=&quot;color: #bbbbbb&quot;&gt; &lt;/span&gt;Monty Python&#x27;s Meaning of Life
&lt;span style=&quot;color: #bbbbbb&quot;&gt;      &lt;/span&gt;&lt;span style=&quot;color: #008000; font-weight: bold&quot;&gt;rating&lt;/span&gt;:&lt;span style=&quot;color: #bbbbbb&quot;&gt; &lt;/span&gt;7
&lt;span style=&quot;color: #bbbbbb&quot;&gt;      &lt;/span&gt;&lt;span style=&quot;color: #008000; font-weight: bold&quot;&gt;review&lt;/span&gt;:&lt;span style=&quot;color: #bbbbbb&quot;&gt; &lt;/span&gt;Better than Brian, but not a Holy Grail, nor Completely Different.
&lt;span style=&quot;color: #bbbbbb&quot;&gt;      &lt;/span&gt;&lt;span style=&quot;color: #008000; font-weight: bold&quot;&gt;tags&lt;/span&gt;:&lt;span style=&quot;color: #bbbbbb&quot;&gt; &lt;/span&gt;[&lt;span style=&quot;color: #BB4444&quot;&gt;&#x27;comedy&#x27;&lt;/span&gt;,&lt;span style=&quot;color: #bbbbbb&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #BB4444&quot;&gt;&#x27;life&#x27;&lt;/span&gt;]
&lt;span style=&quot;color: #bbbbbb&quot;&gt;      &lt;/span&gt;&lt;span style=&quot;color: #008000; font-weight: bold&quot;&gt;prologue&lt;/span&gt;:
&lt;span style=&quot;color: #bbbbbb&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;color: #008000; font-weight: bold&quot;&gt;title&lt;/span&gt;:&lt;span style=&quot;color: #bbbbbb&quot;&gt; &lt;/span&gt;The Crimson Permanent Assurance
&lt;span style=&quot;color: #bbbbbb&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;color: #008000; font-weight: bold&quot;&gt;rating&lt;/span&gt;:&lt;span style=&quot;color: #bbbbbb&quot;&gt; &lt;/span&gt;9
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Even this very straightforwardly nested data can be a real hassle to
manipulate. How would one add a default review for entries without
one? How would one convert the ratings to a 5-star scale? And what
does all of this mean for more complex real-world cases, exemplified
by this excerpt from &lt;a href=&quot;https://api.github.com/users/mahmoud/events&quot;&gt;a real GitHub API&lt;/a&gt; response:&lt;/p&gt;
&lt;p&gt;&lt;a id=&quot;github_event_data&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;div class=&quot;codehilite&quot; style=&quot;background: #f8f8f8&quot;&gt;&lt;pre style=&quot;line-height: 125%;&quot;&gt;&lt;span&gt;&lt;/span&gt;[{
&lt;span style=&quot;color: #bbbbbb&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;color: #008000; font-weight: bold&quot;&gt;&quot;id&quot;&lt;/span&gt;:&lt;span style=&quot;color: #bbbbbb&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #BB4444&quot;&gt;&quot;3165090957&quot;&lt;/span&gt;,
&lt;span style=&quot;color: #bbbbbb&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;color: #008000; font-weight: bold&quot;&gt;&quot;type&quot;&lt;/span&gt;:&lt;span style=&quot;color: #bbbbbb&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #BB4444&quot;&gt;&quot;PushEvent&quot;&lt;/span&gt;,
&lt;span style=&quot;color: #bbbbbb&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;color: #008000; font-weight: bold&quot;&gt;&quot;actor&quot;&lt;/span&gt;:&lt;span style=&quot;color: #bbbbbb&quot;&gt; &lt;/span&gt;{
&lt;span style=&quot;color: #bbbbbb&quot;&gt;      &lt;/span&gt;&lt;span style=&quot;color: #008000; font-weight: bold&quot;&gt;&quot;id&quot;&lt;/span&gt;:&lt;span style=&quot;color: #bbbbbb&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #666666&quot;&gt;130193&lt;/span&gt;,
&lt;span style=&quot;color: #bbbbbb&quot;&gt;      &lt;/span&gt;&lt;span style=&quot;color: #008000; font-weight: bold&quot;&gt;&quot;login&quot;&lt;/span&gt;:&lt;span style=&quot;color: #bbbbbb&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #BB4444&quot;&gt;&quot;mahmoud&quot;&lt;/span&gt;,
&lt;span style=&quot;color: #bbbbbb&quot;&gt;      &lt;/span&gt;&lt;span style=&quot;color: #008000; font-weight: bold&quot;&gt;&quot;gravatar_id&quot;&lt;/span&gt;:&lt;span style=&quot;color: #bbbbbb&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #BB4444&quot;&gt;&quot;&quot;&lt;/span&gt;,
&lt;span style=&quot;color: #bbbbbb&quot;&gt;      &lt;/span&gt;&lt;span style=&quot;color: #008000; font-weight: bold&quot;&gt;&quot;url&quot;&lt;/span&gt;:&lt;span style=&quot;color: #bbbbbb&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #BB4444&quot;&gt;&quot;https://api.github.com/users/mahmoud&quot;&lt;/span&gt;,
&lt;span style=&quot;color: #bbbbbb&quot;&gt;      &lt;/span&gt;&lt;span style=&quot;color: #008000; font-weight: bold&quot;&gt;&quot;avatar_url&quot;&lt;/span&gt;:&lt;span style=&quot;color: #bbbbbb&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #BB4444&quot;&gt;&quot;https://avatars.githubusercontent.com/u/130193?&quot;&lt;/span&gt;
&lt;span style=&quot;color: #bbbbbb&quot;&gt;    &lt;/span&gt;},
&lt;span style=&quot;color: #bbbbbb&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;color: #008000; font-weight: bold&quot;&gt;&quot;repo&quot;&lt;/span&gt;:&lt;span style=&quot;color: #bbbbbb&quot;&gt; &lt;/span&gt;{
&lt;span style=&quot;color: #bbbbbb&quot;&gt;      &lt;/span&gt;&lt;span style=&quot;color: #008000; font-weight: bold&quot;&gt;&quot;id&quot;&lt;/span&gt;:&lt;span style=&quot;color: #bbbbbb&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #666666&quot;&gt;8307391&lt;/span&gt;,
&lt;span style=&quot;color: #bbbbbb&quot;&gt;      &lt;/span&gt;&lt;span style=&quot;color: #008000; font-weight: bold&quot;&gt;&quot;name&quot;&lt;/span&gt;:&lt;span style=&quot;color: #bbbbbb&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #BB4444&quot;&gt;&quot;mahmoud/boltons&quot;&lt;/span&gt;,
&lt;span style=&quot;color: #bbbbbb&quot;&gt;      &lt;/span&gt;&lt;span style=&quot;color: #008000; font-weight: bold&quot;&gt;&quot;url&quot;&lt;/span&gt;:&lt;span style=&quot;color: #bbbbbb&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #BB4444&quot;&gt;&quot;https://api.github.com/repos/mahmoud/boltons&quot;&lt;/span&gt;
&lt;span style=&quot;color: #bbbbbb&quot;&gt;    &lt;/span&gt;},
&lt;span style=&quot;color: #bbbbbb&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;color: #008000; font-weight: bold&quot;&gt;&quot;payload&quot;&lt;/span&gt;:&lt;span style=&quot;color: #bbbbbb&quot;&gt; &lt;/span&gt;{
&lt;span style=&quot;color: #bbbbbb&quot;&gt;      &lt;/span&gt;&lt;span style=&quot;color: #008000; font-weight: bold&quot;&gt;&quot;push_id&quot;&lt;/span&gt;:&lt;span style=&quot;color: #bbbbbb&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #666666&quot;&gt;799258895&lt;/span&gt;,
&lt;span style=&quot;color: #bbbbbb&quot;&gt;      &lt;/span&gt;&lt;span style=&quot;color: #008000; font-weight: bold&quot;&gt;&quot;size&quot;&lt;/span&gt;:&lt;span style=&quot;color: #bbbbbb&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #666666&quot;&gt;1&lt;/span&gt;,
&lt;span style=&quot;color: #bbbbbb&quot;&gt;      &lt;/span&gt;&lt;span style=&quot;color: #008000; font-weight: bold&quot;&gt;&quot;distinct_size&quot;&lt;/span&gt;:&lt;span style=&quot;color: #bbbbbb&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #666666&quot;&gt;1&lt;/span&gt;,
&lt;span style=&quot;color: #bbbbbb&quot;&gt;      &lt;/span&gt;&lt;span style=&quot;color: #008000; font-weight: bold&quot;&gt;&quot;ref&quot;&lt;/span&gt;:&lt;span style=&quot;color: #bbbbbb&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #BB4444&quot;&gt;&quot;refs/heads/master&quot;&lt;/span&gt;,
&lt;span style=&quot;color: #bbbbbb&quot;&gt;      &lt;/span&gt;&lt;span style=&quot;color: #008000; font-weight: bold&quot;&gt;&quot;head&quot;&lt;/span&gt;:&lt;span style=&quot;color: #bbbbbb&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #BB4444&quot;&gt;&quot;27a4bc1b6d1da25a38fe8e2c5fb27f22308e3260&quot;&lt;/span&gt;,
&lt;span style=&quot;color: #bbbbbb&quot;&gt;      &lt;/span&gt;&lt;span style=&quot;color: #008000; font-weight: bold&quot;&gt;&quot;before&quot;&lt;/span&gt;:&lt;span style=&quot;color: #bbbbbb&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #BB4444&quot;&gt;&quot;0d6486c40282772bab232bf393c5e6fad9533a0e&quot;&lt;/span&gt;,
&lt;span style=&quot;color: #bbbbbb&quot;&gt;      &lt;/span&gt;&lt;span style=&quot;color: #008000; font-weight: bold&quot;&gt;&quot;commits&quot;&lt;/span&gt;:&lt;span style=&quot;color: #bbbbbb&quot;&gt; &lt;/span&gt;[
&lt;span style=&quot;color: #bbbbbb&quot;&gt;        &lt;/span&gt;{
&lt;span style=&quot;color: #bbbbbb&quot;&gt;          &lt;/span&gt;&lt;span style=&quot;color: #008000; font-weight: bold&quot;&gt;&quot;sha&quot;&lt;/span&gt;:&lt;span style=&quot;color: #bbbbbb&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #BB4444&quot;&gt;&quot;27a4bc1b6d1da25a38fe8e2c5fb27f22308e3260&quot;&lt;/span&gt;,
&lt;span style=&quot;color: #bbbbbb&quot;&gt;          &lt;/span&gt;&lt;span style=&quot;color: #008000; font-weight: bold&quot;&gt;&quot;author&quot;&lt;/span&gt;:&lt;span style=&quot;color: #bbbbbb&quot;&gt; &lt;/span&gt;{
&lt;span style=&quot;color: #bbbbbb&quot;&gt;            &lt;/span&gt;&lt;span style=&quot;color: #008000; font-weight: bold&quot;&gt;&quot;email&quot;&lt;/span&gt;:&lt;span style=&quot;color: #bbbbbb&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #BB4444&quot;&gt;&quot;mahmoud@hatnote.com&quot;&lt;/span&gt;,
&lt;span style=&quot;color: #bbbbbb&quot;&gt;            &lt;/span&gt;&lt;span style=&quot;color: #008000; font-weight: bold&quot;&gt;&quot;name&quot;&lt;/span&gt;:&lt;span style=&quot;color: #bbbbbb&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #BB4444&quot;&gt;&quot;Mahmoud Hashemi&quot;&lt;/span&gt;
&lt;span style=&quot;color: #bbbbbb&quot;&gt;          &lt;/span&gt;},
&lt;span style=&quot;color: #bbbbbb&quot;&gt;          &lt;/span&gt;&lt;span style=&quot;color: #008000; font-weight: bold&quot;&gt;&quot;message&quot;&lt;/span&gt;:&lt;span style=&quot;color: #bbbbbb&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #BB4444&quot;&gt;&quot;switched reraise_visit to be just a kwarg&quot;&lt;/span&gt;,
&lt;span style=&quot;color: #bbbbbb&quot;&gt;          &lt;/span&gt;&lt;span style=&quot;color: #008000; font-weight: bold&quot;&gt;&quot;distinct&quot;&lt;/span&gt;:&lt;span style=&quot;color: #bbbbbb&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #AA22FF; font-weight: bold&quot;&gt;true&lt;/span&gt;,
&lt;span style=&quot;color: #bbbbbb&quot;&gt;          &lt;/span&gt;&lt;span style=&quot;color: #008000; font-weight: bold&quot;&gt;&quot;url&quot;&lt;/span&gt;:&lt;span style=&quot;color: #bbbbbb&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #BB4444&quot;&gt;&quot;https://api.github.com/repos/mahmoud/boltons/commits/27a4bc1b6d1da25a38fe8e2c5fb27f22308e3260&quot;&lt;/span&gt;
&lt;span style=&quot;color: #bbbbbb&quot;&gt;        &lt;/span&gt;}
&lt;span style=&quot;color: #bbbbbb&quot;&gt;      &lt;/span&gt;]
&lt;span style=&quot;color: #bbbbbb&quot;&gt;    &lt;/span&gt;},
&lt;span style=&quot;color: #bbbbbb&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;color: #008000; font-weight: bold&quot;&gt;&quot;public&quot;&lt;/span&gt;:&lt;span style=&quot;color: #bbbbbb&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #AA22FF; font-weight: bold&quot;&gt;true&lt;/span&gt;,
&lt;span style=&quot;color: #bbbbbb&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;color: #008000; font-weight: bold&quot;&gt;&quot;created_at&quot;&lt;/span&gt;:&lt;span style=&quot;color: #bbbbbb&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #BB4444&quot;&gt;&quot;2015-09-21T10:04:37Z&quot;&lt;/span&gt;
}]
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;The astute reader may spot some inconsistency and general complexity,
but don&#x27;t run away.&lt;/p&gt;
&lt;p&gt;&lt;big&gt;&lt;strong&gt;Remap&lt;/strong&gt;, the &lt;a href=&quot;https://en.wikipedia.org/wiki/Recursion_(computer_science)&quot;&gt;recursive&lt;/a&gt; &lt;a href=&quot;https://docs.python.org/2/library/functions.html#map&quot;&gt;map&lt;/a&gt;, is here to save the day.&lt;/big&gt;&lt;/p&gt;
&lt;p&gt;Remap is a Pythonic traversal utility that creates a transformed copy
of your nested data. It uses three callbacks -- &lt;code&gt;visit&lt;/code&gt;, &lt;code&gt;enter&lt;/code&gt;, and
&lt;code&gt;exit&lt;/code&gt; -- and is designed to accomplish the vast majority of tasks by
passing only one function, usually &lt;code&gt;visit&lt;/code&gt;. &lt;a href=&quot;http://boltons.readthedocs.org/en/latest/iterutils.html#boltons.iterutils.remap&quot;&gt;The API docs have full
descriptions&lt;/a&gt;, but the basic rundown is:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;visit&lt;/code&gt; transforms an individual item&lt;/li&gt;
&lt;li&gt;&lt;code&gt;enter&lt;/code&gt; controls how container objects are created and traversed&lt;/li&gt;
&lt;li&gt;&lt;code&gt;exit&lt;/code&gt; controls how new container objects are populated&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;It may sound complex, but the examples shed a lot of light. So let&#x27;s
get remapping!&lt;/p&gt;
&lt;h2 id=&quot;normalize_keys_and_values&quot;&gt;&lt;a href=&quot;#normalize_keys_and_values&quot; class=&quot;toclink&quot;&gt;Normalize keys and values&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;First, let&#x27;s import the modules and data we&#x27;ll need.&lt;/p&gt;
&lt;div class=&quot;codehilite&quot; style=&quot;background: #f8f8f8&quot;&gt;&lt;pre style=&quot;line-height: 125%;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;span style=&quot;color: #AA22FF; font-weight: bold&quot;&gt;import&lt;/span&gt; &lt;span style=&quot;color: #0000FF; font-weight: bold&quot;&gt;json&lt;/span&gt;
&lt;span style=&quot;color: #AA22FF; font-weight: bold&quot;&gt;import&lt;/span&gt; &lt;span style=&quot;color: #0000FF; font-weight: bold&quot;&gt;yaml&lt;/span&gt;  &lt;span style=&quot;color: #008800; font-style: italic&quot;&gt;# https://pypi.python.org/pypi/PyYAML&lt;/span&gt;
&lt;span style=&quot;color: #AA22FF; font-weight: bold&quot;&gt;from&lt;/span&gt; &lt;span style=&quot;color: #0000FF; font-weight: bold&quot;&gt;boltons.iterutils&lt;/span&gt; &lt;span style=&quot;color: #AA22FF; font-weight: bold&quot;&gt;import&lt;/span&gt; remap  &lt;span style=&quot;color: #008800; font-style: italic&quot;&gt;# https://pypi.python.org/pypi/boltons&lt;/span&gt;

review_map &lt;span style=&quot;color: #666666&quot;&gt;=&lt;/span&gt; yaml&lt;span style=&quot;color: #666666&quot;&gt;.&lt;/span&gt;load(media_reviews)

event_list &lt;span style=&quot;color: #666666&quot;&gt;=&lt;/span&gt; json&lt;span style=&quot;color: #666666&quot;&gt;.&lt;/span&gt;loads(github_events)
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Now let&#x27;s turn back to that GitHub API data. Earlier one may have been
annoyed by the inconsistent type of &lt;code&gt;id&lt;/code&gt;. &lt;code&gt;event[&#x27;repo&#x27;][&#x27;id&#x27;]&lt;/code&gt; is an
integer, but &lt;code&gt;event[&#x27;id&#x27;]&lt;/code&gt; is a string. When sorting events by ID, you
would not want &lt;a href=&quot;https://en.wikipedia.org/wiki/Lexicographical_order&quot;&gt;string ordering&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;With &lt;code&gt;remap&lt;/code&gt;, fixing this sort inconsistency couldn&#x27;t be easier:&lt;/p&gt;
&lt;div class=&quot;codehilite&quot; style=&quot;background: #f8f8f8&quot;&gt;&lt;pre style=&quot;line-height: 125%;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;span style=&quot;color: #AA22FF; font-weight: bold&quot;&gt;from&lt;/span&gt; &lt;span style=&quot;color: #0000FF; font-weight: bold&quot;&gt;boltons.iterutils&lt;/span&gt; &lt;span style=&quot;color: #AA22FF; font-weight: bold&quot;&gt;import&lt;/span&gt; remap

&lt;span style=&quot;color: #AA22FF; font-weight: bold&quot;&gt;def&lt;/span&gt; &lt;span style=&quot;color: #00A000&quot;&gt;visit&lt;/span&gt;(path, key, value):
    &lt;span style=&quot;color: #AA22FF; font-weight: bold&quot;&gt;if&lt;/span&gt; key &lt;span style=&quot;color: #666666&quot;&gt;==&lt;/span&gt; &lt;span style=&quot;color: #BB4444&quot;&gt;&#x27;id&#x27;&lt;/span&gt;:
        &lt;span style=&quot;color: #AA22FF; font-weight: bold&quot;&gt;return&lt;/span&gt; key, &lt;span style=&quot;color: #AA22FF&quot;&gt;int&lt;/span&gt;(value)
    &lt;span style=&quot;color: #AA22FF; font-weight: bold&quot;&gt;return&lt;/span&gt; key, value

remapped &lt;span style=&quot;color: #666666&quot;&gt;=&lt;/span&gt; remap(event_list, visit&lt;span style=&quot;color: #666666&quot;&gt;=&lt;/span&gt;visit)

&lt;span style=&quot;color: #AA22FF; font-weight: bold&quot;&gt;assert&lt;/span&gt; remapped[&lt;span style=&quot;color: #666666&quot;&gt;0&lt;/span&gt;][&lt;span style=&quot;color: #BB4444&quot;&gt;&#x27;id&#x27;&lt;/span&gt;] &lt;span style=&quot;color: #666666&quot;&gt;==&lt;/span&gt; &lt;span style=&quot;color: #666666&quot;&gt;3165090957&lt;/span&gt;

&lt;span style=&quot;color: #008800; font-style: italic&quot;&gt;# You can even do it in one line:&lt;/span&gt;
remap(event_list, &lt;span style=&quot;color: #AA22FF; font-weight: bold&quot;&gt;lambda&lt;/span&gt; p, k, v: (k, &lt;span style=&quot;color: #AA22FF&quot;&gt;int&lt;/span&gt;(v)) &lt;span style=&quot;color: #AA22FF; font-weight: bold&quot;&gt;if&lt;/span&gt; k &lt;span style=&quot;color: #666666&quot;&gt;==&lt;/span&gt; &lt;span style=&quot;color: #BB4444&quot;&gt;&#x27;id&#x27;&lt;/span&gt; &lt;span style=&quot;color: #AA22FF; font-weight: bold&quot;&gt;else&lt;/span&gt; (k, v))
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;By default, &lt;code&gt;visit&lt;/code&gt; gets called on every item in the root structure,
including &lt;a href=&quot;https://docs.python.org/2/tutorial/datastructures.html#more-on-lists&quot;&gt;lists&lt;/a&gt;, &lt;a href=&quot;https://docs.python.org/2/tutorial/datastructures.html#dictionaries&quot;&gt;dicts&lt;/a&gt;, and other containers, so let&#x27;s take a closer
look at its signature. &lt;code&gt;visit&lt;/code&gt; takes three arguments we&#x27;re going to
see in all of remap&#x27;s callbacks:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;path&lt;/code&gt; is a &lt;a href=&quot;https://docs.python.org/2/tutorial/datastructures.html#tuples-and-sequences&quot;&gt;tuple&lt;/a&gt; of keys leading up to the current item&lt;/li&gt;
&lt;li&gt;&lt;code&gt;key&lt;/code&gt; is the current item&#x27;s key&lt;/li&gt;
&lt;li&gt;&lt;code&gt;value&lt;/code&gt; is the current item&#x27;s value&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;code&gt;key&lt;/code&gt; and &lt;code&gt;value&lt;/code&gt; are exactly what you would expect, though it may
bear mentioning that the &lt;code&gt;key&lt;/code&gt; for a list item is its index. &lt;code&gt;path&lt;/code&gt;
refers to the keys of all the parents of the current item, not
including the &lt;code&gt;key&lt;/code&gt;. For example, looking at
&lt;a href=&quot;http://sedimental.org/remap.html#github_event_data&quot;&gt;the GitHub event data&lt;/a&gt;, the commit author&#x27;s
name&#x27;s path is &lt;code&gt;(0, &#x27;payload&#x27;, &#x27;commits&#x27;, 0, &#x27;author&#x27;)&lt;/code&gt;, because the
key, &lt;code&gt;name&lt;/code&gt;, is located in the author of the first commit in the
payload of the first event.&lt;/p&gt;
&lt;p&gt;As for the return signature of &lt;code&gt;visit&lt;/code&gt;, it&#x27;s very similar to the
input. Just return the new &lt;code&gt;(key, value)&lt;/code&gt; you want in the remapped
output.&lt;/p&gt;
&lt;h2 id=&quot;drop_empty_values&quot;&gt;&lt;a href=&quot;#drop_empty_values&quot; class=&quot;toclink&quot;&gt;Drop empty values&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Next up, GitHub&#x27;s move away from &lt;a href=&quot;https://en.wikipedia.org/wiki/Gravatar&quot;&gt;Gravatars&lt;/a&gt; left an
artifact in their API: a blank &lt;code&gt;&#x27;gravatar_id&#x27;&lt;/code&gt; key. We can get rid of
that item, and any other blank strings, in a jiffy:&lt;/p&gt;
&lt;div class=&quot;codehilite&quot; style=&quot;background: #f8f8f8&quot;&gt;&lt;pre style=&quot;line-height: 125%;&quot;&gt;&lt;span&gt;&lt;/span&gt;drop_blank &lt;span style=&quot;color: #666666&quot;&gt;=&lt;/span&gt; &lt;span style=&quot;color: #AA22FF; font-weight: bold&quot;&gt;lambda&lt;/span&gt; p, k, v: v &lt;span style=&quot;color: #666666&quot;&gt;!=&lt;/span&gt; &lt;span style=&quot;color: #BB4444&quot;&gt;&quot;&quot;&lt;/span&gt;
remapped &lt;span style=&quot;color: #666666&quot;&gt;=&lt;/span&gt; remap(event_list, visit&lt;span style=&quot;color: #666666&quot;&gt;=&lt;/span&gt;drop_blank)

&lt;span style=&quot;color: #AA22FF; font-weight: bold&quot;&gt;assert&lt;/span&gt; &lt;span style=&quot;color: #BB4444&quot;&gt;&#x27;gravatar_id&#x27;&lt;/span&gt; &lt;span style=&quot;color: #AA22FF; font-weight: bold&quot;&gt;not&lt;/span&gt; &lt;span style=&quot;color: #AA22FF; font-weight: bold&quot;&gt;in&lt;/span&gt; remapped[&lt;span style=&quot;color: #666666&quot;&gt;0&lt;/span&gt;][&lt;span style=&quot;color: #BB4444&quot;&gt;&#x27;actor&#x27;&lt;/span&gt;]
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Unlike the previous example, instead of a &lt;code&gt;(key, value)&lt;/code&gt; pair, this
&lt;code&gt;visit&lt;/code&gt; is returning a &lt;code&gt;bool&lt;/code&gt;. For added convenience, when &lt;code&gt;visit&lt;/code&gt;
returns &lt;code&gt;True&lt;/code&gt;, &lt;code&gt;remap&lt;/code&gt; carries over the original item
unmodified. Returning &lt;code&gt;False&lt;/code&gt; drops the item from the remapped structure.&lt;/p&gt;
&lt;p&gt;With the ability to arbitrarily transform items, pass through old
items, and drop items from the remapped structure, it&#x27;s clear that the
&lt;code&gt;visit&lt;/code&gt; function makes the majority of recursive transformations
trivial. So many tedious and error-prone lines of traversal code turn
into one-liners that usually &lt;code&gt;remap&lt;/code&gt; with a &lt;code&gt;visit&lt;/code&gt; callback is all
one needs. With that said, the next recipes focus on &lt;code&gt;remap&lt;/code&gt;&#x27;s more
advanced callable arguments, &lt;code&gt;enter&lt;/code&gt; and &lt;code&gt;exit&lt;/code&gt;.&lt;/p&gt;
&lt;h2 id=&quot;convert_dictionaries_to_ordereddicts&quot;&gt;&lt;a href=&quot;#convert_dictionaries_to_ordereddicts&quot; class=&quot;toclink&quot;&gt;Convert dictionaries to OrderedDicts&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;So far we&#x27;ve looked at actions on remapping individual items, using
the &lt;code&gt;visit&lt;/code&gt; callable. Now we turn our attention to actions on
containers, the parent objects of individual items. We&#x27;ll start doing
this by looking at the &lt;code&gt;enter&lt;/code&gt; argument to &lt;code&gt;remap&lt;/code&gt;.&lt;/p&gt;
&lt;div class=&quot;codehilite&quot; style=&quot;background: #f8f8f8&quot;&gt;&lt;pre style=&quot;line-height: 125%;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;span style=&quot;color: #008800; font-style: italic&quot;&gt;# from collections import OrderedDict&lt;/span&gt;
&lt;span style=&quot;color: #AA22FF; font-weight: bold&quot;&gt;from&lt;/span&gt; &lt;span style=&quot;color: #0000FF; font-weight: bold&quot;&gt;boltons.dictutils&lt;/span&gt; &lt;span style=&quot;color: #AA22FF; font-weight: bold&quot;&gt;import&lt;/span&gt; OrderedMultiDict &lt;span style=&quot;color: #AA22FF; font-weight: bold&quot;&gt;as&lt;/span&gt; OMD
&lt;span style=&quot;color: #AA22FF; font-weight: bold&quot;&gt;from&lt;/span&gt; &lt;span style=&quot;color: #0000FF; font-weight: bold&quot;&gt;boltons.iterutils&lt;/span&gt; &lt;span style=&quot;color: #AA22FF; font-weight: bold&quot;&gt;import&lt;/span&gt; remap, default_enter

&lt;span style=&quot;color: #AA22FF; font-weight: bold&quot;&gt;def&lt;/span&gt; &lt;span style=&quot;color: #00A000&quot;&gt;enter&lt;/span&gt;(path, key, value):
    &lt;span style=&quot;color: #AA22FF; font-weight: bold&quot;&gt;if&lt;/span&gt; &lt;span style=&quot;color: #AA22FF&quot;&gt;isinstance&lt;/span&gt;(value, &lt;span style=&quot;color: #AA22FF&quot;&gt;dict&lt;/span&gt;):
        &lt;span style=&quot;color: #AA22FF; font-weight: bold&quot;&gt;return&lt;/span&gt; OMD(), &lt;span style=&quot;color: #AA22FF&quot;&gt;sorted&lt;/span&gt;(value&lt;span style=&quot;color: #666666&quot;&gt;.&lt;/span&gt;items())
    &lt;span style=&quot;color: #AA22FF; font-weight: bold&quot;&gt;return&lt;/span&gt; default_enter(path, key, value)

remapped &lt;span style=&quot;color: #666666&quot;&gt;=&lt;/span&gt; remap(review_list, enter&lt;span style=&quot;color: #666666&quot;&gt;=&lt;/span&gt;enter)
&lt;span style=&quot;color: #AA22FF; font-weight: bold&quot;&gt;assert&lt;/span&gt; remapped[&lt;span style=&quot;color: #BB4444&quot;&gt;&#x27;reviews&#x27;&lt;/span&gt;]&lt;span style=&quot;color: #666666&quot;&gt;.&lt;/span&gt;keys()[&lt;span style=&quot;color: #666666&quot;&gt;0&lt;/span&gt;] &lt;span style=&quot;color: #666666&quot;&gt;==&lt;/span&gt; &lt;span style=&quot;color: #BB4444&quot;&gt;&#x27;movies&#x27;&lt;/span&gt;
&lt;span style=&quot;color: #008800; font-style: italic&quot;&gt;# True because &#x27;reviews&#x27; is now ordered and &#x27;movies&#x27; comes before &#x27;shows&#x27;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;The &lt;code&gt;enter&lt;/code&gt; callable controls both if and how an object is
traversed. Like &lt;code&gt;visit&lt;/code&gt;, it accepts &lt;code&gt;path&lt;/code&gt;, &lt;code&gt;key&lt;/code&gt;, and &lt;code&gt;value&lt;/code&gt;. But
instead of &lt;code&gt;(key, value)&lt;/code&gt;, it returns a tuple of &lt;code&gt;(new_parent,
items)&lt;/code&gt;. &lt;code&gt;new_parent&lt;/code&gt; is the container that will receive items
remapped by the &lt;code&gt;visit&lt;/code&gt; callable. &lt;code&gt;items&lt;/code&gt; is an iterable of &lt;code&gt;(key,
value)&lt;/code&gt; pairs that will be passed to &lt;code&gt;visit&lt;/code&gt;. Alternatively, &lt;code&gt;items&lt;/code&gt;
can be &lt;code&gt;False&lt;/code&gt;, to tell remap that the current value should not be
traversed, but that&#x27;s getting pretty advanced. The API docs have some
other &lt;code&gt;enter&lt;/code&gt; details to consider.&lt;/p&gt;
&lt;p&gt;Also note how this code builds on the default remap logic by calling
through to the &lt;code&gt;default_enter&lt;/code&gt; function, imported from the same place
as &lt;code&gt;remap&lt;/code&gt; itself. Most practical use cases will want to do this, but
of course the choice is yours.&lt;/p&gt;
&lt;h2 id=&quot;sort_all_lists&quot;&gt;&lt;a href=&quot;#sort_all_lists&quot; class=&quot;toclink&quot;&gt;Sort all lists&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The last example used &lt;code&gt;enter&lt;/code&gt; to interact with containers before they
were being traversed. This time, to sort all lists in a structure,
we&#x27;ll use the &lt;code&gt;remap&lt;/code&gt;&#x27;s final callable argument: &lt;code&gt;exit&lt;/code&gt;.&lt;/p&gt;
&lt;div class=&quot;codehilite&quot; style=&quot;background: #f8f8f8&quot;&gt;&lt;pre style=&quot;line-height: 125%;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;span style=&quot;color: #AA22FF; font-weight: bold&quot;&gt;from&lt;/span&gt; &lt;span style=&quot;color: #0000FF; font-weight: bold&quot;&gt;boltons.iterutils&lt;/span&gt; &lt;span style=&quot;color: #AA22FF; font-weight: bold&quot;&gt;import&lt;/span&gt; remap, default_exit

&lt;span style=&quot;color: #AA22FF; font-weight: bold&quot;&gt;def&lt;/span&gt; &lt;span style=&quot;color: #00A000&quot;&gt;exit&lt;/span&gt;(path, key, old_parent, new_parent, new_items):
    ret &lt;span style=&quot;color: #666666&quot;&gt;=&lt;/span&gt; default_exit(path, key, old_parent, new_parent, new_items)
    &lt;span style=&quot;color: #AA22FF; font-weight: bold&quot;&gt;if&lt;/span&gt; &lt;span style=&quot;color: #AA22FF&quot;&gt;isinstance&lt;/span&gt;(ret, &lt;span style=&quot;color: #AA22FF&quot;&gt;list&lt;/span&gt;):
        ret&lt;span style=&quot;color: #666666&quot;&gt;.&lt;/span&gt;sort()
    &lt;span style=&quot;color: #AA22FF; font-weight: bold&quot;&gt;return&lt;/span&gt; ret

remap(review_list, exit&lt;span style=&quot;color: #666666&quot;&gt;=&lt;/span&gt;exit)
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Similar to the &lt;code&gt;enter&lt;/code&gt; example, we&#x27;re building on &lt;code&gt;remap&lt;/code&gt;&#x27;s default
behavior by importing and calling &lt;code&gt;default_exit&lt;/code&gt;. Looking at the
arguments passed to &lt;code&gt;exit&lt;/code&gt; and &lt;code&gt;default_exit&lt;/code&gt;, there&#x27;s the &lt;code&gt;path&lt;/code&gt; and
&lt;code&gt;key&lt;/code&gt; that we&#x27;re used to from &lt;code&gt;visit&lt;/code&gt; and &lt;code&gt;enter&lt;/code&gt;. &lt;code&gt;value&lt;/code&gt; is there,
too, but it&#x27;s named &lt;code&gt;old_parent&lt;/code&gt;, to differentiate it from the new
value, appropriately called &lt;code&gt;new_parent&lt;/code&gt;. At the point &lt;code&gt;exit&lt;/code&gt; is
called, &lt;code&gt;new_parent&lt;/code&gt; is just an empty structure as constructed by
&lt;code&gt;enter&lt;/code&gt;, and &lt;code&gt;exit&lt;/code&gt;&#x27;s job is to fill that new container with
&lt;code&gt;new_items&lt;/code&gt;, a list of &lt;code&gt;(key, value)&lt;/code&gt; pairs returned by &lt;code&gt;remap&lt;/code&gt;&#x27;s
calls to &lt;code&gt;visit&lt;/code&gt;. Still with me?&lt;/p&gt;
&lt;p&gt;Either way, here we don&#x27;t interact with the arguments. We just call
&lt;code&gt;default_exit&lt;/code&gt; and work on its return value, &lt;code&gt;new_parent&lt;/code&gt;, sorting it
in-place if it&#x27;s a &lt;code&gt;list&lt;/code&gt;. Pretty simple! In fact, &lt;em&gt;very&lt;/em&gt; attentive
readers might point out this can be done with &lt;code&gt;visit&lt;/code&gt;, because
&lt;code&gt;remap&lt;/code&gt;&#x27;s very next step is to call &lt;code&gt;visit&lt;/code&gt; with the
&lt;code&gt;new_parent&lt;/code&gt;. You&#x27;ll have to forgive the contrived example and let it
be a testament to the rarity of overriding &lt;code&gt;exit&lt;/code&gt;. Without going into
the details, &lt;code&gt;enter&lt;/code&gt; and &lt;code&gt;exit&lt;/code&gt; are most useful when teaching &lt;code&gt;remap&lt;/code&gt;
how to traverse nonstandard containers, such as non-iterable Python
objects. As mentioned in the &lt;a href=&quot;http://sedimental.org/remap.html#drop_empty_values&quot;&gt;&quot;drop empty values&quot;&lt;/a&gt;
example, &lt;code&gt;remap&lt;/code&gt; is designed to maximize the mileage you get out of
the &lt;code&gt;visit&lt;/code&gt; callback. Let&#x27;s look at an advanced usage reason that&#x27;s
true.&lt;/p&gt;
&lt;h2 id=&quot;collect_interesting_values&quot;&gt;&lt;a href=&quot;#collect_interesting_values&quot; class=&quot;toclink&quot;&gt;Collect interesting values&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Sometimes you just want to traverse a nested structure, and you don&#x27;t
need the result. For instance, if we wanted to collect the full set of
tags used in media reviews. Let&#x27;s create a &lt;code&gt;remap&lt;/code&gt;-based function,
&lt;code&gt;get_all_tags&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;codehilite&quot; style=&quot;background: #f8f8f8&quot;&gt;&lt;pre style=&quot;line-height: 125%;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;span style=&quot;color: #AA22FF; font-weight: bold&quot;&gt;def&lt;/span&gt; &lt;span style=&quot;color: #00A000&quot;&gt;get_all_tags&lt;/span&gt;(root):
    all_tags &lt;span style=&quot;color: #666666&quot;&gt;=&lt;/span&gt; &lt;span style=&quot;color: #AA22FF&quot;&gt;set&lt;/span&gt;()

    &lt;span style=&quot;color: #AA22FF; font-weight: bold&quot;&gt;def&lt;/span&gt; &lt;span style=&quot;color: #00A000&quot;&gt;visit&lt;/span&gt;(path, key, value):
        all_tags&lt;span style=&quot;color: #666666&quot;&gt;.&lt;/span&gt;update(value[&lt;span style=&quot;color: #BB4444&quot;&gt;&#x27;tags&#x27;&lt;/span&gt;])
        &lt;span style=&quot;color: #AA22FF; font-weight: bold&quot;&gt;return&lt;/span&gt; &lt;span style=&quot;color: #AA22FF; font-weight: bold&quot;&gt;False&lt;/span&gt;

    remap(root, visit&lt;span style=&quot;color: #666666&quot;&gt;=&lt;/span&gt;visit, reraise_visit&lt;span style=&quot;color: #666666&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #AA22FF; font-weight: bold&quot;&gt;False&lt;/span&gt;)

    &lt;span style=&quot;color: #AA22FF; font-weight: bold&quot;&gt;return&lt;/span&gt; all_tags

&lt;span style=&quot;color: #AA22FF&quot;&gt;print&lt;/span&gt;(get_all_tags(review_map))
&lt;span style=&quot;color: #008800; font-style: italic&quot;&gt;# set([&#x27;space&#x27;, &#x27;comedy&#x27;, &#x27;life&#x27;])&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Like the first recipe, we&#x27;ve used the &lt;code&gt;visit&lt;/code&gt; argument to &lt;code&gt;remap&lt;/code&gt;, and
like the second recipe, we&#x27;re just returning &lt;code&gt;False&lt;/code&gt;, because we don&#x27;t
actually care about contents of the resulting structure.&lt;/p&gt;
&lt;p&gt;What&#x27;s new here is the &lt;code&gt;reraise_visit=False&lt;/code&gt; keyword argument, which
tells &lt;code&gt;remap&lt;/code&gt; to &lt;strong&gt;keep&lt;/strong&gt; any item that causes a &lt;code&gt;visit&lt;/code&gt; exception. This
practical convenience lets &lt;code&gt;visit&lt;/code&gt; functions be shorter, clearer, and
just more &lt;acronym title=&quot;Easier to Ask Forgiveness than
Permission&quot;&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/Python_syntax_and_semantics#Exceptions&quot;&gt;EAFP&lt;/a&gt;&lt;/acronym&gt;. Reducing the example to a
one-liner is left as an exercise to the reader.&lt;/p&gt;
&lt;h2 id=&quot;add_common_keys&quot;&gt;&lt;a href=&quot;#add_common_keys&quot; class=&quot;toclink&quot;&gt;Add common keys&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;As a final advanced &lt;code&gt;remap&lt;/code&gt; example, let&#x27;s look at adding items to
structures. Through the examples above, we&#x27;ve learned that &lt;code&gt;visit&lt;/code&gt; is
best-suited for 1:1 transformations and dropping values. This leaves
us with two main approaches for addition. The first uses the &lt;code&gt;enter&lt;/code&gt;
callable and is suitable for making data consistent and adding data
which can be overridden.&lt;/p&gt;
&lt;div class=&quot;codehilite&quot; style=&quot;background: #f8f8f8&quot;&gt;&lt;pre style=&quot;line-height: 125%;&quot;&gt;&lt;span&gt;&lt;/span&gt;base_review &lt;span style=&quot;color: #666666&quot;&gt;=&lt;/span&gt; {&lt;span style=&quot;color: #BB4444&quot;&gt;&#x27;title&#x27;&lt;/span&gt;: &lt;span style=&quot;color: #BB4444&quot;&gt;&#x27;&#x27;&lt;/span&gt;,
               &lt;span style=&quot;color: #BB4444&quot;&gt;&#x27;rating&#x27;&lt;/span&gt;: &lt;span style=&quot;color: #AA22FF; font-weight: bold&quot;&gt;None&lt;/span&gt;,
               &lt;span style=&quot;color: #BB4444&quot;&gt;&#x27;review&#x27;&lt;/span&gt;: &lt;span style=&quot;color: #BB4444&quot;&gt;&#x27;&#x27;&lt;/span&gt;,
               &lt;span style=&quot;color: #BB4444&quot;&gt;&#x27;tags&#x27;&lt;/span&gt;: []}

&lt;span style=&quot;color: #AA22FF; font-weight: bold&quot;&gt;def&lt;/span&gt; &lt;span style=&quot;color: #00A000&quot;&gt;enter&lt;/span&gt;(path, key, value):
    new_parent, new_items &lt;span style=&quot;color: #666666&quot;&gt;=&lt;/span&gt; default_enter(path, key, value)
    &lt;span style=&quot;color: #AA22FF; font-weight: bold&quot;&gt;try&lt;/span&gt;:
        new_parent&lt;span style=&quot;color: #666666&quot;&gt;.&lt;/span&gt;update(base_review)
    &lt;span style=&quot;color: #AA22FF; font-weight: bold&quot;&gt;except&lt;/span&gt;:
        &lt;span style=&quot;color: #AA22FF; font-weight: bold&quot;&gt;pass&lt;/span&gt;
    &lt;span style=&quot;color: #AA22FF; font-weight: bold&quot;&gt;return&lt;/span&gt; new_parent, new_items

remapped &lt;span style=&quot;color: #666666&quot;&gt;=&lt;/span&gt; remap(review_list, enter&lt;span style=&quot;color: #666666&quot;&gt;=&lt;/span&gt;enter)

&lt;span style=&quot;color: #AA22FF; font-weight: bold&quot;&gt;assert&lt;/span&gt; review_list[&lt;span style=&quot;color: #BB4444&quot;&gt;&#x27;shows&#x27;&lt;/span&gt;][&lt;span style=&quot;color: #666666&quot;&gt;1&lt;/span&gt;][&lt;span style=&quot;color: #BB4444&quot;&gt;&#x27;review&#x27;&lt;/span&gt;] &lt;span style=&quot;color: #666666&quot;&gt;==&lt;/span&gt; &lt;span style=&quot;color: #BB4444&quot;&gt;&#x27;&#x27;&lt;/span&gt;
&lt;span style=&quot;color: #008800; font-style: italic&quot;&gt;# True, the placeholder review is holding its place&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;The second method uses the &lt;code&gt;exit&lt;/code&gt; callback to override values and
calculate new values from the new data.&lt;/p&gt;
&lt;div class=&quot;codehilite&quot; style=&quot;background: #f8f8f8&quot;&gt;&lt;pre style=&quot;line-height: 125%;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;span style=&quot;color: #AA22FF; font-weight: bold&quot;&gt;def&lt;/span&gt; &lt;span style=&quot;color: #00A000&quot;&gt;exit&lt;/span&gt;(path, key, old_parent, new_parent, new_items):
    ret &lt;span style=&quot;color: #666666&quot;&gt;=&lt;/span&gt; default_exit(path, key, old_parent, new_parent, new_items)
    &lt;span style=&quot;color: #AA22FF; font-weight: bold&quot;&gt;try&lt;/span&gt;:
        ret[&lt;span style=&quot;color: #BB4444&quot;&gt;&#x27;review_length&#x27;&lt;/span&gt;] &lt;span style=&quot;color: #666666&quot;&gt;=&lt;/span&gt; &lt;span style=&quot;color: #AA22FF&quot;&gt;len&lt;/span&gt;(ret[&lt;span style=&quot;color: #BB4444&quot;&gt;&#x27;review&#x27;&lt;/span&gt;])
    &lt;span style=&quot;color: #AA22FF; font-weight: bold&quot;&gt;except&lt;/span&gt;:
        &lt;span style=&quot;color: #AA22FF; font-weight: bold&quot;&gt;pass&lt;/span&gt;
    &lt;span style=&quot;color: #AA22FF; font-weight: bold&quot;&gt;return&lt;/span&gt; ret

remapped &lt;span style=&quot;color: #666666&quot;&gt;=&lt;/span&gt; remap(review_list, exit&lt;span style=&quot;color: #666666&quot;&gt;=&lt;/span&gt;exit)

&lt;span style=&quot;color: #AA22FF; font-weight: bold&quot;&gt;assert&lt;/span&gt; remapped[&lt;span style=&quot;color: #BB4444&quot;&gt;&#x27;shows&#x27;&lt;/span&gt;][&lt;span style=&quot;color: #666666&quot;&gt;0&lt;/span&gt;][&lt;span style=&quot;color: #BB4444&quot;&gt;&#x27;review_length&#x27;&lt;/span&gt;] &lt;span style=&quot;color: #666666&quot;&gt;==&lt;/span&gt; &lt;span style=&quot;color: #666666&quot;&gt;27&lt;/span&gt;
&lt;span style=&quot;color: #AA22FF; font-weight: bold&quot;&gt;assert&lt;/span&gt; remapped[&lt;span style=&quot;color: #BB4444&quot;&gt;&#x27;movies&#x27;&lt;/span&gt;][&lt;span style=&quot;color: #666666&quot;&gt;0&lt;/span&gt;][&lt;span style=&quot;color: #BB4444&quot;&gt;&#x27;review_length&#x27;&lt;/span&gt;] &lt;span style=&quot;color: #666666&quot;&gt;==&lt;/span&gt; &lt;span style=&quot;color: #666666&quot;&gt;42&lt;/span&gt;
&lt;span style=&quot;color: #008800; font-style: italic&quot;&gt;# True times two.&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;By now you might agree that &lt;code&gt;remap&lt;/code&gt; is making such feats positively
routine. Come for the nested data manipulation, stay for the
&lt;a href=&quot;https://en.wikipedia.org/wiki/Phrases_from_The_Hitchhiker&#x27;s_Guide_to_the_Galaxy#Answer_to_the_Ultimate_Question_of_Life.2C_the_Universe.2C_and_Everything_.2842.29&quot;&gt;number jokes&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;corner_cases&quot;&gt;&lt;a href=&quot;#corner_cases&quot; class=&quot;toclink&quot;&gt;Corner cases&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;This whole guide has focused on data that came from &quot;real-world&quot;
sources, such as JSON API responses. But there are certain rare cases
which typically only arise from within Python code:
&lt;a href=&quot;http://pythondoeswhat.blogspot.com/2015/09/loopy-references.html&quot;&gt;self-referential objects&lt;/a&gt;. These are objects that
contain references to themselves or their parents. Have a look at this
trivial example:&lt;/p&gt;
&lt;div class=&quot;codehilite&quot; style=&quot;background: #f8f8f8&quot;&gt;&lt;pre style=&quot;line-height: 125%;&quot;&gt;&lt;span&gt;&lt;/span&gt;self_ref &lt;span style=&quot;color: #666666&quot;&gt;=&lt;/span&gt; []
self_ref&lt;span style=&quot;color: #666666&quot;&gt;.&lt;/span&gt;append(self_ref)
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;The experienced programmer has probably seen this before, but most
Python coders might even think the second line is an error. It&#x27;s a
list containing itself, and it has the rather cool &lt;a href=&quot;https://docs.python.org/2/reference/datamodel.html#object.__repr__&quot;&gt;repr&lt;/a&gt;:
&lt;code&gt;[[...]]&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Now, this is pretty rare, but reference loops do come up in
programming. The &lt;em&gt;good&lt;/em&gt; news is that remap handles these just fine:&lt;/p&gt;
&lt;div class=&quot;codehilite&quot; style=&quot;background: #f8f8f8&quot;&gt;&lt;pre style=&quot;line-height: 125%;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;span style=&quot;color: #AA22FF&quot;&gt;print&lt;/span&gt;(&lt;span style=&quot;color: #AA22FF&quot;&gt;repr&lt;/span&gt;(remap(self_ref)))
&lt;span style=&quot;color: #008800; font-style: italic&quot;&gt;# prints &quot;[[...]]&quot;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;The more common corner case that arises is that of duplicate
references, which remap also handles with no problem:&lt;/p&gt;
&lt;div class=&quot;codehilite&quot; style=&quot;background: #f8f8f8&quot;&gt;&lt;pre style=&quot;line-height: 125%;&quot;&gt;&lt;span&gt;&lt;/span&gt;my_set &lt;span style=&quot;color: #666666&quot;&gt;=&lt;/span&gt; &lt;span style=&quot;color: #AA22FF&quot;&gt;set&lt;/span&gt;()

dupe_ref &lt;span style=&quot;color: #666666&quot;&gt;=&lt;/span&gt; (my_set, [my_set])
remapped &lt;span style=&quot;color: #666666&quot;&gt;=&lt;/span&gt; remap(dupe_ref)

&lt;span style=&quot;color: #AA22FF; font-weight: bold&quot;&gt;assert&lt;/span&gt; remapped[&lt;span style=&quot;color: #666666&quot;&gt;0&lt;/span&gt;] &lt;span style=&quot;color: #AA22FF; font-weight: bold&quot;&gt;is&lt;/span&gt; remapped[&lt;span style=&quot;color: #666666&quot;&gt;-1&lt;/span&gt;][&lt;span style=&quot;color: #666666&quot;&gt;-1&lt;/span&gt;]
&lt;span style=&quot;color: #008800; font-style: italic&quot;&gt;# True, of course&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Two references to the same set go in, two references to a copy of that
set come out. That&#x27;s right: only one copy is made, and then used
twice, preserving the original structure.&lt;/p&gt;
&lt;h2 id=&quot;wrap_up&quot;&gt;&lt;a href=&quot;#wrap_up&quot; class=&quot;toclink&quot;&gt;Wrap-up&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;If you&#x27;ve made it this far, then I hope you&#x27;ll agree that &lt;code&gt;remap&lt;/code&gt; is
useful enough to be your new friend. If that wasn&#x27;t enough detail,
then &lt;a href=&quot;http://boltons.readthedocs.org/en/latest/iterutils.html#boltons.iterutils.remap&quot;&gt;there are the docs&lt;/a&gt;. &lt;code&gt;remap&lt;/code&gt; is
&lt;a href=&quot;https://github.com/mahmoud/boltons/blob/master/tests/test_iterutils.py&quot;&gt;well-tested&lt;/a&gt;, but making something this
general-purpose is a tricky area. Please
&lt;a href=&quot;https://github.com/mahmoud/boltons/issues&quot;&gt;file bugs and requests&lt;/a&gt;. Don&#x27;t forget about &lt;a href=&quot;https://docs.python.org/2/library/pprint.html&quot;&gt;pprint&lt;/a&gt;
and &lt;a href=&quot;https://docs.python.org/2/library/repr.html&quot;&gt;repr&lt;/a&gt;/&lt;a href=&quot;https://docs.python.org/3/library/reprlib.html&quot;&gt;reprlib&lt;/a&gt;, which can help with reading
large structures. As always, &lt;a href=&quot;https://twitter.com/mhashemi&quot;&gt;stay tuned&lt;/a&gt; for &lt;a href=&quot;http://sedimental.org/tagged/boltons/&quot;&gt;future boltons
cookbooklets&lt;/a&gt;, and much much more.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://commons.wikimedia.org/wiki/File:First_matryoshka_museum_doll_open.jpg&quot;&gt;
&lt;img src=&quot;http://sedimental.org/uploads/First_matryoshka_museum_doll_open.jpg&quot; /&gt;
&lt;/a&gt;&lt;/p&gt;
&lt;!-- TODO: closing matroska image --&gt;

&lt;!--
&quot;&quot;&quot;The marker approach to solving self-reference problems in remap
won&#x27;t work because we can&#x27;t rely on exit returning a
traversable, mutable object. We may know that the marker is in the
items going into exit but there&#x27;s no guarantee it&#x27;s not being
filtered out or being made otherwise inaccessible for other reasons.

On the other hand, having enter return the new parent instance
before it&#x27;s populated is a pretty workable solution. The division of
labor stays clear and exit still has some override powers. Also
note that only mutable structures can have self references (unless
getting really nasty with the Python C API). The downside is that
enter must do a bit more work and in the case of immutable
collections, the new collection is discarded, as a new one has to be
created from scratch by exit. The code is still pretty clear
overall.

Not that remap is supposed to be a speed demon, but here are some
thoughts on performance. Memorywise, the registry grows linearly with
the number of collections. The stack of course grows in proportion to
the depth of the data. Many intermediate lists are created, but for
most data list comprehensions are much faster than generators (and
generator expressions). The ABC isinstance checks are going to be dog
slow. As soon as a couple large enough use case cross my desk, I&#x27;ll be
sure to profile and optimize. It&#x27;s not a question of if isinstance+ABC
is slow, it&#x27;s which pragmatic alternative passes tests while being
faster.

## Remap design principles

Nested structures are common. Virtually all compact Python iterative
interaction is flat (list comprehensions, map/filter, generator
expressions, itertools, even other iterutils). remap is a succinct
solution to both quick and dirty data wrangling, as well as expressive
functional interaction with nested structures.

* visit() should be able to handle 80% of my pragmatic use cases, and
  the argument/return signature should be similarly pragmatic.
* enter()/exit() are for more advanced use cases and the signature can
  be more complex.
* 95%+ of applications should be covered by passing in only one
  callback.
* Roundtripping should be the default. Don&#x27;t repeat the faux pas of
  HTMLParser where, despite the nice SAX-like interface, it is
  impossible (or very difficult) to regenerate the input. Roundtripped
  results compare as equal, realistically somewhere between copy.copy
  and copy.deepcopy.
* Leave streaming for another day. Generators can be handy, but the
  vast majority of data is of easily manageable size. Besides, there&#x27;s
  no such thing as a streamable dictionary.

&quot;&quot;&quot;

--&gt;&lt;p&gt;&lt;/p&gt;



&lt;hr /&gt;

</content>

  </entry>
  
  <entry>
    <id>http://sedimental.org/python_community_intro.html</id>
    <author>
      <name>Mahmoud Hashemi</name>
      <uri>http://sedimental.org/</uri>
    </author>
    <title>Python Community Intro</title>
    <link rel="alternate" type="text/html" href="http://sedimental.org/python_community_intro.html" />
    <published>2015-09-22T07:00:00Z</published>
    <updated>2015-09-22T07:00:00Z</updated>
    <category term="python"/>
    

    <content type="html">&lt;p&gt;&lt;p&gt;The &lt;a href=&quot;https://www.python.org/psf/&quot; title=&quot;Python Software Foundation&quot;&gt;PSF&lt;/a&gt;
just created a new mailing list, &lt;a href=&quot;https://mail.python.org/mailman/listinfo/psf-community&quot;&gt;&quot;PSF-Community&quot;&lt;/a&gt;,
then autosubscribed a bunch of people and solicited introductions. At
first I was surprised, but I was quickly charmed by
&lt;a href=&quot;https://mail.python.org/pipermail/psf-community/2015-September/thread.html&quot;&gt;the response&lt;/a&gt; and joined in on the action. Here&#x27;s what
I &lt;a href=&quot;https://mail.python.org/pipermail/psf-community/2015-September/000084.html&quot;&gt;wrote&lt;/a&gt;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;If Alex Martelli &lt;a href=&quot;https://mail.python.org/pipermail/psf-community/2015-September/000081.html&quot;&gt;is doing it&lt;/a&gt;, then brace yourselves
because the floodgates are open.&lt;/p&gt;
&lt;p&gt;I first used Python as a junior in a South Dakota high school, off a
Knoppix CD because &quot;&lt;a href=&quot;https://en.wikipedia.org/wiki/Live_CD&quot;&gt;Live CDs&lt;/a&gt;&quot; were all the rage then. It
was a good fad because I didn’t have a computer, and the Windows
machines at school weren’t writable and didn’t have Python (2.2 at the
time). I read a bit of the tutorial and wrote a really bad
&lt;a href=&quot;https://en.wikipedia.org/wiki/Generating_primes#Prime_sieves&quot;&gt;prime number sieve&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;After a professional loop through Java, C++, C#, and finally PHP, I
resumed Python development in 2009 as a full-stack web developer at
PayPal. I wrote the tool that (still) manages all the pricing
arrangements.&lt;/p&gt;
&lt;p&gt;From there I hired my first teammate and we wrote a couple other
business-critical components before standardizing out PayPal’s first
grassroots alternative stack. That was early 2011 and since then we’ve
had &lt;a href=&quot;https://medium.com/paypal-tech/10-myths-of-enterprise-python-8302b8f21f82&quot;&gt;a lot of fun&lt;/a&gt; and &lt;a href=&quot;https://medium.com/paypal-tech/introducing-support-98945f023a8e&quot;&gt;come so far&lt;/a&gt;. Now we’re
focusing on PayPal’s security offerings: putting Python at the very
heart of PayPal’s availability model, handling &lt;em&gt;billions&lt;/em&gt; of requests
per day. And believe me when I say that’s it’s the best thing that’s
happened to PayPal’s security in a long time! The details will have to
wait for a future blog post (and upcoming O’Reilly project). Or, if
you’re remotely as excited as I am, you can email me directly. :)&lt;/p&gt;
&lt;p&gt;On the side, I really enjoy working on
&lt;a href=&quot;http://listen.hatnote.com/#en&quot;&gt;Wikipedia&lt;/a&gt;-&lt;a href=&quot;http://weekly.hatnote.com/&quot;&gt;based&lt;/a&gt; &lt;a href=&quot;http://rcmap.hatnote.com/#en,de,ru,ja,es,fr&quot;&gt;projects&lt;/a&gt; &amp;gt; &lt;a href=&quot;http://seealso.hatnote.com/&quot;&gt;under&lt;/a&gt; &lt;a href=&quot;https://twitter.com/hatnotable&quot;&gt;the banner of&lt;/a&gt; &lt;a href=&quot;http://blog.hatnote.com/&quot;&gt;Hatnote&lt;/a&gt;, all
Python. Most recently, we did
&lt;a href=&quot;http://blog.hatnote.com/post/124069724187/wikipedia-and-ifttt-a-technical-guide&quot;&gt;the official Wikipedia IFTTT channel&lt;/a&gt; (handling 1.3
million requests per day). And because I can’t get enough, a bunch of
&lt;a href=&quot;https://github.com/mahmoud&quot;&gt;open-source stuff&lt;/a&gt;, most notably &lt;a href=&quot;http://boltons.readthedocs.org/en/latest/&quot;&gt;Boltons&lt;/a&gt;, where
I’ve been particularly busy lately.&lt;/p&gt;
&lt;p&gt;If you’re in the Bay Area, do &lt;em&gt;not&lt;/em&gt; hesitate to reach out to talk about
Python, Wikipedia, security, federated and open systems (like BBS
stuff), or even PayPal!&lt;/p&gt;
&lt;p&gt;Specifically, this is sort of odd, but October 14th at 1pm, I&#x27;m doing
an overview of Python usage at PayPal, and would like to invite anyone
senior and curious to be my guest and come to PayPal in San Jose to
check it out. Guido came in 2012 and &lt;a href=&quot;https://www.flickr.com/photos/mahmoudhashemi/16860083512/in/album-72157651024763880/&quot;&gt;he loved it&lt;/a&gt;. And
stuff now is waaaay cooler!&lt;/p&gt;
&lt;p&gt;Anyways, I just wanted to end by saying thanks to you all. If you
hadn&#x27;t been so numerous and out there, I probably would have gotten
myself fired long before any of this bore fruit. ;)&lt;/p&gt;
&lt;p&gt;THANKS!&lt;/p&gt;
&lt;p&gt;Mahmoud&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;There were a lot of autosubscribed folks deploring the spammish
inquisition and threatening unsubscription, so here&#x27;s hoping my straw
didn&#x27;t break too many camels backs.&lt;p&gt;&lt;/p&gt;



&lt;hr /&gt;

</content>

  </entry>
  
  <entry>
    <id>http://sedimental.org/10_myths_of_enterprise_python.html</id>
    <author>
      <name>Mahmoud Hashemi</name>
      <uri>http://sedimental.org/</uri>
    </author>
    <title>10 Myths of Enterprise Python</title>
    <link rel="alternate" type="text/html" href="http://sedimental.org/10_myths_of_enterprise_python.html" />
    <published>2015-08-25T07:00:00Z</published>
    <updated>2015-08-25T07:00:00Z</updated>
    <category term="code"/><category term="work"/><category term="python"/>
    

    <content type="html">&lt;p&gt;&lt;p&gt;&lt;em&gt;(Originally posted &lt;a href=&quot;https://medium.com/paypal-tech/search?q=python&quot;&gt;on the PayPal Engineering blog&lt;/a&gt;, reproduced here
with minor updates, link fixes, etc.)&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;PayPal enjoys a remarkable amount of linguistic pluralism in its
programming culture. In addition to the long-standing popularity of C++
and Java, an increasing number of teams are choosing JavaScript and
Scala, and &lt;a href=&quot;https://www.braintreepayments.com/&quot;&gt;Braintree&lt;/a&gt;&#x27;s acquisition has introduced a
sophisticated Ruby community.&lt;/p&gt;
&lt;p&gt;One language in particular has both a long history at eBay and PayPal
and a growing mindshare among developers: &lt;a href=&quot;https://www.python.org/&quot;&gt;Python&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Python has enjoyed many years of grassroots usage and support from
developers across eBay. Even before official support from management,
technologists of all walks went the extra mile to reap the rewards of
developing in Python. I joined PayPal a few years ago, and chose
Python to work on internal applications, but I&#x27;ve personally found
production PayPal Python code from nearly &lt;strong&gt;15 years ago&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Today, Python powers &lt;strong&gt;over 50 projects&lt;/strong&gt;, including:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Features and products&lt;/strong&gt;, such as &lt;strong&gt;eBay Now&lt;/strong&gt; and &lt;a href=&quot;https://www.crunchbase.com/organization/redlaser&quot;&gt;RedLaser&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Operations and infrastructure&lt;/strong&gt;, both &lt;a href=&quot;http://www.openstack.org/&quot;&gt;OpenStack&lt;/a&gt; and proprietary&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Mid-tier services and applications&lt;/strong&gt;, like the one used to set
  PayPal&#x27;s prices and check customer feature eligibility&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Monitoring agents and interfaces&lt;/strong&gt;, used for several deployment and
  security use cases&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Batch jobs for data import&lt;/strong&gt;, price adjustment, and more&lt;/li&gt;
&lt;li&gt;And far too many developer tools to count&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In the coming series of posts I&#x27;ll detail the initiatives and
technologies that led the eBay/PayPal Python community to grow from
just under 25 engineers in 2011 to &lt;strong&gt;over 260&lt;/strong&gt; in 2014. For this
introductory post, I&#x27;ll be focusing on the 10 myths I&#x27;ve had to
debunk the most in eBay and PayPal&#x27;s enterprise environments.&lt;/p&gt;
&lt;p&gt;&lt;a name=&quot;myth-1&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3 id=&quot;myth_1_python_is_a_new_language&quot;&gt;&lt;a href=&quot;#myth_1_python_is_a_new_language&quot; class=&quot;toclink&quot;&gt;&lt;a href=&quot;http://sedimental.org/10_myths_of_enterprise_python.html#python-is-new&quot; name=&quot;python-is-new&quot;&gt;Myth #1&lt;/a&gt;: Python is a new language&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;What with all the startups using it and &lt;a href=&quot;http://www.nostarch.com/pythonforkids&quot;&gt;kids learning it
these days&lt;/a&gt;, it&#x27;s easy to see how this myth still
persists. Python is actually &lt;a href=&quot;https://en.wikipedia.org/wiki/Python_(programming_language)#History&quot;&gt;over 23 years old&lt;/a&gt;,
originally released in 1991, 4 years before Java. A now-famous early
usage of Python was in 1996: &lt;a href=&quot;https://news.ycombinator.com/item?id=8587697&quot;&gt;Google&#x27;s first successful web
crawler&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;If you&#x27;re curious about the long history of Python, &lt;a href=&quot;https://en.wikipedia.org/wiki/Guido_van_Rossum&quot;&gt;Guido van Rossum&lt;/a&gt;,
Python&#x27;s creator, &lt;a href=&quot;http://python-history.blogspot.com/2009/01/introduction-and-overview.html&quot;&gt;has taken the care to tell the whole
story&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;a name=&quot;myth-2&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3 id=&quot;myth_2_python_is_not_compiled&quot;&gt;&lt;a href=&quot;#myth_2_python_is_not_compiled&quot; class=&quot;toclink&quot;&gt;&lt;a href=&quot;http://sedimental.org/10_myths_of_enterprise_python.html#python-is-not-compiled&quot; name=&quot;python-is-not-compiled&quot;&gt;Myth #2&lt;/a&gt;: Python is not compiled&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;While not requiring a separate compiler toolchain like C++, Python is
in fact compiled to bytecode, much like Java and many other compiled
languages. Further compilation steps, if any, are at the discretion of
the runtime, be it CPython, PyPy, Jython/JVM, IronPython/CLR, or some
other process virtual machine. See &lt;a href=&quot;http://sedimental.org/10_myths_of_enterprise_python.html#myth-6&quot;&gt;Myth #6&lt;/a&gt; for more info.&lt;/p&gt;
&lt;p&gt;The general principle at PayPal and elsewhere is that the compilation
status of code should not be relied on for security. It is much more
important to secure the runtime environment, as virtually every
language &lt;a href=&quot;https://docs.python.org/2/library/dis.html&quot;&gt;has&lt;/a&gt; &lt;a href=&quot;http://boomerang.sourceforge.net/&quot;&gt;a&lt;/a&gt;
&lt;a href=&quot;http://jd.benow.ca/&quot;&gt;decompiler&lt;/a&gt;, or &lt;a href=&quot;https://docs.python.org/2/library/site.html&quot;&gt;can&lt;/a&gt;
&lt;a href=&quot;http://www.opensourceforu.com/2011/08/lets-hook-a-library-function/&quot;&gt;be&lt;/a&gt; &lt;a href=&quot;http://docs.oracle.com/javase/6/docs/api/java/lang/instrument/Instrumentation.html&quot;&gt;intercepted&lt;/a&gt; to dump protected
state. See the next myth for even more Python security implications.&lt;/p&gt;
&lt;p&gt;&lt;a name=&quot;myth-3&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3 id=&quot;myth_3_python_is_not_secure&quot;&gt;&lt;a href=&quot;#myth_3_python_is_not_secure&quot; class=&quot;toclink&quot;&gt;&lt;a href=&quot;http://sedimental.org/10_myths_of_enterprise_python.html#python-is-not-secure&quot; name=&quot;python-is-not-secure&quot;&gt;Myth #3&lt;/a&gt;: Python is not secure&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Python&#x27;s affinity for the lightweight may not make it seem formidable,
but the intuition here can be misleading. One central tenet of
security is to present as small a target as possible. Big systems are
anti-secure, as they tend to &lt;a href=&quot;http://www.jwz.org/xscreensaver/toolkits.html&quot;&gt;overly centralize
behaviors&lt;/a&gt;, as well as &lt;a href=&quot;https://www.schneier.com/essays/archives/1999/11/a_plea_for_simplicit.html&quot;&gt;undercut developer
comprehension&lt;/a&gt;. Python keeps these demons at bay
by encouraging simplicity. Furthermore, &lt;a href=&quot;https://en.wikipedia.org/wiki/CPython&quot;&gt;CPython&lt;/a&gt;[cypython] addresses
these issues by being a simple, stable, and easily-auditable virtual
machine. In fact, a recent analysis by &lt;a href=&quot;http://www.coverity.com/why-coverity/&quot;&gt;Coverity&lt;/a&gt; Software &lt;a href=&quot;http://www.coverity.com/press-releases/coverity-finds-python-sets-new-level-of-quality-for-open-source-software/&quot;&gt;resulted
in CPython receiving their highest quality rating&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Python also features an extensive array of open-source,
industry-standard security libraries. At PayPal, where we take
security and trust very seriously, we find that a combination of
&lt;a href=&quot;https://docs.python.org/2/library/hashlib.html&quot;&gt;hashlib&lt;/a&gt;, &lt;a href=&quot;https://github.com/dlitz/pycrypto&quot;&gt;PyCrypto&lt;/a&gt;, and &lt;a href=&quot;https://www.openssl.org/&quot;&gt;OpenSSL&lt;/a&gt;, via
&lt;a href=&quot;https://github.com/pyca/pyopenssl&quot;&gt;PyOpenSSL&lt;/a&gt; and our own custom bindings, cover all of
PayPal&#x27;s diverse security and performance needs.&lt;/p&gt;
&lt;p&gt;For these reasons and more, Python has seen some of its fastest
adoption at PayPal (and eBay) within the application security
group. Here are just a few security-based applications utilizing
Python for PayPal&#x27;s security-first environment:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Creating security agents for facilitating key rotation and
  consolidating cryptographic implementations&lt;/li&gt;
&lt;li&gt;Integrating with industry-leading
  &lt;acronym title=&quot;Hardware Security Module&quot;&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/Hardware_security_module&quot;&gt;HSM&lt;/a&gt;&lt;/acronym&gt; technologies&lt;/li&gt;
&lt;li&gt;Constructing TLS-secured wrapper proxies for less-compliant stacks&lt;/li&gt;
&lt;li&gt;Generating keys and certificates for our internal mutual-authentication schemes&lt;/li&gt;
&lt;li&gt;Developing active vulnerability scanners&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Plus, myriad Python-built operations-oriented systems with security
implications, such as firewall and connection management. In the
future we&#x27;ll definitely try to put together a deep dive on PayPal
Python security particulars.&lt;/p&gt;
&lt;p&gt;&lt;a name=&quot;myth-4&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3 id=&quot;myth_4_python_is_a_scripting_language&quot;&gt;&lt;a href=&quot;#myth_4_python_is_a_scripting_language&quot; class=&quot;toclink&quot;&gt;&lt;a href=&quot;http://sedimental.org/10_myths_of_enterprise_python.html#python-is-for-scripting&quot; name=&quot;python-is-for-scripting&quot;&gt;Myth #4&lt;/a&gt;: Python is a scripting language&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Python can indeed be used for scripting, and is one of the forerunners
of the domain due to its simple syntax, cross-platform support, and
ubiquity among Linux, Macs, and other Unix machines.&lt;/p&gt;
&lt;p&gt;In fact, Python may be one of the most flexible technologies among
general-use programming languages. To list just a few:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Telephony infrastructure (&lt;a href=&quot;https://en.wikipedia.org/wiki/Twilio&quot;&gt;Twilio&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;Payments systems (&lt;a href=&quot;https://en.wikipedia.org/wiki/PayPal&quot;&gt;PayPal&lt;/a&gt;, [Venmo][venmo])&lt;/li&gt;
&lt;li&gt;Neuroscience and psychology (&lt;a href=&quot;http://www.frontiersin.org/neuroinformatics/researchtopics/Python_in_neuroscience/8&quot;&gt;citation&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;Numerical analysis and engineering (&lt;a href=&quot;https://en.wikipedia.org/wiki/NumPy&quot;&gt;numpy&lt;/a&gt;, &lt;a href=&quot;http://numba.pydata.org/bin&quot;&gt;numba&lt;/a&gt;, and &lt;a href=&quot;https://wiki.python.org/moin/NumericAndScientific&quot;&gt;many more&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;Animation (&lt;a href=&quot;https://en.wikipedia.org/wiki/LucasArts&quot;&gt;LucasArts&lt;/a&gt;, &lt;a href=&quot;https://disneyanimation.com/open-source/&quot;&gt;Disney&lt;/a&gt;, &lt;a href=&quot;https://en.wikipedia.org/wiki/DreamWorks_Animation&quot;&gt;Dreamworks&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;Gaming backends (&lt;a href=&quot;https://en.wikipedia.org/wiki/Eve_Online&quot;&gt;Eve Online&lt;/a&gt;, &lt;a href=&quot;https://en.wikipedia.org/wiki/Second_Life&quot;&gt;Second Life&lt;/a&gt;, &lt;a href=&quot;https://en.wikipedia.org/wiki/Battlefield_(series)&quot;&gt;Battlefield&lt;/a&gt;, and &lt;a href=&quot;https://wiki.python.org/moin/PythonGames&quot;&gt;so many others&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;Email infrastructure (&lt;a href=&quot;https://en.wikipedia.org/wiki/GNU_Mailman&quot;&gt;Mailman&lt;/a&gt;, &lt;a href=&quot;https://www.mailgun.com/&quot;&gt;Mailgun&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;Media storage and processing (&lt;a href=&quot;https://en.wikipedia.org/wiki/YouTube&quot;&gt;YouTube&lt;/a&gt;, &lt;a href=&quot;http://instagram-engineering.tumblr.com/post/13649370142/what-powers-instagram-hundreds-of-instances&quot;&gt;Instagram&lt;/a&gt;, &lt;a href=&quot;https://tech.dropbox.com/&quot;&gt;Dropbox&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;Operations and systems management (&lt;a href=&quot;https://en.wikipedia.org/wiki/Rackspace&quot;&gt;Rackspace&lt;/a&gt;, &lt;a href=&quot;http://www.openstack.org/&quot;&gt;OpenStack&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;Natural language processing (&lt;a href=&quot;http://www.nltk.org/&quot;&gt;NLTK&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;Machine learning and computer vision (&lt;a href=&quot;http://scikit-learn.org/stable/&quot;&gt;scikit-learn&lt;/a&gt;, &lt;a href=&quot;http://orange.biolab.si/&quot;&gt;Orange&lt;/a&gt;, &lt;a href=&quot;http://simplecv.org/&quot;&gt;SimpleCV&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;Security and penetration testing (&lt;a href=&quot;https://github.com/dloss/python-pentest-tools&quot;&gt;so many&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;Big Data (&lt;a href=&quot;http://discoproject.org/&quot;&gt;Disco&lt;/a&gt;, &lt;a href=&quot;http://blog.cloudera.com/blog/2013/01/a-guide-to-python-frameworks-for-hadoop/&quot;&gt;Hadoop support&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;Internet infrastructure (DNS) (BIND 10)&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Not to mention websites and web services aplenty. In fact, PayPal
engineers seem to have a penchant for going on to start Python-based
web properties. &lt;a href=&quot;https://en.wikipedia.org/wiki/YouTube&quot;&gt;YouTube&lt;/a&gt; and &lt;a href=&quot;http://yelp.com&quot;&gt;Yelp&lt;/a&gt;, for instance.&lt;/p&gt;
&lt;p&gt;&lt;a name=&quot;myth-5&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3 id=&quot;myth_5_python_is_weakly_typed&quot;&gt;&lt;a href=&quot;#myth_5_python_is_weakly_typed&quot; class=&quot;toclink&quot;&gt;&lt;a href=&quot;http://sedimental.org/10_myths_of_enterprise_python.html#python-is-weakly-typed&quot; name=&quot;python-is-weakly-typed&quot;&gt;Myth #5&lt;/a&gt;: Python is weakly-typed&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Python&#x27;s type system is characterized by strong, dynamic
typing. &lt;a href=&quot;https://en.wikipedia.org/wiki/Type_system&quot;&gt;Wikipedia can explain more&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Not that it is a competition, but as a fun fact, Python is more
strongly-typed than Java. Java has a split type system for primitives
and objects, with &lt;code&gt;null&lt;/code&gt; lying in a sort of gray area. On the other
hand, modern Python has a unified strong type system, where the type
of &lt;code&gt;None&lt;/code&gt; is well-specified. Furthermore, the JVM itself is also
dynamically-typed, as it &lt;a href=&quot;https://en.wikipedia.org/wiki/HotSpot#History&quot;&gt;traces its roots back&lt;/a&gt; to an
implemention of a Smalltalk VM acquired by Sun.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://docs.python.org/2/reference/datamodel.html&quot;&gt;Python&#x27;s type system&lt;/a&gt; is very nice, but for
enterprise use there are much bigger concerns at hand.&lt;/p&gt;
&lt;p&gt;&lt;a name=&quot;myth-6&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3 id=&quot;myth_6_python_is_slow&quot;&gt;&lt;a href=&quot;#myth_6_python_is_slow&quot; class=&quot;toclink&quot;&gt;&lt;a href=&quot;http://sedimental.org/10_myths_of_enterprise_python.html#python-is-slow&quot; name=&quot;python-is-slow&quot;&gt;Myth #6&lt;/a&gt;: Python is slow&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;First, a critical distinction: Python is a programming language, not a
runtime. There are several Python implementations:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/CPython&quot;&gt;&lt;strong&gt;CPython&lt;/strong&gt;&lt;/a&gt; is the reference implementation, and also the most widely
   distributed and used.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/Jython&quot;&gt;&lt;strong&gt;Jython&lt;/strong&gt;&lt;/a&gt; is a mature implementation of Python for usage with the JVM.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/IronPython&quot;&gt;&lt;strong&gt;IronPython&lt;/strong&gt;&lt;/a&gt; is Microsoft&#x27;s Python for the Common Language Runtime, aka .NET.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://pypy.org/&quot;&gt;&lt;strong&gt;PyPy&lt;/strong&gt;&lt;/a&gt; is an up-and-coming implementation of Python, with advanced
   features such as JIT compilation, incremental garbage collection,
   and more.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Each runtime has its own performance characteristics, and none of them
are slow per se. The more important point here is that it is a mistake
to assign performance assessments to a programming languages. Always
assess an application runtime, most preferably against a particular
use case.&lt;/p&gt;
&lt;p&gt;Having cleared that up, here is a small selection of cases where
Python has offered significant performance advantages:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Using &lt;a href=&quot;https://en.wikipedia.org/wiki/NumPy&quot;&gt;NumPy&lt;/a&gt; as &lt;a href=&quot;https://software.intel.com/en-us/articles/numpyscipy-with-intel-mkl&quot;&gt;an interface to Intel&#x27;s MKL SIMD&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://pypy.org/&quot;&gt;PyPy&lt;/a&gt;&#x27;s JIT compilation &lt;a href=&quot;http://morepypy.blogspot.com/2011/08/pypy-is-faster-than-c-again-string.html&quot;&gt;achieves faster-than-C performance&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://disqus.com/&quot;&gt;Disqus&lt;/a&gt; scales from &lt;a href=&quot;http://blog.disqus.com/post/62187806135/scaling-django-to-8-billion-page-views&quot;&gt;250 to 500 million users on the same 100 boxes&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Admittedly these are not the newest examples, just my favorites. It
would be easy to get side-tracked into the wide world of
high-performance Python and the unique offerings of runtimes. Instead
of addressing individual special cases, attention should be drawn to
the generalizable impact of developer productivity on end-product
performance, especially in an enterprise setting.&lt;/p&gt;
&lt;p&gt;Given enough time, a disciplined developer can execute the only proven
approach to achieving accurate and performant software:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Engineer&lt;/strong&gt; for correct behavior, including the development of respective tests&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Profile&lt;/strong&gt; and measure performance, identifying bottlenecks&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Optimize&lt;/strong&gt;, paying proper respect to the test suite and &lt;a href=&quot;https://en.wikipedia.org/wiki/Amdahl%27s_law&quot;&gt;Amdahl&#x27;s Law&lt;/a&gt;,
   and taking advantage of Python&#x27;s strong roots in C.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;It might sound simple, but even for seasoned engineers, this can be a
very time-consuming process. Python was designed from the ground up
with developer timelines in mind. In our experience, it&#x27;s not uncommon
for Python projects to undergo three or more iterations in the time it
C++ and Java to do just one. Today, PayPal and eBay have seen multiple
success stories wherein Python projects outperformed their C++ and
Java counterparts, all thanks to fast development times enabling
careful tailoring and optimization. You know, the fun stuff.&lt;/p&gt;
&lt;p&gt;&lt;a name=&quot;myth-7&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3 id=&quot;myth_7_python_does_not_scale&quot;&gt;&lt;a href=&quot;#myth_7_python_does_not_scale&quot; class=&quot;toclink&quot;&gt;&lt;a href=&quot;http://sedimental.org/10_myths_of_enterprise_python.html#python-does-not-scale&quot; name=&quot;python-does-not-scale&quot;&gt;Myth #7&lt;/a&gt;: Python does not scale&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Scale has many definitions, but by any definition, &lt;a href=&quot;https://www.youtube.com/yt/press/statistics.html&quot;&gt;YouTube is a web
site at scale&lt;/a&gt;. More than 1 billion unique visitors per
month, over 100 hours of uploaded video per minute, and going on 20%
of peak Internet bandwidth, all with Python as a core
technology. &lt;a href=&quot;http://techcrunch.com/2013/07/11/how-did-dropbox-scale-to-175m-users-a-former-engineer-details-the-early-days/&quot;&gt;Dropbox&lt;/a&gt;, &lt;a href=&quot;http://blog.disqus.com/post/62187806135/scaling-django-to-8-billion-page-views&quot;&gt;Disqus&lt;/a&gt;,
&lt;a href=&quot;http://www.infoworld.com/article/2608078/application-development/expert-interview--how-to-scale-django.html&quot;&gt;Eventbrite&lt;/a&gt;, &lt;a href=&quot;http://highscalability.com/blog/2013/8/26/reddit-lessons-learned-from-mistakes-made-scaling-to-1-billi.html&quot;&gt;Reddit&lt;/a&gt;,
&lt;a href=&quot;http://www.slideshare.net/twilio/asynchronous-architectures-for-implementing-scalable-cloud-services-evan-cooke-gluecon-2012&quot;&gt;Twilio&lt;/a&gt;, &lt;a href=&quot;http://www.slideshare.net/twilio/asynchronous-architectures-for-implementing-scalable-cloud-services-evan-cooke-gluecon-2012&quot;&gt;Instagram&lt;/a&gt;,
&lt;a href=&quot;http://www.slideshare.net/YelpEngineering/scale-presentation-michael-stoppelman-oct-2014&quot;&gt;Yelp&lt;/a&gt;, &lt;a href=&quot;http://highscalability.com/eve-online-architecture&quot;&gt;EVE Online&lt;/a&gt;, &lt;a href=&quot;http://highscalability.com/second-life-architecture-grid&quot;&gt;Second
Life&lt;/a&gt;, and, yes, eBay and PayPal all have Python
scaling stories that prove scale is more than just possible: it&#x27;s a
pattern.&lt;/p&gt;
&lt;p&gt;The key to success is simplicity and consistency. CPython, the primary
Python virtual machine, maximizes these characteristics, which in turn
makes for a very predictable runtime. One would be hard pressed to
find Python programmers concerned about garbage collection pauses or
application startup time. With strong platform and networking support,
Python naturally lends itself to smart horizontal scalability, as
manifested in systems like &lt;a href=&quot;http://bittorrent.cvs.sourceforge.net/viewvc/bittorrent/BitTorrent/&quot;&gt;BitTorrent&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Additionally, scaling is all about measurement and iteration. Python
is built with &lt;a href=&quot;https://docs.python.org/2/library/profile.html&quot;&gt;profiling&lt;/a&gt; and optimization in mind. See
&lt;a href=&quot;http://sedimental.org/10_myths_of_enterprise_python.html#myth-6&quot;&gt;Myth #6&lt;/a&gt; for more details on how to vertically scale Python.&lt;/p&gt;
&lt;p&gt;&lt;a name=&quot;myth-8&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3 id=&quot;myth_8_python_lacks_good_concurrency_support&quot;&gt;&lt;a href=&quot;#myth_8_python_lacks_good_concurrency_support&quot; class=&quot;toclink&quot;&gt;&lt;a href=&quot;http://sedimental.org/10_myths_of_enterprise_python.html#python-lacks-concurrency&quot; name=&quot;python-lacks-concurrency&quot;&gt;Myth #8&lt;/a&gt;: Python lacks good concurrency support&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Occasionally debunking &lt;a href=&quot;http://sedimental.org/10_myths_of_enterprise_python.html#myth-6&quot;&gt;performance&lt;/a&gt; and &lt;a href=&quot;http://sedimental.org/10_myths_of_enterprise_python.html#myth-7&quot;&gt;scaling&lt;/a&gt;
myths, and someone tries to get technical, &quot;Python lacks concurrency,&quot;
or, &quot;What about the GIL?&quot; If dozens of counterexamples are
insufficient to bolster one&#x27;s confidence in Python&#x27;s ability to scale
vertically and horizontally, then an extended explanation of a
&lt;a href=&quot;https://en.wikipedia.org/wiki/CPython&quot;&gt;CPython&lt;/a&gt; implementation detail probably won&#x27;t help, so I&#x27;ll
keep it brief.&lt;/p&gt;
&lt;p&gt;Python has great concurrency primitives, including
[generators][gen_concurrency], &lt;a href=&quot;https://greenlet.readthedocs.org/en/latest/&quot;&gt;greenlets&lt;/a&gt;,
&lt;a href=&quot;https://twistedmatrix.com/documents/14.0.0/core/howto/defer.html&quot;&gt;Deferreds&lt;/a&gt;, and &lt;a href=&quot;http://pythonhosted.org/futures/&quot;&gt;futures&lt;/a&gt;. Python has great
concurrency frameworks, including &lt;a href=&quot;https://eventlet.readthedocs.io/en/latest/&quot;&gt;eventlet&lt;/a&gt;,
&lt;a href=&quot;http://www.gevent.org/&quot;&gt;gevent&lt;/a&gt;, and &lt;a href=&quot;https://twisted.org/&quot;&gt;Twisted&lt;/a&gt;. Python has had some amazing
work put into customizing runtimes for concurrency, including
&lt;a href=&quot;http://www.stackless.com/&quot;&gt;Stackless&lt;/a&gt; and &lt;a href=&quot;http://pypy.org/&quot;&gt;PyPy&lt;/a&gt;. All of these and more show
that there is no shortage of engineers effectively and
unapologetically using Python for concurrent programming. Also, all of
these are officially support and/or used in enterprise-level
production environments. For examples, refer to &lt;a href=&quot;http://sedimental.org/10_myths_of_enterprise_python.html#myth-7&quot;&gt;Myth #7&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The Global Interpreter Lock, or GIL, is a performance optimization for
most use cases of Python, and a development ease optimization for
virtually all CPython code. The GIL makes it much easier to use OS
threads or &lt;a href=&quot;https://en.wikipedia.org/wiki/Green_threads&quot;&gt;green threads&lt;/a&gt; (greenlets usually), and does
not affect using multiple processes. For more information, &lt;a href=&quot;http://programmers.stackexchange.com/questions/186889/why-was-python-written-with-the-gil&quot;&gt;see this
great Q&amp;amp;A on the topic&lt;/a&gt; and &lt;a href=&quot;https://docs.python.org/3/library/concurrency.html&quot;&gt;this overview from the Python
docs&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Here at PayPal, a typical service deployment entails multiple
machines, with multiple processes, multiple threads, and a very large
number of greenlets, amounting to a very robust and scalable
concurrent environment. In most enterprise environments, parties tends
to prefer a fairly high degree of overprovisioning, for general
prudence and disaster recovery. Nevertheless, in some cases Python services
still see millions of requests per machine per day, handled with ease.&lt;/p&gt;
&lt;p&gt;&lt;a name=&quot;myth-9&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3 id=&quot;myth_9_python_programmers_are_scarce&quot;&gt;&lt;a href=&quot;#myth_9_python_programmers_are_scarce&quot; class=&quot;toclink&quot;&gt;&lt;a href=&quot;http://sedimental.org/10_myths_of_enterprise_python.html#python-programmers-scarce&quot; name=&quot;python-programmers-scarce&quot;&gt;Myth #9&lt;/a&gt;: Python programmers are scarce&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;There is some truth to this myth. There are not as many Python web
developers as PHP or Java web developers. This is probably mostly due
to a combined interaction of industry demand and education, though
&lt;a href=&quot;http://cacm.acm.org/blogs/blog-cacm/176450-python-is-now-the-most-popular-introductory-teaching-language-at-top-us-universities/fulltext&quot;&gt;trends in education suggest that this may change&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;That said, Python developers are far from scarce. There are millions
worldwide, as evidenced by the dozens of Python conferences, tens of
thousands of StackOverflow questions, and companies like YouTube, Bank
of America, and LucasArts/Dreamworks employing Python developers by
the hundreds and thousands. At eBay and PayPal we have hundreds of
developers who use Python on a regular basis, so what&#x27;s the trick?&lt;/p&gt;
&lt;p&gt;Well, why scavenge when one can create? Python is exceptionally easy
to learn, and is a first programming language &lt;a href=&quot;http://www.nostarch.com/pythonforkids&quot;&gt;for
children&lt;/a&gt;, &lt;a href=&quot;http://ocw.mit.edu/courses/electrical-engineering-and-computer-science/6-189-a-gentle-introduction-to-programming-using-python-january-iap-2011/&quot;&gt;university students&lt;/a&gt;, and
&lt;a href=&quot;https://developers.google.com/edu/python/?csw=1&quot;&gt;professionals&lt;/a&gt; alike. At eBay, it only takes one
week to show real results for a new Python programmer, and they often
really start to shine as quickly as 2-3 months, all made possible by
the Internet&#x27;s rich cache of interactive tutorials, books,
documentation, and open-source codebases.&lt;/p&gt;
&lt;p&gt;Another important factor to consider is that projects using Python
simply do not require as many developers as other projects. As
mentioned in Myth #7, lean, effective teams like Instagram are a
common trope in Python projects, and this has certainly been our
experience at eBay and PayPal.&lt;/p&gt;
&lt;p&gt;&lt;a name=&quot;myth-10&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3 id=&quot;myth_10_python_is_not_for_big_projects&quot;&gt;&lt;a href=&quot;#myth_10_python_is_not_for_big_projects&quot; class=&quot;toclink&quot;&gt;&lt;a href=&quot;http://sedimental.org/10_myths_of_enterprise_python.html#python-not-for-big-projects&quot; name=&quot;python-not-for-big-projects&quot;&gt;Myth #10&lt;/a&gt;: Python is not for big projects&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;http://sedimental.org/10_myths_of_enterprise_python.html#myth-7&quot;&gt;Myth #7&lt;/a&gt; discussed running Python projects at scale, but
what about &lt;em&gt;developing&lt;/em&gt; Python projects at scale? As mentioned in
&lt;a href=&quot;http://sedimental.org/10_myths_of_enterprise_python.html#myth-9&quot;&gt;Myth #9&lt;/a&gt;, most Python projects tend not to be
people-hungry. while Instagram reached hundreds of millions of hits a
day at the time of their &lt;a href=&quot;http://www.slate.com/blogs/business_insider/2013/11/14/facebook_s_1_billion_instagram_buy_did_kevin_systrom_sell_too_soon.html&quot;&gt;billion dollar acquisition&lt;/a&gt;,
the whole company was &lt;a href=&quot;http://instagram-engineering.tumblr.com/post/13649370142/what-powers-instagram-hundreds-of-instances&quot;&gt;still only a group of a dozen or so
people&lt;/a&gt;. Dropbox in 2011 &lt;a href=&quot;http://www.forbes.com/sites/victoriabarret/2011/10/18/dropbox-the-inside-story-of-techs-hottest-startup/&quot;&gt;only had 70
engineers&lt;/a&gt;, and other teams were similarly lean. So, can
Python scale to large teams?&lt;/p&gt;
&lt;p&gt;Bank of America actually has &lt;a href=&quot;http://news.efinancialcareers.com/us-en/173476/investment-banking-tech-guru-quits-starts-firm/&quot;&gt;over 5,000 Python
developers, with over 10 million lines of Python in one
project alone&lt;/a&gt;. JP Morgan underwent &lt;a href=&quot;http://www.quora.com/When-why-and-to-what-extent-did-Bank-of-America-rebuild-its-entire-tech-stack-with-Python&quot;&gt;a similar
transformation&lt;/a&gt;. YouTube also has engineers in the
thousands and lines of code &lt;a href=&quot;http://highscalability.com/blog/2012/3/26/7-years-of-youtube-scalability-lessons-in-30-minutes.html&quot;&gt;in the millions&lt;/a&gt;. Big
products and big teams use Python every day, and while it has excellent
modularity and packaging characteristics, beyond a certain point
much of the general development scaling advice stays the same.
Tooling, strong conventions, and code review are what make big
projects a manageable reality.&lt;/p&gt;
&lt;p&gt;Luckily, Python starts with a good baseline on those fronts as
well. We use &lt;a href=&quot;https://github.com/pyflakes/pyflakes/&quot;&gt;PyFlakes&lt;/a&gt; and &lt;a href=&quot;https://pypi.python.org/pypi/flake8&quot;&gt;other tools&lt;/a&gt; to perform
static analysis of Python code before it gets checked in, as well as
adhering to &lt;a href=&quot;https://www.python.org/dev/peps/pep-0008/&quot;&gt;PEP8&lt;/a&gt;, Python&#x27;s language-wide base style guide.&lt;/p&gt;
&lt;p&gt;Finally, it should be noted that, in addition to the scheduling
speedups mentioned in &lt;a href=&quot;http://sedimental.org/10_myths_of_enterprise_python.html#myth-6&quot;&gt;Myth #6&lt;/a&gt; and &lt;a href=&quot;http://sedimental.org/10_myths_of_enterprise_python.html#myth-7&quot;&gt;#7&lt;/a&gt;, projects
using Python generally require fewer developers, as well. Our most
common success story starts with a Java or C++ project slated to take
a team of 3-5 developers somewhere between 2-6 &lt;em&gt;months&lt;/em&gt;, and ends with
a single motivated developer completing the project in 2-6
&lt;strong&gt;weeks&lt;/strong&gt;. It&#x27;s not unheard of for some projects to take hours instead
of weeks, as well.&lt;/p&gt;
&lt;p&gt;A miracle for some, but a fact of modern development, and often a
necessity for a competitive business.&lt;/p&gt;
&lt;h3 id=&quot;a_clean_slate&quot;&gt;&lt;a href=&quot;#a_clean_slate&quot; class=&quot;toclink&quot;&gt;A clean slate&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Mythology can be a fun pastime. Discussions around these myths remain
some of the most active and educational, both internally and
externally, because implied in every myth is a recognition of Python&#x27;s
strengths. Also, remember that the appearance of these seemingly tedious
and troublesome concerns is a sign of steadily growing interest, and
with steady influx of interested parties comes the constant job of
education. Here&#x27;s hoping that this post manages to extinguish a flame
war and enable a project or two to talk about the real work that can
be achieved with Python.&lt;/p&gt;
&lt;p&gt;Keep an eye out for future posts where I&#x27;ll dive deeper into the
details touched on in this overview. If you absolutely must have
details before then, shoot me an email at mahmoud@paypal.com. Until
then, happy coding!&lt;p&gt;&lt;/p&gt;



&lt;hr /&gt;

</content>

  </entry>
  
  <entry>
    <id>http://sedimental.org/designing_a_fast.html</id>
    <author>
      <name>Mahmoud Hashemi</name>
      <uri>http://sedimental.org/</uri>
    </author>
    <title>Designing a fast</title>
    <link rel="alternate" type="text/html" href="http://sedimental.org/designing_a_fast.html" />
    <published>2015-07-16T07:00:00Z</published>
    <updated>2015-07-16T07:00:00Z</updated>
    <category term="life"/><category term="design"/><category term="islam"/>
    

    <content type="html">&lt;p&gt;&lt;p&gt;I wake up with a jolt, spilling most of my breakfast cereal onto a
thirsty couch. My eyes find the clock. Cleaning will have to wait. I&#x27;m
downing water like there&#x27;s no tomorrow, but really tomorrow starts in
one minute. Still drinking. All work is thirsty work if the day is
long enough, and engineering is no exception. Time&#x27;s up.&lt;/p&gt;
&lt;p&gt;From the literal break of dawn to sunset, no food, drink, or other
respite. It&#x27;s &lt;a href=&quot;https://en.wikipedia.org/wiki/Ramadan&quot;&gt;Ramadan&lt;/a&gt;. What does this mean, practically?
Well, summertime here in Silicon Valley, it means from 4am to 9pm, I
battle human nature while writing emails and software. But, far from
an antiquated ritual, I see Ramadan as an exercise in lifestyle
design.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.flickr.com/photos/mahmoudhashemi/15900668295/in/album-72157647187331183/&quot;&gt;
&lt;img src=&quot;http://sedimental.org/uploads/silicon_valley_pano_1_med.jpg&quot; width=&quot;100%&quot; title=&quot;The South Bay packs nearly 500 hours of summertime sun into one month. Oh, goodie.&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;As we near the end of Ramadan &lt;a href=&quot;https://en.wikipedia.org/wiki/Islamic_calendar&quot;&gt;1436&lt;/a&gt;, this year has
proven that even in modern and diverse environs, every year brings the
same reactions and questions as 1435. Mostly boiling down to:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;http://sedimental.org/designing_a_fast.html#what-not-even-water&quot;&gt;&quot;What? Not even water?&quot;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://sedimental.org/designing_a_fast.html#why&quot;&gt;&quot;Why?&quot;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://sedimental.org/designing_a_fast.html#how&quot;&gt;&quot;How?&quot;&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;what_not_even_water&quot;&gt;&lt;a href=&quot;#what_not_even_water&quot; class=&quot;toclink&quot;&gt;What? Not even water?&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;A bit facetious, but this really is the most common question I get. So
just to be clear, traditional interpretation calls for no food, drink
(including water), or drugs. From the crack of dawn to sunset. Or
&lt;a href=&quot;http://www.wunderground.com/sky/ShowSky.asp?TheLat=37.34486389&amp;amp;TheLon=-121.88478088&amp;amp;TimeZoneName=America/Los_Angeles&quot;&gt;in the technical terms&lt;/a&gt;, the beginning of sunrise&#x27;s
&lt;a href=&quot;https://en.wikipedia.org/wiki/Twilight#Astronomical_twilight&quot;&gt;astronomical twilight&lt;/a&gt; to the beginning of sunset&#x27;s
&lt;a href=&quot;https://en.wikipedia.org/wiki/Twilight#Civil_twilight&quot;&gt;civil twilight&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Individuals adjust according to limitations. If you&#x27;re not healthy
enough to fast, you don&#x27;t fast. If you feel like you can&#x27;t complete a
fast, you don&#x27;t. If the &lt;a href=&quot;http://www.theatlantic.com/international/archive/2013/07/how-to-fast-for-ramadan-in-the-arctic-where-the-sun-doesnt-set/277834/&quot;&gt;sun doesn&#x27;t set&lt;/a&gt;, just do
something reasonable. Your intentions are your own, and self-harm does
not enter into the purposes of Ramadan.&lt;/p&gt;
&lt;h2 id=&quot;why&quot;&gt;&lt;a href=&quot;#why&quot; class=&quot;toclink&quot;&gt;Why?&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Everyone has their reasons, but first off Ramadan is not some sort of
collective diet. Yes, Ramadan is used by many as a springboard to
stymie smoking, overeating, and other unhealthy physical habits. But
for me, fasting is about building four virtues:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Empathy&lt;/li&gt;
&lt;li&gt;Reflection&lt;/li&gt;
&lt;li&gt;Discipline&lt;/li&gt;
&lt;li&gt;Confidence&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Not exactly the stuff of classrooms and annual compliance
trainings. And yet people are expected to just find these
characteristics within themselves, even in environments most
antithetical. Countless well-compensated designers and engineers know
about the limits of limitless life. We almost immediately
&lt;a href=&quot;http://www.fastcompany.com/3027379/work-smart/the-psychology-of-limitations-how-and-why-constraints-can-make-you-more-creative&quot;&gt;pine&lt;/a&gt; &lt;a href=&quot;http://tympanus.net/codrops/2011/10/28/be-more-creative-through-design-constraints/&quot;&gt;for&lt;/a&gt;
&lt;a href=&quot;https://medium.com/the-year-of-the-looking-glass/constraints-are-hard-23a05df9bdce&quot;&gt;constraints&lt;/a&gt;. &lt;a href=&quot;https://en.wikipedia.org/wiki/Negative_liberty&quot;&gt;Negative liberty&lt;/a&gt; only goes so
far, then real freedom becomes about the ability to formulate and
follow the orders you give yourself. Design grants creative autonomy,
but design tools offer a hundred possibilities draped in a thousand
distractions.&lt;/p&gt;
&lt;p&gt;Empathy is the most obvious trait built by fasting, and the one
promoted most when I was younger. There are poor people in the world,
and all should experience their hunger and thirst to
understand. Fasting puts you on the path closest to the one they walk,
building a visceral empathy that simple imagination can&#x27;t match. When
was the last time you were &lt;a href=&quot;https://www.youtube.com/watch?v=oOg5VxrRTi0&quot;&gt;hungry like the wolf&lt;/a&gt;? One
month of senses too sharp for civil society. One month of feeling the
natural appetites object and interrupt your every thought. But it
keeps one connected to so many people, from the most
&lt;a href=&quot;https://en.wikipedia.org/wiki/List_of_hunger_strikes&quot;&gt;intense protesters&lt;/a&gt; to as many as
&lt;a href=&quot;http://www.feedingamerica.org/hunger-in-america/impact-of-hunger/child-hunger/child-hunger-fact-sheet.html&quot;&gt;a fifth of&lt;/a&gt; &lt;a href=&quot;http://people.uwec.edu/jamelsem/papers/healthy_lunch/taras_nutrition_paper.pdf&quot;&gt;American students&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Reflection is critical to the Ramadan fast. Take away food and water,
and within a few hours you&#x27;re transported to the banks of a personal
&lt;a href=&quot;https://en.wikipedia.org/wiki/Walden&quot;&gt;Walden Pond&lt;/a&gt;. In much the same way that exercise burns off dirty,
anxious energy, fasting stops it from being produced in the first
place. It quiets the shores of one&#x27;s psyche and in the stillness, all
is clear. This is the part of Ramadan I look forward to most: a
staycation from my usual self-imposed obligations. The line between
essential and unnecessary is bright. I don&#x27;t know much about
meditation, but most days of the month, around sunset, I find a
certain peaceful state, every thought sorted away in its right place.&lt;/p&gt;
&lt;p&gt;Midday is another story. Shouldering a normal workload with the added
constraint of a fast is the definition of a stress test. Except unlike
software and other commonly-tested constructs, the systems at work
here involved grow and strengthen naturally. During Ramadan, I
stockpile this discipline to burn over the next 11 months. Discipline
complements motivation, especially with creative work like software
and architecture. Whereas frustration obviates motivation, &lt;a href=&quot;http://www.wisdomination.com/screw-motivation-what-you-need-is-discipline/&quot;&gt;discipline
rises to the occasion&lt;/a&gt;, grateful for the opportunity to push through
and grow.&lt;/p&gt;
&lt;!-- It&#x27;s a bit crude for direct linking, but I didn&#x27;t have time to find a better one --&gt;

&lt;p&gt;All of the above pours into the last attribute. Confidence is deeply
linked to feelings of sufficiency: the ability to say, &quot;What I have is
enough to do what I want to do.&quot; I&#x27;m a big fan of water myself, but
even something as essential as hydration isn&#x27;t as &lt;a href=&quot;https://www.kickstarter.com/projects/905031711/trago-the-worlds-first-smart-water-bottle&quot;&gt;big&lt;/a&gt;
&lt;a href=&quot;https://www.kickstarter.com/projects/582920317/hidrateme-smart-water-bottle?ref=video&quot;&gt;a deal&lt;/a&gt; &lt;a href=&quot;https://en.wikipedia.org/wiki/Vessyl&quot;&gt;as we make it&lt;/a&gt;. My adolescent fascination
with basketball was rooted in
&lt;a href=&quot;http://www.thenational.ae/sport/north-american-sport/ramadan-or-not-hakeem-olajuwon-a-dominant-force-in-nba&quot;&gt;Hakeem Olajuwon playing whole NBA games&lt;/a&gt; against the Chicago
Bulls, 12 hours into a fast. More recently,
&lt;a href=&quot;http://www.ibtimes.co.uk/ramadan-2014-did-algeria-lose-germany-because-their-players-were-fasting-1454792&quot;&gt;a fasting Algeria played a strong World Cup game&lt;/a&gt; against
winners-to-be Germany. People thirst for confidence, not
water. Ramadan is a reminder that personal excess breeds
anxiety. Consumerism&#x27;s advertising immerses us in false
dependence. Ramadan is the gentle reaffirmation you send yourself
that, yes, &lt;em&gt;you&lt;/em&gt; can do more with less.&lt;/p&gt;
&lt;h2 id=&quot;how&quot;&gt;&lt;a href=&quot;#how&quot; class=&quot;toclink&quot;&gt;How?&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;At this point, the &lt;em&gt;how&lt;/em&gt; is more of a logistical appendix, but this
year&#x27;s approach was particularly successful. Each year, Ramadan&#x27;s
approach gets me nervous. No matter how many times I fast, despite
having survived and thrived not one year ago, I still get skittish at
the thought of it. I focus in on the circumstances new to the year,
and can&#x27;t help tweaking my design.&lt;/p&gt;
&lt;p&gt;Everyone has different lives and schedules, but my Ramadan unfolds in
three phases:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Phase 1: Just make it through in one piece. The first 4-5 days.&lt;/li&gt;
&lt;li&gt;Phase 2: Requires a conscious and concerted effort. The middle twenty days or so.&lt;/li&gt;
&lt;li&gt;Phase 3: The fast is the new normal. Usually just the last few days of the month.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;My Ramadan technique goes into effect from day 1. It can be a rough
transition, involving some falling asleep while eating cereal, but the
long-day summer technique has been perfected over years. Granted, its
design leans on the unique schedule afforded a young software
engineer. Not everyone can switch away from a standard
work-a-day-sleep-at-night schedule. The median practicing Western
Muslim probably approaches Ramadan like this:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Get to work at 9am.&lt;/li&gt;
&lt;li&gt;Work til 5pm.&lt;/li&gt;
&lt;li&gt;Get home at 6pm. Cook, clean, tend to kids.&lt;/li&gt;
&lt;li&gt;Eat at 9pm.&lt;/li&gt;
&lt;li&gt;Sleep around midnight.&lt;/li&gt;
&lt;li&gt;Wake up before 4am, eat again.&lt;/li&gt;
&lt;li&gt;Sleep until 6-8am.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Straightforward enough, but far from optimal. There&#x27;s no period
of sleep longer than 4 hours, which leaves my energy on a different
valence altogether. For the last three years, I&#x27;ve improved on the
naïve solution, by switching to a &lt;a href=&quot;https://en.wikipedia.org/wiki/Segmented_sleep&quot;&gt;bimodal sleep schedule&lt;/a&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Get to work around 11am.&lt;/li&gt;
&lt;li&gt;Skip lunch, hit the books til 5-6pm.&lt;/li&gt;
&lt;li&gt;Get home, take a long nap at 7pm. This last bit would just be
  clockwatching anyways.&lt;/li&gt;
&lt;li&gt;Wake up at 9pm. Dinner for breakfast!&lt;/li&gt;
&lt;li&gt;Read, write, and code for the next 6 hours.&lt;/li&gt;
&lt;li&gt;3:45am. Eat breakfast, taking care not to fall asleep.&lt;/li&gt;
&lt;li&gt;Sleep through til 10am and repeat.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;It&#x27;s a fun change of pace. If the workday seems short, keep in mind
that there are no meal or snack breaks, so it evens out. Similarly,
there&#x27;s a lot of new time discovered in these quiet, contemplative
nights. Overall my energy, while restricted, stays predictable and
manageable. I&#x27;m no Hakeem Olajuwon or Algerian footballist, but this
year I managed to continue to bike everywhere, several times riding 6
to 15 miles per day. Other innovations this year have included playing
violin to stay awake and just eating a small bowl of raisin bran for
breakfast. Eating less is unintuitive, but I wake up less thirsty than
trying to cram in more calories, and hunger is easier to manage than
thirst. Oh, and
&lt;span title=&quot;aka sparkling water aka the original 0-calorie beverage&quot;&gt;bubble water&lt;/span&gt;.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://sedimental.org/uploads/bubble_water.jpg&quot;&gt;
&lt;img src=&quot;http://sedimental.org/uploads/bubble_water.jpg&quot; width=&quot;100%&quot; title=&quot;Bubble water: It&#x27;s good for sippin!™&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;!-- After a 17-hour day, your body greets food and water like parched
earth does rain. Unfamiliar, no matter how much water you drink, it
takes at least an hour before you begin to feel hydrated again. --&gt;

&lt;p&gt;Sometimes during the day I&#x27;d find myself impatient, checking the
calendar to see how many days are left. But just as many times at
night I&#x27;ve caught myself lamenting the quickness with which my split
days have slid past. With &lt;a href=&quot;https://en.wikipedia.org/wiki/Eid_al-Fitr&quot;&gt;Eid-ul-Fitr&lt;/a&gt; right around the
corner, I must admit I am pleased with the special satisfaction
brought by another year, another fast well designed.&lt;p&gt;&lt;/p&gt;



&lt;hr /&gt;

</content>

  </entry>
  
  <entry>
    <id>http://sedimental.org/colophon.html</id>
    <author>
      <name>Mahmoud Hashemi</name>
      <uri>http://sedimental.org/</uri>
    </author>
    <title>Colophon</title>
    <link rel="alternate" type="text/html" href="http://sedimental.org/colophon.html" />
    <published>2015-05-01T07:00:00Z</published>
    <updated>2015-05-01T07:00:00Z</updated>
    <category term="meta"/><category term="code"/>
    

    <content type="html">&lt;p&gt;&lt;p&gt;Most blogs, like this one, are reverse-chronological,
causing the first post to appear last in the archive. This convention
makes a &lt;a href=&quot;https://en.wiktionary.org/wiki/colophon&quot;&gt;colophon&lt;/a&gt; the &lt;a href=&quot;https://en.wikipedia.org/wiki/King&#x27;s_Pawn_Game&quot;&gt;King&#x27;s Pawn Game&lt;/a&gt; of web
authorship; there&#x27;s no better place to showcase certain implementation
details than the first post of a blog.&lt;/p&gt;
&lt;p&gt;This site is generated with &lt;a href=&quot;https://github.com/mahmoud/chert&quot;&gt;Chert&lt;/a&gt;&lt;sup id=&quot;fnref:pronounce&quot;&gt;&lt;a class=&quot;footnote-ref&quot; href=&quot;http://sedimental.org/colophon.html#fn:pronounce&quot;&gt;1&lt;/a&gt;&lt;/sup&gt;, an
open-source static site generator built with &lt;a href=&quot;http://python.org&quot;&gt;Python&lt;/a&gt;,
&lt;a href=&quot;https://en.wikipedia.org/wiki/Markdown&quot;&gt;Markdown&lt;/a&gt;&lt;sup id=&quot;fnref:emd&quot;&gt;&lt;a class=&quot;footnote-ref&quot; href=&quot;http://sedimental.org/colophon.html#fn:emd&quot;&gt;2&lt;/a&gt;&lt;/sup&gt;, &lt;a href=&quot;https://github.com/mahmoud/ashes&quot;&gt;ashes&lt;/a&gt;, &lt;a href=&quot;http://pygments.org/&quot;&gt;pygments&lt;/a&gt;, and
&lt;a href=&quot;https://en.wikipedia.org/wiki/YAML&quot;&gt;YAML&lt;/a&gt;. Chert is named for a very common &lt;a href=&quot;https://en.wikipedia.org/wiki/Chert&quot;&gt;fine-grained
sedimentary rock&lt;/a&gt;, often referred to as &lt;em&gt;flint&lt;/em&gt;, which has
been of critical use to firestarters through the ages.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;(Keep an eye out for a forthcoming, longer entry on why I built Chert
and what makes it different.)&lt;/em&gt;&lt;/p&gt;
&lt;div class=&quot;footnote&quot;&gt;
&lt;hr /&gt;
&lt;ol&gt;
&lt;li id=&quot;fn:pronounce&quot;&gt;
&lt;p&gt;English pronunciation rhymes with &lt;em&gt;dirt&lt;/em&gt;,
maintainer/Farsi pronunciation: &lt;em&gt;chair&lt;/em&gt; with a &lt;em&gt;t&lt;/em&gt; at the end. &lt;a class=&quot;footnote-backref&quot; href=&quot;http://sedimental.org/colophon.html#fnref:pronounce&quot; title=&quot;Jump back to footnote 1 in the text&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;fn:emd&quot;&gt;
&lt;p&gt;Enhanced Markdown, including support for
&lt;a href=&quot;https://python-markdown.github.io/extensions/footnotes/&quot;&gt;footnotes&lt;/a&gt;, &lt;a href=&quot;https://python-markdown.github.io/extensions/definition_lists/&quot;&gt;definition lists&lt;/a&gt;, and &lt;a href=&quot;https://python-markdown.github.io/extensions/toc/&quot;&gt;tables of
contents&lt;/a&gt;. &lt;a class=&quot;footnote-backref&quot; href=&quot;http://sedimental.org/colophon.html#fnref:emd&quot; title=&quot;Jump back to footnote 2 in the text&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;&lt;p&gt;&lt;/p&gt;



&lt;hr /&gt;

</content>

  </entry>
  
</feed>
