<?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: David Alexander</title>
    <description>The latest articles on Forem by David Alexander (@thelonelyghost).</description>
    <link>https://forem.com/thelonelyghost</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%2F788%2Fbc3e8932-0cec-4b28-a4cf-e21ca6fdfb46.jpeg</url>
      <title>Forem: David Alexander</title>
      <link>https://forem.com/thelonelyghost</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/thelonelyghost"/>
    <language>en</language>
    <item>
      <title>Nix Is Worth the Complexity</title>
      <dc:creator>David Alexander</dc:creator>
      <pubDate>Sun, 04 Jul 2021 05:11:27 +0000</pubDate>
      <link>https://forem.com/thelonelyghost/nix-is-worth-the-complexity-4jpl</link>
      <guid>https://forem.com/thelonelyghost/nix-is-worth-the-complexity-4jpl</guid>
      <description>&lt;p&gt;Recently I've gotten fed up with the breaking changes in &lt;a href="https://brew.sh/"&gt;Homebrew package manager&lt;/a&gt;. After some research, using &lt;a href="https://nixos.org/"&gt;Nixpkgs&lt;/a&gt; seemed like a far more stable option for GNU/Linux tooling on MacOS, albeit with a decent learning curve for configuration.&lt;/p&gt;

&lt;p&gt;Without going too much further into it &lt;a href="https://nixos.org/guides/how-nix-works.html"&gt;Nix is pretty cool&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Over the following months, I'd been spending what free time I had tinkering with Nix on MacOS, specifically with &lt;a href="https://github.com/nix-community/home-manager"&gt;Home Manager&lt;/a&gt; and &lt;a href="https://daiderd.com/nix-darwin/"&gt;nix-darwin&lt;/a&gt;. Nix is cross-platform between Linux and MacOS, and, frankly, I found myself maintaining an increasing number of shell scripts for installing important tools I use. I got &lt;em&gt;really&lt;/em&gt; good at writing bash scripts. 🤣&lt;/p&gt;

&lt;p&gt;Bash scripts are really handy, but there are limits. There is no clean state with them, there's only whatever you're working with right then. You try your best to make them idempotent, but there's no reasonable way to test that they meet that expectation. It can only be reliably tested from a clean state once. On the other hand, Nix builds in a clean room every time.&lt;/p&gt;

&lt;h2&gt;
  
  
  Don't pollute the global state
&lt;/h2&gt;

&lt;p&gt;Nix is a clean state, it's purpose-built for isolation between each program, allowing me to better follow the adage "don't mutate global state" and sandbox each tool I needed. Then I could selectively upgrade and, if the upgrade broke something, roll back to previous state easily.&lt;/p&gt;

&lt;p&gt;It has happened more times than I can count, I help my coworkers through a borked python setup when the underlying python version gets upgraded in-place. Thanks &lt;code&gt;brew upgrade&lt;/code&gt;... 😑&lt;/p&gt;

&lt;p&gt;Instead of digging through all of the virtualenvs out there, and rummaging through whether pyenv was setup right for that shell, or any number of other issues, why not decouple it?&lt;/p&gt;

&lt;p&gt;Nix offers the best of both &lt;a href="https://kb.iu.edu/d/akqn"&gt;dynamic and static linking&lt;/a&gt; when building an application. It allows for multiple versions of python 3 at the same time. Or Java. Or Haskell. Or Go. Or glibc. Upgrade one library and it doesn't need to update them all. Similarly if 5 applications all use the same library, there's no reason to duplicate it 5 times on the disk.&lt;/p&gt;

&lt;h2&gt;
  
  
  Keep project-specific tools with the project
&lt;/h2&gt;

&lt;p&gt;I tend to use &lt;a href="https://direnv.net/"&gt;direnv&lt;/a&gt; in my workflow for exactly this purpose: I can keep project-specific settings (e.g., tool selection) specific to that base directory. Unfortunately this is typically limited to &lt;em&gt;versions&lt;/em&gt; of known programs (e.g., python 3.7.3 instead of python 3.9.1) and workstation-specific environment variables (e.g., path to secret files).&lt;/p&gt;

&lt;p&gt;Introducing Nix, this changes my workflow. By using &lt;code&gt;nixify&lt;/code&gt; (roughly inspired by &lt;a href="https://github.com/ejpcmac/config/blob/bc9ee4e7363e4e0ca97f4addbdd9370b83048d3c/zsh/direnv.zsh#L33-L138"&gt;this bash function&lt;/a&gt;) I am able to install and use postgres, limiting it only to being used in this one project directory. Maybe I'll (re)use postgres in another project. Do I need it installed globally? Absolutely not. This is a development machine, not an application server.&lt;/p&gt;

&lt;h2&gt;
  
  
  Current state of integration
&lt;/h2&gt;

