January 22, 2014

Juggling a full time job with aspirations of becoming a full time indie developer means using time as efficiently as possible. I generally plan work around one or two fleeting hours per day. When the stars align, I am allowed half a day, or even a full day to dedicate to my current project. A snow day today allowed me to dedicate an entire day to knocking out a few features. I ran into a somewhat frustrating, and subtle gotcha whose cause is not immediately obvious.

The current, conventional, approach to implementing an Objective-C singleton leverages Grand Central Dispatch (GCD) to control access to a static pointer, pointing to the instantiated object. This approach promises thread-safe access to the singleton, in addition to being an extremely neat and concise implementation. A typical implementation's accessor method should look similar:

+ (instancetype)sharedInstance {
   static dispatch_once_t pred = 0;
   static TPLSettingsManager *_sharedObject = nil;

   dispatch_once(&pred, ^{
      if ( !_sharedObject ) {
         _sharedObject = [[super alloc] init];
      }
   });

   return _sharedObject;
}

Checking whether _sharedObject is a valid address is not necessary, but the extra check does not hurt. Notice that I am calling the alloc method on the the class' super class. My singleton implementation overrides alloc to prevent client code from erroneously invoking it. So far so good, right?

Here's where things get interesting. My settings manager class is Key Value Coding (KVC) compliant, so naturally I implement:

- (void)setValue:(id)value forKey:(NSString *)key
- (void)setValuesForKeysWithDictionary:(NSDictionary *)keyedValues
... 

Read more: Apple Documentation

Internally, I represent settings using an immutable NSDictionary instance. In a moment of distraction, I implemented setValue:forKey by referencing the shared instance instead of self:

- (void)setValue:(id)value forKey:(NSString *)key {
   [self immutableSetValue:value forKey:key];
}

- (void)immutableSetValue:(id)value forKey:(NSString *)key {
   [self willChangeValueForKey:key];

   self.settingsDictionary = [[TPLSettingsManager sharedInstance]] 
     mergeDictionaries:self.settingsDictionary with:@{key: value}];

   [self didChangeValueForKey:key];
}

The error is subtle, and it is transient like an electrical problem in a British, well, anything. What happens is that the call to sharedInstance from self, despite overriding alloc reinitializes _sharedObject. I stepped through the code countless times in the debugger and have verified each time that _sharedObject is set to nil as soon as execution enters sharedInstance. It is very Peculiar. I can only guess the behavior is a result of a scoping conflict for the static reference to the singleton. I suppose it's safer to initialize a static variable to nil than it is to assume an address in an unknown context.

The following change to the the code fixed the issue:

    self.settingsDictionary = [self mergeDictionaries:self.settingsDictionary with:@{key: value}];

Referencing self from within the instance rather than relying on the returned value from sharedInstance is a fix, but I'm not completely sure why.

January 17, 2014

The Germans have a saying that roughly translates to 'the torture of choice'. As much fun as it sounds, independently designing a piece of software from the ground up is a series of small choices. Each choice can either allow progress to continue, or it can destroy any hope of productivity. There is never a single correct permutation of choice, and often times it is impossible to see the forest through the trees.

Ask any developer, and you will be told the waterfall development pattern is synonymous with torture. The waterfall pattern's intent is to specify all design decisions ahead of time, so that development teams are freed from choice during the implementation phase. More simply, it aims to reduce the amount of liberty a single developer can take on a day-to-day basis. We now know that things don't necessarily work that way. Design choice is deferred to the whims of management, which in turn almost guarantees a terribly inadequate end product. I have seen, and been a member of highly motivated teams that were able to make this work, but in my experience that really is an exception to the rule.

I have been struggling with finalizing the 1.0 feature set of the iOS application I have been working on since June. Occasionally, I will think back to how simple it was to walk down the feature list and check things off for a waterfall release. Agile development on a team of just yourself, all while working a real nine to five job, is more like feature triage. Things are addressed as time allows, but more importantly, as the product requires. Now that I finally have a finish in sight, I begin to think about squeezing one more feature into my product. I have weighed the consequences to shipping this thing with the market differentiator I want to implement and have concluded that I would be hurting myself if it were to not be included. I suppose that is the torture of choice.

January 3, 2014

