3 ms·
A few months ago I was making plans for what is now my home base website for App Store & other projects. I'd been working in obj-c for about 2 years both on the
by mrsteveman1 15y ago
A few months ago I was making plans for what is now my home base website for App Store & other projects. I'd been working in obj-c for about 2 years both on the Mac and on iOS, but also had a fair bit of python experience with Django, App Engine, etc. I decided to give it a shot with obj-c.
I knew about the handful of "big" frameworks for handling this task with obj-c, but rejected them in favor of getting more hands-on experience building it, pushing myself and learning in the process. It was, of course, a personal project, something I alone was responsible for working with, so I decided it was OK if I experimented a little.
I went into the project knowing I would eventually have to port it to Python (and I did), but it was a lot of fun :)
I hand picked some lightweight libraries to handle specific parts of the server. One has to be cautious knowing that a library developer who thinks their sole target is a tiny cellphone, may not be worrying about things you will eventually have to worry about on a server.
I picked CocoaHTTPServer to handle requests and responses, and someone else had written a nicer "route" style interface for it which meant all of the possible responses to an http request were simply a series of blocks defined in a row, each with a regex or named parameter style URL route defined right there next to the code that would handle it. This works out to be quite a similar layout in code as something like Bottle/Python or Express/Node.js, both of which I've worked with now and I very much prefer this style.
I made good use of blocks & dispatch queues elsewhere as well, firing off an async block whenever I needed to pull new tweets from Twitter's api, or update Github repo stats (both are cached and displayed on the site).
I picked a Mustache template library and a Markdown parser library I found on Github for handling dynamic page generation & blog post syntax, respectively. Sqlite for storing anything that needed to be stored, Regexkit-lite for properly checking and handling anything that may be passed in to a url query or post body, etc.
I changed the Xcode project type to build me an executable binary that lived inside a bundle (Server.bundle) containing all the pages and assets the thing needed, so it could be deployed as a single "thing".
I also got Lion's sandboxing to work quite easily, which in theory would give some moderate protection against the entire server being compromised if someone managed to get an exploit to run inside the process.
Other than some CPU usage issues with the template library (easily solved by nginx caching pages), it all worked really, really well. I threw enough abuse at it, and did enough debugging that I was confident it would hold up well in production (which turned out to be wrong).
And then it came time to deploy somewhere, a problem I had been working on since day one, so i knew what i was getting in to.
There were only a few options: a cross-compiler framework like Cocotron (compile on Mac, run on Linux), one of the native *step libraries like GNUstep running on Linux or FreeBSD, or simply deploy on a Mac somewhere.
I tried all combinations other than Mac first, I built out a GNUstep environment with libobjc2 on FreeBSD, tried the cocotron->linux stuff, each time watching something blow up in my face due to my choice of components and my requirements.
While obj-c is cross platform, some of the libraries and features I chose to use were not. CocoaHTTPServer is built on top of CFNetwork, which is not part of any obj-c framework/library, but rather a lower level Apple C library only found on Macs. There's a "lite" open source version, but I quickly discovered that solving one issue like that would only bring up another. For instance, dispatch blocks will only work with GNUstep at the moment, and only when it is compiled with clang, against libobjc2, a combination few if any Linux distros actually ship in their repos.
Not a lot of people interested in deploying modern, dispatch/block-heavy, obj-c 2.0 code to Linux, not nearly as many as there are deploying such things to OS X or iOS.
So I decided why not just run on a Mac server somewhere? After all I can't solve every problem all at the same time, and on a Mac a lot of those problems were non-existent, plus the Mac approach would allow me to use things only available on a Mac, like easy sandboxing and potentially keychain integration for auth.
I found a Mac VPS provider that ran Xserves and hosted copies of Lion server inside VMware (HostMyApple, not someone fudging the licensing in moms basement). It worked really, really well, as long as I treated it like a headless server (issues with Lion Server are another story for another time). My sandboxing worked, performance was fantastic aside from the CPU usage during a cache miss, so I was fairly happy.
Long story short though, memory leaks in 3rd party libraries (that only someone running a server would likely hit), coupled with higher hosting costs (and fewer choices), smaller community and a desire to use some things that are really only "mature" in other languages (database adapters, etc), caused me to spend a few days porting the entire thing to Python.
My site now runs on a Linode, and is a nearly identical clone of the obj-c version, ported as a Python/Bottle app. There was nothing particularly wrong with the obj-c approach, but the primary focus of nearly all obj-c developers and libraries is iOS, where processes never live longer than a few minutes, or Mac where a crash or leak is only going to affect one person rather than a few hundred in-flight requests. I expect if I had stuck with one of the "frameworks" intended for this purpose it would have been a viable option but as I said before I wasn't looking for turn-key, but wanting to get my hands dirty :)