&lt;p&gt;I've been working with &lt;a href="https://github.com/nix-community/home-manager"&gt;Home Manager&lt;/a&gt; for managing my dotfiles and (user-scoped) system configuration. So far it has been difficult translating certain parts of &lt;a href="https://github.com/thoughtbot/rcm"&gt;RCM&lt;/a&gt;'s framework, such as its overlay approach (having both &lt;code&gt;~/.dotfiles&lt;/code&gt; and &lt;code&gt;~/.dotfiles-local&lt;/code&gt; repos cloned with the latter containing higher priority config files).&lt;/p&gt;

&lt;p&gt;Instead of symlinking files into place, thereby ensuring any changes to them in-place are reflected back in the git repo, they're made immutable and the &lt;em&gt;only&lt;/em&gt; way to change them is from the git repo.&lt;/p&gt;

&lt;p&gt;I've begun ripping out the version managers like pyenv, asdf, chruby, and others to completely replace it with project-specific Nix expressions.&lt;/p&gt;

</description>
      <category>nix</category>
      <category>devops</category>
      <category>dotfiles</category>
      <category>workstations</category>
    </item>
    <item>
      <title>7 principles of a good sysadmin</title>
      <dc:creator>David Alexander</dc:creator>
      <pubDate>Thu, 15 Apr 2021 03:55:13 +0000</pubDate>
      <link>https://forem.com/thelonelyghost/7-principles-of-a-good-sysadmin-35i3</link>
      <guid>https://forem.com/thelonelyghost/7-principles-of-a-good-sysadmin-35i3</guid>
      <description>&lt;p&gt;This seems to be a common topic of conversation, so I figure I should put it on paper (so to speak) what I value as a systems administrator, or "sysadmin."&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Keep it simple&lt;/li&gt;
&lt;li&gt;Ensure it can be reproduced&lt;/li&gt;
&lt;li&gt;Keep it close to stock&lt;/li&gt;
&lt;li&gt;Magic is bad&lt;/li&gt;
&lt;li&gt;No development tools on the server&lt;/li&gt;
&lt;li&gt;Prefer complexity at compile time over runtime&lt;/li&gt;
&lt;li&gt;Consume artifacts&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;What does this mean?&lt;/p&gt;

&lt;h2&gt;
  
  
  The fewer moving parts, the easier to diagnose
&lt;/h2&gt;

&lt;p&gt;By keeping things simple, reproduceable, and close to their defaults, this sets a sysadmin up for success &lt;em&gt;when&lt;/em&gt; things go wrong. More so, by keeping things close to the default settings you maximize the chance that your setup overlaps someone else's. Bonus to finding info on Stack Overflow or &lt;a href="https://xkcd.com/979/"&gt;that one forum post&lt;/a&gt;!&lt;/p&gt;

&lt;h2&gt;
  
  
  TIP: Script it out" href="tip-script-it"
&lt;/h2&gt;

&lt;p&gt;By scripting out everything you do, no matter how small, this ensures you can walk away mid-thought and pick up where you left off later.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Keep scripts in some central location to share with your team of sysadmins&lt;/li&gt;
&lt;li&gt;Version control systems (VCS) are best for iterating on these scripts&lt;/li&gt;
&lt;li&gt;Make the VCS repo private, lest credentials are mistakenly hardcoded&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Make your shell script &lt;em&gt;executable documentation&lt;/em&gt;. Write it by defining your own shell functions describing each step you're taking.&lt;/p&gt;

&lt;h2&gt;
  
  
  Know your tools
&lt;/h2&gt;

&lt;p&gt;If you don't understand how a thing works, fix that. Learn about it. Pull back that abstraction layer and look under the hood.&lt;/p&gt;

&lt;p&gt;Why is magic bad? When you're troubleshooting some error, how can you logically rule out the tool as a contributing factor?&lt;/p&gt;

&lt;p&gt;This principle does not preclude you from using said magical tool, but it does mandate you dispel that magic by working to understand how it is implemented.&lt;/p&gt;

&lt;h2&gt;
  
  
  Compile time vs. runtime
&lt;/h2&gt;

&lt;p&gt;In a sysadmin context, compile time can mean "the stuff done to configure and setup a service, system, or application before it is immediately needed."&lt;/p&gt;

&lt;p&gt;In contrast, runtime means "stuff being done as the application is being put into its 'running' state."&lt;/p&gt;




&lt;h2&gt;
  
  
  Example: Docker
&lt;/h2&gt;

&lt;p&gt;Some container images contain a shell script as an entrypoint (e.g., &lt;code&gt;entrypoint.sh&lt;/code&gt;). These shift some compile time tasks to execute at runtime, then defer to running the underlying application.&lt;/p&gt;

&lt;p&gt;Reasons for this design might be:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;More in-depth configuration changes required to pivot between environments&lt;/li&gt;
&lt;li&gt;Rapid action may be required to change credentials, so they're only passed at runtime&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Actions taken in a &lt;code&gt;Dockerfile&lt;/code&gt; when &lt;code&gt;docker build&lt;/code&gt; is run are considered "compile time."&lt;/p&gt;

&lt;p&gt;Actions taken when running &lt;code&gt;docker exec&lt;/code&gt;/&lt;code&gt;docker run&lt;/code&gt; are considered "runtime."&lt;/p&gt;




