<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
  
  <title>Robert Rhoades</title>
  <subtitle>Developer &amp;amp; tea maker</subtitle>
  <link href="https://www.studioromeo.co.uk/feed.xml" rel="self" />
  <link href="https://www.studioromeo.co.uk/" />
  <updated>2026-07-26T00:00:00Z</updated>
  <id>https://www.studioromeo.co.uk/</id>
  <author>
    <name>Robert Rhoades</name>
  </author>
  <entry>
    <title>Swapping Thonny for Neovim to Dev on my Pico</title>
    <link href="https://www.studioromeo.co.uk/swapping-thonny-for-neovim-to-dev-on-my-pico/" />
    <updated>2026-07-26T00:00:00Z</updated>
    <id>https://www.studioromeo.co.uk/swapping-thonny-for-neovim-to-dev-on-my-pico/</id>
    <summary>How to program a pico without Thonny using neovim and mpremote</summary>
    <content type="html">&lt;p&gt;Like most devs, I tend to swap around editors quite a bit. I&#39;ve been through a few: Sublime, Coda, Atom, PHPStorm, Eclipse, Visual Studio, VS Code...the list goes on. Lately I&#39;ve been learning to use neovim (maybe I&#39;ll write a post on that) but for the pico I stuck with the default recommended editor Thonny.&lt;/p&gt;
&lt;p&gt;Thonny is great for what it is, it makes it easy to get going with the pico and gives you easy ways to put code onto the pico, install packages, and a REPL, its the complete package! But it&#39;s not my editor. It doesn&#39;t have my theme and as I&#39;m getting used to vim motions going back to a more traditional text editor drags me out of that mindset.&lt;/p&gt;
&lt;p&gt;Programming on the Pico isn&#39;t like a traditional website however. I need to be able to put the code on the pico, run it and see the output to see what I did wrong! I hope thats the right terminology but I&#39;m relatively new to embedded programming.&lt;/p&gt;
&lt;h2&gt;My setup&lt;/h2&gt;
&lt;p&gt;Instead of Thonny I use:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Neovim + Kickstart&lt;/strong&gt;: Out of scope for this post but its just neovim with kickstart. &lt;code&gt;pyright&lt;/code&gt; as my lsp&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;mpremote&lt;/strong&gt;: This bridges the gap between my mac and my pico. It lets me run scripts on the pico.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;micropython-rp2-stubs&lt;/strong&gt;: Will get into this later but without this pyright complains about &lt;code&gt;import machine&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Setting up neovim and pyright&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;In neovim under the lsp settings I added the &lt;code&gt;pyright&lt;/code&gt; key to enable the python lsp. I&#39;m not sure if this is needed for everything but I assume it is, I need to learn more here.&lt;/li&gt;
&lt;/ol&gt;
&lt;pre class=&quot;language-lua&quot;&gt;&lt;code class=&quot;language-lua&quot;&gt;	&lt;span class=&quot;token keyword&quot;&gt;local&lt;/span&gt; servers &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
		pyright &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;ol start=&quot;2&quot;&gt;
&lt;li&gt;Doing this means I have syntax highlighting which is great but as I mentioned earlier &lt;code&gt;import machine&lt;/code&gt; throws up an error as this exists on the pico but not locally on my project so what we need to do is setup a virtual env and install &lt;code&gt;micropython-rp2-stubs&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code&gt;python3 -m venv .venv
source .venv/bin/activate.fish # Note for fish shell users!
pip install micropython-rp2-stubs
&lt;/code&gt;&lt;/pre&gt;
&lt;ol start=&quot;3&quot;&gt;
&lt;li&gt;After this I need to add &lt;code&gt;pyrightconfig.json&lt;/code&gt; to tell the lsp that we have some packages to look at&lt;/li&gt;
&lt;/ol&gt;
&lt;pre class=&quot;language-json&quot;&gt;&lt;code class=&quot;language-json&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;venvPath&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;.&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;venv&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;.venv&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;reportMissingImports&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;none&quot;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;One thats been done all seems to be fine. I do get a warning but thats better than an error! If I figure out a better solution I&#39;ll update this post.&lt;/p&gt;
&lt;h2&gt;The workflow&lt;/h2&gt;
&lt;p&gt;Okay I&#39;m all good to go. Now when I want to work on my pico projects I can plug my pico into the mac and then:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;cd into my project directory&lt;/li&gt;
&lt;li&gt;Open neovim in a pane, then split it with another shell&lt;/li&gt;
&lt;li&gt;Run scripts I&#39;m editing using &lt;code&gt;mpremote run &amp;lt;script&amp;gt;&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;When I&#39;m happy with the final script i can run &lt;code&gt;mpremote fs cp &amp;lt;script&amp;gt; :&amp;lt;script&amp;gt;&lt;/code&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Another way to do this is to use &lt;code&gt;mpremote mount .&lt;/code&gt; and this will mount the entire directory on the pico and drops us into the REPL. We can then run scripts by typing &lt;code&gt;import &amp;lt;script&amp;gt;&lt;/code&gt;. I prefer the simplicity of &lt;code&gt;mpremote run&lt;/code&gt; but just wanted to call this out as another option.&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>Testing Hard Drives with a Raspberry Pi Zero</title>
    <link href="https://www.studioromeo.co.uk/testing-hard-drives-with-a-raspberry-pi-zero/" />
    <updated>2026-04-12T00:00:00Z</updated>
    <id>https://www.studioromeo.co.uk/testing-hard-drives-with-a-raspberry-pi-zero/</id>
    <summary>How I keep my data safe by testing hard drives in isolation using this tiny little computer</summary>
    <content type="html">&lt;p&gt;It&#39;s a good idea to test a hard drive before using it. They can fail in any number of different ways and losing your precious memories is the last thing you want to happen.&lt;/p&gt;
