<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Daniel Brady</title>
    <description>The latest articles on Forem by Daniel Brady (@daniel13rady).</description>
    <link>https://forem.com/daniel13rady</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F290298%2F323cf2b8-0760-4fd4-a640-4c8328c81fff.jpeg</url>
      <title>Forem: Daniel Brady</title>
      <link>https://forem.com/daniel13rady</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/daniel13rady"/>
    <language>en</language>
    <item>
      <title>Guarding Makefile targets</title>
      <dc:creator>Daniel Brady</dc:creator>
      <pubDate>Thu, 23 Jul 2020 03:44:58 +0000</pubDate>
      <link>https://forem.com/daniel13rady/guarding-makefile-targets-1nb8</link>
      <guid>https://forem.com/daniel13rady/guarding-makefile-targets-1nb8</guid>
      <description>&lt;p&gt;This may just be my favorite one liner of my own devising in recent years.&lt;/p&gt;

&lt;p&gt;I love it because of a combination of its utility (🔧), the story behind how it works (💭), and its power to induce headaches to its readers (😅).&lt;/p&gt;

&lt;p&gt;It belongs in a &lt;code&gt;Makefile&lt;/code&gt; :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight make"&gt;&lt;code&gt;&lt;span class="c"&gt;## Returns true if the stem is a non-empty environment variable, or else raises an error.
&lt;/span&gt;&lt;span class="nl"&gt;guard-%&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
  &lt;span class="err"&gt;@&lt;/span&gt;&lt;span class="c"&gt;#$(or ${$*}, $(error $* is not set))
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And has a simple function:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;➜  make guard-FOO
Makefile:12: &lt;span class="k"&gt;***&lt;/span&gt; FOO is not set.  Stop.
➜  &lt;span class="nv"&gt;FOO&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;42 make guard-FOO
➜
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Deciphering from top to bottom, left to right:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The &lt;code&gt;%&lt;/code&gt; symbol used in the target declaration a “static pattern wildcard”, and in more familiar regex terms it translates to &lt;code&gt;guard-(.*)&lt;/code&gt; ; the “stem” of the pattern, i.e. the value of the match group, is stored in &lt;a href="https://www.gnu.org/software/make/manual/html_node/Automatic-Variables.html" rel="noopener noreferrer"&gt;an automatic variable&lt;/a&gt; called &lt;code&gt;$*&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;@&lt;/code&gt; prefix &lt;a href="https://www.gnu.org/software/make/manual/html_node/Echoing.html" rel="noopener noreferrer"&gt;prevents &lt;code&gt;make&lt;/code&gt; from printing out&lt;/a&gt; the command it is about to evaluate. (&lt;em&gt;Hint&lt;/em&gt;: Take this away to actually see what’s happening.)&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;#&lt;/code&gt; is your typical &lt;a href="https://www.tldp.org/LDP/abs/html/special-chars.html" rel="noopener noreferrer"&gt;shell comment character&lt;/a&gt;: anything that comes after it will be interpreted by the shell (and &lt;code&gt;make&lt;/code&gt;) as a comment, and thus ignored in a "truthy" way.&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;$(or …, …, ...)&lt;/code&gt; is a &lt;a href="https://www.gnu.org/software/make/manual/html_node/Conditional-Functions.html" rel="noopener noreferrer"&gt;&lt;code&gt;make&lt;/code&gt; short-circuiting conditional function&lt;/a&gt;: it &lt;em&gt;expands&lt;/em&gt; each item until it finds one that expands to a non-empty string, at which point it stops processing and returns the expansion. (&lt;em&gt;Note&lt;/em&gt;: It does not &lt;em&gt;evaluate&lt;/em&gt; it.)&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;${…}&lt;/code&gt; notation is the &lt;code&gt;make&lt;/code&gt; syntax for &lt;a href="https://www.gnu.org/software/make/manual/html_node/Reference.html#Reference" rel="noopener noreferrer"&gt;evaluating a variable&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;$*&lt;/code&gt; as mentioned previously, holds the value of the matched pattern in the target name.&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;$(error ...)&lt;/code&gt; is a &lt;a href="https://www.gnu.org/software/make/manual/html_node/Make-Control-Functions.html" rel="noopener noreferrer"&gt;&lt;code&gt;make&lt;/code&gt; control-flow form&lt;/a&gt;, and raises an error &lt;em&gt;as soon as it is evaluated&lt;/em&gt;, after allowing for its arguments to be expanded.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So, putting it all together: &lt;code&gt;FOO=42 make guard-FOO&lt;/code&gt; expands to:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;#$(or ${FOO}, $(error FOO is not set))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;which in turn expands to:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;#$(or 42, $(error FOO is not set))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;which, finally, expands to:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;#42&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;which is evaluated by the shell as a comment and ignored, but in a truthy way.&lt;/p&gt;

&lt;p&gt;However, &lt;code&gt;make guard-FOO&lt;/code&gt;  expands to:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;#$(or ${FOO}, $(error FOO is not set))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and then:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;#$(or , $(error FOO is not set))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and then:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;#$(error FOO is not set)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and then a fatal error.&lt;/p&gt;

&lt;p&gt;The value of this is as a &lt;em&gt;prerequisite&lt;/em&gt; for other targets, to easily guard against missing environment variables, e.g.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight make"&gt;&lt;code&gt;&lt;span class="nl"&gt;say-something&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;guard-SOMETHING&lt;/span&gt;
  &lt;span class="err"&gt;echo&lt;/span&gt; &lt;span class="err"&gt;${SOMETHING}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;➜ make say-something
Makefile:12: &lt;span class="k"&gt;***&lt;/span&gt; SOMETHING is not set.  Stop.
➜ &lt;span class="nv"&gt;SOMETHING&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'Hello, world!'&lt;/span&gt; make say-something
&lt;span class="nb"&gt;echo &lt;/span&gt;Hello, world!
Hello, world!
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>bash</category>
      <category>programming</category>
    </item>
    <item>
      <title>Have you ever tried implementing a language spec?</title>
      <dc:creator>Daniel Brady</dc:creator>
      <pubDate>Mon, 24 Feb 2020 10:34:00 +0000</pubDate>
      <link>https://forem.com/daniel13rady/have-you-ever-tried-implementing-a-language-spec-1205</link>
      <guid>https://forem.com/daniel13rady/have-you-ever-tried-implementing-a-language-spec-1205</guid>
      <description>&lt;p&gt;Recently I was reading through Safia(&lt;a class="mentioned-user" href="https://dev.to/captainsafia"&gt;@captainsafia&lt;/a&gt;)'s post, where they dive into &lt;a href="https://www.ecma-international.org/ecma-262/10.0/#sec-array.prototype.filter" rel="noopener noreferrer"&gt;the JavaScript spec&lt;/a&gt; to discuss the implementation of the &lt;code&gt;Array.prototype.filter&lt;/code&gt; function:&lt;/p&gt;


&lt;div class="ltag__link"&gt;
  &lt;a href="/captainsafia" class="ltag__link__link"&gt;
    &lt;div class="ltag__link__pic"&gt;
      &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F37984%2F46b8bf0f-9fb1-4e3b-bd68-3590ea5737b4.jpeg" alt="captainsafia"&gt;
    &lt;/div&gt;
  &lt;/a&gt;
  &lt;a href="https://dev.to/captainsafia/the-fun-of-filter-according-to-the-ecmascript-spec-3ok8" class="ltag__link__link"&gt;
    &lt;div class="ltag__link__content"&gt;
      &lt;h2&gt;The fun of filter, according to the ECMAScript spec&lt;/h2&gt;
      &lt;h3&gt;Safia Abdalla ・ Jan 22 '20&lt;/h3&gt;
      &lt;div class="ltag__link__taglist"&gt;
        &lt;span class="ltag__link__tag"&gt;#javascript&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#spec&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#filter&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#array&lt;/span&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/a&gt;
&lt;/div&gt;


&lt;p&gt;Reading through the algorithm, I felt the urge to implement it. I guess I'm just programmed that way 😆&lt;/p&gt;

&lt;p&gt;I didn't, though. I've thought many times that it would be a fun challenge to implement a language spec, and a great way to learn about language design and the choices made by the creators of my tools. But I still have never tried.&lt;/p&gt;

&lt;p&gt;If you've tried, what was your experience like?&lt;br&gt;
If you haven't tried, why does or doesn't it sound like fun? 🤔&lt;/p&gt;

&lt;p&gt;(I'm asking specifically about implementing an &lt;em&gt;existing&lt;/em&gt; language spec; creating your own sounds fun, too, but not the topic I'm introducing for discussion in this post 😄 another time, perhaps!)&lt;/p&gt;

</description>
      <category>discuss</category>
      <category>language</category>
      <category>design</category>
      <category>thinkdeep</category>
    </item>
    <item>
      <title>syndicate: Harvesting Commits and Drafting to DEV</title>
      <dc:creator>Daniel Brady</dc:creator>
      <pubDate>Sun, 23 Feb 2020 19:44:00 +0000</pubDate>
      <link>https://forem.com/daniel13rady/syndicate-harvesting-commits-and-drafting-to-dev-1kkd</link>
      <guid>https://forem.com/daniel13rady/syndicate-harvesting-commits-and-drafting-to-dev-1kkd</guid>
      <description>&lt;p&gt;&lt;em&gt;I made this for people who write words they share with others:&lt;/em&gt;&lt;/p&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fassets.dev.to%2Fassets%2Fgithub-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/dabrady" rel="noopener noreferrer"&gt;
        dabrady
      &lt;/a&gt; / &lt;a href="https://github.com/dabrady/syndicate" rel="noopener noreferrer"&gt;
        syndicate
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      a simple implementation of the POSSE content publishing model
    &lt;/h3&gt;
  &lt;/div&gt;