&lt;p&gt;Complexity costs at compile time need only be paid down once: when things are being setup.&lt;/p&gt;

&lt;p&gt;If at runtime, cost of complexity is paid down every time the application is started.&lt;/p&gt;

&lt;p&gt;Keep it simple. Pay down the cost as soon as possible.&lt;/p&gt;

&lt;h2&gt;
  
  
  Artifacts are like gold
&lt;/h2&gt;

&lt;p&gt;Whether the application uses an interpreted language (e.g., python) or is statically compiled (e.g., golang), an artifact can be built to make rolling forward and reverting simple.&lt;/p&gt;

&lt;p&gt;In the case of python, a wheel (&lt;code&gt;my_pkg-0.1.0-py3-any.whl&lt;/code&gt;) is a well-formed package holding the python source code. In a &lt;a href="https://docs.python.org/3/tutorial/venv.html"&gt;venv&lt;/a&gt;, install it with &lt;code&gt;pip install ./my_pkg-0.1.1-py3-any.whl&lt;/code&gt; to upgrade and &lt;code&gt;pip install ./my_pkg-0.1.0-py3-any.whl&lt;/code&gt; to roll back.&lt;/p&gt;

&lt;p&gt;With golang it's even easier. Just drop the new binary in place and, if it doesn't work, drop the old binary in that spot instead.&lt;/p&gt;

&lt;p&gt;Some VCS providers, like GitHub.com, allow uploading binaries and other assets related to a release to a location that can be accessed later, perhaps even by shell scripts.&lt;/p&gt;

</description>
      <category>sysadmin</category>
      <category>beginners</category>
      <category>tips</category>
    </item>
    <item>
      <title>What is a Symbol?</title>
      <dc:creator>David Alexander</dc:creator>
      <pubDate>Mon, 09 Oct 2017 23:02:00 +0000</pubDate>
      <link>https://forem.com/thelonelyghost/what-is-a-symbol-3b4</link>
      <guid>https://forem.com/thelonelyghost/what-is-a-symbol-3b4</guid>
      <description>&lt;p&gt;As I was browsing twitter this evening, I came across &lt;a href="https://twitter.com/searls/status/917392217140072449"&gt;a tweet by @searls asking newer rubyists (&amp;lt;5 years) what some still confusing concepts are in Ruby&lt;/a&gt;. The most common concept that remained confusing was symbols, so here’s my explanation of it.&lt;/p&gt;

&lt;p&gt;In order to explain symbols, I must first explain datatypes.&lt;/p&gt;

&lt;h2&gt;
  
  
  Datatypes
&lt;/h2&gt;

&lt;p&gt;Do you know the difference between datatypes?&lt;/p&gt;

&lt;h3&gt;
  
  
  Primitives
&lt;/h3&gt;

&lt;p&gt;There’s a &lt;code&gt;string&lt;/code&gt; (e.g., &lt;code&gt;"Lorem ipsum dolor"&lt;/code&gt;), which is a set of characters (&lt;code&gt;char&lt;/code&gt;s). There are various numbers ranging from an integer (e.g., &lt;code&gt;1&lt;/code&gt; but not &lt;code&gt;1.4&lt;/code&gt;), a double (a really large integer), a float (e.g., &lt;code&gt;1.4&lt;/code&gt; or &lt;code&gt;1.0&lt;/code&gt;), and any of those can be signed (including negative numbers) or unsigned (absolute values, positive numbers only). There are super simple concepts like booleans, which can be exactly “yes” or “no”.&lt;/p&gt;

&lt;p&gt;Why are there all these variations? Isn’t it all just text? Think about this:&lt;/p&gt;

&lt;h3&gt;
  
  
  Binary
&lt;/h3&gt;

&lt;p&gt;A computer thinks in binary, ones and zeros. Binary can represent any number, such as &lt;code&gt;000000&lt;/code&gt; represents zero and &lt;code&gt;000001&lt;/code&gt; represents one, as one might imagine. The tricky part is &lt;code&gt;000010&lt;/code&gt; represents two. How’s that? Let’s continue.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;000011&lt;/code&gt; → three&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;000100&lt;/code&gt; → four&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;000101&lt;/code&gt; → five&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;000110&lt;/code&gt; → six&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;000111&lt;/code&gt; → seven&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;001000&lt;/code&gt; → eight&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Get the idea? If we continue with this pattern, we’ll see that we eventually hit &lt;code&gt;111111&lt;/code&gt; (sixty-three), but that’s not the last number there exists, is it? We need another digit to hold a zero or one and it represents all the way up to one-hundred twenty-seven. Wow, that’s quite a jump, right? How does all of this have anything to do with data types?&lt;/p&gt;

&lt;h3&gt;
  
  
  Datatypes in binary
&lt;/h3&gt;

&lt;p&gt;A computer has to store a representation of data in memory. But wait, didn’t we just cover that a computer thinks in binary? Well that’s still true. We have to come up with a shorthand for storing things like &lt;code&gt;1.3&lt;/code&gt; in binary.&lt;/p&gt;