&lt;p&gt;Testing them involves writing and reading data to the entire disk over and over. The idea being if its going to fail let it be while we&#39;re writing gibberish.&lt;/p&gt;
&lt;p&gt;In Linux there&#39;s a tool &lt;code&gt;badblocks&lt;/code&gt;; it writes patterns to a disk and reads them back. For example &lt;em&gt;0101&lt;/em&gt;, &lt;em&gt;1010&lt;/em&gt;, &lt;em&gt;1111&lt;/em&gt;, and &lt;em&gt;0000&lt;/em&gt; in 4 separate passes. If a block can&#39;t be read or written to, it will be logged.&lt;/p&gt;
&lt;p&gt;This combined with S.M.A.R.T. data can give you confidence in the drive.&lt;/p&gt;
&lt;p&gt;One harsh reality is this process can take a while, days rather than minutes. This varies by size and speed of the disk. A 500GB disk will complete the test much faster than a 20TB disk. Equally a 7200rpm drive will be faster than a 5400rpm drive of the same capacity.&lt;/p&gt;
&lt;p&gt;So we know this is going to take a while. Unfortunately the only computer that I have running all day is my NAS. I could run the test on that but one typo and I could accidentally wipe the wrong disk!&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://www.studioromeo.co.uk/testing-hard-drives-with-a-raspberry-pi-zero/24X4p4IlG6-800.webp&quot;&gt;&lt;img loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://www.studioromeo.co.uk/testing-hard-drives-with-a-raspberry-pi-zero/24X4p4IlG6-800.jpeg&quot; alt=&quot;A photo of my raspberry pi setup&quot; width=&quot;800&quot; height=&quot;535&quot;&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;I want to reduce the consequences of a mistake by having an air gap from my &amp;quot;production&amp;quot; services.&lt;/p&gt;
&lt;p&gt;I have a spare Raspberry Pi Zero 2 W which I can use. It even has a few advantages over my laptop:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;It can run Linux.&lt;/li&gt;
&lt;li&gt;It&#39;s small and low power (2 watts-ish).&lt;/li&gt;
&lt;li&gt;It&#39;s wireless so can be left anywhere.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;It&#39;s not perfect though; it&#39;s USB 2 so the writes are capped at around &lt;span style=&quot;white-space: nowrap;&quot;&gt;40MB/s&lt;/span&gt;. This means our test isn&#39;t going to be an absolute torture fest but it&#39;s enough to see if these drives will work.&lt;/p&gt;
&lt;p&gt;The ports are another downside. While I could have bought a Micro-USB to USB-A dongle, I primarily use USB-C. So I opted instead for a Micro-USB to USB-C adapter. This way, if I&#39;m on holiday with any Micro-USB devices, I don&#39;t need to pack a separate charger.&lt;/p&gt;
&lt;h2&gt;Setting up the Pi&lt;/h2&gt;
&lt;p&gt;To get started, flash Raspberry Pi lite OS (I used 64-bit but 32-bit would be fine) to the SD card. Also be sure to fill in the extras so the zero can connect to the network, and your public key so you can ssh in.&lt;/p&gt;
&lt;p&gt;Put the SD card into the zero and power it on. I like to leave it for a few minutes to sort itself out on the first boot.&lt;/p&gt;
&lt;p&gt;After installing the OS, as a best practice, we should check for updates.&lt;/p&gt;
&lt;pre class=&quot;language-sh&quot;&gt;&lt;code class=&quot;language-sh&quot;&gt;&lt;span class=&quot;token function&quot;&gt;sudo&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;apt-get&lt;/span&gt; update
&lt;span class=&quot;token function&quot;&gt;sudo&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;apt&lt;/span&gt; upgrade&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Once done, we can reboot to apply those changes.&lt;/p&gt;
&lt;pre class=&quot;language-sh&quot;&gt;&lt;code class=&quot;language-sh&quot;&gt;&lt;span class=&quot;token function&quot;&gt;sudo&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;reboot&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now lets ensure S.M.A.R.T. tools are installed so we can keep an eye on the hard drives health.&lt;/p&gt;
&lt;pre class=&quot;language-sh&quot;&gt;&lt;code class=&quot;language-sh&quot;&gt;&lt;span class=&quot;token function&quot;&gt;sudo&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;apt&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;install&lt;/span&gt; smartmontools&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Lets also install &lt;code&gt;tmux&lt;/code&gt; so we can leave running commands without stopping.&lt;/p&gt;
&lt;pre class=&quot;language-sh&quot;&gt;&lt;code class=&quot;language-sh&quot;&gt;&lt;span class=&quot;token function&quot;&gt;sudo&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;apt&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;install&lt;/span&gt; tmux&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Luckily, &lt;code&gt;badblock&lt;/code&gt; is usually part of Raspberry Pi OS so we don&#39;t need to install it. With that we have all the software we need.&lt;/p&gt;
&lt;h2&gt;Running the test&lt;/h2&gt;
&lt;p&gt;Now we can plug in our hard drive into the Pi.&lt;/p&gt;
&lt;p&gt;For 3½&amp;quot; drives we&#39;ll need it to be powered separately but with 2½&amp;quot; we may get away with using the usb port on the Pi itself. YMMV.&lt;/p&gt;
&lt;p&gt;Next lets find our drive name.&lt;/p&gt;
&lt;pre class=&quot;language-sh&quot;&gt;&lt;code class=&quot;language-sh&quot;&gt;lsblk&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This will list all our drives. I tend to use the size to identify it. Lets make a note of the name, it&#39;ll become very important later on.&lt;/p&gt;
&lt;pre class=&quot;language-sh&quot;&gt;&lt;code class=&quot;language-sh&quot;&gt;NAME        MAJ:MIN RM   SIZE RO TYPE MOUNTPOINTS
loop0         &lt;span class=&quot;token number&quot;&gt;7&lt;/span&gt;:0    &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;   416M  &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt; loop
sda           &lt;span class=&quot;token number&quot;&gt;8&lt;/span&gt;:0    &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;465&lt;/span&gt;.8G  &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt; disk // &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt; this is our harddrive &lt;span class=&quot;token builtin class-name&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
├─sda1        &lt;span class=&quot;token number&quot;&gt;8&lt;/span&gt;:1    &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;     1G  &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt; part
├─sda2        &lt;span class=&quot;token number&quot;&gt;8&lt;/span&gt;:2    &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;     1G  &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt; part
└─sda3        &lt;span class=&quot;token number&quot;&gt;8&lt;/span&gt;:3    &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;463&lt;/span&gt;.8G  &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt; part
sdb           &lt;span class=&quot;token number&quot;&gt;8&lt;/span&gt;:16   &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;     0B  &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt; disk
sdc           &lt;span class=&quot;token number&quot;&gt;8&lt;/span&gt;:32   &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;     0B  &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt; disk
mmcblk0     &lt;span class=&quot;token number&quot;&gt;179&lt;/span&gt;:0    &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;  &lt;span class=&quot;token number&quot;&gt;59&lt;/span&gt;.5G  &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt; disk
├─mmcblk0p1 &lt;span class=&quot;token number&quot;&gt;179&lt;/span&gt;:1    &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;   512M  &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt; part /boot/firmware
└─mmcblk0p2 &lt;span class=&quot;token number&quot;&gt;179&lt;/span&gt;:2    &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;    59G  &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt; part /
zram0       &lt;span class=&quot;token number&quot;&gt;254&lt;/span&gt;:0    &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;   416M  &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt; disk &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;SWAP&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Open a tmux session &lt;code&gt;tmux&lt;/code&gt; and check the drives block size. In the code sample below I&#39;ve used sda but it might be different so use the &lt;strong&gt;name&lt;/strong&gt; noted previously.&lt;/p&gt;
&lt;pre class=&quot;language-sh&quot;&gt;&lt;code class=&quot;language-sh&quot;&gt;&lt;span class=&quot;token function&quot;&gt;sudo&lt;/span&gt; blockdev &lt;span class=&quot;token parameter variable&quot;&gt;--getbsz&lt;/span&gt; /dev/sda&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This will give us a number, such as &lt;em&gt;4096&lt;/em&gt;. In fact most hard drives that are 4 terabytes or greater will have a 4096 block size.&lt;/p&gt;
&lt;p&gt;We are now ready for the most dangerous part of the operation. Running our test will overwrite the entire disk so its vital we &lt;strong&gt;double check the name of our drive&lt;/strong&gt;. If there is any doubt, run &lt;code&gt;lsblk&lt;/code&gt; again.&lt;/p&gt;
&lt;pre class=&quot;language-sh&quot;&gt;&lt;code class=&quot;language-sh&quot;&gt;&lt;span class=&quot;token function&quot;&gt;sudo&lt;/span&gt; badblocks &lt;span class=&quot;token parameter variable&quot;&gt;-w&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-s&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-b&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;4096&lt;/span&gt; /dev/sda&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We can then quit tmux using &lt;kbd&gt;ctrl + b&lt;/kbd&gt; and then &lt;kbd&gt;d&lt;/kbd&gt;.&lt;/p&gt;
&lt;p&gt;That&#39;s it, we are now testing the drive!&lt;/p&gt;
&lt;p&gt;During the test we can take a look at our S.M.A.R.T. attributes at any time.&lt;/p&gt;
&lt;pre class=&quot;language-sh&quot;&gt;&lt;code class=&quot;language-sh&quot;&gt;&lt;span class=&quot;token function&quot;&gt;sudo&lt;/span&gt; smartctl &lt;span class=&quot;token parameter variable&quot;&gt;-A&lt;/span&gt; /dev/sda&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It will return something like this:&lt;/p&gt;
&lt;pre class=&quot;language-sh&quot;&gt;&lt;code class=&quot;language-sh&quot;&gt;ID&lt;span class=&quot;token comment&quot;&gt;# ATTRIBUTE_NAME          FLAG     VALUE WORST THRESH TYPE      UPDATED  WHEN_FAILED RAW_VALUE&lt;/span&gt;
  &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt; Raw_Read_Error_Rate     0x002f   &lt;span class=&quot;token number&quot;&gt;200&lt;/span&gt;   &lt;span class=&quot;token number&quot;&gt;200&lt;/span&gt;   051    Pre-fail  Always       -       &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;
  &lt;span class=&quot;token number&quot;&gt;3&lt;/span&gt; Spin_Up_Time            0x0027   &lt;span class=&quot;token number&quot;&gt;164&lt;/span&gt;   &lt;span class=&quot;token number&quot;&gt;159&lt;/span&gt;   021    Pre-fail  Always       -       &lt;span class=&quot;token number&quot;&gt;4800&lt;/span&gt;
  &lt;span class=&quot;token number&quot;&gt;4&lt;/span&gt; Start_Stop_Count        0x0032   090   090   000    Old_age   Always       -       &lt;span class=&quot;token number&quot;&gt;10065&lt;/span&gt;
  &lt;span class=&quot;token number&quot;&gt;5&lt;/span&gt; Reallocated_Sector_Ct   0x0033   &lt;span class=&quot;token number&quot;&gt;200&lt;/span&gt;   &lt;span class=&quot;token number&quot;&gt;200&lt;/span&gt;   &lt;span class=&quot;token number&quot;&gt;140&lt;/span&gt;    Pre-fail  Always       -       &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;
  &lt;span class=&quot;token number&quot;&gt;7&lt;/span&gt; Seek_Error_Rate         0x002e   &lt;span class=&quot;token number&quot;&gt;100&lt;/span&gt;   &lt;span class=&quot;token number&quot;&gt;253&lt;/span&gt;   000    Old_age   Always       -       &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;
  &lt;span class=&quot;token number&quot;&gt;9&lt;/span&gt; Power_On_Hours          0x0032   001   001   000    Old_age   Always       -       &lt;span class=&quot;token number&quot;&gt;75711&lt;/span&gt;
 &lt;span class=&quot;token number&quot;&gt;10&lt;/span&gt; Spin_Retry_Count        0x0032   &lt;span class=&quot;token number&quot;&gt;100&lt;/span&gt;   &lt;span class=&quot;token number&quot;&gt;100&lt;/span&gt;   000    Old_age   Always       -       &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;
 &lt;span class=&quot;token number&quot;&gt;11&lt;/span&gt; Calibration_Retry_Count 0x0032   &lt;span class=&quot;token number&quot;&gt;100&lt;/span&gt;   &lt;span class=&quot;token number&quot;&gt;253&lt;/span&gt;   000    Old_age   Always       -       &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;
 &lt;span class=&quot;token number&quot;&gt;12&lt;/span&gt; Power_Cycle_Count       0x0032   &lt;span class=&quot;token number&quot;&gt;100&lt;/span&gt;   &lt;span class=&quot;token number&quot;&gt;100&lt;/span&gt;   000    Old_age   Always       -       &lt;span class=&quot;token number&quot;&gt;86&lt;/span&gt;