&lt;/div&gt;


&lt;p&gt;&lt;em&gt;It distributes copies of the content you create to various publishing sites automatically.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;It took me a week of focused evenings and a weekend of dedicated hacking to polish it to my liking; and another week to write about it.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;This is how I did it.&lt;/em&gt;&lt;/p&gt;




&lt;p&gt;With the &lt;a href="https://github.com/dabrady/syndicate/tree/30fbc16d30212cf3f94c9644370e724d1050077c" rel="noopener noreferrer"&gt;skeleton of a project&lt;/a&gt; in place and &lt;a href="https://dev.to/daniel13rady/syndicate-prototype-requirements-and-design-455k"&gt;a clear direction&lt;/a&gt; to go in, I was ready to get started in earnest.&lt;/p&gt;

&lt;p&gt;I decided to get &lt;a href="https://docs.dev.to/api"&gt;the DEV.to API&lt;/a&gt; interactions working first, and then I would need to figure out how to harvest a &lt;code&gt;git&lt;/code&gt; commit for the actual input to DEV.&lt;/p&gt;

&lt;p&gt;Creating basic wrappers for the &lt;a href="https://github.com/dabrady/syndicate/blob/69b30c13bd02eb3223e27dc05693f1c32ce5ef47/syndicate/silos/dev.py#L33-L68" rel="noopener noreferrer"&gt;"create"&lt;/a&gt; and &lt;a href="https://github.com/dabrady/syndicate/blob/69b30c13bd02eb3223e27dc05693f1c32ce5ef47/syndicate/silos/dev.py#L70-L93" rel="noopener noreferrer"&gt;"update"&lt;/a&gt; end points of the DEV.to API went fairly smoothly and quickly: I'd already front-loaded the learning curve earlier with my &lt;a href="https://github.com/dabrady/syndicate/commit/30fbc16d30212cf3f94c9644370e724d1050077c#diff-cb2f5f82bf237a14ae65cba33e47ccf7" rel="noopener noreferrer"&gt;"fetch"&lt;/a&gt; implementation.&lt;/p&gt;

&lt;p&gt;Now came the bits which would prove to give me the most challenge in this project: doing things with &lt;code&gt;git&lt;/code&gt;. This is where the &lt;a href="https://help.github.com/en/actions/configuring-and-managing-workflows" rel="noopener noreferrer"&gt;Github Workflow&lt;/a&gt; and &lt;a href="https://help.github.com/en/actions/building-actions" rel="noopener noreferrer"&gt;Action documentation&lt;/a&gt; became truly valuable: it showed me that I had access to many &lt;code&gt;git&lt;/code&gt;-related things concerning the commit that triggered the workflow, exposed to my action in the form of &lt;a href="https://help.github.com/en/actions/configuring-and-managing-workflows/using-environment-variables" rel="noopener noreferrer"&gt;environment variables&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;For my purposes, the most valuable of these would turn out to be:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;the &lt;code&gt;GITHUB_TOKEN&lt;/code&gt; (used for &lt;a href="https://help.github.com/en/actions/configuring-and-managing-workflows/authenticating-with-the-github_token" rel="noopener noreferrer"&gt;authenticating requests&lt;/a&gt; to the Github API)&lt;/li&gt;
&lt;li&gt;the &lt;code&gt;GITHUB_SHA&lt;/code&gt; (the commit SHA that triggered the workflow)&lt;/li&gt;
&lt;li&gt;the &lt;code&gt;GITHUB_REPOSITORY&lt;/code&gt; (the full name of the repo containing the workflow)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It quickly became apparent that the actual contents of the commit which triggered the workflow were not available to me out of the box; I would need to get them myself, somehow. I had started this project expecting the only external APIs I'd be interacting with would be the ones for the silo platfroms I included support for; but this new development meant I needed to learn about &lt;a href="https://developer.github.com/v3/" rel="noopener noreferrer"&gt;the Github API&lt;/a&gt;, as well.&lt;/p&gt;

&lt;p&gt;If I had opted to use the Github API directly through the &lt;code&gt;requests&lt;/code&gt; package, like I was doing with the DEV.to API, I would have had a very different experience (though not necessarily a better or worse one). But I did not do that.&lt;/p&gt;

&lt;p&gt;Instead, I went looking for a Github-specific Python library to use. I don't remember why I chose this path, but it might have simply been because I knew so many Github extensions and integrations existed that there were bound to be some who had wrapped the Github API into an easier-to-consume Python library.&lt;/p&gt;

&lt;p&gt;And indeed there were several options to choose from. The first option advertised by the internet via Google was &lt;code&gt;PyGithub&lt;/code&gt;. But &lt;a href="https://pygithub.readthedocs.io/" rel="noopener noreferrer"&gt;the documentation felt terrible&lt;/a&gt;: a full half of the README was simply bragging about who was using the library and linking to people on the internet recommending it. For that reason alone, I almost immediately went searching for some other option.&lt;/p&gt;