&lt;p&gt;Let’s tear this apart. This is a float datatype. We have to come up with some shorthand for noting what is before the decimal point and what is after. How about we say the first four digits are the number before the decimal point and the last four are the number after. We can extend this beyond eight digits later.&lt;/p&gt;

&lt;p&gt;In this case the binary representation of &lt;code&gt;1.3&lt;/code&gt; might be &lt;code&gt;00010011&lt;/code&gt;. What’s the difference between this and the integer &lt;code&gt;19&lt;/code&gt;? Both are represented by the same binary, right? We’ll need to come up with some universal shorthand to note the difference.&lt;/p&gt;

&lt;p&gt;In an integer, we know the same value &lt;code&gt;010011&lt;/code&gt; (19) might also be positive or negative. This is called a “signed” integer. Other numeric datatypes can be signed as well, but we’ll keep it simple with integers for now. We’ll keep our shorthand of splitting up the digits, but whether it’s positive or negative is just 2 choices. We can probably keep to the first digit where &lt;code&gt;1&lt;/code&gt; means negative and &lt;code&gt;0&lt;/code&gt; means positive. Therefore &lt;code&gt;19&lt;/code&gt; means &lt;code&gt;0010011&lt;/code&gt; and &lt;code&gt;-19&lt;/code&gt; means &lt;code&gt;1010011&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Data headers
&lt;/h3&gt;

&lt;p&gt;We have all these shorthand tricks we have to remember, but at the end of the day it’s just 1’s and 0’s. How will we differentiate between an unsigned &lt;code&gt;19&lt;/code&gt; and &lt;code&gt;1.3&lt;/code&gt; from before? Let’s come up with one, universal shorthand to determine which data type we will be storing for the next few digits. Three digits should cover it for now. We’ll remember some datatypes by this mapping for now:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;001&lt;/code&gt; → char&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;010&lt;/code&gt; → unsigned integer&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;011&lt;/code&gt; → signed integer&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;100&lt;/code&gt; → float&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;110&lt;/code&gt; → double&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;111&lt;/code&gt; → boolean&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;To integrate this we’ll tack this onto the starting of each value and just remember to interpret the first 3 digits as the datatype indicators.&lt;/p&gt;

&lt;h3&gt;
  
  
  Data maximums/minimums
&lt;/h3&gt;

&lt;p&gt;In order to have all of these shorthands, we have to agree on the next &lt;em&gt;X&lt;/em&gt; number of digits which will signify the value of the datatype. A boolean, true and false, only needs one digit (plus the header) while an unsigned integer can only count between 0 and 127 with 3 digits, which might not be enough for fun things like counting the number of seats in a stadium.&lt;/p&gt;

&lt;p&gt;We’ll come up with some arbitrary lengths of digits for these datatypes. Here are some examples:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;0000000000&lt;/code&gt; → char (10 digits)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;0000000000000&lt;/code&gt; → float (13 digits)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;000000000&lt;/code&gt; → unsigned integer (9 digits)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;0000000000&lt;/code&gt; → signed integer (10 digits)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;0&lt;/code&gt; → boolean (1 digit)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;All together, a float will take up 13 digits for the value + 3 digits for the header indicating that it’s a float. 16 digits. If we take a multiple instances of data (datatype header + value in binary), we can string them together.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;1000000000010011&lt;/code&gt; → float datatype of value &lt;code&gt;1.3&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;1110&lt;/code&gt; → boolean datatype of value &lt;code&gt;false&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Let’s take these two example data instances and put them together like a computer might keep it in memory: &lt;code&gt;11101000000000010011&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;What?&lt;/p&gt;

&lt;p&gt;Okay, let's tear it apart again.&lt;/p&gt;

&lt;p&gt;If we saw just this binary without any other context, we can remember our shorthand for the headers by reading left to right. The first 3 digits signify it’s a boolean, which we know has a value length of 1 digit. We read it as boolean &lt;code&gt;false&lt;/code&gt; and we’ve parsed the first 4 digits in the example data.&lt;/p&gt;

&lt;p&gt;Since we're done with the first 4, we'll start at digit 5, follow along the same pattern with interpreting the first 3 digits as the datatype (&lt;code&gt;100&lt;/code&gt; = float), and parse the next &lt;em&gt;X&lt;/em&gt; digits (float value → 13 digits) as the value. The next 13 digits amount to &lt;code&gt;0000000010011&lt;/code&gt;, which we’ll pretend like we already established a new shorthand where floats have the last 3 digits reserved for the decimal number. This makes it easier since we remember this was &lt;code&gt;1.3&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Doing this again with another example value: &lt;code&gt;01100000111010010001011100&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Reading the first 3 digits (&lt;code&gt;011&lt;/code&gt;) we see it’s a signed integer. This means we read the next 10 digits (&lt;code&gt;0000011101&lt;/code&gt;) as the value. Knowing our shorthand for signed integers, we recall the first digit of the value (&lt;code&gt;0&lt;/code&gt;) tells us whether it’s positive or negative, and the remaining digits (&lt;code&gt;000011101&lt;/code&gt;) are the number itself. We can then tell it’s &lt;code&gt;+29&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The next three digits after that’s done is &lt;code&gt;001&lt;/code&gt;, which means a character. You know from before that a character datatype reserves the next 10 digits for its value, but we don’t know how to decode it. We haven’t established that shorthand. The important part here, though, is that we can differentiate between the different datatypes when they’re thrown together in one, long, unbreaking string of 1’s and 0’s.&lt;/p&gt;