&lt;span class=&quot;token number&quot;&gt;192&lt;/span&gt; Power-Off_Retract_Count 0x0032   &lt;span class=&quot;token number&quot;&gt;200&lt;/span&gt;   &lt;span class=&quot;token number&quot;&gt;200&lt;/span&gt;   000    Old_age   Always       -       &lt;span class=&quot;token number&quot;&gt;8&lt;/span&gt;
&lt;span class=&quot;token number&quot;&gt;193&lt;/span&gt; Load_Cycle_Count        0x0032   &lt;span class=&quot;token number&quot;&gt;197&lt;/span&gt;   &lt;span class=&quot;token number&quot;&gt;197&lt;/span&gt;   000    Old_age   Always       -       &lt;span class=&quot;token number&quot;&gt;10065&lt;/span&gt;
&lt;span class=&quot;token number&quot;&gt;194&lt;/span&gt; Temperature_Celsius     0x0022   &lt;span class=&quot;token number&quot;&gt;109&lt;/span&gt;   082   000    Old_age   Always       -       &lt;span class=&quot;token number&quot;&gt;38&lt;/span&gt;
&lt;span class=&quot;token number&quot;&gt;195&lt;/span&gt; Hardware_ECC_Recovered  0x0036   001   001   000    Old_age   Always       -       &lt;span class=&quot;token number&quot;&gt;342037046&lt;/span&gt;
&lt;span class=&quot;token number&quot;&gt;196&lt;/span&gt; Reallocated_Event_Count 0x0032   &lt;span class=&quot;token number&quot;&gt;200&lt;/span&gt;   &lt;span class=&quot;token number&quot;&gt;200&lt;/span&gt;   000    Old_age   Always       -       &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;
&lt;span class=&quot;token number&quot;&gt;197&lt;/span&gt; Current_Pending_Sector  0x0032   &lt;span class=&quot;token number&quot;&gt;200&lt;/span&gt;   &lt;span class=&quot;token number&quot;&gt;200&lt;/span&gt;   000    Old_age   Always       -       &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;
&lt;span class=&quot;token number&quot;&gt;198&lt;/span&gt; Offline_Uncorrectable   0x0030   &lt;span class=&quot;token number&quot;&gt;100&lt;/span&gt;   &lt;span class=&quot;token number&quot;&gt;253&lt;/span&gt;   000    Old_age   Offline      -       &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;
&lt;span class=&quot;token number&quot;&gt;199&lt;/span&gt; UDMA_CRC_Error_Count    0x0032   &lt;span class=&quot;token number&quot;&gt;200&lt;/span&gt;   &lt;span class=&quot;token number&quot;&gt;200&lt;/span&gt;   000    Old_age   Always       -       &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;
&lt;span class=&quot;token number&quot;&gt;200&lt;/span&gt; Multi_Zone_Error_Rate   0x0008   &lt;span class=&quot;token number&quot;&gt;100&lt;/span&gt;   &lt;span class=&quot;token number&quot;&gt;253&lt;/span&gt;   000    Old_age   Offline      -       &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It&#39;s useful to keep an eye on it for changes.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;Current_Pending_Sector&lt;/code&gt;, &lt;code&gt;Reallocated_Sector_Ct&lt;/code&gt; and &lt;code&gt;Offline_Uncorrectable&lt;/code&gt; are worth keeping an eye on. These identify when the drive was not able to read the data it has written and are indicators of a failure.&lt;/p&gt;
&lt;p&gt;Another attribute to keep an eye on is &lt;code&gt;Temperature_Celsius&lt;/code&gt; which tells us how hot our drive is in ℃. A good range is 20-45℃ and most drives under test will sit towards the top end of that range.&lt;/p&gt;
&lt;p&gt;Finally &lt;code&gt;Power_On_Hours&lt;/code&gt; lets us know how old the drive is. My drive has &amp;gt;75k hours which equates to over 8 years!&lt;/p&gt;
&lt;h2&gt;Happy testing!&lt;/h2&gt;
&lt;p&gt;What I love most about this setup is how unobtrusive it is. It sits in the corner, quietly testing my drive, sipping watts as it does so.&lt;/p&gt;
&lt;p&gt;Should the worst happen, we can start over knowing the damage is limited to the Pi. This alone saves me a lot of stress when running tests!&lt;/p&gt;
&lt;p&gt;What&#39;s the oldest hard drive you&#39;ve got still going strong? I&#39;d love to know!&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>Fixing SMB Transfers on Mac</title>
    <link href="https://www.studioromeo.co.uk/fixing-smb-transfers-on-mac/" />
    <updated>2026-04-05T00:00:00Z</updated>
    <id>https://www.studioromeo.co.uk/fixing-smb-transfers-on-mac/</id>
    <summary>My notes on how to fix SMB transfer speeds on Mac Tahoe on Unraid NAS</summary>
    <content type="html">&lt;p&gt;Setting up my NAS last year was probably one of the best things I did, I&#39;ll try and do another post on all that but the long and short is I&#39;m using an old PC with Unraid.&lt;/p&gt;