&lt;p&gt;The package I decided to use was called &lt;code&gt;github3.py&lt;/code&gt;. By comparison, &lt;a href="https://github3py.readthedocs.io" rel="noopener noreferrer"&gt;the documentation felt wonderful&lt;/a&gt;, like the package authors actually cared about helping people understand the software, and not just each bit of code in isolation. (NOTE TO SELF: don't be a hypocrite, create a great ReadTheDocs site for &lt;code&gt;syndicate&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;But there was a problem: adding &lt;code&gt;github3.py&lt;/code&gt; to my project dependencies broke everything.&lt;/p&gt;

&lt;p&gt;The root cause, again, was that my Docker image did not create the environment necessary to support the code I was trying to run. I quickly discovered that switching from using &lt;code&gt;python:3-alpine&lt;/code&gt; back to &lt;code&gt;python:3&lt;/code&gt; resolved the build issues, though it also brought back the "this thing takes too damn long to build" problem. But I was impatient, so I decided to put up with the longer build times to unblock what felt like the "real project development" and deferred solving this performance problem until the end of the project.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;🐌🌸 &lt;strong&gt;Note From Future Me&lt;/strong&gt;&lt;br&gt;
&lt;small&gt;I would eventually switch from using &lt;code&gt;github3.py&lt;/code&gt; to using &lt;code&gt;PyGithub&lt;/code&gt; (which did not introduce the same build issues), and if I had just tried it out at this point instead of being so impatient to continue feature development, I could have saved myself a lot of time and self-induced frustration felt while waiting for my code to compile.&lt;/small&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;With the build back to a stable state, I finally began to tackle the challenge of figuring out how to transform a &lt;code&gt;git&lt;/code&gt; commit into a draft on DEV.to.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;github3.py&lt;/code&gt; API documentation is great, and I quickly figured out how to extract the contents of the added/changed files in the commit that had triggered the action. I realized, however, that I couldn't assume all the changed files in the commit were posts that needed syndication; I needed a way to identify the files the commiter &lt;em&gt;intended&lt;/em&gt; to syndicate.&lt;/p&gt;

&lt;p&gt;A quick and easy solution was to introduce a configuration variable for my Github action specifying a path prefix that could be used to distinguish 'posts' from other files in their repository. This has downsides: it assumes the author keeps all their posts in a particular location, and it assumes that all files in that particular location are posts.&lt;/p&gt;

&lt;p&gt;That said, it would suffice until it actually caused someone problems, so I went with that approach. I opted to make it an environment variable instead of an explicit input to the action because of how Github Workflows work: this value is static information about the repository, and my action might get used in multiple steps within the same workflow; using an environment variable allows it to be specified at a higher level than the individual action config if you want, which let's you share the value across a larger part of your workflow and avoid duplication.&lt;/p&gt;

&lt;p&gt;Now that I could accurately &lt;a href="https://github.com/dabrady/syndicate/blob/69b30c13bd02eb3223e27dc05693f1c32ce5ef47/syndicate/utils.py#L114-L128" rel="noopener noreferrer"&gt;identify "posts" in a given commit&lt;/a&gt;, I needed to be able to parse out the details necessary for the API call that would be made.&lt;/p&gt;

&lt;p&gt;To create a post, the only actual &lt;a href="https://docs.dev.to/api/index.html#operation/createArticle"&gt;data required by the DEV.to API&lt;/a&gt; is a title. Simple. Now that I could access everything about the files being syndicated, I could just grab their titles and contents, plug them into the API request, and win at life.&lt;/p&gt;

&lt;p&gt;But...wait. Where is the title of a post? 🤔&lt;/p&gt;

&lt;p&gt;An obvious, but probably poor, answer is "in the file name." I could already tell that going down that route would lead to pain and suffering, so I decided to make another assumption: my action would expect all posts to be written in Markdown, and contain a YAML frontmatter with at least a &lt;code&gt;title&lt;/code&gt; attribute.&lt;/p&gt;

&lt;p&gt;Given my initial target audience are those who write for DEV.to, and that is how posts are formatted there, it isn't as random of a choice as it might first appear. But still, I did not do any research on the prevalence of this format adoption, and that may come back to bite me in the future.&lt;/p&gt;

&lt;p&gt;But for the first iteration, it would do just fine. I now needed a way to parse YAML out of a string; I knew YAML is pretty widely used in software configuration, and Python is known for its usage in data processing, so I expected there to be a good library for working with it.&lt;/p&gt;

&lt;p&gt;And indeed there was. &lt;a href="https://pypi.org/project/PyYAML/" rel="noopener noreferrer"&gt;&lt;code&gt;PyYAML&lt;/code&gt;&lt;/a&gt; seemed canonical, from what I could tell, but it also seemed like overkill for my needs; plus, &lt;a href="https://pyyaml.org/wiki/PyYAMLDocumentation" rel="noopener noreferrer"&gt;the documentation was ugly and hard to use&lt;/a&gt; (again NOTE TO SELF: ugly docs discourage users). I kept searching, and in one of my queries I included the keyword 'frontmatter' and caught a lucky break: &lt;a href="https://python-frontmatter.readthedocs.io/" rel="noopener noreferrer"&gt;&lt;code&gt;python-frontmatter&lt;/code&gt;&lt;/a&gt; was a small library specifically for manipulating YAML metadata embedded within text documents, and perfect for my needs.&lt;/p&gt;

&lt;p&gt;At that point, it only took a bit of tinkering and &lt;a href="https://github.com/dabrady/syndicate/commit/49d7a062df17d4f7a93eef02d94a749245147cb4" rel="noopener noreferrer"&gt;suddenly I had something&lt;/a&gt; that would automatically push my newly created content to DEV.to as a draft, when I pushed it to my repo. It was time for my happy dance.&lt;/p&gt;

&lt;p&gt;But the game had only just begun: I now needed to determine if I'd previously created a draft for a given post in order to avoid creating duplicates, and set the stage for pushing updates to existing content if possible.&lt;/p&gt;

</description>
      <category>showdev</category>
      <category>python</category>
      <category>development</category>
    </item>
    <item>
      <title>syndicate: Prototype, Requirements and Design</title>
      <dc:creator>Daniel Brady</dc:creator>
      <pubDate>Sat, 22 Feb 2020 15:01:00 +0000</pubDate>
      <link>https://forem.com/daniel13rady/syndicate-prototype-requirements-and-design-455k</link>
      <guid>https://forem.com/daniel13rady/syndicate-prototype-requirements-and-design-455k</guid>
      <description>&lt;p&gt;&lt;em&gt;I made this for people who write words they share with others:&lt;/em&gt;&lt;/p&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fassets.dev.to%2Fassets%2Fgithub-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/dabrady" rel="noopener noreferrer"&gt;
        dabrady
      &lt;/a&gt; / &lt;a href="https://github.com/dabrady/syndicate" rel="noopener noreferrer"&gt;
        syndicate
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      a simple implementation of the POSSE content publishing model
    &lt;/h3&gt;
  &lt;/div&gt;
&lt;/div&gt;


&lt;p&gt;&lt;em&gt;It distributes copies of the content you create to various publishing sites automatically.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;It took me a week of focused evenings and a weekend of dedicated hacking to polish it to my liking; and another week to write about it.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;This is how I got started.&lt;/em&gt;&lt;/p&gt;




&lt;p&gt;After my &lt;a href="https://dev.to/daniel13rady/syndicate-initial-research-and-setup-1cmh"&gt;initial research and setup&lt;/a&gt;, I was eager to start spec'ing out the &lt;em&gt;actual&lt;/em&gt; thing I intended to build. I began by converting my implementation of the "Hello, world!" &lt;a href="https://help.github.com/en/actions/building-actions/creating-a-docker-container-action" rel="noopener noreferrer"&gt;Docker action tutorial&lt;/a&gt; into a Python project that would run in a Docker container.&lt;/p&gt;

&lt;p&gt;The first challenge I overcame was finding a Docker image that would actually run Python. As it turns out, the &lt;code&gt;alpine&lt;/code&gt; image used in the tutorial does not come with Python installed, so I needed to either install it myself or look for a different container that came with it. I opted for the second approach first, and a simple search of "python Docker image" led me to...the &lt;a href="https://hub.docker.com/_/python" rel="noopener noreferrer"&gt;&lt;code&gt;python&lt;/code&gt; Docker image&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;At first, I simply swapped out my &lt;code&gt;alpine&lt;/code&gt; image for the &lt;code&gt;python:3&lt;/code&gt; image, but that significantly increased the action build time (by 2 or 3x 😬) so I was immediately skeptical of using it. Luckily, I decided to read beyond the "How to use this image" section of the documentation, and discovered there were a couple of 'light-weight' versions. Since I didn't yet have any project dependencies, I decided to try using &lt;code&gt;python:3-alpine&lt;/code&gt; because of its boasted performance characterisics, and then forget about it until it no longer worked. It did the thing, and my base build time was only about 6 seconds.&lt;/p&gt;

&lt;p&gt;Now that I had a Github Action building a container that could run Python, I needed to figure out how to use the &lt;a href="https://docs.dev.to/api"&gt;DEV.to API&lt;/a&gt; I had discovered earlier. But more importantly, I needed to figure out how to do it &lt;strong&gt;in Python&lt;/strong&gt;, ideally using some sort of standard or canonical library.&lt;/p&gt;

&lt;p&gt;The &lt;a href="https://requests.readthedocs.io/" rel="noopener noreferrer"&gt;&lt;code&gt;requests&lt;/code&gt;&lt;/a&gt; package was the answer, quickly found, and its documentation was to become the third and final sacred text in my project's development.&lt;/p&gt;

&lt;p&gt;I started to familiarize myself with &lt;code&gt;requests&lt;/code&gt; and the DEV.to API by transforming my existing action code into a simple prototype. Given my inexperience in basically everything about this project, I decided to start out building something that would react to pushing a commit to my Github repository by fetching my posts from DEV.to and logging out their titles. Reading from DEV was the simplest interaction with the API that seemed like it would also make for a good exercise.&lt;/p&gt;

&lt;p&gt;Once I got that working, I thought about whether I would actually need that functionality in &lt;code&gt;syndicate&lt;/code&gt;. It wasn't clear at that point, because I hadn't actually done any design work for the project yet.&lt;/p&gt;

&lt;p&gt;I decided to spend time maturing this first bit of logic into an example for myself to follow later on, with respect to using the DEV API and &lt;code&gt;requests&lt;/code&gt; package properly. I would include things like request authentication, input validation, error and failed request handling, testing, and logging.&lt;/p&gt;

&lt;p&gt;This decision proved quite valuable. It gave me a small but wholistic exercise in which I figured out how my overall application logic might flow, and learned things like how to print to the Github Workflow log; how to read information from the Github Workflow environment; and how to use Pytest to write specifications for my code.&lt;/p&gt;

&lt;p&gt;By the end of that exercise, I had:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://github.com/dabrady/syndicate/blob/30fbc16d30212cf3f94c9644370e724d1050077c/.github/workflows/main.yml" rel="noopener noreferrer"&gt;a Github Workflow definition&lt;/a&gt; that used my action and provided it with a list of platforms to publsh to, along with the API keys required for using their APIs&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/dabrady/syndicate/blob/30fbc16d30212cf3f94c9644370e724d1050077c/entrypoint.py" rel="noopener noreferrer"&gt;an entrypoint for the Docker container&lt;/a&gt; that invoked my 'main' Python application with any arguments specified by the Github Workflow&lt;/li&gt;
&lt;li&gt;a small but functional Python module called 'syndicate' which defined &lt;a href="https://github.com/dabrady/syndicate/blob/30fbc16d30212cf3f94c9644370e724d1050077c/syndicate/__init__.py#L8-L27" rel="noopener noreferrer"&gt;a single function, &lt;code&gt;elsewhere&lt;/code&gt;&lt;/a&gt;, responsible for basic input validation, delegation to the appropriate syndication code, and final reporting&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/dabrady/syndicate/blob/30fbc16d30212cf3f94c9644370e724d1050077c/syndicate/silos/dev.py#L14-L42" rel="noopener noreferrer"&gt;a function that fetched and returned my published posts&lt;/a&gt; from DEV.to using the API key provided by the Github Workflow&lt;/li&gt;
&lt;li&gt;the beginnings of &lt;a href="https://github.com/dabrady/syndicate/blob/30fbc16d30212cf3f94c9644370e724d1050077c/syndicate/utils.py" rel="noopener noreferrer"&gt;a utility library&lt;/a&gt;, with functions that handled printing to the Github Workflow log at various log levels&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/dabrady/syndicate/blob/30fbc16d30212cf3f94c9644370e724d1050077c/tests/test_dev.py" rel="noopener noreferrer"&gt;a small test suite&lt;/a&gt; for my DEV 'fetch' logic&lt;/li&gt;
&lt;li&gt;a fully polished and tested example of how to interact with the DEV.to API via the &lt;code&gt;requests&lt;/code&gt; package&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And let's not overlook the experience gained using Python itself!&lt;/p&gt;

&lt;p&gt;I was happy with my prototype, and I had learned many useful things. At this point, I paused development to take stock of where I was and where I needed to go.&lt;/p&gt;

&lt;p&gt;I spent an evening working on a set of initial requirements and high-level technical design for the actual thing I wanted to build, and this is what I came up with:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Initial Requirements&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;My MVP (and possibly first release) would only support DEV.to&lt;/li&gt;
&lt;li&gt;It needed to be easy to add support for publishing to new platforms&lt;/li&gt;
&lt;li&gt;Given a Markdown file, it needed to be able to create a draft on DEV.to with its contents&lt;/li&gt;
&lt;li&gt;Given a (presumably changed) Markdown file previously syndicated to DEV.to, it needed to be able to replace the syndicated copy with the new version&lt;/li&gt;
&lt;li&gt;Given a commit that triggered a workflow using the &lt;code&gt;syndicate&lt;/code&gt; action, it needed to be able to identify and extract the contents of the added/modified files to syndicate from that commit&lt;/li&gt;
&lt;li&gt;It needed to be able to identify files that had been syndicated to a given silo previously, in order to decide whether to create a draft or push an update&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;High-level Tech Design&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;syndicate&lt;/code&gt; would be designed as a Github Action, to be incorporated into a Github Workflow for managing content syndication&lt;/li&gt;
&lt;li&gt;Inputs:

&lt;ul&gt;
&lt;li&gt;a list of 'silo' platforms to syndicate to&lt;/li&gt;
&lt;li&gt;any secrets required to use the APIs associated with the given silos&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;Outputs:

&lt;ul&gt;
&lt;li&gt;a summary of the files added/modified on each silo platform&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;Mechanisms for interacting with a particular silo should be encapsulated in their own 'adapter' files with a single point of entry; the &lt;code&gt;syndicate.elsewhere&lt;/code&gt; function would be responsible for engaging the appropriate adapters and aggregating the output&lt;/li&gt;

&lt;li&gt;Syndicated files would be 'tagged' with unique identifiers provided (presumably) by the silos themselves in the 'draft' API response; this tagging would allow the action to recognize files in the repo that already exist on a given silo&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;Seeing it laid out on paper (yes, that still exists) was getting me excited! I gutted the prototype I had created, keeping only the main structure and wiring along with some of the more useful code snippets as comments, and set to work.&lt;/p&gt;

</description>
      <category>showdev</category>
      <category>python</category>
      <category>thinkdeep</category>
      <category>development</category>
    </item>
    <item>
      <title>syndicate: Initial Research and Setup</title>
      <dc:creator>Daniel Brady</dc:creator>
      <pubDate>Sat, 22 Feb 2020 14:56:00 +0000</pubDate>
      <link>https://forem.com/daniel13rady/syndicate-initial-research-and-setup-1cmh</link>
      <guid>https://forem.com/daniel13rady/syndicate-initial-research-and-setup-1cmh</guid>
      <description>&lt;p&gt;&lt;em&gt;I made this for people who write words they share with others:&lt;/em&gt;&lt;/p&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fassets.dev.to%2Fassets%2Fgithub-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/dabrady" rel="noopener noreferrer"&gt;
        dabrady
      &lt;/a&gt; / &lt;a href="https://github.com/dabrady/syndicate" rel="noopener noreferrer"&gt;
        syndicate
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      a simple implementation of the POSSE content publishing model
    &lt;/h3&gt;
  &lt;/div&gt;
&lt;/div&gt;


&lt;p&gt;&lt;em&gt;It distributes copies of the content you create to various publishing sites automatically.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;It took me a week of focused evenings and a weekend of dedicated hacking to polish it to my liking; and another week to write about it.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;This is how I got started.&lt;/em&gt;&lt;/p&gt;




&lt;p&gt;In essence, the thing I wanted to build would take changes I made to files in a &lt;code&gt;git&lt;/code&gt; repo, and push them someplace else. Classic Patrick Star.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5un4pmjb3ng8pzuy0qd7.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5un4pmjb3ng8pzuy0qd7.gif" alt="Why don't we just take it and push it somewhere else?" width="480" height="442"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;One of my first questions was, "Can I communicate with DEV.to programmatically?" DEV.to is currently the only place I publish writing, so if the only answer involved pretending to be a human and programmatically engaging with the UI to manipulate blog posts, I was likely to abandon the idea (though I probably would have tried it just for fun).&lt;/p&gt;

&lt;p&gt;Thankfully, my project was saved by a quick Google search: DEV has a &lt;a href="https://docs.dev.to/api"&gt;beta API&lt;/a&gt; that exposes end points I could leverage.&lt;/p&gt;

&lt;p&gt;My next question was one of automation: how to trigger a DEV.to API call in response to changes in my &lt;code&gt;git&lt;/code&gt; repository? My immediate reaction was "&lt;code&gt;git&lt;/code&gt; hooks."&lt;/p&gt;

&lt;p&gt;I've played with &lt;code&gt;git&lt;/code&gt; hooks in the past for doing things like automatically &lt;a href="https://gist.github.com/dabrady/29b33ef867ca6f0c5d9a60ae5b36f7fc" rel="noopener noreferrer"&gt;injecting a JIRA ticket&lt;/a&gt; number into my commit messages when pushing; and automatically &lt;a href="https://gist.github.com/dabrady/4b9e57fb2529ca256dfb506dbb5103b1" rel="noopener noreferrer"&gt;running database migrations locally after pulling&lt;/a&gt; if the schema changed or migration files were added. They seemed like the perfect mechanism to use for this project.&lt;/p&gt;

&lt;p&gt;Recently, though, I noticed something called &lt;a href="https://github.com/features/actions" rel="noopener noreferrer"&gt;Actions&lt;/a&gt; show up on my Github repositories. I didn't really know what they were, but on the surface it seemed like a Github service implemented on top of &lt;code&gt;git&lt;/code&gt; hooks.&lt;/p&gt;

&lt;p&gt;I hadn't really imagined that the tool I would build might have any actual interface besides an automatic trigger. Thinking about Github Actions made me realize it would be nice to have my tool respond to changes on a &lt;em&gt;remote&lt;/em&gt; repository (i.e. on a &lt;code&gt;push&lt;/code&gt; command) and run on someone else's computer, rather than operating on a user's local machine; it would minimize "works on my machine ¯\_(ツ)_/¯" headaches when installing and using the tool itself. And it would be awesome to have some sort of interface for monitoring progress and output, and maybe even a logging mechanism.&lt;/p&gt;

&lt;p&gt;Github is my private choice of remote source control platform, so I looked into Actions and how to create them. I was pleasantly surprised at the extent of &lt;a href="https://help.github.com/en/actions" rel="noopener noreferrer"&gt;Github's documentation&lt;/a&gt; on the subject, and it would become the first of a few sacred texts I relied on throughout my project.&lt;/p&gt;

&lt;p&gt;The docs had two tutorials: one using JavaScript and one using Docker. I chose to follow the Docker tutorial because I'm not familiar with container technology and it could potentially benefit me in my upcoming transition to a DevOps role at Tapjoy.&lt;/p&gt;

&lt;p&gt;I dedicated a few evenings to the "Hello, world!" tutorial, trying to massage the steps into something close to what I imagined I'd need for my real project. I took my time, and gave particular focus to the parts concerning Docker: I wasn't sure this would be a proper fit for my project, so I wanted to be sure before I dismissed it as an option.&lt;/p&gt;

&lt;p&gt;I'm glad I went slowly at the beginning. By the time I had completed the tutorial to my satisfaction, I had learned two important things: a Github Action would be a good way to manifest this tool, and I didn't want to build it out of shell scripts.&lt;/p&gt;

&lt;p&gt;I can count on one hand the number of devs I know who can effectively read shell scripting languages, let alone effectively write them; I myself only have a passing proficiency at shell scripting, and I wanted this project to be easy for others to grow to suit their needs.&lt;/p&gt;

&lt;p&gt;Python was a choice I was primed to make: it's a language I had virtually zero experience developing with; it's easy to pick up and is widely used; it's been on my list of tools to familiarize myself with for awhile; and I have a friend who is enamored by it and is always touting its benefits in web programming.&lt;/p&gt;

&lt;p&gt;I'd used Python before, nigh on a decade ago. But if I wanted to start this project off in a good direction, I needed to brush up on contemporary best practices. My primary concerns, at least in the beginning, were project structure and development tools. How do I lay out this project, and what will help me build it?&lt;/p&gt;

&lt;p&gt;The internet doth provide: &lt;a href="https://docs.python-guide.org" rel="noopener noreferrer"&gt;&lt;em&gt;The Hitchhiker's Guide to Python&lt;/em&gt;&lt;/a&gt; was often referenced, so I concluded it must espouse a highly regarded opinion and decided to adopt it as another of my sacred texts. Indeed, it proved very useful as a quickish reference for many things: project structure, package management, testing tools, documentation practices....&lt;/p&gt;

&lt;p&gt;Armed with an initial (and empty) project layout and a basic Github Workflow that would execute my "Hello, world!" Action any time I pushed to Github, I could finally get started on the logic that would become &lt;a href="https://github.com/dabrady/syndicate" rel="noopener noreferrer"&gt;&lt;code&gt;syndicate&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>showdev</category>
      <category>python</category>
      <category>development</category>
    </item>
    <item>
      <title>syndicate: Why I Made It</title>
      <dc:creator>Daniel Brady</dc:creator>
      <pubDate>Tue, 18 Feb 2020 21:01:00 +0000</pubDate>
      <link>https://forem.com/daniel13rady/syndicate-why-i-made-it-3m9g</link>
      <guid>https://forem.com/daniel13rady/syndicate-why-i-made-it-3m9g</guid>
      <description>&lt;p&gt;I made this for people who write words they share with others:&lt;/p&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fassets.dev.to%2Fassets%2Fgithub-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/dabrady" rel="noopener noreferrer"&gt;
        dabrady
      &lt;/a&gt; / &lt;a href="https://github.com/dabrady/syndicate" rel="noopener noreferrer"&gt;
        syndicate
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      a simple implementation of the POSSE content publishing model
    &lt;/h3&gt;
  &lt;/div&gt;
&lt;/div&gt;


&lt;p&gt;It distributes copies of the content you create to various publishing sites automatically.&lt;/p&gt;

&lt;p&gt;It took me a week of focused evenings and a weekend of dedicated hacking to polish it to my liking; and another week to write about it.&lt;/p&gt;

&lt;p&gt;This is the first in a series of writeups on why I did it, how I did it, and what comes next.&lt;/p&gt;




&lt;p&gt;Why's are important to me. I don't like doing things with my time without a reason, even if that reason is as vague as "huh, sounds like fun." Why's help me figure out if I care enough to continue, by situating my actions into some wider context. I've learned that most of the time, when I find my interest in something is waning, it's because I've either lost site of my why or because my why is no longer good enough to keep me coming back.&lt;/p&gt;

&lt;p&gt;In the case of &lt;a href="https://github.com/dabrady/syndicate" rel="noopener noreferrer"&gt;&lt;code&gt;syndicate&lt;/code&gt;&lt;/a&gt;, my why started from one of those complex moments of understanding that often follow deep dives into rabbit holes, where a lot of things you've been processing in the background of your mind come suddenly to the front.&lt;/p&gt;

&lt;p&gt;On this particular occasion, I was researching the subject of blogging. I had only recently written &lt;a href="https://dev.to/daniel13rady/declaring-variables-in-javascript-31ch"&gt;my first blog post&lt;/a&gt;, and so I had a lot to learn. I read about many things: &lt;a href="http://www.rebeccablood.net/essays/weblog_history.html" rel="noopener noreferrer"&gt;the origins of blogging&lt;/a&gt; in the "weblogs" of the late 1990s; &lt;a href="https://dev.to/amrutaranade/how-to-write-a-blog-post-the-four-drafts-method-1k7b"&gt;various techniques&lt;/a&gt; I could use to help me during the writing process; the communities fostered by different blogging platforms. It was this last one that eventually lead me to &lt;a href="https://indieweb.org/POSSE" rel="noopener noreferrer"&gt;the IndieWeb&lt;/a&gt; and the concept of &lt;em&gt;POSSE&lt;/em&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;&lt;em&gt;POSSE&lt;/em&gt;&lt;/strong&gt; is an abbreviation for &lt;strong&gt;Publish (on your) Own Site, Syndicate Elsewhere&lt;/strong&gt;, a content publishing model that starts with posting content on your own domain first, then syndicating out copies to 3rd party services with permashortlinks back to the original on your site.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This makes a lot of intuitive sense to me, since it is basically the same process used in the creation of more traditional forms of media like books and magazines: the author distributes copies of their work to the publishing companies they want to work with.&lt;/p&gt;

&lt;p&gt;But more importantly, it reminded me that I'm not in control of the internet, and if I use the internet to create content, instead of creating content for the internet, I might not be in control of that, either. I don't care so much about &lt;em&gt;possessing&lt;/em&gt; what I create, so much as I care about having some measure of control of and responsibility for it.&lt;/p&gt;

&lt;p&gt;I decided I would adopt POSSE, and started thinking about how I would do it.&lt;/p&gt;

&lt;p&gt;I felt this approach to content creation could be boiled down to a few simple steps:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Create a "source of truth" for your writing.&lt;/li&gt;
&lt;li&gt;Know where you want to distribute, and how to do it.&lt;/li&gt;
&lt;li&gt;When your truths change, ensure they are ferried to the right places.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;It didn't take much imagination to see the parallels with software deployment. I could easily picture how it would work:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Create a &lt;code&gt;git&lt;/code&gt; repo for my writing.&lt;/li&gt;
&lt;li&gt;Decide on the platforms I want to distribute to, and write scripts to do so via public APIs.&lt;/li&gt;
&lt;li&gt;Use &lt;code&gt;git&lt;/code&gt; hooks or some other mechanism to run those scripts when changes are made.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;I was immediately taken with this idea. Automating my jobs away is a minor passion of mine, and when I'm the only stakeholder, I like to indulge in a little premature automation just for the fun of it. I mean, who doesn't like &lt;a href="https://sims.fandom.com/wiki/The_Sims:_Makin%27_Magic" rel="noopener noreferrer"&gt;makin' magic&lt;/a&gt;?&lt;/p&gt;

&lt;p&gt;And it looked like a fun challenge! There was a clear objective and definition of success, and it seemed like something that other people besides myself would find useful.&lt;/p&gt;

&lt;p&gt;So I made a Trello board, created a repository on Github, and started Googling.&lt;/p&gt;

</description>
      <category>showdev</category>
      <category>blog</category>
      <category>thinkdeep</category>
      <category>motivation</category>
    </item>
    <item>
      <title>I don't prep for the 'tech' part of tech interviews; does that work for you, too?</title>
      <dc:creator>Daniel Brady</dc:creator>
      <pubDate>Tue, 18 Feb 2020 11:31:00 +0000</pubDate>
      <link>https://forem.com/daniel13rady/i-don-t-prep-for-the-tech-part-of-tech-interviews-does-that-work-for-you-too-4mjd</link>
      <guid>https://forem.com/daniel13rady/i-don-t-prep-for-the-tech-part-of-tech-interviews-does-that-work-for-you-too-4mjd</guid>
      <description>&lt;p&gt;This has always been met with vehement opposition, feelings of being offended, and made sages out of friends as they become suddenly protective of me and wanting to "steer me right."&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;So let me just preface this&lt;/strong&gt; with, "This works for me, I'm open to improvements, and I'm not disparaging what works for anyone else."&lt;/p&gt;

&lt;p&gt;I don't prep for the 'tech' part of tech interviews.¯\_(ツ)_/¯&lt;/p&gt;

&lt;p&gt;It has nothing to do with having a large ego or confidence in interviewing or anything like that, but rather more to do with how I judge myself.&lt;/p&gt;

&lt;p&gt;It's mostly an extension of my approach to any sort of examination or evaluation growing up: if the progression of my life thus far hasn't &lt;em&gt;already&lt;/em&gt; prepared me, then I'm obviously not ready for whatever the next step is, regardless of what the examiner says. Intentional preparation for things like exams has always felt...fake, I guess? If I pass an evaluation after spending days or weeks of studying for it specifically, then what is the evaluation really telling me about how well I'm prepared for whatever comes next? Isn't it mostly just telling me how well I passed the test?&lt;/p&gt;

&lt;p&gt;When I transitioned out of a formal school setting and into "the real world" several years ago, that attitude towards evaluating myself didn't change. Job interviews are very obvious forms of evaluation, and I approach them with the same attitude: if I'm not ready, I'm not ready, and stressing myself out to get a job I'm not ready for doesn't help anyone, especially me. Failing an interview helps me learn where I should improve if I want a similar role in the future.&lt;/p&gt;

&lt;p&gt;It's worked well for me so far: I've held two professional software jobs, and I started both of them with minimal self-doubt and virtually no imposter syndrome.&lt;/p&gt;

&lt;p&gt;That said, I've had a few interview experiences that have revealed what I consider a major flaw in my approach: it assumes too much about the ability of the examination process to adequately and accurately evaluate.&lt;/p&gt;

&lt;p&gt;Basically, as a student I tended to think that if I did not pass an exam, I was not ready to proceed in the coursework. Similarly, I now tend to think that if I was not given an offer after an interview, then I was not a good fit for the role.&lt;/p&gt;

&lt;p&gt;But the reality is that accurate evaluation of people is &lt;em&gt;hard&lt;/em&gt;; any feedback (external or internal) about yourself and your abilities has to be taken with a healthy amount of skepticism.&lt;/p&gt;

&lt;p&gt;And this is why I specifically said I don't prep for the &lt;strong&gt;tech&lt;/strong&gt; part of interviews. The tech part is the simpler (but not necessarily easier) part for me: once I'm asked a question, my own reaction to it can generally tell me how equipped I am to approach a solution to it, and hopefully that tells me &lt;em&gt;something&lt;/em&gt; about how equipped I am for the role I'm trying for.&lt;/p&gt;

&lt;p&gt;The real challenge of interviews, for me, has always been the part where I'm supposed be interviewing &lt;em&gt;them&lt;/em&gt; as a prospective employer and potential teammate. 😓 This is the part of tech interviews I often forgot about early on and actually try to prepare for these days, because my success in that area relies on my ability in judging others accurately, and as I've tried to establish previously, that's hard.&lt;/p&gt;

&lt;p&gt;Anyways, this is getting longer than I intended. I mostly wanted to share my flawed-but-works-well-for-me approach to tech interviews, and I'm curious if anyone else follows a similar approach. If you follow a different one, why does it work for you more than others you've tried?&lt;/p&gt;

</description>
      <category>discuss</category>
      <category>career</category>
    </item>
    <item>
      <title>syndicate: a POSSE way to DEV</title>
      <dc:creator>Daniel Brady</dc:creator>
      <pubDate>Thu, 13 Feb 2020 11:26:00 +0000</pubDate>
      <link>https://forem.com/daniel13rady/syndicate-a-p-o-s-s-e-way-to-dev-5bnc</link>
      <guid>https://forem.com/daniel13rady/syndicate-a-p-o-s-s-e-way-to-dev-5bnc</guid>
      <description>&lt;p&gt;Until a month ago I had never written a blog post.&lt;/p&gt;

&lt;p&gt;My recent discovery of DEV has a lot to do with why I started, and indeed, I created &lt;a href="https://dev.to/daniel13rady/declaring-variables-in-javascript-31ch"&gt;my first post&lt;/a&gt; right here on DEV.&lt;/p&gt;

&lt;p&gt;While educating myself on the art of writing for other people, I came across the term "POSSE", which I had never heard of before but &lt;a href="https://indieweb.org/POSSE" rel="noopener noreferrer"&gt;is apparently kind of a big deal&lt;/a&gt;. It is a principle that is embraced by DEV itself, according to Ben.&lt;/p&gt;


&lt;div class="liquid-comment"&gt;
    &lt;div class="details"&gt;
      &lt;a href="/ben"&gt;
        &lt;img class="profile-pic" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F1%2Ff451a206-11c8-4e3d-8936-143d0a7e65bb.png" alt="ben profile image"&gt;
      &lt;/a&gt;
      &lt;a href="/ben"&gt;
        &lt;span class="comment-username"&gt;Ben Halpern&lt;/span&gt;
      &lt;/a&gt;
      &lt;span class="color-base-30 px-2 m:pl-0"&gt;•&lt;/span&gt;

&lt;a href="https://dev.to/ben/comment/d8pj" class="comment-date crayons-link crayons-link--secondary fs-s"&gt;
  &lt;time class="date-short-year"&gt;
    Jul 21 '19
  &lt;/time&gt;

&lt;/a&gt;

    &lt;/div&gt;
    &lt;div class="body"&gt;
      &lt;p&gt;Hey, this is really on point, and we’ve been working on a lot of features to help people pull off POSSE in a simpler manner, while also trying to roadmap a future where trust is pretty clearly baked into our product.&lt;/p&gt;


&lt;div class="ltag__link"&gt;
  &lt;a href="/devteam" class="ltag__link__link"&gt;
    &lt;div class="ltag__link__org__pic"&gt;
      &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Forganization%2Fprofile_image%2F1%2Fd908a186-5651-4a5a-9f76-15200bc6801f.jpg" alt="The DEV Team"&gt;
      &lt;div class="ltag__link__user__pic"&gt;
        &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F1%2Ff451a206-11c8-4e3d-8936-143d0a7e65bb.png" alt=""&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/a&gt;
  &lt;a href="https://dev.to/devteam/medium-was-never-meant-to-be-a-part-of-the-developer-ecosystem-25a0" class="ltag__link__link"&gt;
    &lt;div class="ltag__link__content"&gt;
      &lt;h2&gt;Medium Was Never Meant to Be a Part of the Developer Ecosystem&lt;/h2&gt;
      &lt;h3&gt;Ben Halpern for The DEV Team ・ Jun 3 '19&lt;/h3&gt;
      &lt;div class="ltag__link__taglist"&gt;
        &lt;span class="ltag__link__tag"&gt;#meta&lt;/span&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/a&gt;
&lt;/div&gt;



&lt;div class="ltag__link"&gt;
  &lt;a href="/devteam" class="ltag__link__link"&gt;
    &lt;div class="ltag__link__org__pic"&gt;
      &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Forganization%2Fprofile_image%2F1%2Fd908a186-5651-4a5a-9f76-15200bc6801f.jpg" alt="The DEV Team"&gt;
      &lt;div class="ltag__link__user__pic"&gt;
        &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F1%2Ff451a206-11c8-4e3d-8936-143d0a7e65bb.png" alt=""&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/a&gt;
  &lt;a href="https://dev.to/devteam/project-benatar-fending-off-data-black-holes-499g" class="ltag__link__link"&gt;
    &lt;div class="ltag__link__content"&gt;
      &lt;h2&gt;Project Benatar: Fending Off Data Black Holes&lt;/h2&gt;
      &lt;h3&gt;Ben Halpern for The DEV Team ・ Jun 17 '19&lt;/h3&gt;
      &lt;div class="ltag__link__taglist"&gt;
        &lt;span class="ltag__link__tag"&gt;#meta&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#opensource&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#projectbenatar&lt;/span&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/a&gt;
&lt;/div&gt;


&lt;p&gt;I’m not sure if you’ve read those, and some of the other posts we’ve made on the subject, but let me know what you think!&lt;/p&gt;


    &lt;/div&gt;
&lt;/div&gt;


&lt;p&gt;The idea intrigued me, as do most things that involve "write once and reuse" concepts. I began to imagine how such a thing might be accomplished, and just like P.O.S.S.E. itself, the recipe for its implementation seemed simple on the surface:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Create a "source of truth" for your writing.&lt;/li&gt;
&lt;li&gt;Know where you want to distribute, and how to do it.&lt;/li&gt;
&lt;li&gt;When your truths change, ensure a process is triggered to ferry your changes to the right places.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;I don't know about you, but that sequence of steps strongly reminds me of the basic recipe for deploying software. And so I immediately re-imagined it as such:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Create a &lt;code&gt;git&lt;/code&gt; repo for my writing.&lt;/li&gt;
&lt;li&gt;Decide on the platforms I want to distribute to, and write scripts to do so via public APIs.&lt;/li&gt;
&lt;li&gt;Setup &lt;code&gt;git&lt;/code&gt; hooks to run those scripts when changes are made.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Long story short (the "long story long" will come as a separate post), I took a week of evenings and a weekend, and made this:&lt;/p&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fassets.dev.to%2Fassets%2Fgithub-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/dabrady" rel="noopener noreferrer"&gt;
        dabrady
      &lt;/a&gt; / &lt;a href="https://github.com/dabrady/syndicate" rel="noopener noreferrer"&gt;
        syndicate
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      a simple implementation of the POSSE content publishing model
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;syndicate&lt;/h1&gt;
&lt;/div&gt;
&lt;p&gt;A simple implementation of the &lt;a href="https://indieweb.org/POSSE" rel="nofollow noopener noreferrer"&gt;POSSE&lt;/a&gt; content publishing model, packaged as a Github Action.&lt;/p&gt;
&lt;p&gt;Write your content, store it on Github, and use this action in a workflow to draft it to silo platforms like &lt;a href="https://dev.to" rel="nofollow"&gt;DEV.to&lt;/a&gt;. The action will keep the silos up to date with your latest changes here on Github.&lt;/p&gt;
&lt;p&gt;Wherever possible, when content is syndicated to a silo for the first time, it is created in an unpublished/"draft" form. Any exceptions to this will be called out in the documentation for &lt;a href="https://github.com/dabrady/syndicate#silos" rel="noopener noreferrer"&gt;&lt;code&gt;silos&lt;/code&gt;&lt;/a&gt; below.&lt;/p&gt;
&lt;p&gt;The silos currently supported are:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://dev.to" rel="nofollow"&gt;https://dev.to&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;A key assumption&lt;/strong&gt; made by this project is that your content is written as Markdown, and includes a YAML frontmatter containing at least a &lt;code&gt;title&lt;/code&gt; property. If this is not the case for you, this action sadly does not currently support your worflow. If you would like to see support for some other way of making…&lt;/p&gt;
&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/dabrady/syndicate" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;


&lt;p&gt;As the README describes, it will let you write your content on Github, and distribute it automatically to DEV.to, keeping subsequent changes in the content on Github synced to DEV.&lt;/p&gt;

&lt;p&gt;It is designed to be used as &lt;a href="https://github.com/features/actions" rel="noopener noreferrer"&gt;an action in a Github Workflow&lt;/a&gt;, but technically it is just a simple Python program that can be run with Docker if you want (I include a Dockerfile). To use it as intended, all you need to have is a Github repository, and all you need to do is create a Github workflow in that repository which uses &lt;code&gt;dabrady/syndicate&lt;/code&gt; in one of its steps.&lt;/p&gt;

&lt;p&gt;For now, it only recognizes one silo platform, DEV.to, because that's the only platform I currently publish on. But I made it simple to add plugins/adapters for other silo platforms, so if you'd like to contribute, that's a great way to do so!&lt;/p&gt;

&lt;p&gt;Like my first blog post, this is my first project written with the intent to share with other people. It's also my first time using Python in almost a decade, so I used &lt;em&gt;&lt;a href="https://docs.python-guide.org/" rel="noopener noreferrer"&gt;The Hitchhiker's Guide to Python&lt;/a&gt;&lt;/em&gt; as my main resource for project management and layout. Any and all feedback is greatly appreciated! 🙏 I hope it benefits us.&lt;/p&gt;

</description>
      <category>meta</category>
      <category>productivity</category>
      <category>blog</category>
      <category>showdev</category>
    </item>
    <item>
      <title>What's your current favorite shell command?</title>
      <dc:creator>Daniel Brady</dc:creator>
      <pubDate>Fri, 31 Jan 2020 12:46:02 +0000</pubDate>
      <link>https://forem.com/daniel13rady/what-s-your-current-favorite-shell-command-1e2j</link>
      <guid>https://forem.com/daniel13rady/what-s-your-current-favorite-shell-command-1e2j</guid>
      <description></description>
      <category>discuss</category>
      <category>watercooler</category>
    </item>
    <item>
      <title>What's your favorite line of code?</title>
      <dc:creator>Daniel Brady</dc:creator>
      <pubDate>Sun, 26 Jan 2020 23:22:35 +0000</pubDate>
      <link>https://forem.com/daniel13rady/what-s-your-favorite-line-of-code-5el1</link>
      <guid>https://forem.com/daniel13rady/what-s-your-favorite-line-of-code-5el1</guid>
      <description>&lt;p&gt;Abstract answers and actual code snippets are both welcome 😄&lt;/p&gt;

</description>
      <category>discuss</category>
      <category>watercooler</category>
    </item>
    <item>
      <title>Iterating with loops</title>
      <dc:creator>Daniel Brady</dc:creator>
      <pubDate>Sun, 26 Jan 2020 20:31:54 +0000</pubDate>
      <link>https://forem.com/daniel13rady/iterating-with-loops-1lp1</link>
      <guid>https://forem.com/daniel13rady/iterating-with-loops-1lp1</guid>
      <description>&lt;p&gt;&lt;small&gt;Cover photo by Sebastian Alvarez on &lt;a href="https://unsplash.com/photos/1-XS37EZ_Kg" rel="noopener noreferrer"&gt;Unsplash&lt;/a&gt;&lt;/small&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  &lt;em&gt;Previously, on "Iteration"...&lt;/em&gt;
&lt;/h1&gt;


&lt;div class="ltag__link"&gt;
  &lt;a href="/daniel13rady" class="ltag__link__link"&gt;
    &lt;div class="ltag__link__pic"&gt;
      &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F290298%2F323cf2b8-0760-4fd4-a640-4c8328c81fff.jpeg" alt="daniel13rady"&gt;
    &lt;/div&gt;
  &lt;/a&gt;
  &lt;a href="https://dev.to/daniel13rady/iterating-with-recursion-3i5e" class="ltag__link__link"&gt;
    &lt;div class="ltag__link__content"&gt;
      &lt;h2&gt;Iterating with recursion&lt;/h2&gt;
      &lt;h3&gt;Daniel Brady ・ Jan 25 '20&lt;/h3&gt;
      &lt;div class="ltag__link__taglist"&gt;
        &lt;span class="ltag__link__tag"&gt;#beginners&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#thinkdeep&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#programming&lt;/span&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/a&gt;
&lt;/div&gt;


&lt;p&gt;I introduced the concept of iteration by way of a whimsical allegory about counting a staircase. To count the steps of a staircase, we first came up with a practical definition of what the "length" of a staircase is:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The length of a staircase can be described as &lt;strong&gt;the value of the first stair, plus the length of the rest of the staircase&lt;/strong&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;We then used that definition to derive an intuitive algorithm for calculating staircase length:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;When counting the steps of a staircase, if you're at the top, stop counting.&lt;br&gt;
Otherwise, add 1 to the result of counting the rest of the staircase.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;My implementation of that algorithm showcased the elegance of &lt;strong&gt;recursion&lt;/strong&gt;, which deconstructs a problem into a composition of the solutions to its parts. And we saw that recursion lends itself well to &lt;strong&gt;wholistic computation&lt;/strong&gt;, i.e. situations in which you only care about the final result.&lt;/p&gt;

&lt;h1&gt;
  
  
  Constructive iteration
&lt;/h1&gt;

&lt;p&gt;Today, I want to talk about other ways of approaching iteration that might lend themselves better to &lt;strong&gt;constructive computation&lt;/strong&gt;. I'm using the term &lt;em&gt;constructive&lt;/em&gt; in &lt;a href="https://en.wikipedia.org/wiki/Constructive_proof" rel="noopener noreferrer"&gt;the mathematical sense&lt;/a&gt;, which I just learned about recently and think fits this topic particularly well.&lt;/p&gt;

&lt;p&gt;A constructive process, in my mind, is one that gives you insight into the &lt;strong&gt;progress&lt;/strong&gt; of the computation it is performing.&lt;/p&gt;

&lt;p&gt;To keep with the "staircase traversal" imagery from my previous discussion of iteration, I imagine a &lt;em&gt;constructive&lt;/em&gt; traversal of a staircase to be one in which, after each step, you know exactly how many you've climbed.&lt;/p&gt;

&lt;p&gt;It's like you're actually building the staircase as you go, keeping track of how many steps you've added so far. Once you've decided to stop, you already know exactly &lt;a href="https://www.youtube.com/watch?v=5ZtbCOpx8Sk" rel="noopener noreferrer"&gt;how many steps are in the staircase&lt;/a&gt; without further computation.&lt;/p&gt;

&lt;p&gt;We-Who-Code often refer to this type of iteration as &lt;strong&gt;looping&lt;/strong&gt;, which captures the idea that each step you take closes a 'loop' in a larger 'circuit' of computation.&lt;/p&gt;

&lt;p&gt;When looping, you can stop at the end of any step without worrying so much about unfinished work: if you stop precisely at the "end" of your computation, your record-keeping will reflect the solution to the whole thing; on the other hand, if you stop early, you'll still have something to show for it, it might just be an &lt;em&gt;approximation&lt;/em&gt; of the result you were driving towards.&lt;/p&gt;

&lt;h1&gt;
  
  
  How many stairs are in a staircase?
&lt;/h1&gt;

&lt;p&gt;So: how do you count the stairs of a staircase like this?&lt;/p&gt;

&lt;p&gt;The basic algorithm is the same: climb until you reach the top, tracking each step you take.&lt;/p&gt;

&lt;p&gt;The difference in implementation is in &lt;em&gt;the way you track your steps&lt;/em&gt;: instead of waiting to evaluate the sum once you've reached the top, you evaluate as you go.&lt;/p&gt;

&lt;p&gt;Our recursive implementation of &lt;code&gt;#count-stairs&lt;/code&gt; from &lt;a href="https://dev.to/daniel13rady/iterating-with-recursion-3i5e"&gt;last time&lt;/a&gt; looked like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4830lsr1tt4hdv180e66.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4830lsr1tt4hdv180e66.png" alt="Staircase counting algorithm" width="800" height="234"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As we saw, this builds up a single computation by keeping a tally of the steps you've climbed and evaluates it once you've reached the top. For example, calling this version of &lt;code&gt;#count-stairs&lt;/code&gt; with a staircase of four steps would build and evaluate an expression like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3eszvw059b6ot699vmwl.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3eszvw059b6ot699vmwl.png" alt="Addition sequence" width="800" height="208"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;With only a slight modification, this 'non-constructive' iteration can become constructive. Let's give it a try.&lt;/p&gt;

&lt;p&gt;If we want to keep track of how many steps we've taken at every step we take, we need a place to store that information. So the first thing to do is introduce a variable to hold the result of that computation: let's call it &lt;code&gt;tally&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzub10oib52zickjo3bvn.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzub10oib52zickjo3bvn.png" alt="Introduce tally variable for holding intermediate results" width="800" height="252"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Since &lt;code&gt;tally&lt;/code&gt; will hold the number of stairs we've stepped, and the number of stairs we've stepped is precisely the length of the staircase we've climbed, we now want to return our &lt;code&gt;tally&lt;/code&gt; once we reach the top.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fiiquoj0g3fezn2f3qcek.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fiiquoj0g3fezn2f3qcek.png" alt="Return final tally when we stop looping" width="800" height="252"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Finally, we add the current step to our &lt;code&gt;tally&lt;/code&gt; and count the rest of the staircase.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnzkqgdh4qqq8vw6y8amb.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnzkqgdh4qqq8vw6y8amb.png" alt="Increment tally and recur with rest of staircase" width="800" height="227"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This new way of 'counting the rest' is the key to an implementation that evaluates the tally as it counts, rather than deferring evaluation of the tally to when counting has stopped.&lt;/p&gt;

&lt;p&gt;Putting it all together, our new &lt;code&gt;#count-stairs&lt;/code&gt; function looks like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnn9a2n093920bp8lovu6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnn9a2n093920bp8lovu6.png" alt="Tail-recursive version of count-stairs" width="800" height="209"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Quite similar to the original, no?&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;💡 This form of recursion is often called 'tail recursion', because the "do it again" part happens at the tail-end of the loop, and no more computation is done in the same loop.&lt;/p&gt;

&lt;p&gt;To anyone who writes code, I &lt;strong&gt;highly&lt;/strong&gt; recommend the book &lt;a href="https://www.goodreads.com/book/show/43713.Structure_and_Interpretation_of_Computer_Programs" rel="noopener noreferrer"&gt;&lt;em&gt;Structure and Interpretation of Computer Programs&lt;/em&gt;&lt;/a&gt;, by Harold Abelson and Gerald Jay Sussman. This section &lt;a href="https://xuanji.appspot.com/isicp/1-2-procedures.html" rel="noopener noreferrer"&gt;in particular&lt;/a&gt; is a great resource on the topics I'm discussing here.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;What I find fascinating is how the shape of the computation changes with just these few simple modifications. Taking again a staircase of four steps to illustrate our algorithm, our computation diagram now looks something more like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhtr8bpj1ybkdyp3z5xnu.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhtr8bpj1ybkdyp3z5xnu.png" alt="Computational diagram of tail-recursive function" width="800" height="352"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Do you see the staircase we're climbing? 😄&lt;/p&gt;

&lt;h1&gt;
  
  
  Loop constructs
&lt;/h1&gt;

&lt;p&gt;Iteration is useful and loops prevalent. We-Who-Code even &lt;a href="https://www.ntaskmanager.com/blog/what-is-agile-iterative-approach/" rel="noopener noreferrer"&gt;apply the concept of iteration to applying the concept of iteration&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;But depending on the tools you're using, repeatedly calling the same function isn't the only way to loop.&lt;/p&gt;

&lt;p&gt;Many languages provide explicit "loop constructs" we can use in situations where a recursive function call may negatively impact how well our code communicates our intent to other humans and machines.&lt;/p&gt;

&lt;p&gt;There are also times where it may not be the most mechanically efficient one, either; see &lt;a href="https://xuanji.appspot.com/isicp/1-2-procedures.html#%_sec_1.2.1" rel="noopener noreferrer"&gt;SICP&lt;/a&gt; for a brief discussion on the performance of various compilers with respect to handling iterative code patterns.&lt;/p&gt;

&lt;p&gt;Since these constructs are language-specific, I won't go into much more detail than to mention a few names they are commonly given, to aid you in your quest to better know your tools:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;for&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;while&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;until&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;loop&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;each&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;do-while&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;&lt;em&gt;Every tool has its use. Some can make your code clearer to humans or clearer to machines, and some can strike a bit of balance between both.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;"Good enough to work" should not be "good enough for you." &lt;strong&gt;Hold yourself to a higher standard&lt;/strong&gt;: learn a little about a lot and a lot about a little, so that when the time comes to do something, you've got a fair idea of how to do it well.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>beginners</category>
      <category>thinkdeep</category>
      <category>programming</category>
    </item>
    <item>
      <title>Iterating with recursion</title>
      <dc:creator>Daniel Brady</dc:creator>
      <pubDate>Sat, 25 Jan 2020 20:25:37 +0000</pubDate>
      <link>https://forem.com/daniel13rady/iterating-with-recursion-3i5e</link>
      <guid>https://forem.com/daniel13rady/iterating-with-recursion-3i5e</guid>
      <description>&lt;p&gt;&lt;small&gt;Cover photo by Ludde Lorentz on &lt;a href="https://unsplash.com/photos/YfCVCPMNd38" rel="noopener noreferrer"&gt;Unsplash&lt;/a&gt;&lt;/small&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  How many stairs are in a staircase?
&lt;/h1&gt;

&lt;p&gt;You're walking along, thinking about dinner. &lt;em&gt;Should I have &lt;a href="https://www.instagram.com/tsurumendavis/" rel="noopener noreferrer"&gt;ramen&lt;/a&gt; or &lt;a href="https://www.instagram.com/yumegaarukara/" rel="noopener noreferrer"&gt;udon&lt;/a&gt;?&lt;/em&gt; you ask yourself.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;❗ A wild staircase appears!&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Thoughts of noodles recede from your mind as you consider this new development in staircase behavior, which may be worthy of a &lt;em&gt;Nat Geo&lt;/em&gt; special.&lt;/p&gt;

&lt;p&gt;The staircase is not too tall; you can't tell exactly how many steps there are, but you're pretty confident you can conquer them.&lt;/p&gt;

&lt;p&gt;But...how can you be sure?&lt;/p&gt;

&lt;p&gt;You've climbed hundreds, if not thousands, of steps in your lifetime, enough that this new set shouldn't be a problem. The secret, you know, is twofold:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Know when to stop.&lt;/li&gt;
&lt;li&gt;Take the next step.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;And you really can't climb a staircase and emerge unscathed without knowing this secret.&lt;/p&gt;

&lt;p&gt;You recall a time when you continued to think about noodles while trying to ascend a staircase, and tripped: you'd made a mistake taking the next step.&lt;/p&gt;

&lt;p&gt;You also recall, during this very same ascension, how it felt when you reached the top but kept on climbing because you were &lt;em&gt;still&lt;/em&gt; weighing your noodle options: your foot came down hard and you pitched forward, nearly falling flat on your face. You'd momentarily forgotten the other secret of climbing stairs: knowing when to stop.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3mbpyjswy4hjmol5pe1b.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3mbpyjswy4hjmol5pe1b.png" alt="Staircase climbing algorithm" width="800" height="266"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You eye the stairs before you, and, driven by the need to know just how many there are, you make the only reasonable decision: you clear your mind of noodles, and take the first step.&lt;/p&gt;

&lt;p&gt;Confidence in your ability to conquer &lt;em&gt;any&lt;/em&gt; flight of stairs, even if you've never done it, seems valuable to you in your future as a human.&lt;/p&gt;

&lt;p&gt;But how do you incorporate counting into it? 🤔&lt;/p&gt;

&lt;p&gt;It's simple, you realize: you merely keep a tally of the stairs you've stepped as you climb. The length of a staircase can thus be described as &lt;strong&gt;the value of the first stair, plus the length of the rest of the staircase&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmpfhxxqt2zepjib7381z.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmpfhxxqt2zepjib7381z.png" alt="Recursive summation" width="800" height="138"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you've reached the top, you stop climbing, and thus stop counting. Otherwise, you can focus on stepping and summing, and wait to evaluate the tally you've kept until you've stopped.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4830lsr1tt4hdv180e66.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4830lsr1tt4hdv180e66.png" alt="Staircase counting algorithm" width="800" height="234"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Smiling and slightly winded, you reach the top and look at how far you've come. Full of the glow of victory, you wonder at the power of this simple algorithm. Your smile fades to a frown, however, as you remember a more pressing concern: what bowl of noodles should you have for dinner?&lt;/p&gt;




&lt;p&gt;This approach to solving problems that can be broken down into a sequence of similar steps, where&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;you do something at every step&lt;/li&gt;
&lt;li&gt;you know how to get to the next step, and&lt;/li&gt;
&lt;li&gt;you know how to determine if you should stop stepping&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;is fundamental in computing science and every-day programming.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Iteration&lt;/strong&gt;, that's what we've landed on. Doing things over and over until a particular goal is reached.&lt;/p&gt;

&lt;p&gt;The example functions I used to illustrate the story above implemented iteration in a &lt;strong&gt;recursive&lt;/strong&gt; fashion.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Recursive functions are the simplest form of programatic iteration&lt;/strong&gt;: they are functions designed to deconstruct a problem into a linear computation of its pieces, and then evaluate it as a whole.&lt;/p&gt;

&lt;p&gt;Thinking about it so formally can get a bit confusing. I find it easiest to grok by reading a simple recursive function aloud. Revisiting our &lt;code&gt;#count-stairs&lt;/code&gt; example:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4830lsr1tt4hdv180e66.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4830lsr1tt4hdv180e66.png" alt="Staircase counting algorithm" width="800" height="234"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This can be read in plain English as: &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;When counting the steps of a staircase, if you're at the top, stop counting.&lt;br&gt;
Otherwise, add 1 to the result of counting the rest of the staircase.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Bit of a strange loop, to be sure; but note how each time we "count the rest" of the staircase, the amount of things we are counting is &lt;em&gt;getting smaller&lt;/em&gt; until eventually, there's nothing left to count: we've reached the top.&lt;/p&gt;

&lt;p&gt;Let's draw out an example computation to help us see this in action:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjgfz3ajl53h5d33t9tqm.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjgfz3ajl53h5d33t9tqm.png" alt="Computation diagram of recursively counting stairs" width="800" height="196"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Quite elegant, no?&lt;/p&gt;

&lt;p&gt;Readers may notice, especially after seeing the computation diagram above, that we're arriving at the final summation &lt;strong&gt;without tracking the intermediate results&lt;/strong&gt;. Good eyes, dear reader. 👏&lt;/p&gt;

&lt;p&gt;As we've seen, this style of recursion approaches a problem &lt;em&gt;wholistically&lt;/em&gt; and &lt;em&gt;lazily&lt;/em&gt;: it views the solution to a problem as an aggregation of the solution to its parts, and thus doesn't compute the whole solution until it has broken it down fully.&lt;/p&gt;

&lt;p&gt;But what happens if we fall off the stairs? What happens if we get too hungry, and need to abandon our climb in order to go eat noodles, but want to return to finish counting later? What happens if we want to text someone our current location, and tell them what step we're on?&lt;/p&gt;

&lt;p&gt;In such situations, we care about &lt;strong&gt;partially computing&lt;/strong&gt; results. At any given step, we may want to stop and reflect on how far we've come, beyond just asking "are we done yet?" And in these cases, the approach we've taken today may not be the best one for the job.&lt;/p&gt;

&lt;p&gt;For this and other reasons, many programming languages give you access to &lt;strong&gt;loop constructs&lt;/strong&gt;, and I'll talk more about those next time. 👋&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Every tool has its use. Some can make your code clearer to humans or clearer to machines, and some can strike a bit of balance between both.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;"Good enough to work" should not be "good enough for you." &lt;strong&gt;Hold yourself to a higher standard&lt;/strong&gt;: learn a little about a lot and a lot about a little, so that when the time comes to do something, you've got a fair idea of how to do it well.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>beginners</category>
      <category>thinkdeep</category>
      <category>programming</category>
    </item>
  </channel>
</rss>