&lt;h2&gt;
  
  
  Characters versus Strings
&lt;/h2&gt;

&lt;p&gt;In case you weren’t already aware, a character might represent any one key on your keyboard, including letters, numbers, punctuation (like &lt;code&gt;?&lt;/code&gt; and &lt;code&gt;!&lt;/code&gt;), or other bits of written language (like &lt;code&gt;{&lt;/code&gt; or &lt;code&gt;)&lt;/code&gt;). A character can make up individual letters you might not see on your keyboard, like “Ã©” or “â†’”. The point is, a character can be a large number of possible values taking up the same physical space on your screen as a 1 or 0.&lt;/p&gt;

&lt;p&gt;Going back to what was said before, computers think in binary. We could come up with a way to store every character, mapping to a numerical value. These are called character encodings. Like other datatypes this tells us how many digits each character will take up. A character might be ASCII and be only what you might see on a QWERTY keyboard, or it might be UTF-8 and include emoji and other richer styles of a character. For the sake of simplicity, we’ll stick with ASCII.&lt;/p&gt;

&lt;p&gt;There are 26 letters in the english alphabet, plus 11 special symbol keys (upper- and lowercase for each, so 22 characters), plus the number key line of 10 keys (so +20 characters), plus the spacebar, which brings us to 69 possible characters. We need enough binary digits, or bits, to handle a maximum number of 69. By my calculations, that’s 7 bits. Not too far off from our 10 bits we reserved earlier for holding character data, right?&lt;/p&gt;

&lt;p&gt;To make a string like &lt;code&gt;"Hello world!"&lt;/code&gt;, we need to disect it. It’s the character &lt;code&gt;H&lt;/code&gt;, then the character &lt;code&gt;e&lt;/code&gt;, then the character &lt;code&gt;l&lt;/code&gt;, and so on for the word “Hello”.&lt;/p&gt;

&lt;p&gt;Wait a second, we have capital letters here too?! Shoot. Let’s amend our count of 69 characters to add in 26 more, 1 more for each letter of the alphabet in its capital form. That’s a total of 95 possible characters. Good thing our 7 bits are able to store a representation of any number between 0 and 127.&lt;/p&gt;

&lt;p&gt;So we have “Hello” and “world!” separated by a space character, which amounts to 12 characters. Since each character takes up 10 bits (3 header + 7 value), we’re looking at 120 bits to render &lt;code&gt;"Hello world!"&lt;/code&gt; as binary data. Here’s where I’m going to stop while you to ponder that for a minute.&lt;/p&gt;

&lt;h2&gt;
  
  
  Symbol datatype
&lt;/h2&gt;

&lt;p&gt;Let’s assume you have a mapping of characters to bit values and the maximum bits mapped out perfectly. You have that string that takes up 12 characters for 120 bits just to say hello to the world. What if there’s something you only want to reference internally for your own purposes? We don’t care about the actual value, we just care that the value happens to be unique from any other value. It has semantic meaning only. You know how we have those mappings of letters, base10 numbers, etc. to binary? Those are the same concept of a symbol. That’s part of the &lt;code&gt;char&lt;/code&gt; shorthand. What if we took it a step further?&lt;/p&gt;

&lt;p&gt;First, after all that binary-talk, I need to take my head out of the theoretical for a moment. I need to go back to the programming I know: Ruby, Python, etc.&lt;/p&gt;

&lt;p&gt;Ruby and Python are dynamic languages where you rarely have to know how many bits in memory a variable, holding a particular datatype, will take up. The way I operate, I care about how easily I can keep the inner workings of a program in my head at any one time. I need cues that won’t matter to the computer, but do only to me as the programmer. Take a logging class (in most any language), for example.&lt;/p&gt;

&lt;p&gt;We have the concept of a logger which takes an enum of various error levels: &lt;code&gt;ERROR&lt;/code&gt;, &lt;code&gt;WARN&lt;/code&gt;, &lt;code&gt;INFO&lt;/code&gt;, &lt;code&gt;DEBUG&lt;/code&gt;, and possibly more. Do we care about storing the string of characters to represent it? No. We just need some internal representation to reference. Let’s choose a datatype that has a really small memory footprint here.&lt;/p&gt;

