<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" ><generator uri="https://jekyllrb.com/" version="3.10.0">Jekyll</generator><link href="http://marczych.com/feed.xml" rel="self" type="application/atom+xml" /><link href="http://marczych.com/" rel="alternate" type="text/html" /><updated>2024-08-16T05:02:53+00:00</updated><id>http://marczych.com/feed.xml</id><title type="html">Marc Zych</title><subtitle>I&apos;m Marc Zych, software developer extraordinaire!</subtitle><entry><title type="html">Skynet</title><link href="http://marczych.com/2020/05/10/skynet.html" rel="alternate" type="text/html" title="Skynet" /><published>2020-05-10T19:37:52+00:00</published><updated>2020-05-10T19:37:52+00:00</updated><id>http://marczych.com/2020/05/10/skynet</id><content type="html" xml:base="http://marczych.com/2020/05/10/skynet.html"><![CDATA[<p>The house I’m renting has skylights and electric shades in every bedroom which gives you some options for how much light to let into the room at any given time.
Even better, there are remote controls for opening and closing the shades.
The problem is that the IR receiver for the remote controls is in the hallway along with the “manual” buttons which doesn’t do much good if you want to operate it without leaving the room.</p>

<p>I figured now was as good a time as any to finally set something up to make it more convenient.
I ended up using a Raspberry Pi Zero W set up in the hallway to send IR commands to the receiver.
It hosts a REST API and React frontend on the local network so anyone on the network can operate the skylights.
All of the gory technical details can be found on <a href="https://github.com/marczych/skynet">GitHub</a>.</p>

<p>Overall I’m very happy with how everything turned out.
It was fun working in a different environment with different tools and constraints.
Of course, the process was far from smooth because most of the docs around the IR shield and LIRC were out of date due to some changes in the kernel last year.
I ended up not using LIRC and recorded/replayed raw IR signals using gpio-ir directly which works great for my use case but potentially not for others.</p>

<p>So now I had a REST API and frontend but I wanted it to be even easier to control via my phone.
I discovered <a href="https://play.google.com/store/apps/details?id=ch.rmy.android.http_shortcuts">HTTP Request Shortcuts</a> which allows you to configure home screen shortcuts to send HTTP requests.
It was super easy to set up and has been working flawlessly ever since.
Well, it was very straightforward but was still tedious to type in HTTP requests on a phone keyboard.</p>

<p>The final piece of the puzzle was connecting it to my phone alarm so the shade will open when my alarm goes off in the morning.
My original plan was to run something on the Pi to poll for alarms from my Google account but I was unable to find an API to list alarms.
As far as I know they are synced somewhere but it may be as Android application data rather than an official user facing Google API.</p>

<p>I instead found <a href="https://play.google.com/store/apps/details?id=net.dinglisch.android.taskerm">Tasker</a> which is a general purpose Android automation app.
Setting up the HTTP requests was straightforward just like the app shortcuts.
However, I had a lot of difficulty with the alarm integration.
I selected what sounded like the correct trigger for an alarm but it didn’t work.
I tried a few other alarm triggers just in case but those didn’t work either.</p>

<p>This is where things get pretty fuzzy because I didn’t do a very deep dive on Tasker.
Eventually I stumbled upon <a href="https://play.google.com/store/apps/details?id=com.joaomgcd.autoalarm">AutoAlarm</a> which is a Tasker plugin that allows you to set a global variable with the time of the next alarm.
That imported a very lengthy Tasker task to keep the variables up to date but I quickly discovered that it doesn’t unset it when the alarm is disabled.
I worked around that by running the task periodically to reset things in case the alarm was disabled or an update was missed somehow.
Finally, this allowed me to close the loop and open the skylight when my alarm goes off!</p>

<p>However, this isn’t without its shortcomings.
First, while Tasker is a very full featured and flexible app, the user interface was infuriating.
There were many unintuitive interactions all over the app e.g. the back button pops a Toast rather than going back so you have to find the back button on the top right of the app.
All the while, there were near constant modals with tips and warnings about settings that I should change e.g. turn off battery saver, no active profiles, notifications prompting the user to disable them entirely.
I understand that this is a power user app but it still makes me appreciate the polish on the apps I use day to day.</p>

<p>My final gripe with Tasker is that the OS constantly displays an alarm for some time in the future even when I don’t have one enabled.
It’s often exactly 10 minutes in the future and updates as time ticks on which makes me think that it’s how Tasker does some of the alarm based triggers.</p>

<p>All of these issues gives me the feeling that it’s all held together by shoestrings and can fall apart at any time.
Also, Tasker feels like a supercharged V12 engine which is significantly overpowered for my needs.
I can only assume that it has negatively impacted my battery usage but I don’t have any evidence to back this up.</p>

<p>I’m pretty happy with how everything turned out.
The Raspberry Pi was super great.
Sending IR commands took some trial and error but it’s now working out very well.
Setting up the REST API was super straightforward.
I enjoyed using React for this project but was disappointed by several aspects of it coming from Vue.
The Android alarm integration is by far the least successful part of the project so that could use some work eventually.</p>

<p>It’s all open source so feel free to tweak it to suit your needs!</p>]]></content><author><name></name></author><summary type="html"><![CDATA[The house I’m renting has skylights and electric shades in every bedroom which gives you some options for how much light to let into the room at any given time. Even better, there are remote controls for opening and closing the shades. The problem is that the IR receiver for the remote controls is in the hallway along with the “manual” buttons which doesn’t do much good if you want to operate it without leaving the room.]]></summary></entry><entry><title type="html">Animals and Cars Aren’t Polymorphic</title><link href="http://marczych.com/2019/05/20/animals-and-cars-arent-polymorphic.html" rel="alternate" type="text/html" title="Animals and Cars Aren’t Polymorphic" /><published>2019-05-20T00:05:52+00:00</published><updated>2019-05-20T00:05:52+00:00</updated><id>http://marczych.com/2019/05/20/animals-and-cars-arent-polymorphic</id><content type="html" xml:base="http://marczych.com/2019/05/20/animals-and-cars-arent-polymorphic.html"><![CDATA[<p>I’ve grown tired of the common polymorphism example classes and think that they do polymorphism a disservice because they don’t demonstrate the real power of virtual dispatch.
For example:</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">class</span> <span class="nc">Animal</span><span class="p">():</span>
    <span class="k">def</span> <span class="nf">sound</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
        <span class="k">raise</span> <span class="nb">NotImplementedError</span><span class="p">()</span>


