{
    "version": "https://jsonfeed.org/version/1",
    "title": "Alex Sparrow",
    "home_page_url": "https://alexsparrow.dev",
    "feed_url": "https://alexsparrow.dev/rss/feed.json",
    "description": "Your blog description",
    "icon": "https://alexsparrow.dev/favicon.ico",
    "author": {
        "name": "Alex Sparrow"
    },
    "items": [
        {
            "id": "https://alexsparrow.dev/articles/building-beampipe-part-2",
            "content_html": "<p><em>Originally published <a href=\"https://medium.com/beampipe/building-beampipe-part-ii-frontend-9825d69571c4\">here</a>.</em></p>\n<p>Hello again 👋👋👋 and welcome to part two of this series talking about how we build beampipe.io, a privacy-conscious and fun alternative to Google Analytics.</p>\n<hr/>\n<p>In part one we talked about backend so naturally it&#x27;s now time for us to turn to frontend. I&#x27;ll start with a confession - I am not by skill or by inclination a frontend developer. Don&#x27;t get me wrong, I&#x27;ve written a lot of frontend code over the years (perhaps I&#x27;m just in denial) but it&#x27;s normally been about getting something built rather than more careful crafting. I&#x27;d say that&#x27;s changed a little in the last few years as frontend tooling has improved drastically. Seriously, if you are a backend engineer looking to get your feet wet, no time like the present.</p>\n<h2>Typescript + React</h2>\n<p>Anyway back to the subject, what tools are we using and why. Let&#x27;s start with some easy decisions. It&#x27;s probably not an understatement to say that I like static types. The stronger the type system the better. Particularly with web development, I find this drastically reduces the number of mistakes I make (typos in variable names or wrong usage of APIs being particularly common problems). So without a very compelling reason not to, I start every project with Typescript.</p>\n<p>The other easy pick for me is React. This is pragmatic more than principled. I&#x27;m sure Vue and Angular and Alpine.js are all great in their own ways but as a lone developer I&#x27;ve got enough plates spinning already so I pick something simple which I now know relatively well.</p>\n<img alt=\"The Lambda cube. About the prettiest thing I could find related to static-types. Head on down the wiki rabbithole: https://en.wikipedia.org/wiki/Lambda_cube\" src=\"/_next/static/media/lambdacube.9fa0b555.png\" width=\"1600\" height=\"1290\" decoding=\"async\" data-nimg=\"1\" loading=\"lazy\" style=\"color:transparent\"/>\n<h2>NextJS</h2>\n<p>Like a lot of modern applications, Beampipe&#x27;s UI is mostly a single page application (SPA). This means that your browser typically downloads a blob of javascript which dynamically manipulates the content of the webpage to show the UI and effect transitions between pages. This is a particularly good fit for Beampipe, which is interactive and data-heavy.</p>\n<p>create-react-app is a fantastically easy way to get started with React. However, for beampipe I opted to use NextJS instead.</p>\n<p>NextJS&#x27;s main claim to fame is that it shakes up the SPA model a little by enabling server side rendering (SSR). This means NextJS can execute your React code server side, render the UI of your application and send this down to your browser as fully-formed HTML. This reduces the delay before your application is rendered on the client and also helps search engines index your content.</p>\n<p><strong>But actually neither of these are very compelling things for Beampipe</strong>. We generally don&#x27;t need Google to index an analytics dashboard and the rendering latency is also not a huge concern (particularly as the client will often request new data as the user interacts with the page). On the other hand, I&#x27;ve found NextJS really easy to write code in and the SSR capabilities are handy for some of the public pages. For instance NextJS is able to statically render the landing and authentication pages which is quite nice when I get the odd spike of traffic.</p>\n<p>Using NextJS means I do have to run another container, but since I&#x27;m already using Kubernetes, this isn&#x27;t a big problem. That said, for someone who hasn&#x27;t used NextJS before, I&#x27;d probably default to create-react-app and save some of the headache.</p>\n<h2>APIs</h2>\n<p>Back in part one, I mentioned that we&#x27;re using GraphQL for the API along with urql on the client. urql is great. Whenever I need a more advanced feature, I reach for it and it&#x27;s there without having to dig deep into the internals (as I sometimes found I had to with apollo-client). React hooks make it a joy to use. It&#x27;s also well supported in NextJS via next-urql. This will talk to your API server side and thus pass the page to the client fully formed and ready to go.</p>\n<h2>😆CSS / Design</h2>\n<p>As I said, frontend development generally hasn&#x27;t been a strong point for me. However, the analytics space is filled with some very beautiful UIs (plausible, fathom among others). To compete at all with them, I&#x27;d need to make beampipe at least passable from a design perspective. In practice, this means having fairly tight control over the design and not (as I have done previously) just shoving in a framework.</p>\n<p>For this reason, I picked TailwindCSS. Tailwind is a fairly new, low-level CSS framework which basically just gives you some utility classes for doing things like adding padding or setting fixed sizes or working with flexbox. This looks and sounds horrifying at first but it actually seems to produce pretty good results. You can use React to abstract components with standardised (but very customised) look and feel. It&#x27;s also quite handy when you want to take inspiration from other sites (a growing number are using tailwind) 😃.</p>\n<p>A fringe benefit of choosing such a low level CSS framework is that it&#x27;s really forced me to try to get my head around things like Flexbox and the various quirks of how browsers render and size elements on the page. I won&#x27;t pretend to enjoy this but it has been worthwhile and I&#x27;d recommend any frontend-curious backend engineer give it a spin.</p>\n<img alt=\"Real life Tailwind code from Beampipe&#x27;s landing page. Looks gross. Actually not half bad.\" src=\"/_next/static/media/css.ef71ff45.png\" width=\"1600\" height=\"1084\" decoding=\"async\" data-nimg=\"1\" loading=\"lazy\" style=\"color:transparent\"/>\n<p>Programmers often fear things that we do not understand or which appear to behave unpredictably. I&#x27;m sure many of us nightmares (or even current experiences) of impossible to track down bugs or things that seemed to just make no sense. I certainly experience this occasionally but it&#x27;s something that has become joyfully less frequent as I&#x27;ve gained experience. It&#x27;s now quite rare for me to feel stressed or intimidated by a bug.</p>\n<p><strong>Not so with CSS</strong>. Magic incantations that I don&#x27;t understand copied and pasted from StackOverflow. It scares me. The solution to this, quite naturally, is to knuckle down and learn it properly (kind of). I now find the fear and self-doubt is starting to recede and UI work, whilst still frustrating, has become more fun. It&#x27;s also really liberating to see something you don&#x27;t like in the UI and generally just be able to go in and fix it up right away.</p>\n<hr/>\n<p>That&#x27;s all for now. In the meantime do come have click around at beampipe.io or write to us <a href=\"mailto:hello@beampipe.io\">hello@beampipe.io</a> Cheers!</p>",
            "url": "https://alexsparrow.dev/articles/building-beampipe-part-2",
            "title": "Building beampipe part II: frontend",
            "summary": "Hello again 👋 and welcome to part two of this series talking about how we build beampipe.io, a privacy-conscious and fun alternative to Google Analytics. In part one we talked about backend so…",
            "date_modified": "2020-08-21T00:00:00.000Z",
            "author": {
                "name": "Alex Sparrow"
            }
        },
        {
            "id": "https://alexsparrow.dev/articles/how-we-build-beampipe",
            "content_html": "<p><em>Originally published <a href=\"https://medium.com/beampipe/how-we-build-beampipe-50618730a0fd\">here</a>.</em></p>\n<img alt=\"Dashboard view\" src=\"/_next/static/media/screenshot.58eef793.png\" width=\"2484\" height=\"1471\" decoding=\"async\" data-nimg=\"1\" loading=\"lazy\" style=\"color:transparent\"/>\n<p>I wanted to kick this blog off with a discussion of some of the technical decisions we made while building beampipe. However, I guess I can’t really get away without talking at all about what the product is so here goes…</p>\n<p>Beampipe is a simple, privacy-focussed web analytics tool. It’s somewhat similar in concept to <a href=\"https://www.usefathom.com\">Fathom</a> and <a href=\"https://www.plausible.io\">Plausible</a> but with some slightly different goals, particularly with regards to our future roadmap. Put simply, and most fundamentally, we think <strong>web analytics tools should be easy and fun to use</strong>. Secondly, we think that where possible, these tools should respect <strong>user’s privacy</strong>. We take the same cookieless approach as the two aforementioned tools and explicitly not that of Google Analytics. Thirdly and hopefully distinctively, <strong>we think web analytics tools should be powerful</strong>. They should give you useful, actionable insights. We feel that there is no tool on the market ticking all three of these boxes and that we can build it!</p>\n<p>Ok so now that I’ve kept our marketing department happy, how are we building it? I’m going to start out by describing how a web analytics service works.</p>\n<p>All of the products I name-dropped in the preamble function in basically the same way. You drop a little (or not-so-little in the case of Google Analytics) chunk of Javascript onto your page. That Javascript will then make a connection to a backend service and phone home with a little blob of data describing (to various levels of detail) who the user is and what they’re doing on your site. There are some variations here: for instance that you can forego Javascript in favour of an invisible image. But that’s pretty muchthe size of it.</p>\n<p>So the first piece to any web analytics service is to build this tracking script and a suitable backend to process and store the data that it spits out. So what did we choose here?</p>\n<img alt=\"An actual beampipe. Courtesy of CERN Courier.\" src=\"/_next/static/media/beampipe.be9f5378.jpeg\" width=\"640\" height=\"427\" decoding=\"async\" data-nimg=\"1\" loading=\"lazy\" style=\"color:transparent\"/>\n<h2>Kotlin + Micronaut</h2>\n<p>I’m a big fan of Kotlin, a relatively new programming language from the JetBrains. Kotlin is built upon the Java Virtual Machine (JVM), inheriting a huge base of libraries and frameworks as well as an extremely performant runtime. On top of this, and much more importantly from my perspective, it is extremely fun and productive to write code in. It mixes in just enough functional programming magic to make you feel clever and powerful without quite the learning curve, cognitive burden and multiple competing styles that comes with languages like Haskell (or to a lesser degree, Scala).</p>\n<p>On top of these strengths, Kotlin also has some very nice support for asynchronous programming using coroutines, which can be quite an advantage from two perspectives:</p>\n<ul>\n<li><strong>Performance</strong>. I/O heavy code can share operating system threads. This helps us keep our costs down.</li>\n<li><strong>Reasoning about concurrency.</strong> We have several features within the application which call out to external APIs and may perform a chain of operations on the results, handling errors appropriately. Coroutines, in my opinion at least, give a nice readable way of structuring this logic.</li>\n</ul>\n<p>On top of Kotlin, I had to pick a web framework. For this I chose Micronaut which is a fairly full-featured JVM-based web framework with some specific support for Kotlin. Whilst I’ve previously preferred less full-featured frameworks, I’ve actually found that, once through the learning curve, Micronaut gives you a lot of useful stuff out of the box without forcing you to use it (e.g. security/authentication, database connection pools, GraphQL).</p>\n<h2>Database</h2>\n<p>So here we come to perhaps the most important choice. Web analytics tools have some fairly specific needs from a database point of view and ones I shan’t pretend to be an expert in. Write rates are high (at least once people are using the tool). So we need something that can support a fairly high sustained write rate (equivalent to the peak simultaneous traffic for all of the sites using the service). Secondly, we are dealing with timeseries data — something for which certain databases have specific support. Query patterns against the data are often going to be so-called OLAP queries — i.e. aggregations over various axes in the recorded data.</p>\n<p>There are a lot of potentially good database choices here: influxdb, clickhouse, bigquery, redshift etc. However, two concerns led our decision: low overall ops overhead and low cost (since we want to be able to offer a free tier for the service). For this reason, we chose TimescaleDB which is a plugin on top of the excellent PostgreSQL database. This means we only have to live with a single database (including our non-timeseries data) and let’s us get started quickly and at low cost. In future, we may well switch out for something else, but this has served us well so far.</p>\n<h2>APIs</h2>\n<p>Having strong API support is part of the longer term vision for the product. We want our customers to be able to integrate deeply with their analytics data. We also want to build a fantastic frontend experience and do it quickly (the first version of the product was launched within a week).</p>\n<p>Thus we chose GraphQL. Why? Web analytics data is not well represented by a graph and thus doesn’t really benefit from GraphQL’s namesake feature. On the other hand, we’ve found it very useful for building rich APIs with more sophisticated querying capabilities. It is also strongly typed, meaning that users of the API can have some confidence in the shape of the data structures returned. Lastly, alongside frontend libraries like apollo-client or urql we have a very opinionated, simple and powerful way to hook our web interface up to backend queries. This makes development easy and code readable.</p>\n<img alt=\"Very rough architecture diagram for the backend.\" src=\"/_next/static/media/architecture.d7221b19.png\" width=\"510\" height=\"507\" decoding=\"async\" data-nimg=\"1\" loading=\"lazy\" style=\"color:transparent\"/>\n<h2>Build/DevOps</h2>\n<p>So first an admission, despite the pronouns employed in this blog post, Beampipe is a single engineer at the moment — namely me! As a full stack engineer with a lot of ground to cover, automation is key. On the other hand, I have to pick my battles. Continuous Integration (CI) tooling is essential. I simply don’t have time to be manually testing, building and uploading things every time I make a change, at least not if we want to maintain velocity on the product. But I also don’t have time for the kind of build and deployment pipeline you might find on bigger engineering teams.</p>\n<p>For this reason, I build the backend code as a Docker image using GitHub Actions. The build itself is coordinated with Gradle and makes use of Google’s handy jib plugin which produces small, cacheable docker images.</p>\n<p>Deployment is another area where there were trade-offs to be made. I’d love to use something like Heroku and really not have to worry about deploying the application. On the other hand, these tend to be quite cost prohibitive and not necessarily a good fit for how I wanted to build the app. For that reason, I picked Kubernetes on Scaleway’s hosted Kapsule service. I’ve used this for a few projects now and it’s been excellent.</p>\n<p>Currently the backend is deployed as a monolith but it should be fairly easy to split things up should we need to scale component individually (e.g. separating the data ingest service from the query layer).</p>\n<p>So that pretty much wraps it up on the backend pieces of the app. In the next article we’ll discuss the frontend in a similar manner. Hit me up with questions or feedback on <a href=\"mailto:hello@beampipe.io\">hello@beampipe.io</a> Cheers!</p>",
            "url": "https://alexsparrow.dev/articles/how-we-build-beampipe",
            "title": "How we build Beampipe",
            "summary": "Beampipe is a simple, powerful, privacy-focussed web analytics service. We discuss our tech stack which allows us to deliver features rapidly and reliably.",
            "date_modified": "2020-08-11T00:00:00.000Z",
            "author": {
                "name": "Alex Sparrow"
            }
        },
        {
            "id": "https://alexsparrow.dev/articles/async-therefore-i-am",
            "content_html": "<p><em>Originally published <a href=\"https://medium.com/quartictech/async-therefore-i-am-7458bb336b9e\">here</a>.</em></p>\n<p>At <a href=\"https://www.quartic.io/\">Quartic Technologies</a> we spend a lot of our time building micro-services. Our flagship product, GroundControl, consists of about 6 different services (with another 5 or 6 satellites for integration with external databases and APIs). We’ve more-or-less standardised on the Dropwizard framework, which has overall been a good choice — it’s fast, pretty low on boilerplate, and opinionated enough about healthchecks, metrics, configuration and such that we’ve so far avoided an endless spiral of bikeshedding on those topics.</p>\n<p>One thing that has left me a little envious when prospecting alternatives such as Ratpack is the promise of asynchronous IO (or “async” as it’s often abbreviated). As it turns out, servicing requests asynchronously with Dropwizard is not only eminently possible but actually downright straightforward.</p>\n<h2>Making Dropwizard async</h2>\n<p>Curiously, despite the popularity of asynchronous web frameworks, there seems to be pretty scant mention of how to get Dropwizard to service requests asynchronously. A quick Google for “dropwizard async” provided my first clue: <a href=\"https://jersey.java.net/documentation/latest/async.html\">https://jersey.java.net/documentation/latest/async.html</a>. Getting started is surprisingly easy:</p>\n<pre class=\"language-java\"><code class=\"language-java\"><span class=\"token annotation punctuation\">@Path</span><span class=\"token punctuation\">(</span><span class=\"token string\">&quot;/resource&quot;</span><span class=\"token punctuation\">)</span>\n<span class=\"token keyword\">public</span> <span class=\"token keyword\">class</span> <span class=\"token class-name\">HelloResource</span> <span class=\"token punctuation\">{</span>\n    <span class=\"token annotation punctuation\">@GET</span>\n    <span class=\"token keyword\">public</span> <span class=\"token keyword\">void</span> <span class=\"token function\">asyncHelloWorld</span><span class=\"token punctuation\">(</span><span class=\"token annotation punctuation\">@Suspended</span> <span class=\"token keyword\">final</span> <span class=\"token class-name\">AsyncResponse</span> asyncResponse<span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n        <span class=\"token keyword\">new</span> <span class=\"token class-name\">Thread</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">-&gt;</span> <span class=\"token punctuation\">{</span>\n            <span class=\"token function\">sleepUninterruptibly</span><span class=\"token punctuation\">(</span><span class=\"token number\">1000</span><span class=\"token punctuation\">,</span> MILLISECONDS<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n            asyncResponse<span class=\"token punctuation\">.</span><span class=\"token function\">resume</span><span class=\"token punctuation\">(</span><span class=\"token string\">&quot;Hello world!&quot;</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n        <span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">.</span><span class=\"token function\">start</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n    <span class=\"token punctuation\">}</span>\n<span class=\"token punctuation\">}</span>\n</code></pre>\n<p>So as you’ll see above, your async resource methods receive an <code>AsyncResponse</code> object annotated with <code>@Suspended</code>. Your code can now schedule some long running computation or IO operation and hand control back to Dropwizard immediately, freeing the request thread up for other things. Once you have a result, the <code>AsyncResponse</code> object lets you drop it back to the client.</p>\n<h2>A real world example</h2>\n<p>An important part of <strong>GroundControl</strong> is the geospatial backend (internally we call it Weyl after the <a href=\"https://en.wikipedia.org/wiki/Hermann_Weyl\">awesome physicist</a>). One of this service’s jobs is to render vector tiles from our datastore and serve them up to the user. This involves a fairly costly sequence of events:</p>\n<ul>\n<li>Receive a request for a particular map layer at a particular tile coordinate and zoom level.</li>\n<li>Calculate the rectangle enclosing this tile.</li>\n<li>Query our geospatial index for features from the layer within the rectangle.</li>\n<li>Process and transform the features for display (this can involve a coordinate transformation, geometry simplification and preprocessing of attribute data to make the clients life easier).</li>\n<li>Render to the protobuf based <a href=\"https://www.mapbox.com/vector-tiles/\">vector tile format</a>.</li>\n<li>Return the result to the user.</li>\n</ul>\n<p>When the datasets become large, this pipeline can take several seconds to complete. Worse still, our client-side mapping layer (based on mapbox-gl) will often fire off a ton of requests simultaneously. Since this pipeline is compute bound, there is no point trying to process more tiles in parallel than we have cores. Moreover, we’d like to avoid filling up Dropwizard’s thread pool with a load of requests all pointlessly fighting for limited CPU time.</p>\n<p>To maintain responsiveness under load, we want to offload these computations to a fixed size thread pool, handing the request thread back to Dropwizard to use for other things.</p>\n<img alt=\"Threads. Awesome when they come in pretty colours like this. Sometimes less awesome.\" src=\"/_next/static/media/threads.75856c96.webp\" width=\"1280\" height=\"960\" decoding=\"async\" data-nimg=\"1\" loading=\"lazy\" style=\"color:transparent\"/>\n<p>It was a pretty simple job to switch our resource methods to use the <code>@Suspended</code> magic. With a few changes to the tile rendering pipeline to make it use a small, fixed-size thread pool we were handling tile requests fully asynchronously!</p>\n<p>One piece worth noting here is that this change didn’t come without cost — in particular it meant rewriting some of our resource tests to deal with the AsyncResponse object.</p>\n<h2>It’s all about the thread count</h2>\n<p>To test things were working as intended, I spun up the Locust load-testing tool and simulated 500 users all requesting vector tiles from our backend. This <a href=\"https://visualvm.github.io/\">VisualVM</a> graph was particularly satisfying!</p>\n<img alt=\"&lt;b&gt;Before (Synchronous)&lt;/b&gt;. The thread count climbs as Locust “hatches” simulated users.\" src=\"/_next/static/media/before.b1f942d2.webp\" width=\"960\" height=\"380\" decoding=\"async\" data-nimg=\"1\" loading=\"lazy\" style=\"color:transparent\"/>\n<img alt=\"&lt;b&gt;After (Asynchronous)&lt;/b&gt;. Dropwizard happily queuing up requests without spinning up a million threads\" src=\"/_next/static/media/after.b2dca22f.webp\" width=\"962\" height=\"376\" decoding=\"async\" data-nimg=\"1\" loading=\"lazy\" style=\"color:transparent\"/>\n<h2>Conclusion</h2>\n<p>Asynchronous web frameworks offer some pretty compelling performance improvements at the cost of a little code complexity and a slightly more difficult testing story. We’ve found this trade-off to be worthwhile for certain workloads, and Dropwizard lets us mix and match synchronous and asynchronous resource methods as we like.</p>\n<h2>About me</h2>\n<p>I’m <a href=\"https://www.linkedin.com/in/alex-sparrow-763a113b\">Alex</a>, and I work at <a href=\"http://www.quartic.io/\">Quartic Technologies</a>. We help companies use data to improve their field operations.</p>",
            "url": "https://alexsparrow.dev/articles/async-therefore-i-am",
            "title": "Async therefore I am",
            "summary": "Going async with Dropwizard",
            "date_modified": "2017-03-02T00:00:00.000Z",
            "author": {
                "name": "Alex Sparrow"
            }
        }
    ]
}