&lt;p&gt;Representing &lt;code&gt;"ERROR"&lt;/code&gt; (as a string) would be 5 characters Ã— 10 bits per character = 50 bits. Other logging levels might be greater or fewer characters in number, so we just need to have a datatype less than 50 bits, or binary digits long to stand in for the one other, more memory intensive value. Let’s choose the unsigned integer &lt;code&gt;4&lt;/code&gt;, and the other logging levels as unsigned integers as well. We don’t care about the value &lt;code&gt;4&lt;/code&gt;, only what it represents, so it could just as easily be &lt;code&gt;986&lt;/code&gt; or a poop emoji. It is meant to differentiate &lt;code&gt;ERROR&lt;/code&gt; from &lt;code&gt;WARN&lt;/code&gt; and the others.&lt;/p&gt;

&lt;p&gt;So the unsigned integer &lt;code&gt;4&lt;/code&gt; is represented with &lt;code&gt;010000000100&lt;/code&gt; in binary. That’s 12 bits long when the string version could be 50 bits. That’s quite the savings! Only 25% of the original memory footprint!&lt;/p&gt;

&lt;p&gt;In a language like ruby, a small savings like that might not make too big of a difference, but say it could encode it in binary instead of unsigned integer, with all the wasted space up front reclaimed. We only need the first 3 bits for the header and the 3 bits following for the value of &lt;code&gt;4&lt;/code&gt;. What if our compiler was smart enough to see we only needed a maximum value of &lt;code&gt;4&lt;/code&gt;?&lt;/p&gt;

&lt;p&gt;In that case, we could remember a new datatype that says the following &lt;em&gt;X&lt;/em&gt; digits represent a symbol, where &lt;em&gt;X&lt;/em&gt; is determined once the entire program is analyzed to figure out the max value one might ever see. In our case, it’s 4 so we downsize the number of bits used from 12 to 6. What once was &lt;code&gt;010000000100&lt;/code&gt; is now &lt;code&gt;010100&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;But wait, we still have the datatype header for an unsigned integer! That’ll screw everything up! That’s very true. We can't keep breaking our own shorthand conventions with encoding/decode binary, so we’ll have to come up with a new, on-the-fly datatype which we’ll refer to as a symbol. It’ll go by the header &lt;code&gt;101&lt;/code&gt;, since it hasn’t been used yet.&lt;/p&gt;

&lt;p&gt;From the original 50 bits, to &lt;code&gt;010000000100&lt;/code&gt; (12 bits), to &lt;code&gt;101100&lt;/code&gt; (6 bits), that’s quite a bit of downsizing for the exact same functionality as far as both the programmer and the end user are concerned.&lt;/p&gt;

&lt;h2&gt;
  
  
  Recap
&lt;/h2&gt;

&lt;p&gt;Symbols are just what they sound like: an in-memory stand-in value for something else. Their function is to save on memory usage when you don’t need to allocate a ton of bits in order to have a label that only needs to represent that it's different from other labels. The values don't actually matter. They are a handy representation which shifts work onto the compiler initially, but nets less memory (and equal computation power) at runtime.&lt;/p&gt;

&lt;h2&gt;
  
  
  Moving forward
&lt;/h2&gt;

&lt;p&gt;These optimizations occur not only for storing data, but referencing binary chunk of data representing logic the computer is supposed to follow. Do you really think your computer remembers to look in that file for the string &lt;code&gt;my_main_function()&lt;/code&gt; in order call the logic defined therein? Do you feel the computer cares how you name things? No! It reads the logic into binary and determines a symbol only it remembers in order for it to easily call the functionality. These are more compilation optimizations that happen automatically in the programming languages you use.&lt;/p&gt;

&lt;p&gt;Languages like C and Ruby allow you direct access to symbols as a datatype, but languages like PHP and earlier versions of Java require you to declare your preferred datatype and value, leaving the memory optimization to the programmer when defining that a symbol exists.&lt;/p&gt;

&lt;p&gt;Are symbols helpful? Sure. How often? That depends on what and how you’re coding the task at hand. Hopefully this will serve as an introduction for what circumstances would be best to use symbols versus other datatypes.&lt;/p&gt;

</description>
      <category>computerscience</category>
      <category>data</category>
      <category>compiler</category>
    </item>
    <item>
      <title>On the Importance of Packaging</title>
      <dc:creator>David Alexander</dc:creator>
      <pubDate>Tue, 06 Jun 2017 10:18:53 +0000</pubDate>
      <link>https://forem.com/thelonelyghost/on-the-importance-of-packaging</link>
      <guid>https://forem.com/thelonelyghost/on-the-importance-of-packaging</guid>
      <description>&lt;p&gt;You have an idea and want to turn it into a bit of code to carry it out. What do you do? You open up your IDE/Editor, perhaps you structure it inside of a folder with some default tooling for linting and (if necessary) compiling, and you get the code to work. It's hacky, it's ugly, but it works.&lt;/p&gt;

&lt;p&gt;Now that you have something, you want to add one more feature to it or work out a bug. What do you do? You follow the same process. If you're feeling zesty, maybe you init a new git repository at the base of the project, but there's no real point to branching and merging back into master. Backing up the code? Might be an account on Bitbucket, or maybe something with GitLab. They both have free usage tiers with private repositories, and this definitely isn't good enough for the public to see.&lt;/p&gt;