<span class="k">class</span> <span class="nc">Dog</span><span class="p">(</span><span class="n">Animal</span><span class="p">):</span>
    <span class="k">def</span> <span class="nf">sound</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
        <span class="k">return</span> <span class="s">'woof'</span>


<span class="k">class</span> <span class="nc">Cat</span><span class="p">(</span><span class="n">Animal</span><span class="p">):</span>
    <span class="k">def</span> <span class="nf">sound</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
        <span class="k">return</span> <span class="s">'meow'</span>


<span class="k">class</span> <span class="nc">Fox</span><span class="p">(</span><span class="n">Animal</span><span class="p">):</span>
    <span class="k">def</span> <span class="nf">sound</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
        <span class="k">return</span> <span class="s">'ring-ding-ding-ding-dingeringeding'</span>


<span class="k">for</span> <span class="n">animal</span> <span class="ow">in</span> <span class="p">[</span><span class="n">Dog</span><span class="p">(),</span> <span class="n">Cat</span><span class="p">(),</span> <span class="n">Fox</span><span class="p">()]:</span>
    <span class="k">print</span><span class="p">(</span><span class="n">animal</span><span class="p">.</span><span class="n">sound</span><span class="p">())</span>
</code></pre></div></div>

<p>I’ll spare you the example implementation but also remember the classic <code class="language-plaintext highlighter-rouge">Car</code> base class with abstract <code class="language-plaintext highlighter-rouge">wheelCount()</code> and <code class="language-plaintext highlighter-rouge">doorCount()</code> methods for derived classes to implement.</p>

<p>A programmer might understand how these classes behave and reason through code using them but still not understand when polymorphism should be used.
In fact, this is a bad use of polymorphism.
A better implementation would merely have a single class with member variables to capture the relevant information along with factory functions to create common instances of them:</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">class</span> <span class="nc">Animal</span><span class="p">():</span>
    <span class="k">def</span> <span class="nf">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">sound</span><span class="p">):</span>
        <span class="bp">self</span><span class="p">.</span><span class="n">sound</span> <span class="o">=</span> <span class="n">sound</span>

    <span class="k">def</span> <span class="nf">sound</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
        <span class="k">return</span> <span class="bp">self</span><span class="p">.</span><span class="n">sound</span>


<span class="k">def</span> <span class="nf">Dog</span><span class="p">():</span>
    <span class="k">return</span> <span class="n">Animal</span><span class="p">(</span><span class="s">'woof'</span><span class="p">)</span>


<span class="k">def</span> <span class="nf">Cat</span><span class="p">():</span>
    <span class="k">return</span> <span class="n">Animal</span><span class="p">(</span><span class="s">'meow'</span><span class="p">)</span>


<span class="k">def</span> <span class="nf">Fox</span><span class="p">():</span>
    <span class="k">return</span> <span class="n">Animal</span><span class="p">(</span><span class="s">'ring-ding-ding-ding-dingeringeding'</span><span class="p">)</span>


<span class="k">for</span> <span class="n">animal</span> <span class="ow">in</span> <span class="p">[</span><span class="n">Dog</span><span class="p">(),</span> <span class="n">Cat</span><span class="p">(),</span> <span class="n">Fox</span><span class="p">()]:</span>
    <span class="k">print</span><span class="p">(</span><span class="n">animal</span><span class="p">.</span><span class="n">sound</span><span class="p">())</span>
</code></pre></div></div>

<p>An <code class="language-plaintext highlighter-rouge">enum</code> with singletons for the necessary instances would also be a good choice but you get the idea.</p>

<p>So what <em>is</em> a good example of polymorphism?
Something that actually requires different code to run rather than only different data:</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">class</span> <span class="nc">ChatChannel</span><span class="p">():</span>
    <span class="k">def</span> <span class="nf">send_message</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">message</span><span class="p">):</span>
        <span class="k">raise</span> <span class="nb">NotImplementedError</span><span class="p">()</span>


<span class="kn">import</span> <span class="nn">slack</span>


<span class="k">class</span> <span class="nc">SlackChannel</span><span class="p">(</span><span class="n">ChatChannel</span><span class="p">):</span>
    <span class="k">def</span> <span class="nf">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">channel</span><span class="p">):</span>
        <span class="bp">self</span><span class="p">.</span><span class="n">channel</span> <span class="o">=</span> <span class="n">channel</span>

    <span class="k">def</span> <span class="nf">send_message</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">message</span><span class="p">):</span>
        <span class="n">slack</span><span class="p">.</span><span class="n">send_message</span><span class="p">(</span><span class="bp">self</span><span class="p">.</span><span class="n">channel</span><span class="p">,</span> <span class="n">message</span><span class="p">)</span>


<span class="kn">import</span> <span class="nn">hipchat</span>


