Back after a 5 year hiatus.
Well that was a fair bit of gap in between posts.
Femtoblogger is now on its 4th implementation. I feel the need to try out Swift on the server, so here we are. 100% pure Swift Femtoblogger.
The previous incarnation was Go. Before that was PHP. There was probably a never deployed Python version in there too.
Thoughts on Swift and the design of the server this time around…
- I very much like the type safety of Swift. When I code in Swift there are no runtime explosions, and very few bugs discovered in testing.
- The Swift code is more information dense than the Go code was. The Go code felt like a great sea of text with a little bit of content. The Swift code packs a lot of content into a screen of code.
- Performance appears to be a non-issue. SQLite backed pages are serving in 3-12ms. For comparison I added a caching layer for most popular queries and dropped that into the 80µs range for the query handling. That's not real, I handle them by doing a
X-Accel-Redirect
header back to Nginx and letting it serve a file out of a RAM disk directly. But it means my process is not going to be buried.
- I haven't bothered with any compiler optimization. I want the checks to stay in place while I see if I've screwed up somewhere.
- It's a small thing, but Swift Argument Parser really got things right. Very easy and natural to use.
The Network End of Things
- The Swift server network library, NIO, really wants to push you into a futures and promises style of programming. I resisted because it is so clumsy at the source code level. Your code begins to vanish under a sea of ritual. That said, I probably would have been better off to embrace it. A request needs to get out of the network queues to free them up while it gets in a non-concurrent model queue to work with the data, then out of there as soon as possible and into a render queue to do template expansion and back into the network queues to send the data out. It's a lot to coordinate.
- I suppose I'll continue avoiding futures and promises in femtoblogger until Swift 6 and the beginning of its new concurrency model make it into NIO.
- I didn't use Vapor or similar web frameworks, I build my server directly on NIOHTTP1 so I'd understand the architecture. The first 90% was simple! Then I needed to parse some form data and couldn't find the calls in the API. Eventually I found an email in a filing cabinet behind a sign that said "Beware of the Leopard" where the NIO team proclaimed that "out of scope". Maybe I'll make a post on parsing "multipart/form-data" (which can't be a String because it might not be valid) and parsing HTTP header values.
Using Other People's Packages
- I did reach out for 'random dude' packages for a higher level SQLite API, Markdown to HTML conversion, and template expansion. It's a bit of a mixed bag there. I'm glad I did it, but there were issues. As always it seems to take a lot of research time to figure out which solution is well supported, not horrible, and will likely last a while.
- I used SQLite.swift for accessing SQLite. The tutorial writing crowd on the internet likes it. It gives you a type safe way of interacting with SQLite without too much ritual. The package is a few years old and has been dormant for most of a year. I found a design flaw where it would try to read a mismatched datatype and explode your process. (Just because you called a SQLite column TEXT doesn't mean it isn't going to return a BLOB for one of the rows.) It looked to be an involved fix to use the receiver's datatype instead of the provider's, and in the absence of an active maintainer I didn't want to invest in making the changes. It was easier to rewrite all the rows to have their TEXT really be TEXT.
- I used Ink for Markdown to HTML conversion. It is simple to use. Out of the box it choked on CRLF line endings. The patch ended up being a
, "\r\n"
in just the right place, plus about 16 lines of test cases. Hint:"\r\n"
is a single Character in Swift… grapheme clusters and all. The maintainer is active so I sent that one in.
- I used Stencil for template expansion. I've used it before and the rough edges I used to have to hammer off are now addressed. Note: Stencil could really use a SafeExpansion mode which escapes HTML for when you have untrusted users. It has user created filters, I ended up making one instead of forking and adding a safe expansion feature.