&lt;p&gt;This continues with more features hacked on, with no tests and zero documentation (except a comment here and there), all kept 100% private. Maybe you try to make it work on a Digital Ocean server you have stood up as a floating workspace with a persistent internet connection. It was difficult, but it works now. Kinda. Well, some of the time, anyway.&lt;/p&gt;

&lt;p&gt;Your code portfolio is still missing a lot. Not a whole lot is visible because not a whole lot is in good enough condition to show anybody. You have a lot of these tiny projects that are riddled with what you know are bad practices, but were so much easier that figuring out the right way to do it. You treat your open source code contributions almost like a stage performance where you have everything perfectly thought out. First you have to write documentation, which means you have to clearly define that snowflake server you have setup to run your script. It also means you have to write usage documentation. Automated tests too, with varying importance depending on the community surrounding the language in which your project is implemented.&lt;/p&gt;

&lt;p&gt;This has been my process for years with any number of once-off scripts. Projects that were intended for a recurring, minisculely scoped purpose I would have privately and, when I didn't have need for them anymore or they broke due to changes elsewhere (e.g., web scrapers breaking because website updates), I would just delete the project and call it done. Of course I would only be able to verbally mention "Yeah, I built something like that in my free time" during job interviews, but wouldn't be able to prove it because it was longer than a week ago and I didn't save the work.&lt;/p&gt;

&lt;p&gt;What I've found, recently, is that there is a way to ease these growing pains.&lt;/p&gt;

&lt;h1&gt;
  
  
  Packaging
&lt;/h1&gt;

&lt;p&gt;Every (legitimate) language these days has a package management strategy. Not familiar with the concept of package management? Let's talk about that for a sec.&lt;/p&gt;

&lt;p&gt;You have a new project, let's say it's written in Python for now. The standard package format is well defined for installing using &lt;code&gt;pip&lt;/code&gt;. It includes dependencies, name of the package, author name and contact info, version constraints for dependencies... a lot of information that is--and should be--standardized. In python, that's consistently defined in &lt;code&gt;setup.py&lt;/code&gt; at the base of the repository.&lt;/p&gt;

&lt;p&gt;Consider the following repository structure:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;├── LICENSE.md
├── README.md
├── setup.py
└── my_project
    ├── __init__.py
    ├── core
    │   ├── admin_commands.py
    │   ├── inbox.py
    │   ├── initialize.py
    │   ├── mentions.py
    │   ├── posts.py
    │   ├── user_interaction.py
    │   └── validation.py
    ├── helpers
    │   ├── misc.py
    │   └── wiki.py
    ├── main.py
    └── strings
        ├── debug.py
        ├── posts.py
        ├── responses.py
        └── urls.py
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We have a project named &lt;code&gt;my_project&lt;/code&gt;, which is should be the name of the package in &lt;code&gt;setup.py&lt;/code&gt;. Python has the Java-esque convention of &lt;code&gt;import package.name.here&lt;/code&gt; to map to &lt;code&gt;package/name/here.py&lt;/code&gt; filesystem structure.&lt;/p&gt;

&lt;h1&gt;
  
  
  Readme
&lt;/h1&gt;

&lt;p&gt;Packages always have a README. If you use a package generator (like &lt;code&gt;bundle gem&lt;/code&gt;) and it generates a README, &lt;em&gt;always&lt;/em&gt; remove the default generated description (and other TODO-lines) and insert your own. Not sure what your project is about? Note what it currently covers. You can update it later. That's the point of version control.&lt;/p&gt;

&lt;p&gt;In the README, include installation instructions that are realistic to your situation. Are there native OS dependencies that you need installed too? Those might not fit well in the &lt;code&gt;setup.py&lt;/code&gt; or &lt;code&gt;*.gemspec&lt;/code&gt; files. In that case, put it in the README.&lt;/p&gt;

&lt;p&gt;A lot of times the boilerplate includes a lot of noise that might not be necessary for publicly publishing a package. Here are the bare minimum requirements for any package I make, public or private. I'm a forgetful person so coming back to a project 2 months later will require some getting up-to-speed again anyway. I like to make it easier for myself with this list of requirements for a README:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Usage&lt;/li&gt;
&lt;li&gt;Installation procedure (assume a freshly installed OS)&lt;/li&gt;
&lt;li&gt;Description&lt;/li&gt;
&lt;li&gt;(if applicable) Assumptions of native platform dependencies&lt;/li&gt;
&lt;/ul&gt;

&lt;h1&gt;
  
  
  Dependencies
&lt;/h1&gt;

&lt;p&gt;Packages provide a very clear definition of what it takes to run a piece of software that was written. I've been hearing for years that successful projects include a very narrowly defined scope and that the best way to do that is through narrowly defined interfaces.&lt;/p&gt;