<span class="k">class</span> <span class="nc">HipChatChannel</span><span class="p">(</span><span class="n">ChatChannel</span><span class="p">):</span>
    <span class="k">def</span> <span class="nf">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">channel</span><span class="p">):</span>
        <span class="k">if</span> <span class="n">channel</span><span class="p">.</span><span class="n">startswith</span><span class="p">(</span><span class="s">'@'</span><span class="p">):</span>
            <span class="bp">self</span><span class="p">.</span><span class="n">is_user</span> <span class="o">=</span> <span class="bp">True</span>
            <span class="bp">self</span><span class="p">.</span><span class="n">channel</span> <span class="o">=</span> <span class="n">channel</span><span class="p">.</span><span class="n">lstrip</span><span class="p">(</span><span class="s">'@'</span><span class="p">)</span>
        <span class="k">else</span><span class="p">:</span>
            <span class="bp">self</span><span class="p">.</span><span class="n">is_user</span> <span class="o">=</span> <span class="bp">False</span>
            <span class="bp">self</span><span class="p">.</span><span class="n">channel</span> <span class="o">=</span> <span class="n">channel</span><span class="p">.</span><span class="n">lstrip</span><span class="p">(</span><span class="s">'#'</span><span class="p">)</span>

    <span class="k">def</span> <span class="nf">send_message</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">message</span><span class="p">):</span>
        <span class="k">if</span> <span class="bp">self</span><span class="p">.</span><span class="n">is_user</span><span class="p">:</span>
            <span class="n">hipchat</span><span class="p">.</span><span class="n">send_user_message</span><span class="p">(</span><span class="bp">self</span><span class="p">.</span><span class="n">channel</span><span class="p">,</span> <span class="n">message</span><span class="p">)</span>
        <span class="k">else</span><span class="p">:</span>
            <span class="n">hipchat</span><span class="p">.</span><span class="n">send_channel_message</span><span class="p">(</span><span class="bp">self</span><span class="p">.</span><span class="n">channel</span><span class="p">,</span> <span class="n">message</span><span class="p">)</span>


<span class="n">channels</span> <span class="o">=</span> <span class="p">[</span>
    <span class="n">SlackChannel</span><span class="p">(</span><span class="s">'#general'</span><span class="p">),</span>
    <span class="n">SlackChannel</span><span class="p">(</span><span class="s">'@alice'</span><span class="p">),</span>
    <span class="n">HipChatChannel</span><span class="p">(</span><span class="s">'#random'</span><span class="p">),</span>
    <span class="n">HipChatChannel</span><span class="p">(</span><span class="s">'@bob'</span><span class="p">),</span>
<span class="p">]</span>

<span class="k">for</span> <span class="n">channel</span> <span class="ow">in</span> <span class="n">channels</span><span class="p">:</span>
    <span class="n">channel</span><span class="p">.</span><span class="n">send_message</span><span class="p">(</span><span class="s">'Hello World!'</span><span class="p">)</span>
</code></pre></div></div>

<p>This example has a <code class="language-plaintext highlighter-rouge">ChatChannel</code> class which is implemented by <code class="language-plaintext highlighter-rouge">SlackChannel</code> and <code class="language-plaintext highlighter-rouge">HipChatChannel</code>.
<code class="language-plaintext highlighter-rouge">SlackChannel</code> uses the <code class="language-plaintext highlighter-rouge">slack</code> library to send a message while <code class="language-plaintext highlighter-rouge">HipChatChannel</code> uses the <code class="language-plaintext highlighter-rouge">hipchat</code> library and has some special handling for users and channels.
The different library dependencies and logic is something that you can’t do with pure data like in the revised <code class="language-plaintext highlighter-rouge">Animal</code> example.
You <em>could</em> do it by passing in a lambda, storing it as a member variable, and calling that to send the message.
However, that’s just hand rolled virtual dispatch at which point you’re better off using proper inheritance for it.</p>

<p>All of this is <em>not</em> to say that the <code class="language-plaintext highlighter-rouge">Animal</code> example shouldn’t be used at all!
It can be useful to demonstrate the concept in a very basic way but the conversation should quickly move to more motivational examples to help explain when polymorphism should and should not be used.</p>]]></content><author><name></name></author><summary type="html"><![CDATA[I’ve grown tired of the common polymorphism example classes and think that they do polymorphism a disservice because they don’t demonstrate the real power of virtual dispatch. For example:]]></summary></entry><entry><title type="html">1-indexed time?</title><link href="http://marczych.com/2019/04/06/1-indexed-time.html" rel="alternate" type="text/html" title="1-indexed time?" /><published>2019-04-06T19:51:28+00:00</published><updated>2019-04-06T19:51:28+00:00</updated><id>http://marczych.com/2019/04/06/1-indexed-time</id><content type="html" xml:base="http://marczych.com/2019/04/06/1-indexed-time.html"><![CDATA[<p>The clock in my car has an interesting quirk: it often resets to 1:00 shortly after starting the engine.
Electrical issues aside, it made me think about how we represent time in terms of hours in a day.
In particular, I’ve always been perplexed by 11PM to 12AM being the boundary of the day.
Not only does the number increase but there is also a transition from post meridiem to ante meridiem.
This, of course, results in confusion when declaring deadlines and specifying times on exactly 12AM and often 11:59PM is used instead to clarify.</p>

<p>Oddly enough, this weird system lines up nicely with 24-hour time (military time).
Other than 00:00 and 12AM, the times match if you subtract 12 hours from the PM times.
This is awfully convenient for programmers when looking at log files because the conversion is very straightforward.
Although, there is often a time zone offset to account for which gums up the works.</p>

<p>So in some sense, our hours are 0-indexed because 01:00 is the <em>second</em> hour rather than the first.
And now returning to the clock in my car, they most likely decided to 1-index it to make the spec as simple as “count from 1 to 12 and loop around.”</p>