Technology is often times iteratively and so subtly improved that when a truly amazing breakthrough occurs the luster has already faded. The ability of a computer to accurately recognize human speech firmly falls into this category. My earliest realization that a computer could one day be capable of natural language recognition was sometime in the mid-to-late 1990s when Dragon Naturally Speaking made its way into PC and Mac Mall catalogs. While they did exist in the consumer market, I didn't actually get a chance to experience the technology until Apple developed and bundled PlainTalk with Mac OS 9 in 1999. PlainTalk, like Dragon sought to solve the problem of data input. PlainTalk floundered and subsequently disappeared in the transition to OS X (voice recognition returned in Mountain Lion) and the use cases for Dragon dried up as people became better at typing, yet for me, these two products set my imagination ablaze with possibility.

Based on where my interests were focused during the 2000s voice recognition fell off the radar and I missed quite a bit. Fast forward to 2011 and the introduction of Siri as the iPhone 4s' killer feature. A decade had passed and technology had progressed to the point of harnessing humanity's internet hosted knowledge through the power of voice. When you think about it, it is an amazing feat. What a profoundly impactful development that was hindered by our inability as humans to see past the flaws of the implementation. Siri's voice recognition and language processing were, and still are quite remarkable with profound accuracy. Server load and internet latency have crippled the product despite it being quite remarkable.

Xbox One brought voice control into the living room with mass market appeal. Microsoft takes a different approach to the problem by delivering a self reliant unit. Unlike the iPhone, Xbox One can process commands offline with a deeper understanding to the context of supplied commands. It doesn't come without fault though. Voice commands are often painfully slow to process or completely fail. When it does work though, the experience is quite magical and it really does provide a proper demonstration of the future. I do believe wholeheartedly in the future of the remote-less living room, we will first have to suffer through the dark years before it evolves into something amazing. For now though, I fear voice recognition in available consumer devices is no better than a dog at understanding context. While it is cute and endearing for an animal to struggle with fulfilling commands, it is nothing but madness when communicating with a soulless object.

January 3, 2014

You should feel guilty for buying things online. Well, not really, but that's what retailers would like you to believe. Amazon and Ebay, perhaps the two defining faces of web retail since the dawn of the internet age have lured customers out of brick and mortar stores in droves. The backlash from the traditional outlets in the last year leads me to believe the economy of middle men 'retailers' is about to collapse. Desperation, fear, and the inability to gauge the strength of retail space have lead many brick and mortar shops to marketing campaigns intended to guilt you into walking through the doors. Guilt is a powerful emotion, but forcing that onto your consumers is not fair. These campaigns should be called out for what they are: logical fallacies.

I am not particularly interested in getting into the business of small retailers, or even large retail chains other than to highlight how they operate. Retailers work out an arrangement to buy merchandise at some unit cost for price X. The retailer then puts that product on the shelf for price Y. Price Y is usually derived from the item manufacturer's suggested retail price. When you, the customer buy that item you're paying a tax in the form of the product's markup in exchange for instant gratification. The markup covers the the sales associates' wages, employee benefits, loss prevention, etc. This is all reasonable, right? That shop has staff dedicated to managing this stuff, and in theory the money trickles down through the employees and spreads to the rest of the economy. If that item were to be purchased online, you'd be stealing money out of the pockets of those employees and small business owners and retarding the rest of the economy. Shame on you.

The world doesn't really work like that. Online retailers are also run by people, often times with many employees who also have bills to pay. Guilting customers into potentially paying more for equal, or worse service is reprehensible. It is easier to deal with change than it is to reject it.

December 29, 2013

300

I feel like I take for granted the thousands of words I read each day without a second thought. Many words lack meaning or thought, yet some capture true thoughts, considerations, and even arguments. It is a true skill to be able to clearly express a thought or an idea. It is my goal over the next year to improve my writing by forcing myself to write three hundred words a day.

I am inclined to believe in the 10,000 hour rule. The 10,000 hour rule states that in order to become a master of a domain you must spend at least 10,000 hours actively doing it. While I have no intention to get anywhere close to spending that much time writing, I would still like to increase the time I spend writing (Anything better than 0 hours is an improvement). In order for me to truly and earnestly pursue my professional goals I need to improve at writing.

Passion drives me to improve, it drives me to change. A math professor I had would call this rule 0. He would always say "it has got to matter". A decade later I still take his advice to heart. Software development and cycling have worked their way into my life and have made such a huge impact on my life that I cannot imagine doing anything else. These disparate passions are something I would like to meld professionally. Much of my writing will certainly fall into one, or both of these categories.

With that said, I hope to write as much as time and my wife will allow. I hope to keep it interesting with pictures and insight into my passions. I have a few ideas for weekly features. The thought of writer's block and lacking source material is something that threatens procrastination but I hope my desire to improve is stronger than my laziness.