Support for nested couriers, add helper functions, cleanup

Cleaned and dry'ed up most of the methods with some generic helper functions. Ideally, nothing should be broken since no actual logic was really changed (save for one or two helper functions, which I briefly tested), and everything looks good so far inside my app. We can always iterate on this PR if some small errors show up here and there, as they are bound to. I also added support for nested couriers, meaning you can declare couriers like `courierName.courierType` for better organization/preference handling. 

Just in case nested couriers seems like an unnecessary feature, I'll just briefly explain my reasoning:
For my app, I realized that I was doing a lot of extra work for what (I think) should be part of this package's core: nested couriers. Fine-grained control over couriers and their associated preferences were a hassle to deal with, since I either had to customize the set/get `userPreference` functions, or duplicate a lot of couriers. One concrete example, to illustrate: say I'm making a Medium clone, and I want to setup notifications for new posts. Because new posts can come from different sources (some from trending feed, some from people I'm following, etc.) there ends up being multiple couriers pointing to the same notification template (`newPostTrending`, `newPostFollowing`, etc.). And for each of these couriers, you'd have a separate entry in `profile.notifications` when they should really be grouped together, say, under `newPost`. So by adding it by default, from the user's perspective, there's no change in API -- just greater flexibility in how couriers can be organized (`newPost.trending`, `newPost.following`). Plus, it only adds a few extra lines.

Cheers!