<p>Anyway, <a href="https://zachholman.com/talk/utc-is-enough-for-everyone-right">time is hard</a> and I should probably buy a new car.</p>]]></content><author><name></name></author><summary type="html"><![CDATA[The clock in my car has an interesting quirk: it often resets to 1:00 shortly after starting the engine. Electrical issues aside, it made me think about how we represent time in terms of hours in a day. In particular, I’ve always been perplexed by 11PM to 12AM being the boundary of the day. Not only does the number increase but there is also a transition from post meridiem to ante meridiem. This, of course, results in confusion when declaring deadlines and specifying times on exactly 12AM and often 11:59PM is used instead to clarify.]]></summary></entry><entry><title type="html">git-first-parent-bisect</title><link href="http://marczych.com/2019/03/24/git-first-parent-bisect.html" rel="alternate" type="text/html" title="git-first-parent-bisect" /><published>2019-03-24T23:51:13+00:00</published><updated>2019-03-24T23:51:13+00:00</updated><id>http://marczych.com/2019/03/24/git-first-parent-bisect</id><content type="html" xml:base="http://marczych.com/2019/03/24/git-first-parent-bisect.html"><![CDATA[<p>I just open sourced <a href="https://github.com/marczych/git-first-parent-bisect"><code class="language-plaintext highlighter-rouge">git-first-parent-bisect</code></a>.
This is something that I’ve wanted for so long but didn’t think was actually possible to do until I found this <a href="https://stackoverflow.com/a/5650992/1135611.">StackOverflow answer</a>.
I clearly had a use for such a script otherwise I wouldn’t have been searching for thatso I whipped up a hacky version of it and let it loose on the bug I was facing.
Sure enough, it took me straight to the offending branch and allowed me to root cause how the bug was introduced.</p>

<p>This script doesn’t have many miles under its belt but it has worked well for me a few times so I hope it works for you too!</p>]]></content><author><name></name></author><summary type="html"><![CDATA[I just open sourced git-first-parent-bisect. This is something that I’ve wanted for so long but didn’t think was actually possible to do until I found this StackOverflow answer. I clearly had a use for such a script otherwise I wouldn’t have been searching for thatso I whipped up a hacky version of it and let it loose on the bug I was facing. Sure enough, it took me straight to the offending branch and allowed me to root cause how the bug was introduced.]]></summary></entry><entry><title type="html">Strategically Tactical Programming</title><link href="http://marczych.com/2019/02/20/strategically-tactical-programming.html" rel="alternate" type="text/html" title="Strategically Tactical Programming" /><published>2019-02-20T02:29:47+00:00</published><updated>2019-02-20T02:29:47+00:00</updated><id>http://marczych.com/2019/02/20/strategically-tactical-programming</id><content type="html" xml:base="http://marczych.com/2019/02/20/strategically-tactical-programming.html"><![CDATA[<p>I just finished reading Ben McCormick’s excellent blog post on <a href="https://benmccormick.org/2019/02/18/strategic-coding">Strategic Coding</a>.
It makes a lot of great points about something that is awfully hard to get right in software development: when should you take shorcuts and when should you invest the time doing it right from the beginning?
I agree with all of what Ben (and John Ousterhout for that matter) said but I have a few things to add.</p>

<p>The holy grail is doing <em>both</em> strategic and tactical programming.
The trick is to find the boundaries where you need to change your mindset from one to the other.
Things that are hard to change should be done strategically because changing them can have rippling effects on other components whose changes and deployment might need to be done in lockstep.</p>

<p>Some examples of things to do strategically:</p>

<ul>
  <li><strong>APIs</strong>: Changing any public API ranges from hard to impossible because many of the clients could be entirely out of your control and even unaware to you. REST API endpoints, public methods in code, network protocols, environment variables, and command line arguments come to mind.</li>
  <li><strong>Data formats</strong>: Data formats are a kind of public API but with some extra caveats. When changing the data format you would ideally do it in a backwards compatible way. When making backwards incompatible changes you can must choose to maintain code to deal with the old format, bite the bullet and migrate all existing data into the new format, or decide to entirely drop support for old data. Database migrations can be particularly cumbersome. Even when you control the only client using the database, you’ll often have to do a staged rollout to avoid downtime or data in an inconsistent state. Database schemas and file formats are the obvious examples.</li>
</ul>

<p>The flip side of this is all of the things that we can afford to do tactically!
Fortunately, strong APIs provide <em>encapsulation</em> which allow us to hide implementation details behind the facade of the public interface.
We can be less thoughtful when it comes to internal choices such as data structures, algorithms, code style, and even choice of programming language and framework.
We can leverage tools like <a href="https://www.docker.com/">Docker</a> and <a href="https://swagger.io/docs/specification/about/">OpenAPI</a> to encapsulate the dirty details inside.</p>

<p>These ideas are powerful because you can get the best of both worlds.
Spend time on the things that are hard to change and spend much less time on the things that can easily be improved in the future.
This results in a significant time savings when you never end up making those further improvements down the line or, in extreme cases, scrap the entire thing.
Depending on the project, this is a likely outcome.
However, you still need to be careful not to over-architect the public API because even those choices can take a lot of time.</p>

<p>I’ve found myself using these principles to great effect during code reviews.
I’m much more lenient when it comes to things like local variable names, algorithms, HTML structure, and command line scripts and refrain from making nitpicky comments that result in more time wasted than the theoretical benefit they would provide.
Most frontend programming falls into this category.
Other than URL structure and cookies, frontend code in general just needs to be internally consistent which is great news because Typescript, refactoring tools, and unit tests make it easy to be confident when making these types of changes.</p>