&lt;p&gt;In programming, you might see a junior dev hack away at a magic method that takes inputs in any variety of forms and is able to normalize it. Unless that is the primary function of the method/command/atomic unit they're creating, more experienced developers realize this very easily snowballs into a maintenance nightmare. The same might be said for dependency tracking. Having a clearly defined set of required dependencies (instead of the end user doing trial and error to install everything) will always be better.&lt;/p&gt;

&lt;h1&gt;
  
  
  Overkill
&lt;/h1&gt;

&lt;p&gt;Python, for example, involves some bootstrapping to setup a package. For me, it has involved looking up prior projects' &lt;code&gt;setup.py&lt;/code&gt; file, modifying it to fit the new project, and creating some default structures like &lt;code&gt;my_project/__init__.py&lt;/code&gt; containing variables for version (&lt;code&gt;__version__&lt;/code&gt;) and author (&lt;code&gt;__author__&lt;/code&gt;). It also involves setting up automated testing with unittest and shell scripts to make automated testing easy to execute.&lt;/p&gt;

&lt;p&gt;Here's my heuristic when it comes to creating a package:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Are there &lt;em&gt;any&lt;/em&gt; dependencies that require a package manager (e.g., &lt;code&gt;pip&lt;/code&gt;, &lt;code&gt;npm&lt;/code&gt;, &lt;code&gt;gem&lt;/code&gt;)?&lt;/li&gt;
&lt;li&gt;Does the source code need to be split up into multiple files?&lt;/li&gt;
&lt;li&gt;Am I testing my work with any more granularity than full, end-to-end tests?&lt;/li&gt;
&lt;li&gt;Do I need to deploy this easily as, e.g., a command line tool?&lt;/li&gt;
&lt;li&gt;Do I need to version the releases and have stable, beta, and dev copies of the source code?&lt;/li&gt;
&lt;li&gt;Am I tracking code changes with git?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If I've answered yes to any &lt;em&gt;one&lt;/em&gt; of these questions, I know to create turn the project into a package.&lt;/p&gt;

&lt;p&gt;This means I...&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;create a new git repository (and private remote, for backup purposes)&lt;/li&gt;
&lt;li&gt;create a README (in markdown, preferably)&lt;/li&gt;
&lt;li&gt;track dependencies I install or remove, as I install or remove them&lt;/li&gt;
&lt;li&gt;formulate a testing strategy to make sure everything works as expected (either automated or manual)&lt;/li&gt;
&lt;li&gt;create a set of convenience scripts for running repeatable tasks scoped only to the current project (e.g., Makefile, Rakefile, bundler binstubs, shell script)&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>workflow</category>
      <category>opensource</category>
      <category>python</category>
    </item>
    <item>
      <title>Local Gems With Bundler</title>
      <dc:creator>David Alexander</dc:creator>
      <pubDate>Wed, 28 Dec 2016 17:27:06 +0000</pubDate>
      <link>https://forem.com/thelonelyghost/local-gems-with-bundler</link>
      <guid>https://forem.com/thelonelyghost/local-gems-with-bundler</guid>
      <description>&lt;p&gt;Testing an unreleased version of a gem? Want to develop 2 unreleased projects that are based on each other and not have to worry about the following?&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;gem&lt;/span&gt; &lt;span class="s1"&gt;'some_gem'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;path: &lt;/span&gt;&lt;span class="s1"&gt;'../my-dev-snapshot'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Leaving the &lt;code&gt;Gemfile&lt;/code&gt; as such will screw with your project history, so we want the version of &lt;code&gt;Gemfile&lt;/code&gt; as it will be when the gem is released, keeping that version in our “git memory”. See the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;bundle&lt;/span&gt; &lt;span class="n"&gt;config&lt;/span&gt; &lt;span class="n"&gt;local&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;some_gem&lt;/span&gt; &lt;span class="s2"&gt;"$(realpath ../my-dev-snapshot)"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will allow your &lt;code&gt;Gemfile&lt;/code&gt; to remain pristine without the &lt;code&gt;path: '../foo'&lt;/code&gt;hacks so others can set their own path to the gem source directory.&lt;/p&gt;

&lt;h2&gt;
  
  
  Caveats:
&lt;/h2&gt;

&lt;p&gt;The gem, in this case &lt;code&gt;some_gem&lt;/code&gt;, must be pointed at a git repository. In this case, it would need to be:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;gem&lt;/span&gt; &lt;span class="s1"&gt;'some_gem'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;github: &lt;/span&gt;&lt;span class="s1"&gt;'foo/bar'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;branch: &lt;/span&gt;&lt;span class="s1"&gt;'master'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This would allow us not only to optimize network traffic so we don’t make calls out to the git repository all the time, but also point it toward a local working copy.&lt;/p&gt;

&lt;p&gt;There is an additional caveat, though. The given branch – in the example,&lt;code&gt;master&lt;/code&gt; – must match the branch of the current working copy at the path specified with &lt;code&gt;bundle config&lt;/code&gt; from earlier.&lt;/p&gt;

</description>
      <category>notes</category>
    </item>
  </channel>
</rss>
