It got a lot of positive feedback on Reddit and I received many questions on /r/learnprogramming about our tech stack and process so I figured I’d write a short blog post about it here.
The stack overview
Backend: Ruby on Rails
Domain Register: Namecheap (Disclosure: affiliate link)
At its core, the iOS app is pretty barebones. The MVP consisted of just a few features.
- A user can set their preferences of who they wanted to match with
- A user had a screen where they can swipe on cards
- A user had a screen where they can send and respond to messages
- A user had a profile screen where they can edit their basic information
Swift or Objective-C
The question that’s always asked in an iOS project is whether to write it in Swift or Objective-C.
If you were to ask me about a year ago, I’d lean more towards Objective-C as many 3rd party frameworks on Github were just getting started. Nowadays, modern projects supporting Swift is comparable, if not exceeds in numbers of projects that support Objective-C.
Swift by most indicators seem to be the future for mobile iOS development so you can’t go wrong getting a head start in learning if you haven’t already. However, at the end of the day, it’s really about what sorts of language you’re most comfortable in and how much time you’re willing to invest.
1. Adding cards and swipes
When programming, so much time is wasted rewriting the same functionality that has existed before. My philosophy when it comes to mobile app development is: Why reinvent the wheel when you can just install it via CocoaPods?
For those that are initiated, CocoaPods is a dependency manager for iOS. Traditionally, when one wanted to integrate a 3rd party library, one would have to manually download zip files, unarchive and import them into their projects, then manually configure project build flags to not completely mess up your build. CocoaPods solves this by handling it automatically.
I would highly recommend you use CocoaPods for your projects as this saves a lot of time dealing with framework conflicts and keeping frameworks up to date.
For us, we ended up deciding to go with Koloda to handle our swipe view. But even if you’re not making a card view / swipe type of app, the same principle applies: Don’t reinvent the wheel. Go on Github, do a search and see if there’s already a library that can help you with what you want to achieve.
2. Spinning up the backend
We used Ruby on Rails for our backend.
I know there are a lot of other web alternatives out there, and people have varying opinions, but for me, Rails has always been the fastest and most straight forward way to quickly deploy a CRUD (basic) backend server.
I’ve also always been a fan of Rails Composer when starting up a new Rails project. It helps me handle a lot of the boiler plate such as setting up your mailer, adding a user object and enabling it to work with Devise / Omniauth, setting up user roles, etc.
Regardless of what you choose, the process for creating the backend would still be the same. We have a “User” object with basic user information such as username, first name, photos, age, two columns for lat and long.
Basically, all you need is for the User model to have a “find_matches” method which returns a list of potential matches based upon the user’s preference / location.
In order to handle profile creation from Facebook, we also had to use Sidekiq with Redis so our profile creation jobs can be done on the background. The reason why it needs to be asynchronous is due to the time it may take to download and upload a photo from Facebook, the entire HTTP request can take 10+ seconds which otherwise would clog up your ability to serve other HTTP requests.
As mentioned, we used Sidekiq, but others swear by Resque. I’m not smart enough to know the difference so I just picked one.
As far as data storage goes, we, like everyone else on the planet, used Paperclip and Amazon’s S3 for storage. Paperclip has a nice adapter already built in for S3 which makes processing, uploading and retrieving images magical. It also takes care of resizing for thumbnails.
As far as an MVP goes, this was pretty much all we needed to get user login and swipes to start working. Again, the gist of it is, don’t reinvent the wheel when you’re trying to put out something quickly. Use all tools out there at your disposal.
3. Connecting the backend with the app
I think most everyone uses JSON as their preferred format for exchanging information from the backend to front end.
Luckily, if you’re on Rails, it comes already packaged with a JSON serializer and if you’re using Alamo Fire (which is my preferred HTTP library for Swift), it also comes equipped with a JSON to Swift object deserializer as well. If you’re on Objective-C, the ASIHTTP library also handles JSON serialization for you.
For an MVP, I don’t think it’s really necessary to go too overboard with data persistence on the client side. I think this is a mistake that a lot of developers old and new make when starting their projects because data synchronization between different components is always a challenge. Especially in the earlier stages when your backend’s schema is more volatile and you’ll probably end up wasting a lot of time having to do a lot of pesky migrations.
The only thing you would need client side persistent storage for is your “User” object. The client side User object should have up and down syncing methods to be able to POST new data up to the server and sync information back down to the app.
4. Adding messaging to the app
This was probably the trickiest part in building the app and took the most amount of time. We originally tried integrating various pre-built chat solutions but they all back fired. It ended up taking way longer to customize the libraries than we had thought and by the end of it, we had a half working solution that was very poorly written and hard to maintain.
We ended up having to scrap about 2–3 days of work and decided to implement our own custom solution instead. Luckily, it wasn’t that hard with Rails.
This sort of highlights why even though I’ve used many other web frameworks before, I always find myself coming back Rails. When Rails works, it works great. As long as you’re doing things within the expected convention, it‘s my opinion that it’s the fastest way to get something up and running as there seems to be a Gem for mostly everything.
I found one for messaging on Github called “acts-as-messageable” and it was basically as simple as adding two lines into your User activerecord model. It not only allows the user objects to send and receive messages but also takes care of constructing the conversation model. The only problem is that it’s not truly a live chat system as it requires periodic polling rather than a publish / subscription paradigm that notifies the UI to instantly refresh. This also means it lacks things like a typing indicator.
There’s probably some performance trade offs to this, but we figured that early on, we most likely wouldn’t have to rewrite this component until we scaled into the hundreds of thousands of users anyways. Besides, we were dating app and we didn’t need all the bells and whistles of a chat app.
On the iOS client side, we used the pod “JSQMessageViewController” which provided all the necessary UI elements and it worked beautifully straight out of the box.
5. Deploying to production
When deploying your backend app, there are a lot of solutions out there. I’ll be honest that I’m not too knowledgeable on all of them, but I think in general there a few points you should consider.
On one hand, you have PaaS (platforms as a service) like Heroku. The problem with Heroku is that it can get very expensive for the amount of hardware specs you’re getting. On the other hand, there are other options like AWS EC2 where you can freely spin up your own virtual instance and have nearly full control when it comes to provisioning, but require more time and energy.
Depending where you choose to spin up your EC2 instance, what size and your contract agreement, you may be able to see cost reductions as much as 4–5x in terms of similar hardware performance on EC2.
However, the pros of Heroku is that it may just end up saving you a lot of time and headache. I myself am a developer first and not so much of an sysadmin / ops kind of guy. Therefore, working in the terminal and debugging problems in black and white text on a Unix system is not really my cup of tea.
For me, I feel like the benefits greatly outweigh the costs when choosing Heroku as a platform. However, if you’re more experienced in ops, you may want to look into spinning up instances purely on EC2 due to the cost savings or you may want to do a more hybrid option like rolling out your own open sourced deployment platform with Dokku.
For example, DigitalOcean is a cloud computing platform I’ve utilized extensively in the past. They have images ready to spun up in seconds including Dokku if you want something that feels like Heroku but with the cost savings.
6. Miscellaneous ops stuff
After your app is deployed, you’ll probably want to add some monitors to make sure you’re alerted when things inevitably blow up.
For basic HTTP monitoring, I was grandfathered into Pingdom’s free plan so I went with that. However, I’ve also heard good things about StatusCake which advertises themselves as free forever. This type of monitoring basically just let’s you know when your app is down and unresponsive.
For performance monitoring, we’re using New Relic, but you may want to try others as well. Performance monitoring let’s you dig into your app’s performance like response time, memory and app level code. This let’s you know where things are slow or eating up memory and where you can optimize.
For error monitoring, we’re using Rollbar, but for no other reason than it was the first thing that came up on a Google search. You may want to check out Airbrake, or similar services as well. Error monitoring allows you to catch errors that happen in your app and log them in an external, more human readable format. For instance, if you wanted to track the frequency of a certain error and mark them as fixed.
Lastly, for general logging, we’re on Logentries. I was on Papertrail originally, but I think Logentries just provided more bang for the buck. It also better sorted out the errors and the interface was a bit easier to set up alerts.
The problems most hobbyist and professionals make when starting a new project is that they don’t limit their scope and also don’t reuse tools that are already available to them.
When defining your scope, make sure to limit it to 3–5 major features or even less if you can. If you have an entire whiteboard full of features, you’re definitely doing it wrong. It may be good to know what features you want on your roadmap, but put them in the ice bucket because we’re talking MVP here.
When it comes to building your project, I’d highly recommend you choose a stack that has abundant community support. This will allow you to just search on Github and throw things into your project. Just be careful you note the licensing on the project.
If you reached the end of this blog post and you’re still hesitant to start hacking, just GO DO IT.