<p>As always, I’m still working on honing my skills in this area to be more effective.
Thanks for the interesting read, Ben!</p>]]></content><author><name></name></author><summary type="html"><![CDATA[I just finished reading Ben McCormick’s excellent blog post on Strategic Coding. It makes a lot of great points about something that is awfully hard to get right in software development: when should you take shorcuts and when should you invest the time doing it right from the beginning? I agree with all of what Ben (and John Ousterhout for that matter) said but I have a few things to add.]]></summary></entry><entry><title type="html">It Turns Out You Need /usr/lib</title><link href="http://marczych.com/2019/02/17/it-turns-out-you-need-usr-lib.html" rel="alternate" type="text/html" title="It Turns Out You Need /usr/lib" /><published>2019-02-17T20:42:47+00:00</published><updated>2019-02-17T20:42:47+00:00</updated><id>http://marczych.com/2019/02/17/it-turns-out-you-need-usr-lib</id><content type="html" xml:base="http://marczych.com/2019/02/17/it-turns-out-you-need-usr-lib.html"><![CDATA[<p>It was a Tuesday night at the office around 5:30 PM.
I had gotten in around 7:30 AM so I was far from operating at full capacity at this point.
The task at hand was to write an internal <a href="https://vuejs.org/">Vue</a> quickstart guide so anyone in the company can get a quick overview of how we do front end apps and get them off the ground quickly.
I was working with the great <a href="https://cli.vuejs.org/guide/">Vue CLI 3</a> which I’d had success with in the past but this time around I couldn’t get the generated project to run properly.
<code class="language-plaintext highlighter-rouge">yarn serve</code> was failing because it couldn’t find the <code class="language-plaintext highlighter-rouge">vue-cli-service</code> executable on the PATH.
I found several issues on the subject with various solutions (<a href="https://github.com/vuejs/vue-cli/issues/2404">1</a>, <a href="https://github.com/vuejs/vue-cli/issues/1105">2</a>).
I tried the relevant solutions but couldn’t get anything to stick.
The strangest thing is that I remember having this same issue months ago and had apparently fixed it one way or another.
In fact, I could run our other Vue apps created with a very similar template without any problems.</p>

<p><em>What was different about these apps?</em></p>

<p>I tried reinstalling dependencies, starting from scratch, etc. but to no avail.
Eventually I decided that it must be my node/npm/yarn install so I set out to nuke it from my system and install it from scratch.</p>

<p>I was a little disappointed that there didn’t appear to be any equivalent to <code class="language-plaintext highlighter-rouge">npm uninstall -g everything</code>.
There were some scary looking bash commands that claimed to clean everything up but I didn’t want anything to go astray so I opted to do it by hand instead.</p>

<p>Things were fine at first when I started running <code class="language-plaintext highlighter-rouge">sudo rm -rf /usr/local/lib/node</code> and <code class="language-plaintext highlighter-rouge">sudo rm -rf ~/.yarn</code>.
I then found <code class="language-plaintext highlighter-rouge">/usr/lib/npm/node_modules</code> and inspected its contents with <code class="language-plaintext highlighter-rouge">ls</code>.
I quickly modified the previous command by putting <code class="language-plaintext highlighter-rouge">sudo rm -rf</code> at the beginning and backspaced a little to far to leave <code class="language-plaintext highlighter-rouge">/usr/lib</code> at the end and hit Enter.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ sudo rm -rf /usr/lib

</code></pre></div></div>

<p>Oops.</p>

<p>There was no prompt for sudo password because I had already been running commands under sudo.
As soon as I realized what I had done (about half a second), I mashed Ctrl-C a few times.
<em>Phew</em>.
It must okay, right?
I mean, how much damage could that have caused?</p>

<p>I ran <code class="language-plaintext highlighter-rouge">ls /usr/lib</code> and saw a few broken symlinks.
Well, maybe I can just reinstall that package and things’ll be fine.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ sudo apt-get update
sudo: unknown uid xxxxxxx: who are you?
</code></pre></div></div>

<p>Hmm, not a good sign.
Well, maybe I can copy the relevant files from a coworker and that’ll be good enough.
Oh wait, I can’t do that without root/sudo.</p>

<p>At this point I accepted that the machine was more or less a lost cause so I had to go into recovery mode and get it ready for imaging.
Fortunately, <code class="language-plaintext highlighter-rouge">/home</code> was on a different drive entirely so I only had to worry about system configuration.
I figured that <code class="language-plaintext highlighter-rouge">/etc/</code>, <code class="language-plaintext highlighter-rouge">/var/</code>, and <code class="language-plaintext highlighter-rouge">/opt/</code> would be a good start so I inserted a flash drive and tried to mount it but quickly realized I couldn’t do that without root.
Well, let’s just copy those to my home directory then.
Not so fast - you need root to be able to read most of those files.</p>

<p>This seemed like as good a time as any to call it a night and go home.</p>

<p>In the morning, I got the machine reimaged, discovered that my home directory was on a RAID1 array, reassembled said RAID array, mounted it over <code class="language-plaintext highlighter-rouge">/home/</code>, and I was off to the races!
I had the usual set backs one would expect and slowly installed the necessary packages to start working e.g. <code class="language-plaintext highlighter-rouge">git</code>, <code class="language-plaintext highlighter-rouge">tmux</code>, <code class="language-plaintext highlighter-rouge">vim</code>.</p>

<p>Okay, what was I doing before?
Right, trying to run a barebones Vue app.
I installed node and yarn from scratch and tried creating the app again.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ yarn serve
/bin/sh: vue-cli-service: command not found
</code></pre></div></div>

<p>What?!</p>

<p>At this point I was baffled.
I started modifying the scripts in <code class="language-plaintext highlighter-rouge">package.json</code> to debug it.
It turns out that <code class="language-plaintext highlighter-rouge">yarn serve</code> adds some directories to <code class="language-plaintext highlighter-rouge">$PATH</code> so binaries in installed packages can be called by name e.g. <code class="language-plaintext highlighter-rouge">$(pwd)/node_modules/.bin</code>.
It just so happened that I was testing these apps in temporary directories that are made with a bash function:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>function cd_temp {
   local name; name="${1:-default}"
   local date; date=$(date "+%Y-%m-%d.%H:%M:%S")
   local template; template="${date}_${name}_XXX"

   if [ "$(uname)" = "Darwin" ]; then
       cd "$(mktemp -d -t "$template")"
   else
       cd "$(mktemp --tmpdir --directory "$template")"
   fi
}
</code></pre></div></div>