&lt;p&gt;Unraid gives you a few options to connect to your NAS, I first tried SMB, I really liked how Mac Finder just discovered it, I didn&#39;t have to remember any IP addresses or special commands.&lt;/p&gt;
&lt;p&gt;Reads were good, I could browse directories pretty quick, open up files fine. But writing was extremely slow, and worse with lots of files.&lt;/p&gt;
&lt;p&gt;At the time I didn&#39;t really know what to do, someone on the internet said try NFS and the transfers were much better. But today accidentally crashed my server (my fault not Unraid) and I thought ok time to give SMB another shot.&lt;/p&gt;
&lt;p&gt;I tested this by transfering a folder of varying sized MP4&#39;s. Finder doesn&#39;t have a fancy transfer rate window like windows does so I used Activity Monitors network view which does the job.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://www.studioromeo.co.uk/fixing-smb-transfers-on-mac/u3_umFDKX0-800.webp&quot;&gt;&lt;img loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://www.studioromeo.co.uk/fixing-smb-transfers-on-mac/u3_umFDKX0-800.jpeg&quot; alt=&quot;View of graph&quot; width=&quot;800&quot; height=&quot;198&quot;&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;This sawtooth pattern is weird, it looks like finder is transferring one file, then reading it before transferring the next.&lt;/p&gt;
&lt;p&gt;The internet said that macs aren&#39;t setup great for SMB performance. And after a while of trial and error I settled on this config&lt;/p&gt;
&lt;pre class=&quot;language-toml&quot;&gt;&lt;code class=&quot;language-toml&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token table class-name&quot;&gt;default&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;# Disable signing&lt;/span&gt;
&lt;span class=&quot;token key property&quot;&gt;signing_required&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;=&lt;/span&gt;no
&lt;span class=&quot;token comment&quot;&gt;# Turn off validation of the negotiate info (helps with signing issues)&lt;/span&gt;
&lt;span class=&quot;token key property&quot;&gt;validate_neg_off&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;=&lt;/span&gt;yes
&lt;span class=&quot;token comment&quot;&gt;# Force SMB 3+ for better performance&lt;/span&gt;
&lt;span class=&quot;token key property&quot;&gt;protocol_vers_map&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;6&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;After connecting to an smb share on mac we can run &lt;code&gt;smbutil statshares -a&lt;/code&gt; to get a picture of what that looks like. Unfortunately for me &lt;code&gt;signing_require&lt;/code&gt; didn&#39;t seem to change this to OFF even after restarting.&lt;/p&gt;
&lt;pre class=&quot;language-txt&quot;&gt;&lt;code class=&quot;language-txt&quot;&gt;SMB_CURR_SIGN_ALGORITHM       AES_128_GMAC&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I got the same transfer performance when I tested which confirmed more work needed to be done. This config might be unnecessary, and if thats the true I&#39;ll update this article.&lt;/p&gt;
&lt;p&gt;Next up lets make sure that signing is not on the NAS. In Unraid, Settings &amp;gt; SMB &amp;gt; Samba extra configuration:&lt;/p&gt;
&lt;pre class=&quot;language-toml&quot;&gt;&lt;code class=&quot;language-toml&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;# Force signing off&lt;/span&gt;
server signing &lt;span class=&quot;token punctuation&quot;&gt;=&lt;/span&gt; disabled
strict sync &lt;span class=&quot;token punctuation&quot;&gt;=&lt;/span&gt; no&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It was adding &lt;code&gt;strict sync = no&lt;/code&gt; that made the difference, since adding my network transfer looked a lot more consistent.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://www.studioromeo.co.uk/fixing-smb-transfers-on-mac/YJRrG04vlp-794.webp&quot;&gt;&lt;img loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://www.studioromeo.co.uk/fixing-smb-transfers-on-mac/YJRrG04vlp-794.jpeg&quot; alt=&quot;View of graph&quot; width=&quot;794&quot; height=&quot;189&quot;&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;Speeds aren&#39;t amazing but this is equivalent to NFS so I&#39;m happy. After &lt;a href=&quot;https://www.samba.org/samba/docs/using_samba/ch11.html&quot;&gt;reading the docs&lt;/a&gt; I think it was requiring the server to do a WRITE &amp;gt; READ cycle for every file.&lt;/p&gt;
&lt;p&gt;Hopefully this will help you, or more likely future me after I&#39;ve forgotten about this&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>Lessons Learned the Hard Way with Dependencies</title>
    <link href="https://www.studioromeo.co.uk/dev-diaries-episode-2/" />
    <updated>2023-04-23T00:00:00Z</updated>
    <id>https://www.studioromeo.co.uk/dev-diaries-episode-2/</id>
    <summary>Learning the hard way that sometimes it&#39;s better to build your own than to struggle with existing tools</summary>
    <content type="html">&lt;p&gt;We&#39;re working on adding OpenID Connect to the app. Luckily for us we only needed to create a client rather than the server, that was being handled by another team. Theres a saying in software, don&#39;t roll your own security. And for us that naturally lead us to looking for a dependency.&lt;/p&gt;
