THIS REFLECTS MY PERSONAL PHILOSOPHY
I just wanted to make it clear that the approach, and the resulting structure that we will develop, is based upon my own personal experience and viewpoint. There are definitely other ways to do this; some, a bit simpler.
But I have been writing SDKs since the 1980s, and I think that my point of view “has legs,” so to speak.
When I write SDKs, I like to keep these basic priorities in mind:
It’s very important to K.I.S.S. (Keep It Simple, Stupid). Not “stupid” simple, but no more complicated than it needs to be for the user of the SDK. It’s really important for me to remember that the users’ needs trump my needs every time. This is all about empowering the user and making sure that they have a useful tool.
The use case might be quite complex, and, thus, the SDK will likely also be non-simple. That’s OK, as long as I don’t add stuff that has no direct relevance to the vast majority of users.
If adding a feature will add complexity to the system, I need to ask myself “How important is it?”. If, say, one user demands a feature to fit their workflow, but adding the feature would make life less simple for the other 3,000 users of the SDK, then we should really spend some quality time, examining our motives.
It can be complex as all git-go, under the hood, but the face that I present to the user needs to be as simple as possible.
An SDK needs to be absolutely trustworthy; especially if it’s a closed-source system. I need to set a bar higher for an SDK, than for my own work; which is already insanely high.
The SDK needs to be of “ultra-high” quality. No excuses.
It’s really important that my SDKs be absolutely clear on what they can and can’t do. The code needs to be written in such a way that it makes the boundaries clear. Enums need to have a concrete, and complete, set of cases; visibility levels need to be made clear (for example, I will often declare properties and methods “
internal,” even though this is not necessary in Swift).
It’s really important to have as much consistency as possible, throughout the SDK. I need to develop a “style guide,” even if just in my own head, and develop naming conventions to denote certain types of functionality. The code needs to be of very high quality (not just bug-free, but also eminently readable, and written to be understood by others).
It’s important to not “change our voice” in the middle of writing the SDK. For example, we should not be using camelCase for early property names, and snake_case for later names.
It’s important to have clear, well-written, informative, accessible, accurate documentation of the SDK; especially at the user level. If we need to have separate, more intricate documentation for the maintainer, then so be it. We should never expose the internals to the user.
So remember: S.Q.U.I.D.
A BLUETOOTH SDK; NOT JUST A BLUETOOTH INTERFACE FILE
I develop using what I call my “layer cake” approach. I code in modules and layers; each with its own configuration management and project identity, and the coupling between layers and modules as loose as possible.
So what we’ll do here, is write the Bluetooth interface as a Swift Framework. I prefer to use a “pure Swift” framework, as opposed to one that can be used for Objective-C projects (with a custom header), because I like to use things like Swift’s powerful enums and tuples, which don’t really export very well, and I’d like to avoid forcing the user to use NS-based classes (which are necessary for ObjC bridging).
It also makes the projects much simpler, and easier to test.
When we write device interface code; especially for a really “messy” interface like BLE, it’s quite difficult to have true automated testing of the whole stack. We can do permanent unit testing of components, but the stack usually has to be ambitious enough to merit that (which this won’t be -it’s a “magic 8-ball” app).
As we get to the point of actual communications, testing will be the rather old-fashioned kind of “monkey test” that we’re used to, and will involve the apps as test harnesses.
We’ll follow these steps (and preparations) to develop the SDK:
- We’ll design a protocol-based API for the SDK.
- We’ll establish some mock behavior for the API, and run some “proof tests,” to validate the design.
- At this point, we will bring in the near-complete apps, and start to integrate the SDK into them.
- We will start work on adding real Bluetooth communication.
- We will perform integration testing with the new fully-formed SDK.
The Bluetooth part won’t start until step four, but a lot of code will be written in step three. This is a fairly typical kind of sequence, when writing these kinds of infrastructure components. It’s very important to make sure the quality is “over the top.”
There will be a “dark age,” between 3 and 5. This can’t really be helped. We may be able to do stepwise “in-place” testing, as we go along.
Now that we know where we are going, let’s start to design our API.