One of the things that we want to do at CollectedIt! is provide users with a frictionless way to share pictures of their collectibles. In fact the original incarnation of the product launch was a vision of Pinterest for collectibles with our roadmap including a marketplace. Marketplace is on the roadmap, but we're going to focus more on the Collector experience for now. After the initial web-only launch we knew that it was still a little bit of a hassle to upload your pictures so we really wanted a streamlined process. To do that we started with an iPhone app, hoping that we'll launch an Android app in the near future. As a start-up we had to pick where to focus our resources and right now it still makes sense to focus on the iPhone first, everything else second.
This will be a series of three to five articles on how we built the iPhone app. I'm going to get fairly specific here and eventually we'll get to some code. This first article, however, will focus on the overall picture. In fact, here it is:
Remember in previous post I mentioned that each layer has a cost. In fact originally I didn't have the layer referred to as "Phone.Services". What we found is that we could dramatically improve performance by having an intermediate layer that would cache data on the phone. But enough with that, let's dive a little bit deeper. I'll start with each layer and give an overview and describe its purpose.
Right now and probably for the foreseeable future we'll be using SQL Server as our primary data store. Microsoft has an excellent program called BizSpark that makes it very affordable to have a world class database server as your back end. There's no reason for us to not select SQL Server, especially since we have extensive Microsoft experience. Probably 99% of what we do with the database is done through stored procs, with just a couple of utilities that might access the data through raw SQL. (None of these would be available from the web site; no possibility of SQL injection attacks.) We're of the opinion that the database should be for storing data. Period. Our stored procedures are very short and there's practically zero logic in them. In the future I'll blog about how our data structure looks as it's intentionally denormalized in some respects.
Before landing on the idea of doing a Collectibles site, we kicked around several ideas. This included a fitness based app, a FaceBook game app, and then finally we went back to our roots and decided that a collectibles ecosystem would be de bomb. But since we knew that we'd be trying different ideas, we created a generic company called "23bits.com, LLC". And because of that our namespaces are "Bit". It's nice, short, easy to type, and catchy. So there.
So the primary Services Layer has the responsibility of getting data from the database, doing any manipulations, and then providing simple data entity types to the ASP.net layer. These services are the same for the web site and the iPhone app. I'll go into a lot more detail here in one of the next discussions. There are probably a dozen or so services that cover security, users, collectibles, forums, communities, and a lot of new features not yet turned on. Dependencies between the services are managed by DI (Dependency Injection) using Ninject. In theory we could vertically partition these services to dedicated hardware if we get that big. They're some ick in there, but if we really start to grow I'm sure we could segregate the services.
Internet Boundary (ASP.net MVC3.5)
So this currently is ASP.net MVC3, but I've also run it as MVC4 and I'm treating it pretty darn close to MVC4. We'll be upgrading shortly and I may use more of the way cool Web API technology. In the meantime it's JSON based service calls. Now don't get all hacker on me and think that just because I told you this you can hack the collective. I'll have a whole blog post on how we secure our services. I've started to be a fan of using Areas within an ASP.net MVC project to put together relatively stand-along groups of functionality. Well, this is how the API interface works for the iPhone. This API will also be used for the Android and Windows app that we'll build.
Huuuh? Turtles all the way down? Well, the client-service programming pattern doesn't mean that you only ever have one client and one service. In this case we have the service that lives on our back end servers, with the client on the iPhone. Then on the iPhone to help facilitate communication (and the faults that can occur) there is a ClientServices layer that is a service to the native iPhone app. The primary concern of the ClientServices is to make sure that we can talk to the server without crashing the iPhone app, even if the innerwebs are down. It has to do this securely as well.
Finally we're at a layer that is probably platform-specific. This layer was added after we did some field tests and found that by adding just a little bit of caching we could dramatically improve the phone's performance. Maybe something that the Facebook app could use, aye? (Mark, call me. I'll give you a deal.) Sure, I could have put that inside the Bit.ClientServices and made that layer responsible for caching. But when we drill down on the details you'll see that the Bit.ClientServices layer is actually a portable layer that I'll be able to re-use on the Android and Windows phone app. This is where the device-specific caching is done. It's pretty light weight and basically mirrors the ClientServices calls. It just knows what it can cache and what it can't. And to properly do that, it does need to know about specific UI controls. So there you have it.
UPDATE: Thankfully they listened to me! You can now get your newly improved native Facebook app for the iPhone.
Mobile Technology choices
Sorry, but there just isn't any room for all of you guys and also the differently angle-bracketed language that is ObjC. Wait. Hey. Thank goodness there's Xamarin, a true cross-platform development environment for mobile development with some serious backing. And best of all: it's based on Mono technology. So it was a no-brainer to pick MonoTouch to launch with. Go with what you know. I'll talk a bit more about the decision making process and what we tried, what worked, what sortof worked, and where we ended up. And mind you our initial app is very, very basic. But we have all of the fundamentals in place now to grow. So I'm happy about that. Well, that and generics and lambdas, and ... well more in the next set of posts.