&lt;p&gt;We also noted that OpenID certifies packages for compliance to the spec, pretty handy! We found two for Angular that we thought would work. The first one we tried was a bit of a dud for our cordova setup so we flipped to the other. This worked well and we managed to get the flow to work.&lt;/p&gt;
&lt;p&gt;OpenID comes with tokens, these are used to talk to a protected API. They can expire and if they do we can exchange for a new one. It was this exchange task that was the beginning of our problems. Our issue was trying to make the exchange process work with a device that maybe offline for long periods of time. The plugin would simply keep trying every few seconds which caused our logger to fill up with lots of failed requests.&lt;/p&gt;
&lt;p&gt;We tried everything to keep the dependency. We tried patching the dependency using something like patch package but this wasn&#39;t possible because of the way angular packages are precompiled, perhaps it&#39;s possible but that is beyond my skills. We tried treating it like a black box, changing the responses from requests to blank ones. This also didn&#39;t work. We even looked at alternative dependencies but they also had issues one way or another.&lt;/p&gt;
&lt;p&gt;In the end we were left with only one option. Write our own. In some ways after going down that rabbit hole I&#39;m kinda glad. Writing the code ourselves is daunting in the sense of doing it wrong bu at least its our code, we have the ability to fix it if we need.&lt;/p&gt;
&lt;p&gt;What I&#39;ve learned from this process is that you should use dependencies, but maybe with a little care and nuance which might not always be apparent at the time.&lt;/p&gt;
&lt;p&gt;Theres a lot that some dependencies offer. They&#39;re often authored by multiple people over a period of years so the code is usually quite well battle tested across a bunch of projects and contexts. This is useful as it decreases the risk of bugs. Sometimes they can also be certified by an external body, for example OpenID projects can be certified for compliance against the spec which is what drew us to using a dependency.&lt;/p&gt;
&lt;p&gt;But be careful. It&#39;s worth taking the time to look at the dependencies available to you. Look at the common things like:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;em&gt;How many authors are there?&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Whats the activity like on the repository?&lt;/em&gt; &lt;br&gt;Is there a lot of recent action or has it been untouched for years? This might not be a bad thing if the dependency does what it needs to and has no bugs but it could also be a sign of a dead project.&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Whats the license like?&lt;/em&gt; &lt;br&gt;Can you even use this dependency? Is there a fee you need to pay?&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;There are also more nuanced things to look at, personal to you, your team &amp;amp; project.&lt;/p&gt;
&lt;p&gt;Check out the code. How much of what it does is relevant to your needs? For example our dependency included code for the entire OpenID Connect spec. We only needed the Authorization Code flow so a lot of the code in the dependency was redundant. During debugging this meant we had a lot of irrelevant code to comb through to understand what was going on.&lt;/p&gt;
&lt;p&gt;If you do need to tweak, can you? Without it being a bit of a pain in the bum. Some dependencies that are a bit larger make use of adapter / strategy patterns that allow you to write custom code that adheres to an interface. If you can&#39;t, is it patchable?&lt;/p&gt;
&lt;p&gt;Lastly should you need to switch to something else, what options are available to you? Are you spoilt for choice or is it slim pickings? If its the latter how confident are you in being able to replace it with something you&#39;ve written?&lt;/p&gt;
&lt;p&gt;As for us, we&#39;re on the road towards writing our own package. It&#39;s a slow process but we&#39;re getting there, cobbling together knowledge from specs and other projects to build something that works for us.&lt;/p&gt;
&lt;p&gt;Hopefully this ends up turning out okay...&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>Writing a Tool to Help Test Migrating Lots of Code</title>
    <link href="https://www.studioromeo.co.uk/dev-diaries-episode-1/" />
    <updated>2023-02-11T00:00:00Z</updated>
    <id>https://www.studioromeo.co.uk/dev-diaries-episode-1/</id>
    <summary>
My day job involves working on a mobile app for a well known medical journal based in the UK. It provides healthcare professionals with the latest evidence-bas</summary>
    <content type="html">&lt;p&gt;My day job involves working on a mobile app for a well known medical journal based in the UK. It provides healthcare professionals with the latest evidence-based clinical decision support information.&lt;/p&gt;