<p>You might notice that the template for the directory has two <code class="language-plaintext highlighter-rouge">:</code> characters in it.
You might remember that <code class="language-plaintext highlighter-rouge">:</code> is the character used as the separator in <code class="language-plaintext highlighter-rouge">$PATH</code> so rather than adding the current directory to the path it ended up adding a bunch of gibberish to the path.
No wonder it couldn’t find <code class="language-plaintext highlighter-rouge">vue-cli-service</code>!</p>

<p>Sure enough, I <a href="https://github.com/marczych/dotfiles/commit/c8be0f3032e9b5a5e461b09e33f507f62ad8d4e6">changed</a> the function to not use <code class="language-plaintext highlighter-rouge">:</code> in the template and everything worked.</p>

<p>Ultimately, this wasn’t a huge set back with all things considered.
I was back up and running in a few hours and during that time I was still somewhat productive without a functional desktop by responding to emails/Slack/etc.
There are definitely some takeaways, though:</p>

<ul>
  <li>Tools should have an easy way to uninstall the packages that they maintain e.g. <code class="language-plaintext highlighter-rouge">yarn</code>/<code class="language-plaintext highlighter-rouge">npm</code>.</li>
  <li>Be careful when running any command that starts with <code class="language-plaintext highlighter-rouge">sudo rm -rf /</code>.</li>
  <li>Make sure that you backup important data in case you need to recover it or start from scratch.</li>
</ul>]]></content><author><name></name></author><summary type="html"><![CDATA[It was a Tuesday night at the office around 5:30 PM. I had gotten in around 7:30 AM so I was far from operating at full capacity at this point. The task at hand was to write an internal Vue quickstart guide so anyone in the company can get a quick overview of how we do front end apps and get them off the ground quickly. I was working with the great Vue CLI 3 which I’d had success with in the past but this time around I couldn’t get the generated project to run properly. yarn serve was failing because it couldn’t find the vue-cli-service executable on the PATH. I found several issues on the subject with various solutions (1, 2). I tried the relevant solutions but couldn’t get anything to stick. The strangest thing is that I remember having this same issue months ago and had apparently fixed it one way or another. In fact, I could run our other Vue apps created with a very similar template without any problems.]]></summary></entry><entry><title type="html">Actually Writing Code</title><link href="http://marczych.com/2018/08/24/actually-writing-code.html" rel="alternate" type="text/html" title="Actually Writing Code" /><published>2018-08-24T04:37:09+00:00</published><updated>2018-08-24T04:37:09+00:00</updated><id>http://marczych.com/2018/08/24/actually-writing-code</id><content type="html" xml:base="http://marczych.com/2018/08/24/actually-writing-code.html"><![CDATA[<p>I just read an article that chronicled the development of a small programming project by a relatively inexperienced developer.
It’s not very important which one but a few times it said something along the lines of “I’ve only spent 5% of my time actually writing code.”
I’ve heard that phrase a lot over the years.
Hell, I’ve said it myself from time to time.
It should probably be included in <a href="https://hackernoon.com/shit-programmers-say-translated-946849c2fbd4">Shit Programmers Say</a>.</p>

<p>Programmers like to write code and view anything other than writing code as unproductive time.
“I only <em>actually write code</em> 20 hours a week.”
“That project took 10 hours but I only spent a few hours <em>actually writing code</em>.”</p>

<p>It’s understandable because that’s what we’re trained to do and shipping code is generally the “useful output” that is valuable to the company and customers.</p>

<p>However, technical challenges surrounding programming tasks are often necessary evils.
The article that prompted this one in particular described the battle between JavaScript libraries and clashing CSS.
Sure - spending a few hours getting that sorted out is unfortunate but it likely far outweighs the cost of implementation without leveraging those libraries.
Docker giving you problems?
You have to learn its idiosyncrasies and play along if you want the isolation and reproducibility that it offers.
What about wanting hermetic builds from Bazel but struggling to shoehorn your project into its prescriptive worldview?
It’s up to you to decide if the benefits outweigh the downsides.</p>

<p>As for a professional software engineer, there are plenty of important things to do that are <em>not</em> actually writing code: documentation, code review, design docs, project planning/scheduling, and performance reviews to name a few.
With any luck, these tasks will be an efficient and worthwhile use of time.</p>

<p><a href="http://www.cs.nott.ac.uk/~pszcah/G51ISS/Documents/NoSilverBullet.html">No Silver Bullet</a> discusses how there won’t be single breakthrough in computing that results in an order of magnitude increase in productivity, performance, efficiency, etc.
Libraries, languages, frameworks, and the like yield modest yet significant results in some of those categories.
However, they sometimes result in <em>less</em> time actually writing code because more of the work has been shifted into installing, configuring, and generally understanding how to use these tools.
And that’s okay.
The end goal isn’t to write more code - the code is merely a means to an end.
Shipping a product and solving a customer’s problem is the end goal.
I haven’t been in the game very long but it appears that over time programming has moved to more of a plumbing job in that you need to find compatible parts and put them together in a particular way to solve the problem at hand.
Even visual programming removes the need to actually write any code because it’s just clicking and dragging boxes and lines around yet you can still solve some real problems.</p>

<p>I don’t mean to imply that struggling with tools is a necessary evil and we shouldn’t try to fix it - quite the opposite in fact.
Better tools, development environments, and libraries are accelerating the rate of development like never before and result in better products so we should continue to make them better.
Productivity should be measured more on how much of a problem is solved in a given amount of time <em>not</em> how much of it is spent actually writing code or how many lines of code were written.
It’s often much much easier to solve a problem by coming up with a better and more pragmatic solution rather than immediately jumping into the code when the first solution presents itself.</p>

