<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Programming on Not the Answer</title><link>//blog.ismail-s.com/tags/programming/</link><description>Recent content in Programming on Not the Answer</description><generator>Hugo -- gohugo.io</generator><language>en</language><lastBuildDate>Wed, 30 Aug 2017 15:14:37 +0000</lastBuildDate><atom:link href="//blog.ismail-s.com/tags/programming/index.xml" rel="self" type="application/rss+xml"/><item><title>Migrating a REST API from Javascript to Haskell</title><link>//blog.ismail-s.com/posts/jtime-migrating-to-haskell/</link><pubDate>Wed, 30 Aug 2017 15:14:37 +0000</pubDate><guid>//blog.ismail-s.com/posts/jtime-migrating-to-haskell/</guid><description>&lt;h3 id="background">Background&lt;/h3>
&lt;p>For just over a year, I&amp;rsquo;ve been running the &lt;a href="https://www.gitlab.com/ismail-s/jtime">JTime project&lt;/a>, which consists of a REST API, an Android app and a website, the latter two of which talk to the REST API. The JTime project allows me to see nearby prayer times. I don&amp;rsquo;t advertise it, as it is more of an educational project to try new technologies, and I just don&amp;rsquo;t want to be promoting it in case people think I&amp;rsquo;m clever for having made it (I don&amp;rsquo;t like showing off, and generally the people around me are non-programmers). So barely anyone uses it.&lt;/p></description><content>&lt;h3 id="background">Background&lt;/h3>
&lt;p>For just over a year, I&amp;rsquo;ve been running the &lt;a href="https://www.gitlab.com/ismail-s/jtime">JTime project&lt;/a>, which consists of a REST API, an Android app and a website, the latter two of which talk to the REST API. The JTime project allows me to see nearby prayer times. I don&amp;rsquo;t advertise it, as it is more of an educational project to try new technologies, and I just don&amp;rsquo;t want to be promoting it in case people think I&amp;rsquo;m clever for having made it (I don&amp;rsquo;t like showing off, and generally the people around me are non-programmers). So barely anyone uses it.&lt;/p>
&lt;p>Initially, the REST API was written in Javascript, using the &lt;a href="https://loopback.io">loopback&lt;/a> framework which helped me to get moving fast and gave a good structure to the code. This api was run on &lt;a href="https://www.digitalocean.com/">Digital Ocean&lt;/a>.&lt;/p>
&lt;p>Fast-forward many months, and my DO free student credit was running out, so I looked for the cheapest place to host the api. After browsing around, &lt;a href="https://www.nearlyfreespeech.net/">NearlyFreeSpeech&lt;/a> seemed like it could be the cheapest option. So I switched hosts.&lt;/p>
&lt;p>After switching, I noticed that running the server was costing me more than I&amp;rsquo;d like. This was because the rest api consumed too much memory (~200MiB including a postgres instance), which cost me a bit too much money (NFS (NearlyFreeSpeech) charges directly based on CPU, RAM, disk and bandwidth usage). Loopback is a bit RAM-heavy, which I hadn&amp;rsquo;t had to think about before.&lt;/p>
&lt;p>So, to save money, I decided to rewrite the api in Haskell.&lt;/p>
&lt;h3 id="why-haskell">Why Haskell?&lt;/h3>
&lt;ul>
&lt;li>I&amp;rsquo;ve used it before, so I can get moving faster.&lt;/li>
&lt;li>It&amp;rsquo;s a functional programming language. Since learning Haskell I&amp;rsquo;ve started to fall in love with FP.&lt;/li>
&lt;li>It can produce small and fast binaries. Not always, but I&amp;rsquo;ve so far found this to hold true.&lt;/li>
&lt;li>The type system is awesome (although no dependent types yet).&lt;/li>
&lt;/ul>
&lt;p>I also considered:&lt;/p>
&lt;ul>
&lt;li>Rewriting in Rust, but the ecosystem is still very new and big changes seemed to still be being made. And it would take time to get up to speed with it (I started reading some Rust tutorials before deciding it would take too long to learn).&lt;/li>
&lt;li>Using a smaller js framework, as I&amp;rsquo;d be able to reuse code. But the amount of code that would have to be rewritten anyways meant that I felt it would be worth just switching languages anyways. And AFAICT the issue with Loopback was more that the amount of stuff it was doing, and that it was a js framework (so interpreted with a JIT) meant it took up a bit of ram. I&amp;rsquo;d essentially be reconstructing a stripped-down version of loopback, and would still have the overhead of the interpreter and JIT.&lt;/li>
&lt;/ul>
&lt;p>I also decided to use &lt;a href="https://haskell-servant.readthedocs.io/en/stable/">Servant&lt;/a> for routing, which in hindsight was a very good decision (IMO they&amp;rsquo;ve basically figured out how to define a rest api). If you haven&amp;rsquo;t heard of it, look into it. It&amp;rsquo;s &lt;em>really&lt;/em> good. In a nutshell, you specify your API as a type. Servant then automagically does routing, serialisation/deserialisation and validation (ok, there is some stuff you need to do, but not too much).&lt;/p>
&lt;h3 id="how-the-rewrite-went">How the rewrite went&lt;/h3>
&lt;p>As per usual, the rewrite took much longer than expected. And the haskell tooling itself let me down at times:&lt;/p>
&lt;ul>
&lt;li>GHC takes &lt;em>ages&lt;/em> to compile. Like absolutely ages, especially on older hardware. Compiling from scratch could take over an hour, and each incremental compilation afterwards would take at least a minute, even for minor changes. Using Emacs with Intero helped somewhat to speed up development (though Intero is quite RAM heavy, which slowed it down a bit). But CI builds still take 15-45 minutes.&lt;/li>
&lt;li>The record types naming issue is annoying. I could have used lenses, but I didn&amp;rsquo;t want my builds taking even longer.&lt;/li>
&lt;li>Stack uses way too much disk space. And that&amp;rsquo;s after setting the option to use the system GHC. (Yes, I&amp;rsquo;m aware it&amp;rsquo;s 2017, but that doesn&amp;rsquo;t mean everyone is running the latest Macbook with plenty of disk space and ram).&lt;/li>
&lt;li>The server was going to be run on nearly free speech, which uses freebsd. This meant that I either needed to compile on freebsd or cross-compile. Cross-compilation doesn&amp;rsquo;t seem to be used much, and those who were doing it seemed to have trouble doing it, especially with template Haskell. This meant I needed a freebsd machine. The only way I managed to do this was to run one in a VM. But this was a pain as it restricted what machines I could compile for production on. It also meant I couldn&amp;rsquo;t do the compilation in gitlab ci (well, I think it is possible, but it would involve running freebsd using kqemu, which &lt;a href="https://erouault.blogspot.co.uk/2016/09/running-freebsd-in-travis-ci.html">someone&lt;/a> has managed to do on Travis ci, but I couldn&amp;rsquo;t get this to work on gitlab ci). In the end, I randomly noticed that NFS had a ubuntu1604 beta realm that isn&amp;rsquo;t advertised anywhere. There were some random issues with this (eg website going down unexpectedly, filesystem watching not working (as in calling the &lt;code>initINotify&lt;/code> kernel function thing would fail)) but it meant I could compile and deploy from Gitlab CI without jumping through cross-compilation hoops.&lt;/li>
&lt;/ul>
&lt;p>Also, I underestimated just how lax loopback was regarding the input it would accept. Servant is very strict, which meant I had to add some code to deal with various types of input that loopback would have just happily accepted. I don&amp;rsquo;t see this as an issue with either library, more that they take different decisions about how strict to be about the kinds of input that are accepted.&lt;/p>
&lt;p>Deploying the new server was a bit of fun. I planned and rehearsed the whole sequence, before switching off the old server, migrating the data across (using a Python script and sqlalchemy) and reconfiguring DNS entries (the new server was switched on beforehand to save time).&lt;/p>
&lt;h3 id="results">Results&lt;/h3>
&lt;p>My main aim was to cut costs, which it did:&lt;/p>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th>Category&lt;/th>
&lt;th>March&lt;/th>
&lt;th>April&lt;/th>
&lt;th>May&lt;/th>
&lt;th>June&lt;/th>
&lt;th>July&lt;/th>
&lt;th>August&lt;/th>
&lt;th>Total&lt;/th>
&lt;th>Average&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>Deposit Fee&lt;/td>
&lt;td>$1.00&lt;/td>
&lt;td>$0.00&lt;/td>
&lt;td>$0.00&lt;/td>
&lt;td>$0.00&lt;/td>
&lt;td>$0.87&lt;/td>
&lt;td>$0.00&lt;/td>
&lt;td>$1.87&lt;/td>
&lt;td>$0.31&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Resource Charge&lt;/td>
&lt;td>$0.53&lt;/td>
&lt;td>$5.34&lt;/td>
&lt;td>$5.50&lt;/td>
&lt;td>$5.29&lt;/td>
&lt;td>$1.83&lt;/td>
&lt;td>$1.26&lt;/td>
&lt;td>$19.75&lt;/td>
&lt;td>$3.29&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Site Charge&lt;/td>
&lt;td>$0.03&lt;/td>
&lt;td>$0.30&lt;/td>
&lt;td>$0.31&lt;/td>
&lt;td>$0.35&lt;/td>
&lt;td>$0.35&lt;/td>
&lt;td>$0.28&lt;/td>
&lt;td>$1.62&lt;/td>
&lt;td>$0.27&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Storage Charge&lt;/td>
&lt;td>$0.02&lt;/td>
&lt;td>$0.08&lt;/td>
&lt;td>$0.09&lt;/td>
&lt;td>$0.08&lt;/td>
&lt;td>$0.13&lt;/td>
&lt;td>$0.12&lt;/td>
&lt;td>$0.52&lt;/td>
&lt;td>$0.09&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Total&lt;/td>
&lt;td>$1.58&lt;/td>
&lt;td>$5.72&lt;/td>
&lt;td>$5.90&lt;/td>
&lt;td>$5.72&lt;/td>
&lt;td>$3.18&lt;/td>
&lt;td>$1.66&lt;/td>
&lt;td>$23.76&lt;/td>
&lt;td>$3.96&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;p>&lt;em>Costs so far for NearlyFreeSpeech for 2017&lt;/em>&lt;/p>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th>Historical Resource Usage&lt;/th>
&lt;th>&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>Month&lt;/td>
&lt;td>RAUs&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>2017-03&lt;/td>
&lt;td>940.62&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>2017-04&lt;/td>
&lt;td>9185.87&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>2017-05&lt;/td>
&lt;td>9479.13&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>2017-06&lt;/td>
&lt;td>9096.4&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>2017-07&lt;/td>
&lt;td>1433.64&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;p>&lt;em>Resource usage for the old Javascript server&lt;/em>&lt;/p>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th>Historical Resource Usage&lt;/th>
&lt;th>&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>Month&lt;/td>
&lt;td>RAUs&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>2017-06&lt;/td>
&lt;td>25.86&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>2017-07&lt;/td>
&lt;td>1708.9&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>This Month (so far)&lt;/td>
&lt;td>2214.54&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;p>&lt;em>Resource usage for the new Haskell server&lt;/em>&lt;/p>
&lt;p>Yeah, I know, the amount of money involved is peanuts, but I wanted to make this recurring bill as small as possible (and tbh, 4-5 cents a day sounds pretty decent to me). And I&amp;rsquo;m now down to ~57 Mib (including an nginx instance as I was having issues with serving static files with Haskell) although CPU usage is periodically spiking to 1%.&lt;/p>
&lt;p>As with most rewrites, the new code is probably better structured. As it&amp;rsquo;s Haskell, it is less verbose. The Haskell code runs pretty fast too, but Phoenix, Arizona (where NFS have their servers) is an ocean away from me, so there is more latency than with the old server due to the speed of light.&lt;/p>
&lt;h3 id="sidenote-on-using-nearlyfreespeech-with-haskell">Sidenote on using NearlyFreeSpeech with Haskell&lt;/h3>
&lt;p>I mentioned the cross-compilation issues above. Minus that, Haskell works well with NearlyFreeSpeech. Some issues/gotchas I have found with NearlyFreeSpeech have been:&lt;/p>
&lt;ul>
&lt;li>No sudo. Only the software installed can be used (quite a bit is installed though). Anything else can only be used if you do a local non-sudo install. Expect to have to compile stuff from scratch if you can&amp;rsquo;t find a binary.&lt;/li>
&lt;li>NFS seems to have been initially designed for PHP apps, with support for running custom processes added later. This shows in places in their control panel.&lt;/li>
&lt;li>Automated deployments are a bit trickier to set up, as there is no API for restarting a process. This means you need some sort of master process that runs your server and watches (or polls) the filesystem for some kind of change that then triggers restarting/reloading the server. Your automated deployment script then just ssh&amp;rsquo;s into NFS and modifies the filesystem as necessary.&lt;/li>
&lt;li>Networking between processes (eg between an app server and a database) isn&amp;rsquo;t done using localhost addresses, but using &lt;a href="http://yoursitename.local">http://yoursitename.local&lt;/a> . Don&amp;rsquo;t ask me why.&lt;/li>
&lt;li>NFS is very much a DIY service. Expect to get your hands dirty. They do have a support service, or you can just post in their forum or check their wiki (both of these are for members only, and perhaps unsurpisingly are both PHP apps).&lt;/li>
&lt;/ul>
&lt;h3 id="links">Links&lt;/h3>
&lt;ul>
&lt;li>&lt;a href="https://gitlab.com/ismail-s/JTime/tree/b59042c158a520151e1dbcdc08873a4ec30e4f8a/JTime-rest">Old Javascript server&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://gitlab.com/ismail-s/JTime/tree/071ed4664e8f685776da912573d1f4ff219dab53/JTime-servant">New Haskell server&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://jtime.ismail-s.com">Running website&lt;/a>&lt;/li>
&lt;/ul>
&lt;p>Also, shoutout to Michael Snoyman. His &lt;a href="https://www.snoyman.com/blog/2017/04/haskell-success-stories">blog post&lt;/a> provided some encouragement in getting me to actually write this post.&lt;/p></content></item><item><title>Thoughts on Haskell</title><link>//blog.ismail-s.com/posts/thoughts-on-haskell/</link><pubDate>Mon, 04 Jul 2016 07:54:59 +0000</pubDate><guid>//blog.ismail-s.com/posts/thoughts-on-haskell/</guid><description>&lt;p>Over the past few months, I have been learning haskell. It is truly an amazing language, unlike the heavyweight languages (Java, Python, C#), with a lot of innovative features in it. This is probably due to it being originally (although it still is) a research language, though it does seem very capable for use in production. Here are a few of my thoughts about it so far.&lt;/p>
&lt;ul>
&lt;li>GHC, the standard compiler/interpreter, is awesome. The compiler times could be faster, but the executables it produces are very fast.&lt;/li>
&lt;li>The language is very beautiful. To give an example: &lt;code>fibs = 0:1:(map (\n -&amp;gt; fibs!!n + fibs!!(n+1)) [0..])&lt;/code> is an infinite list of the Fibonacci numbers. It is not the fastest way of doing this (matrix exponentiation is really fast) but it is very good in terms of performance.&lt;/li>
&lt;li>The level of support for higher order functions and currying is really good. In particular, I like the way function types are expressed, eg &lt;code>func :: Integer -&amp;gt; Integer -&amp;gt; String&lt;/code> is a function that takes 2 numbers and returns a string. It can also be thought of (and used) as a function that takes one number and returns a new function, that takes one number and returns a string. This builtin currying allows for simplifying various problems in a beautiful way.&lt;/li>
&lt;li>The type system is really powerful. Writing functions that work on classes of types is very straightforward, and type inference means that a lot of the time, you don&amp;rsquo;t need to write types. Although standard practice is to write out the types of functions, purely to help people reading the code. Often, you can just let ghc figure out what the type of a function is, and just copy paste it back into your code for documentation.&lt;/li>
&lt;li>There are a lot of extensions built into GHC, and these extensions can be enabled on a file by file basis by adding flags at the top of the file.&lt;/li>
&lt;/ul>
&lt;p>I also have issues with haskell:&lt;/p></description><content>&lt;p>Over the past few months, I have been learning haskell. It is truly an amazing language, unlike the heavyweight languages (Java, Python, C#), with a lot of innovative features in it. This is probably due to it being originally (although it still is) a research language, though it does seem very capable for use in production. Here are a few of my thoughts about it so far.&lt;/p>
&lt;ul>
&lt;li>GHC, the standard compiler/interpreter, is awesome. The compiler times could be faster, but the executables it produces are very fast.&lt;/li>
&lt;li>The language is very beautiful. To give an example: &lt;code>fibs = 0:1:(map (\n -&amp;gt; fibs!!n + fibs!!(n+1)) [0..])&lt;/code> is an infinite list of the Fibonacci numbers. It is not the fastest way of doing this (matrix exponentiation is really fast) but it is very good in terms of performance.&lt;/li>
&lt;li>The level of support for higher order functions and currying is really good. In particular, I like the way function types are expressed, eg &lt;code>func :: Integer -&amp;gt; Integer -&amp;gt; String&lt;/code> is a function that takes 2 numbers and returns a string. It can also be thought of (and used) as a function that takes one number and returns a new function, that takes one number and returns a string. This builtin currying allows for simplifying various problems in a beautiful way.&lt;/li>
&lt;li>The type system is really powerful. Writing functions that work on classes of types is very straightforward, and type inference means that a lot of the time, you don&amp;rsquo;t need to write types. Although standard practice is to write out the types of functions, purely to help people reading the code. Often, you can just let ghc figure out what the type of a function is, and just copy paste it back into your code for documentation.&lt;/li>
&lt;li>There are a lot of extensions built into GHC, and these extensions can be enabled on a file by file basis by adding flags at the top of the file.&lt;/li>
&lt;/ul>
&lt;p>I also have issues with haskell:&lt;/p>
&lt;ul>
&lt;li>GHC is massive to download (btw use &lt;a href="http://docs.haskellstack.org/en/stable/README/">stack&lt;/a> to install haskell). Like, massive. I know that hard drives are bigger these days, that network speeds are faster, but I don&amp;rsquo;t think that gives developers a right to make things massive when they don&amp;rsquo;t need to be (at least, not for a few years). I don&amp;rsquo;t use the most up to date devices, as I like to keep using older hardware rather than waste resources and money continually upgrading.&lt;/li>
&lt;li>The language can be hard to understand, and explanations found online can sometimes require understanding various bits of theory from maths. Now, I am a mathematician (not in terms of working as one but in doing maths at uni), but I prefer simple explanations at all times. And it annoys me when people complicate things for no reason, especially when creating learning materials, or APIs (if you want to see stupidly designed APIs, look at various Java libraries).&lt;/li>
&lt;/ul></content></item></channel></rss>