&lt;p&gt;These days the tech stack is aging but its much too large to rewrite all in one go. So instead we are doing a phased migration, gradually re-writing the application bit by bit between releases. We are moving from AngularJS to Angular, which incase you don&#39;t know is a huge change as it involves a new framework and language!&lt;/p&gt;
&lt;p&gt;I would explain more but it&#39;s a long story so I&#39;ll save that for another post.&lt;/p&gt;
&lt;p&gt;This is the first of a series of posts where I hope to write about the challenges we faced and how we got (or didn&#39;t get) over them.&lt;/p&gt;
&lt;p&gt;In the app we use content from an API that is stored in JSON serialised form. To display content we first transform this into an object before handing it off to the rendering code to display.&lt;/p&gt;
&lt;p&gt;As part of the migration we have to rewrite the transformation layer. Problem is theres about 20,000 lines of code (including tests) which increases the workload and also the chances of bugs sneaking in.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://www.studioromeo.co.uk/dev-diaries-episode-1/Tk4V-THB2c-354.webp&quot;&gt;&lt;img loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://www.studioromeo.co.uk/dev-diaries-episode-1/Tk4V-THB2c-354.jpeg&quot; alt=&quot;Github lines changed stat showing 19,093 lines added and 125 lines deleted&quot; width=&quot;354&quot; height=&quot;130&quot;&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;As it stands the layer is written as a single class with a bunch of static methods which we mock during testing. One of the issues with this approach is that the file becomes really large and unwieldy as it has to contain transformation code for every single content type. The other issue is that mocking can often mask issues if the mock doesn&#39;t reflect the real world.&lt;/p&gt;
&lt;p&gt;Instead we switched to using pure functions, because transforming objects from one format to another seems like the perfect candidate for a pure function if you read enough articles about it. For tests we use the pure functions that we&#39;ve tested elsewhere rather than mocking. Pros are that we&#39;re not mocking much code. Cons are that if something goes wrong jasmine doesn&#39;t make it the easiest to see whats up. Trade offs innit.&lt;/p&gt;
&lt;p&gt;Another issue we have is despite having a lot of tests it&#39;s hard to be sure that the new layer works the same as the old layer. This is a sign that the tests could be improved but thats a story for another day.&lt;/p&gt;
&lt;p&gt;We could just risk it and fix problems as we discover them but that sounds like a lot of stress too.&lt;/p&gt;
&lt;p&gt;A few years ago my friend &lt;a href=&quot;https://www.tomseldon.co.uk&quot;&gt;Tom&lt;/a&gt; created a section in the app for dev tooling to live which is super handy. A new tool was added which had one job…&lt;/p&gt;
&lt;h2&gt;The task&lt;/h2&gt;
&lt;p&gt;For every topic downloaded in the app, first run all the transformers split between old and new, then compare them! If they match then great carry on. If they don&#39;t match then stop and show where they differ in something thats easy to use.&lt;/p&gt;
&lt;p&gt;Using this tool we can then be happy that both old and new transformers are working the same.&lt;/p&gt;
&lt;p&gt;We&#39;d also need to test this against other content languages such as Spanish. Different languages are an area we are particularly weak testing as most tests use English.&lt;/p&gt;
&lt;p&gt;Ok well to build this we have to solve a few problems along the way.&lt;/p&gt;
&lt;h2&gt;Problem #1: How to flip ­between old and new transformers?&lt;/h2&gt;
&lt;p&gt;First up we want to restrict how much code we have to write at once before we can get to testing. The transformation layer is sits below the repository layer so thats where we need to switch between old and new transformers. Each repository extends a &lt;code&gt;BaseRepository&lt;/code&gt; class which contains some helper methods that all repositories can use.&lt;/p&gt;
&lt;p&gt;In &lt;code&gt;BaseRepository&lt;/code&gt; we added a new private method which checks if we should use the new transformer. This keeps the logic in one place instead of spread out across multiple repositories:&lt;/p&gt;
&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token function&quot;&gt;_isNewTransformerEnabled&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;_featureFlag&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;isEnabled&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;new_transformer&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then in each repository (the layer above the transformer) we call this method to see if we should use the old or new transformer&lt;/p&gt;
&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token function&quot;&gt;find&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;topicId&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;_rawTopicsRepository&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;findRawTopic&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;topicId&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;then&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;raw&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;_isNewTransformerEnabled&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;then&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;enabled&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; enabled &lt;span class=&quot;token operator&quot;&gt;?&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;_$window&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;newHotness&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;topicParser&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;parse&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;raw&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;
        TopicParser&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;parse&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;raw&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Cool thats the first problem sorted, we can now toggle between old and new transformers 🙌&lt;/p&gt;
&lt;h2&gt;Problem #2: How can we ­toggle the feature on demand?&lt;/h2&gt;
&lt;p&gt;In the past our feature flag looked at the state from two sources, either remotely via firebase or locally via the codebase depending on the type of flag it was. This is fine 99% of the time but for our tool we wanted to be able to toggle the feature at runtime, otherwise we&#39;d be comparing the same transformer against itself 🤦‍♂️&lt;/p&gt;
&lt;p&gt;To do this we added an overrides feature to the feature flag service. This would allow us to have the final say on whether a flag is enabled or disabled.&lt;/p&gt;
&lt;p&gt;The way it works is quite simple, we have an array in the service that stores the overrides. We then have a method which lets users of the feature flag service add overrides.&lt;/p&gt;
&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token function&quot;&gt;addOverride&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;flagName&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; state&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;_overrides&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;flagName&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; state&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Consumers of the feature flag service call &lt;code&gt;isEnabled()&lt;/code&gt; which gets the status of the flag. If an override exists it ignores the original setting and instead resolves the override. We don&#39;t check for falsy because we might want to return false from the overrides.&lt;/p&gt;
&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token function&quot;&gt;isEnabled&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;flagName&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;_overrides&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;flagName&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;!==&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;undefined&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;_$q&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;resolve&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;_overrides&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;flagName&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

  &lt;span class=&quot;token comment&quot;&gt;//--- Rest of code gets the flag state from firebase or locally depending on the flag type&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Cool, so this allows us to change the state of a flag whenever we want. A nice bonus is we have a feature flag dev tool which at the moment just shows the state of the flags. Now we have overrides we could toggle flags on or off from the dev tool which would be pretty neat!&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://www.studioromeo.co.uk/img/fzP2gY4e2g-800.webp&quot;&gt;&lt;img loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://www.studioromeo.co.uk/img/fzP2gY4e2g-800.jpeg&quot; alt=&quot;A screenshot of the app with a list of feature flags. Next to it are toggles that are currently disabled&quot; width=&quot;800&quot; height=&quot;415&quot;&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;h2&gt;Making the page&lt;/h2&gt;
&lt;p&gt;Ok so the page is actually pretty simple, it&#39;s just some text that describes what it does and a button that starts the testing.&lt;/p&gt;
&lt;p&gt;Initially I struggled to write the code to make all this work, sometimes I get myself in a bit of muddle. To recap what I need to do is:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Get all the topics we have in the database&lt;/li&gt;
&lt;li&gt;For each topic get more data about the topic so I know its type. Different topic types need a different set of transformers&lt;/li&gt;
&lt;li&gt;We then need to get all the repositories related to the topic&lt;/li&gt;
&lt;li&gt;For each repository we need to do the following
&lt;ol&gt;
&lt;li&gt;Disable the &lt;code&gt;new_transformer&lt;/code&gt; flag&lt;/li&gt;
&lt;li&gt;Get the data from the repository&lt;/li&gt;
&lt;li&gt;Enable the &lt;code&gt;new_transformer&lt;/code&gt; flag&lt;/li&gt;
&lt;li&gt;Get the data from the repository again (this time it&#39;ll be using the new transformers)&lt;/li&gt;
&lt;li&gt;Check both to see if they are the same and if not show the difference&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;I started by getting the topics, then looping over those and getting information about the topics inside that loop, then getting the repositories inside that loop again and then running the tests twice in that loop.&lt;/p&gt;
&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; topic &lt;span class=&quot;token keyword&quot;&gt;of&lt;/span&gt; topics&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
 &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; topic &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;getTopicInfo&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;topic&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
 &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; repositories &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;getRepositoryForTopic&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;topic&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
 &lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; repo &lt;span class=&quot;token keyword&quot;&gt;of&lt;/span&gt; repositories&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token function&quot;&gt;disableFlag&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; a &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;test&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token function&quot;&gt;enableFlag&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; b &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;test&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token function&quot;&gt;compare&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;a&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; b&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;bad&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    console&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;what went wrong&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;break&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
 &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Imagine this with promises too and its a bit of a mind &lt;s&gt;f*ck&lt;/s&gt;. So a ranty walk later I switched approach.&lt;/p&gt;
&lt;p&gt;Instead we use promises as they were meant to be used and chain them. (Why didn&#39;t I do it this way to start with?!). Starting off we get the topics then with that we map over the resolved array to get more info about each topic like so:&lt;/p&gt;
&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;_topicRepository&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;findAll&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;then&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;topics&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;_$q&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;all&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
        topics&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;topic&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;_topicRepository&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;findById&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;topic&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;id&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Cool we have an array of detailed topics! Thank u, next.&lt;/p&gt;
&lt;p&gt;Now we want to turn this list of topics into a list of repositories. To make this easier in my head I used the jobs analogy so we&#39;re creating a flat list of jobs to iterate against. A flat list is easier to imagine than nested loops!&lt;/p&gt;
&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token function&quot;&gt;_createJobPayload&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;topic&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; jobs &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; repositories &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;_getRepositoryFromType&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;topic&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;type&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; key &lt;span class=&quot;token keyword&quot;&gt;in&lt;/span&gt; repositories&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    jobs&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;push&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;token literal-property property&quot;&gt;topic&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; topic&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token literal-property property&quot;&gt;repository&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; repositories&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;key&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token literal-property property&quot;&gt;repositoryName&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; key
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; jobs&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;So we take a topic and get the repositories for its type. For each repository we create an array of jobs which contains the topic, the repository and the name of the repository. Unfortunately this returns a nested array like this, which isn&#39;t what we want because it makes dealing with it much more complex.&lt;/p&gt;
&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;[ [[job1], [job2]], [[job3]], …]&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Luckily es6 added a new array method called &lt;code&gt;flatMap&lt;/code&gt; which is absolutely marvellous! It turns our nested arrays into a nice flat list 👩‍🍳&lt;/p&gt;
&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;then&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;topics&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; topics&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;flatMap&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;topic&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;_createJobPayload&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;topic&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And voila! We now have a nice flat array of jobs to test against.&lt;/p&gt;
&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;[ job1, job2, job3, …]&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Next up (I promise we&#39;re nearly done), we need to run the tests sequentially. Normally we could use &lt;code&gt;async/await&lt;/code&gt; for this but unfortunately for me this wasn&#39;t possible (babel in our build system is too old and doesn&#39;t understand async/await syntax, yet another reason we want to update).&lt;/p&gt;
&lt;p&gt;I wasn&#39;t sure how to do this but a quick stack overflow later I found my answer which was surprisingly simple!&lt;/p&gt;
&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;jobs&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;reduce&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;promise&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; job&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt;
        promise&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;then&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;_test&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;job&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;repository&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; job&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;topic&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; job&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;key&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;_$q&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;resolve&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This uses the reduce function and starts off with a resolved promise, it then chains subsequent promises for each job so we only run the next job if the previous one resolved.&lt;/p&gt;
&lt;p&gt;Finally (home stretch now) we need to actually do the test. Yep all this waffle above was just getting to the point where we could actually test! Thank you for sticking with me!&lt;/p&gt;
&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token function&quot;&gt;_test&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;repository&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; topic&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; key&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  console&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;testing…&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;topic&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; topic&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;id&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;repository&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; key &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; a &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; b &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;_disableNewTransformer&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;then&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;_testRepository&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;repository&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; topic&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;then&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;output&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; a &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; output&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;then&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;_enableNewTransformer&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;then&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;_testRepository&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;repository&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; topic&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;then&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;output&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; b &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; output&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;then&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; transformSame &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;JSON&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;stringify&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;a&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;JSON&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;stringify&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;b&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
      &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;transformSame&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        console&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;error&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;detailedDiff&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;a&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; b&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;old&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; a&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; b &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;throw&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Error&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;Transform failed for repository: &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;key&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;, topic: &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;topic&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;id&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This is pretty similar to the mock code earlier. We disable the flag, test, enable then test again. To compare the two results we use &lt;code&gt;JSON.stringify()&lt;/code&gt; which I got from &lt;a href=&quot;https://www.samanthaming.com/tidbits/33-how-to-compare-2-objects/&quot;&gt;Samantha&#39;s Blog&lt;/a&gt; which advised this would do the job albeit with performance and ordering issues but both of these weren&#39;t a concern for this, we just wanted to know that they were the same output.&lt;/p&gt;
&lt;p&gt;If they don&#39;t match we throw an error with the repository and topic that failed. Also we log to the console both old and new JSON so we can dig into it and see whats up.&lt;/p&gt;
&lt;h3&gt;Quality of life extras&lt;/h3&gt;
&lt;p&gt;We&#39;re more or less done with the tool now which is great news but I wanted to add a few extra things just to make life using the tool a bit nicer. As it stands if there was a difference in the output between transformers it would be pretty tricky to know exactly where that difference is, these objects are often quite big and heavily nested!&lt;/p&gt;
&lt;p&gt;We installed a new package called &lt;a href=&quot;https://www.npmjs.com/package/deep-object-diff&quot;&gt;deep-object-diff&lt;/a&gt; which is cool because it tells you exactly where the two objects differ. We use &lt;code&gt;detailedDiff&lt;/code&gt; which separates what was added, removed and updated into an object that can be logged to the console. This along with the log of the objects themselves makes finding the change much easier.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://www.studioromeo.co.uk/dev-diaries-episode-1/yCvs15jZcS-800.webp&quot;&gt;&lt;img loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://www.studioromeo.co.uk/dev-diaries-episode-1/yCvs15jZcS-800.jpeg&quot; alt=&quot;A screenshot of Google Chrome with the dev tool running the test. On the right hand side is the console with the failing results listed&quot; width=&quot;800&quot; height=&quot;565&quot;&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;Another quality of life update (well thats stretching it a bit). We wanted to know how far in the test we got before it failed, so we added a progress bar and some job counts. It doesn&#39;t really help much with the task of fixing differences but it does help game-ify it a bit.&lt;/p&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;So thats it really. The tool was a bit of work but it&#39;s already been really useful as its identified a few differences which the tests did not pick up. We can then fix those and fix the tests too so we know it&#39;ll always behave that way in the future.&lt;/p&gt;
&lt;p&gt;Eventually we won&#39;t need the tool after we&#39;ve removed the old transformation layer. But for now it sure helps us all sleep at night better knowing its working just as it did before.&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>Polymer</title>
    <link href="https://www.studioromeo.co.uk/polymer/" />
    <updated>2016-05-01T00:00:00Z</updated>
    <id>https://www.studioromeo.co.uk/polymer/</id>
    <summary>Polymer is an framework which is used to create custom HTML elements. In this talk we explore what it is and build a cat pintrest app for cat lovers everywhere</summary>
    <content type="html">&lt;p&gt;Another talk I did back in November was on Polymer.&lt;/p&gt;
&lt;p&gt;&lt;a title=&quot;Play Video&quot; class=&quot;o-media c-media u-link-default&quot; href=&quot;https://www.youtube.com/embed/s4dybsEIAIs&quot;&gt;
&lt;svg class=&quot;o-media__body c-media__play &quot; xmlns=&quot;http://www.w3.org/2000/svg&quot; width=&quot;32&quot; viewBox=&quot;0 0 512 512&quot;&gt;
&lt;title&gt;Play Video&lt;/title&gt;
&lt;use xlink:href=&quot;/img/assets/icons.svg#icon-play&quot;&gt;&lt;/use&gt;
&lt;/svg&gt;
&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Polymer is an interesting framework which is used to create custom HTML elements using the browsers web components API&#39;s if it can. In my talk we&#39;ll make our very own elements and use them to create a cat pinterest style application for cat lovers everywhere.&lt;/p&gt;
&lt;p&gt;As I was recording this my screen recorder crashed which meant I had to bail from screen recording my talk. I don&#39;t think my mac likes screen recording while trying to power a projector and it&#39;s screen!&lt;/p&gt;
&lt;p&gt;I also listed some useful links which weren&#39;t captured in the video so here are the links below:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/studioromeo/kitteh-components&quot;&gt;Screencast Sourcecode&lt;/a&gt; - The sourcecode for the kitteh app that we built in this screencast&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.polymer-project.org/1.0/&quot;&gt;Official Polymer Site&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/PolymerLabs/polylint&quot;&gt;Polylint&lt;/a&gt; - A useful linter which is good at picking up common errors&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/PolymerLabs/polyserve&quot;&gt;Polyserve&lt;/a&gt; - A simple server to load your Polymer elements&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://webcomponents.org/&quot;&gt;Webcomponents&lt;/a&gt; - Collection of all things web components&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.youtube.com/playlist?list=PLNYkxOF6rcICdISJclfQhj2S8QZGjXV8J&quot;&gt;Polymer Summit&lt;/a&gt; - Youtube playlist of the latest Polymer summit&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://codelabs.developers.google.com/polymer-summit&quot;&gt;Codelabs&lt;/a&gt; - Useful collection of hands on tutorials on how to do cool stuff with Polymer&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.youtube.com/playlist?list=PLOU2XLYxmsII5c3Mgw6fNYCzaWrsM3sMN&quot;&gt;Polycasts&lt;/a&gt; - A youtube series hosted by Rob Dodson on polymer topics, very handy stuff!&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Thank you for watching!&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>All About Atom</title>
    <link href="https://www.studioromeo.co.uk/all-about-atom/" />
    <updated>2016-04-19T00:00:00Z</updated>
    <id>https://www.studioromeo.co.uk/all-about-atom/</id>
    <summary>Atom is an exciting new editor built on web tech. In the talk I go through how atom works and some of the changes I&#39;ve made to it to make it work for me</summary>
    <content type="html">&lt;p&gt;I did this talk way back in November last year but it&#39;s only now I&#39;ve managed to see about putting it on the interwebs.&lt;/p&gt;
&lt;p&gt;Apologies the fan noise towards the end, I&#39;m still using an old mac from the days when only rappers had gold macs.&lt;/p&gt;
&lt;p&gt;&lt;a title=&quot;Play Video&quot; class=&quot;o-media c-media u-link-default&quot; href=&quot;https://www.youtube.com/embed/iVFQp0b8DXI&quot;&gt;
&lt;svg class=&quot;o-media__body c-media__play &quot; xmlns=&quot;http://www.w3.org/2000/svg&quot; width=&quot;32&quot; viewBox=&quot;0 0 512 512&quot;&gt;
&lt;title&gt;Play Video&lt;/title&gt;
&lt;use xlink:href=&quot;/img/assets/icons.svg#icon-play&quot;&gt;&lt;/use&gt;
&lt;/svg&gt;
&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;This time I&#39;m talking about my latest escapades with the open source editor &lt;a href=&quot;https://atom.io&quot;&gt;Atom&lt;/a&gt;. I really like using this editor as it feels approachable and most importantly for a coder, tweak-able!&lt;/p&gt;
&lt;p&gt;In the talk I go through how atom works and some of the changes I&#39;ve made to it to make it work for me. I also look at other projects which have benefitted from the work done on Atom and it&#39;s child project &lt;a href=&quot;https://electron.atom.io&quot;&gt;Electron&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Since then I&#39;ve removed a lot of stuff that I originally had added, this is mostly to squeeze as much performance as possible out of atom as it can still be a bit of a sloth at times (usually when you&#39;re trying to do just one quick change).&lt;/p&gt;
&lt;p&gt;And as always thanks for watching!&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>Refactoring with BEM</title>
    <link href="https://www.studioromeo.co.uk/refactoring-with-bem/" />
    <updated>2016-02-23T00:00:00Z</updated>
    <id>https://www.studioromeo.co.uk/refactoring-with-bem/</id>
    <summary>3 years ago I put the finishing touches to my first design. We&#39;ll go over what I&#39;ve changed since and where I hope to go next</summary>
    <content type="html">&lt;p&gt;It was around this time &lt;a href=&quot;https://www.studioromeo.co.uk/suit-and-tie&quot;&gt;3 years ago&lt;/a&gt; I was putting the finishing touches to this design.&lt;/p&gt;
&lt;p&gt;Back then Jekyll didn&#39;t compile sass and since the design was quite simple I didn&#39;t feel the need for it, plus I&#39;d probably forget to compile half the time anyway!&lt;/p&gt;
&lt;p&gt;I wrote my css the old fashioned way, starting with the header and working my way down to the footer. It was great in the beginning but after a while a few drawbacks started to emerge:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;No build process to minify and concatenate (I could have made one but then I would have just used sass)&lt;/li&gt;
&lt;li&gt;High specificity caused clashes and made it easy to add bugs&lt;/li&gt;
&lt;li&gt;Duplicated code for similar objects and redundancies&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;I had been meaning to tidy it up for ages but I just didn&#39;t know what to do. I was aware of &lt;a href=&quot;https://thesassway.com/intermediate/using-object-oriented-css-with-sass&quot;&gt;OOCSS&lt;/a&gt; &amp;amp; &lt;a href=&quot;https://smacss.com&quot;&gt;SMACSS&lt;/a&gt; but didn&#39;t understand them. Lately I&#39;ve been getting into &lt;a href=&quot;https://getbem.com/&quot;&gt;BEM&lt;/a&gt; because it is a simpler concept
to grasp.&lt;/p&gt;
&lt;p&gt;After doing a bit at work and also reading &lt;a href=&quot;https://csswizardry.com/2015/03/more-transparent-ui-code-with-namespaces/&quot;&gt;about namespaces&lt;/a&gt; I finally felt confident to try and refactor this :hankey:&lt;/p&gt;
&lt;p&gt;I ended up with this &lt;a href=&quot;https://github.com/studioromeo/studioromeo.github.com/tree/d2a28c0577fd0cac191ba1f9851f2b93f0134498/_sass&quot;&gt;structure&lt;/a&gt; which I&#39;m not fully convinced by but it&#39;s a vast improvement on what it replaces. It&#39;s still BEM but with namespaces to add a bit more information.&lt;/p&gt;
&lt;p&gt;These aren&#39;t just namespaces plucked out of thin air either, they explain how explicit the styles are. Starting from generic wide ranging styles to more focused styles that only affect a handful of elements.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Settings &amp;amp; Tools&lt;/strong&gt;: Contains sass variables and my animations&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Generic&lt;/strong&gt;: Resets, spacing and box models&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Base&lt;/strong&gt;: Element selectors only, no classes here&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Object&lt;/strong&gt;: Inspired by the media object in OOCSS this contains code shared across two or more components. Purely class selectors from here on&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Component&lt;/strong&gt;: Main parts of the design, highly specific code that affects very few html elements&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Finally theres trumps which is the most explicit layer. Use of &lt;code&gt;!important&lt;/code&gt; here is OK since I know that this is the final layer of specificity.&lt;/p&gt;
&lt;p&gt;This format is nice to work in because I know what impact my changes will have. A useful tool I borrowed from csswizardry was his debug stylesheet which outlines different components on the page
which is handy.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://www.studioromeo.co.uk/img/aSdll3z_hv-643.webp&quot;&gt;&lt;img loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://www.studioromeo.co.uk/img/aSdll3z_hv-643.jpeg&quot; alt=&quot;Site with coloured outlines for different classes&quot; width=&quot;643&quot; height=&quot;506&quot;&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;As an added bonus naming my files like this makes it really easy to find what I&#39;m looking for. I guess the only downside to this technique is knowing what to call things!&lt;/p&gt;
&lt;p&gt;Additionally I added &lt;a href=&quot;https://github.com/brigade/scss-lint&quot;&gt;scss-lint&lt;/a&gt; to the CI to make sure that my code stayed consistent which while annoying at the time is really handy. I just had to spend some time making sure I had it set up with the correct rules.&lt;/p&gt;
&lt;p&gt;Feel free to nose around the &lt;a href=&quot;https://github.com/studioromeo/studioromeo.github.com/pull/25&quot;&gt;pull request&lt;/a&gt;. Thanks for reading!&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>Congestion Busting with Blackfire.io</title>
    <link href="https://www.studioromeo.co.uk/congestion-busting-blackfire/" />
    <updated>2016-02-13T00:00:00Z</updated>
    <id>https://www.studioromeo.co.uk/congestion-busting-blackfire/</id>
    <summary>
Recently at work I was involved a project which aimed to improve the performance of one of our analytics systems. We needed a way of measuring our progress of </summary>
    <content type="html">&lt;p&gt;Recently at work I was involved a project which aimed to improve the performance of one of our analytics systems. We needed a way of measuring our progress of certain user flows before and after optimization so we could give the client feedback on how the project was progressing.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://blackfire.io/&quot;&gt;Blackfire&lt;/a&gt; is a performance measuring tool written by the folks behind the symfony php framework and was ideal for the task. You can read about my experience with blackfire over on the &lt;a href=&quot;https://boxuk.com/insight/tech-posts/reducing-congestion-with-blackfire-io&quot;&gt;Box UK dev blog&lt;/a&gt;.&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>Responsive Day Out</title>
    <link href="https://www.studioromeo.co.uk/responsive-day-out/" />
    <updated>2015-10-07T00:00:00Z</updated>
    <id>https://www.studioromeo.co.uk/responsive-day-out/</id>
    <summary>Responsive day out is a front-end focused conference sharing tips and tricks on workflow, techniques and experiences on dealing with a responsive web.</summary>
    <content type="html">&lt;p&gt;This is my second talk of the year and first duet with &lt;a href=&quot;https://twitter.com/littlecrome&quot;&gt;Christelle&lt;/a&gt; (I&#39;m not sure if thats the right terminology but lets run with it). At &lt;a href=&quot;https://boxuk.com&quot;&gt;Box&lt;/a&gt; whenever someone goes to a conference they can do a short talk to summarise the event for those who couldn&#39;t attend.&lt;/p&gt;
&lt;p&gt;Responsive day out is a front-end focused conference sharing tips and tricks on workflow, techniques and experiences on dealing with a responsive web. The nice thing about this conference was it contained both devs and designers!&lt;/p&gt;
&lt;p&gt;&lt;a title=&quot;Play Video&quot; class=&quot;o-media c-media u-link-default&quot; href=&quot;https://www.youtube.com/embed/fU_OlZdwUcI&quot;&gt;
&lt;svg class=&quot;o-media__body c-media__play &quot; xmlns=&quot;http://www.w3.org/2000/svg&quot; width=&quot;32&quot; viewBox=&quot;0 0 512 512&quot;&gt;
&lt;title&gt;Play Video&lt;/title&gt;
&lt;use xlink:href=&quot;/img/assets/icons.svg#icon-play&quot;&gt;&lt;/use&gt;
&lt;/svg&gt;
&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;We both found this one tough for the following reasons:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;We needed to deliver it soon after coming back so that the day remained fresh in our heads but we were also very busy at the time&lt;/li&gt;
&lt;li&gt;The conference was intense even by single day standards and a lot of ground was covered in a short space of time. Compressing this into a 30 minute chunk and retaining its structure was tough&lt;/li&gt;
&lt;li&gt;Making sure we both felt we contributed equally was also really hard&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The talk was well received with most saying it was the best that they had experienced of this type! :smile:&lt;/p&gt;
&lt;p&gt;The conference was a blast and I really enjoyed producing this talk with &lt;a href=&quot;https://twitter.com/littlecrome&quot;&gt;Christelle&lt;/a&gt;. Hopefully we can do it again someday!&lt;/p&gt;
</content>
  </entry>
</feed>