<p>So stop being so concerned about not actually writing code - it’s sometimes a better use of your time.</p>]]></content><author><name></name></author><summary type="html"><![CDATA[I just read an article that chronicled the development of a small programming project by a relatively inexperienced developer. It’s not very important which one but a few times it said something along the lines of “I’ve only spent 5% of my time actually writing code.” I’ve heard that phrase a lot over the years. Hell, I’ve said it myself from time to time. It should probably be included in Shit Programmers Say.]]></summary></entry><entry><title type="html">The Truman Show and Twitch.tv</title><link href="http://marczych.com/2018/07/29/the-truman-show-and-twitch-tv.html" rel="alternate" type="text/html" title="The Truman Show and Twitch.tv" /><published>2018-07-29T19:34:00+00:00</published><updated>2018-07-29T19:34:00+00:00</updated><id>http://marczych.com/2018/07/29/the-truman-show-and-twitch-tv</id><content type="html" xml:base="http://marczych.com/2018/07/29/the-truman-show-and-twitch-tv.html"><![CDATA[<p>I’ve been watching video game streamers on Twitch.tv lately - primarily shroud and chocoTaco.
Other than being exceptionally good at PUBG, they have interesting anecdotes throughout the stream and know how to keep things interesting.
Perhaps most intriguing to me is how <em>different</em> their lives are compared to mine.
I go into an office, work on my computer along with a slew of other people, and head home about 9 hours later.
The likes of shroud and chocoTaco wake up, turn on their computers, flip on their webcams, and broadcast their screens and faces to whomever is interested in watching.</p>

<p>I find this endlessly intriguing.
What is their relationship with video games?
Do they game after “work”?
How do they feel about their lives being broadcast to so many people?
How much of their personal life do they divulge?
Do they worry about people seeing their eating, dressing, and bathroom habits?</p>

<p>I recently rewatched The Truman Show.
Besides being a very enjoyable movie, it has thought provoking commentary on social media today and, being released in 1998, was ahead of its time.
There is a <a href="https://www.youtube.com/watch?v=cLJAXu5OD-c">fantastic Nerdwriter video</a> about it which I highly recommend.</p>

<p>I can’t help but see the parallels between streamers on Twitch.tv and The Truman Show.
The most obvious being a window into someone else’s life.</p>

<p>The platform makes it trivial to have a constant video stream of whatever you choose.
The Truman Show, specifically the fake show inside the movie, was a massive production but it doesn’t have to be to get a similar effect.
I wouldn’t be at all surprised if there is a stream emulating The Truman Show because the barrier to entry is so low these days.
Probably not of a person against their will but very likely of a pet who is none the wiser.</p>

<p>Perhaps the most interesting parallel is advertising because it’s already happening to some degree.
Meryl Burbank, Truman’s wife, often advertises directly to a camera while in the same room as Truman.
This is effective because it is embedded into the content and there are lots of eyeballs on the screen.
This differs from traditional advertising in that the advertisements are in a distinct section compared to the content.
This has a severe disadvantage because we have all learned to ignore this type of advertising.</p>

<p>Streamers can be sponsored by companies and brand their stream.
They can get more subtle by getting paid to casually mention a product during their stream.
Or get even more subtle by showing a branded coffee mug to the webcam.</p>

<p>I’d imagine this would be super effective because the streamers have 1000’s of subscribers and a very particular audience and I’m surprised that this isn’t more common.</p>]]></content><author><name></name></author><summary type="html"><![CDATA[I’ve been watching video game streamers on Twitch.tv lately - primarily shroud and chocoTaco. Other than being exceptionally good at PUBG, they have interesting anecdotes throughout the stream and know how to keep things interesting. Perhaps most intriguing to me is how different their lives are compared to mine. I go into an office, work on my computer along with a slew of other people, and head home about 9 hours later. The likes of shroud and chocoTaco wake up, turn on their computers, flip on their webcams, and broadcast their screens and faces to whomever is interested in watching.]]></summary></entry><entry><title type="html">Fantastic Products and Where to Find Them</title><link href="http://marczych.com/2018/07/22/fantastic-products-and-where-to-find-them.html" rel="alternate" type="text/html" title="Fantastic Products and Where to Find Them" /><published>2018-07-22T22:07:02+00:00</published><updated>2018-07-22T22:07:02+00:00</updated><id>http://marczych.com/2018/07/22/fantastic-products-and-where-to-find-them</id><content type="html" xml:base="http://marczych.com/2018/07/22/fantastic-products-and-where-to-find-them.html"><![CDATA[<p>I’ve been meaning to write this post for several years now so I’m glad that I’m finally getting around to it.
There are a few products that I’ve been using that are especially elegant and are a pleasure to use.</p>

<h1 id="vitamix">Vitamix</h1>

<p>The Vitamix blender has won many awards and it doesn’t need repeating that it’s a great and versatile kitchen appliance.
I have the <a href="https://www.amazon.com/Vitamix-5300-Low-Profile-Professional-Grade-Self-Cleaning/dp/B01688AFFC/">5300</a> model but they all appear to be pretty comparable as far as I can tell.
What I like the most about it is how <em>simple</em> yet <em>effective</em> it is.</p>

<p>Let’s consider the <a href="https://www.amazon.com/Oster-12-Speed-Blender-Brushed-Nickel/dp/B001KBY9PU">Oster 6811 blender</a>.
It has 12 different settings: pulse, pulse, grate, easy clean, blend, puree, shred, cream, grind, chop, liquefy, whip, ice crush, and mix.
Phew.
I don’t know about you, but I don’t know when I would use some of those settings rather than other ones and the sheer number of options is dizzying.</p>

<p>Or how about the <a href="https://www.amazon.com/Blendtec-TB-621-20-Blender-Classic-FourSide/dp/B000GIGZXM">Blendtec TB-621-20</a>?
It certainly has fewer options than the Oster but there are only icons on the buttons so it’s unclear to me what each one does.
Also, the -/+ buttons operate in addition to the different modes?</p>

<p>Finally, let’s move on to the Vitamix.
It has a start/stop toggle, hold for pulse switch, and 1-10 speed knob.
It’s pretty clear from the get-go that you flip it on, crank the knob to the desired speed, and turn it off when it’s done.
It is great at what it does so it doesn’t require any features to persuade people to buy it.
The product speaks for itself.</p>

