What is the correct system design when dealing with third party API?

292 views Asked by At

This blog post by Joubert just opened my eyes. I have dealt with a lot of design patterns in Java and other languages. But Objective-C is a rather unique language.

Let's say that in a project we talk with a third party API, like Dropbox or Facebook. What I've been doing so far is to combine everything that has to do with the third party API into a singleton class. So I can access the class from anywhere in my view controllers. I can just go for example: [[DropboxModel sharedInstance] uploadFile:aFile]

However as the blog post noted, this isn't efficient and leads to spaghetti code and bad unit testing. So what is the best way to design the system so that it's modular and easy to use?

3

There are 3 answers

3
JeremyP On BEST ANSWER

I would dispute the idea that singletons lead to spaghetti code and are inefficient. However, the unit testing problem is legitimate and singletons do reduce modularity since they are really just fancy global variables.

I like Joubert's idea of injecting the singleton instance into the controller(s) from the app delegate (which is itself a singleton, ahem). I think the same approach would work for you.

What I normally do in these situations where I might want to use a different stub object in unit tests is define a protocol to represent the API and make my "real" API object conform to it and also my stub API object. I use the stub in the unit tests and the real object in the app.

0
Chris On

Not that this really solves any architectural problems associated with singletons, but for the sake of readability and typability you can always define a macro in your DropboxModel header file, eg:

#define DBM [DropboxModel sharedInstance]

<...>
[DBM uploadFile:aFile];
0
justin On

i'll typically create an abstraction layer. this wraps a simple interface onto the library's calls which you use, while giving you a chance to introduce whatever state (e.g. variables) you'll need.

you can then expose only what you need and use, and add your own state, checks, and conveniently deal with all issues of the library from one place. 'issues' may be introduced for several reasons - it could be threading, resources, state, or undesired behavioral changes across versions.

most libraries are not meant to be used solely via a singleton. in such cases, it's best (subjective) to create interfaces as you would normally -- of course, being mindful of the constraints behind the abstraction layer. in that sense, you simply create object based interfaces which are divided by size/task/purpose/functionality -- all as you'd usually do when writing your own classes.

if you don't need the library all over the place, then i think it's also good to wrap what you need to minimize dependencies (increasingly important in large projects).

if you use the library all over the place, then you may also prefer to use the calls without the abstraction layer.