<p>Granted, some of the other settings could come in handy from time to time and the price point of each product should be considered as well.
I very much appreciate the simplicity of the Vitamix and how you know what is going to happen when you flip it on.</p>

<h1 id="sonicare">Sonicare</h1>

<p>The <a href="https://www.amazon.com/Philips-Sonicare-Rechargeable-Toothbrush-HX9331/dp/B07C79J42M">Philips Sonicare Diamond</a> toothbrush is another elegant and effective product.
It is “just a toothbrush” yet the attention to detail is impressive.</p>

<p>There is a single button on the device that is used to turn it on, change modes if it was recently turned on, and turn it off.
The conductive charging technology provides lots of benefits:</p>

<ul>
  <li>Charging is easier than plugging a cable into it (just plunk it down in the charging stand!)</li>
  <li>Waterproof because there aren’t any exposed ports</li>
  <li>The toothbrush fits nicely in the travel case which is set up with conductive charging just like the stands</li>
</ul>

<p>It’s a pretty powerful toothbrush and Philips thoughtfully built in a few week ramp up period to slowly increase the power to allow your gums to adjust.
The only visual indicator on it is the battery level which is very sleek and elegant.</p>

<p>The brush timer that triggers every 30 seconds to indicate that it’s time to switch sides is clever.
The obvious way to do this would be either with a visual indicator or a sound of some sort.
A visual indicator is out of the question because you likely can’t see the device when the business end is in your mouth!
A sound could work pretty well but would require special hardware in the toothbrush to make that happen.
They ended up using haptic feedback by changing the vibration pattern slightly which is very (but not overly) noticeable in one’s mouth.</p>

<hr />

<p>What the Vitamix and Sonicare have most in common is a simple and reliable design which is important in terms of usability, durability, manufacturing, and maintenance.
Although I don’t own one myself, KitchenAid stand mixers are in the same category.
They have simple controls, do one thing well, yet are very versatile.
All of these qualities make them a joy to use and result in happy customers.</p>

<p>Other companies should take note.</p>]]></content><author><name></name></author><summary type="html"><![CDATA[I’ve been meaning to write this post for several years now so I’m glad that I’m finally getting around to it. There are a few products that I’ve been using that are especially elegant and are a pleasure to use.]]></summary></entry><entry><title type="html">file-pager</title><link href="http://marczych.com/2018/06/25/file-pager.html" rel="alternate" type="text/html" title="file-pager" /><published>2018-06-25T01:29:59+00:00</published><updated>2018-06-25T01:29:59+00:00</updated><id>http://marczych.com/2018/06/25/file-pager</id><content type="html" xml:base="http://marczych.com/2018/06/25/file-pager.html"><![CDATA[<p>I end up opening files in a terminal to browse their contents fairly often.
<code class="language-plaintext highlighter-rouge">pager</code> and <code class="language-plaintext highlighter-rouge">less</code> make quick work of local files but aren’t immediately useful for text logs and other content served over http(s).
The following bash script can be used to open either a local file or URL in a pager by conditionally downloading the file into a temporary directory beforehand:</p>

<figure class="highlight"><pre><code class="language-bash" data-lang="bash"><span class="c">#!/usr/bin/env bash</span>

<span class="nb">set</span> <span class="nt">-euo</span> pipefail

<span class="k">if</span> <span class="o">[[</span> <span class="nv">$# </span><span class="o">==</span> 0 <span class="o">||</span> <span class="nv">$1</span> <span class="o">==</span> <span class="s2">"-h"</span> <span class="o">||</span> <span class="nv">$1</span> <span class="o">==</span> <span class="s2">"--help"</span> <span class="o">]]</span><span class="p">;</span> <span class="k">then
    </span><span class="nb">echo</span> <span class="s2">"Usage: </span><span class="nv">$0</span><span class="s2"> file"</span>
    <span class="nb">exit </span>0
<span class="k">fi

</span><span class="nv">file</span><span class="o">=</span><span class="s2">"</span><span class="nv">$1</span><span class="s2">"</span>

<span class="k">if</span> <span class="o">[[</span> <span class="nv">$file</span> <span class="o">=</span>~ ^http<span class="o">(</span>s<span class="o">)</span>?:// <span class="o">]]</span><span class="p">;</span> <span class="k">then
    </span><span class="nv">temp_file</span><span class="o">=</span><span class="si">$(</span><span class="nb">mktemp</span><span class="si">)</span>
    wget <span class="nt">--quiet</span> <span class="s2">"</span><span class="nv">$file</span><span class="s2">"</span> <span class="nt">--output-document</span> <span class="s2">"</span><span class="nv">$temp_file</span><span class="s2">"</span>
    <span class="nv">file</span><span class="o">=</span><span class="nv">$temp_file</span>
<span class="k">fi

if </span><span class="nb">hash </span>pager 2&gt;/dev/null<span class="p">;</span> <span class="k">then
    </span>pager <span class="s2">"</span><span class="nv">$file</span><span class="s2">"</span>
<span class="k">else
    </span>less <span class="s2">"</span><span class="nv">$file</span><span class="s2">"</span>
<span class="k">fi</span></code></pre></figure>

<p>This could easily be expanded to support other protocols e.g. <code class="language-plaintext highlighter-rouge">(s)ftp://</code>.
This script is also in <a href="https://gist.github.com/marczych/0f2c85fdf4fee4b698375e65f744bf4f">gist</a> form.</p>]]></content><author><name></name></author><summary type="html"><![CDATA[I end up opening files in a terminal to browse their contents fairly often. pager and less make quick work of local files but aren’t immediately useful for text logs and other content served over http(s). The following bash script can be used to open either a local file or URL in a pager by conditionally downloading the file into a temporary directory beforehand:]]></summary></entry></feed>