Why I’m Firing TimeWarner Cable TV

I’ve been pretty dissatisfied with TimeWarner cable for a long time. Some of this stems from having run across several lousy contractors/technicians. But my more recent complaints include:

  1. A very high number of bugs in their DVR programming.
    It seems that each DVR code update fixes one or two bugs, but always adds a few new bugs. They evidently do not test their code before delivering it to my DVR. I say this because I typically find bugs within minutes of using the updated code. I can’t recall a time when there weren’t bugs in my DVR, even after exchanging units, trying different models, etc. As the director of a large group of programmers, I know that I shouldn’t be discovering their bugs for them. That’s what Software Testing and QA is all about.
  2. Dishonest technical support
    They appear to have a standard response of “Oh, we fixed something in our back-end (or database).” I’ve heard this multiple times in situations where it was pretty clear to me that this was a stalling tactic, or an item on their support check-list. For example, on New Year’s day I was unable to watch video-on-demand, including trailers. I suspect that a lot of folks were home that day, and the high volume of on-demand streaming overloaded their back-end systems. I remember thinking at the time “this will be resolved tomorrow when everyone goes back to work”. Well, a few days later I started getting recorded phone calls informing me that “they had done some investigating and fixed some settings in their database, would I please retry the problem to see if it had been fixed.” Sheesh. Liars.
  3. Automated, nagging phone calls. They’re using computer generated phone calls to repeatedly call me day and night. I scheduled a technician to come out as a result of the New Years outage, but I’ve also been having low signal problems (intermittent pixellation). Now their computer is calling me with a recorded message lying to me about having “fixed the problem”, and would I please confirm and call them back at some stated phone number, otherwise my technician appointment might be cancelled. The message is fairly short, and the phone number stated twice before hanging up. WTF? How about giving me a chance to write the number down? To make matters worse, their computer wouldn’t leave a message when I didn’t answer, so I couldn’t even get the number from replaying their message. Does anybody at TimeWarner every try using their own service?

On the one hand, they provide the fastest internet service in my area. The RV park where my RV is currently parked provides cable hookups at the site, so TimeWarner is conveniently available to me when not traveling. And it’s pretty time consuming and inconvenient to switch provides (eg. cable to Dish or DirecTV). However, I feel like I’m not being a responsible consumer by continuing to subscribe to such an unethical, incompetent company.

Most of the people I know switched to Dish, DirecTV, or U-Verse long ago. Since I live in an RV, my options are somewhat limited. I don’t have the option of U-Verse, and until recently the mobile antennas available for Dish and DirecTV only support 1 channel viewing/recording. This has changed recently though, so I’ll be investigating my options and making a switch to Dish or DirecTV.

As inconvenient and expensive as it will be to switch, I refuse to continue to support a company that treats its customers like this.

TimeWarner, your monopoly on cable service is not enough to keep me as a customer. Get your act together or go out of business.

Follow up note 1/15/14

We had Dish installed last week and have been delighted. I’m sorry that I waited so long to make the switch. Primetime Anytime is awesome, and the responsiveness of the box to the remote is astounding. Installation was a breeze. We called on Saturday, and they installed it on Monday morning!

Not much blogging activity during 2013

2013 is winding down. I’ve been fairly busy blogging and writing technical stuff over on iOSUnitTesting.com, finishing up a new lynda.com course, and managing the best group of iOS developers on the planet. I haven’t posted here since last March.

I’m going to try to start doing more blogging here, keeping it more personal. Look for my iOS unit testing musing and reporting over at my iOS Unit Testing website. I’m going to try to keep this website more personal, talking about vacations, hobbies, family, travels, and travails.

 

AppCode 2.0 Released

JetBrainz has released a major update (2.0) to AppCode. I purchased my copy about 6 months ago, so the upgrade is free (anytime within 12 months).

The announcement says that Kiwi is now supported, so of course I needed to get a copy and check it out.

I’ve been wanting to redo the WhatsMySpeed code using true TDD with Kiwi, so I’m going to take this opportunity to try out AppCode 2.0 while I’m at it. I’m renaming it to HowsMyFuel to avoid confusion with the older code.

I’ve created a new public repository on GitHub to track this work. Feel free to watch and comment as I go. Since it is on git, you can use the git commit comments to monitor updates.

Motivation for Converting from Subversion to Git

We’re in the process of converting to Git at work. We’ve been talking about doing this for quite awhile, but never really had a compelling reason to do so. Recently though, something happened that has given us that reason.

Many of our projects are done with teams in both Hyderabad and India. We refer to these as “hybrid” projects. In a recent hybrid project, the SVN repository contained a lot of large assets (movies, images, PSDs, etc). Unfortunately, the internet bandwidth in our India office has been pretty bad. This caused updates to/from the svn server to take a very long time. This by itself caused delays, due to the time it took to sync up at the beginning and end of each location’s workday.

But then we threw a real monkey wrench into the works by converting the project to “Branch Based Development”. BBD has become a best practice where I work. We use this term to mean that a branch is created for each and every development task, then the branch is merged back into trunk only after it has been completed, tested, and code reviewed. However, branching/merging in Subversion requires essentially downloading then uploading the entire branch/trunk. I’m probably oversimplifying this, but the result was that each task ended up incurring that long update delay. Often multiple tasks can be completed in a single day, so now instead of a single delay at the beginning or end of the day, we ended up having this delay multiple times per day. At its worst, we were looking a 1-2 hours of delay per task!

At that point, someone pointed out that had we been using Git, this would not have been a problem. Git is much smarter about its branching, and doesn’t require this full upload/download to the remote. Granted, better organization of our svn repositories could have alleviated much of this problem, but we recognized that for international development, a DVCS like Git would be valuable and improve productivity.

So we’re using Git now. My experience with Git has been pretty much limited to clicking on the “Clone in Mac” button on Github. So I needed to learn Git.

Luckily, lynda.com has a very nice Git Essential Training course by Kevin Skoglund. I just completed that course this morning, and I’m excited now to get started using Git.  I recommend that you checkout the lynda.com course if you are just getting started with Git also.

iOS Development on iPad

I’ve started looking at if/how to do iOS development on an actual iPad. I currently use an 11″ Macbook Air. It’s portable and powerful. But I find myself doing everything on the MBA instead of learning how to really use the iPad.

With that in mind, I’m trying to force myself into really using the iPad for everything. It’s clear that most things will be a snap (email, chat, conferencing, etc), but iOS development is a bit of a challenge.

A couple approaches appear obvious:

  1. Remote Desktop to a development system
  2. Edit on iPad, and use FTP/Dropbox/etc. to sync to a development system.
  3. Get Apple to recompile Xcode for iPad (or JetBrains to recompile AppCode for iPad).

The first option is fairly straight forward. Tools such as TeamViewer and PocketCloud make this fairly simple. The only trick here is to set the development system’s screen resolution to match the iPad. This eliminates the need to scroll over the viewport.

The second option is perhaps more interesting. It should have a definite performance advantages, but somewhat greater complexity. There are several blogs talking about using DropBox to expose files on the iPad, then using Textastic or Koder to do the editing.

Option 3 is of course Nirvana for this, but totally out of our control. Anyone from Apple or JetBrains listening?

Vacation 2012

We finally took the RV out on the open road, driving from Austin to LA and back with stops at the Ice Caves near Roswell, the Grand Canyon, 3 days at Disneyland, and a few days at our timeshare at the Flamingo.

Travelling with me was my lovely wife Shelley, our oldest son Brian, and his two twins Ethan and Gillian. Together we hit the road to discover America!

Running a Jira server on Mac OSX

I’m currently using Jira at Mutual Mobile where I work, and I’m looking at using it with my hobby projects. It appears that this can be done very inexpensively if I host it myself on my Mac. I’d probably want to do that anyways, if not just from a learning perspective, but because of the cost ($70 one time cost for almost all the Atlassian apps):

  • Jira 10 users ($10 one time)
  • GreenHopper ($10)
  • Bonfire ($10)
  • Confluence ($10)
  • FishEye ($10)
  • Bamboo ($10)
  • Crucible ($10)
  • Jira Mobile Connect (free)
  • gliffy (free, $10 donation to requested)

I am choosing not to go with HipChat because I’m using Google+, nor Team Calendars because I’m using Google calendars for my simple needs.

Installing Jira on OSX

Installation on OS X is possible, although not officially supported by Atlassian.

  1. Identify $JAVA_HOME on your system. On my Mountain Lion system typing /usr/libexec/java_home results in /System/Library/Java/JavaVirtualMachines/1.6.0.jdk/Contents/Home
  2. Ensure the $JAVA_HOME environment variable is set. Type “echo $JAVA_HOME”. It should display the path. If not, set it to do so. A good option  for Mountain Lion is to add it to the /etc/launchd.conf  by adding “setenv JAVA_HOME <path>”. If you’re not familiar with editing in the terminal, try “sudo nano /etc/launchd.conf”. Reboot, and verify that “$JAVA_HOME/bin/java -version” works.
  3. Purchase and download a copy of Standalone Jira, and extract the files. Put the files in a location of your choice. I chose my user folder /Users/ronlisle.
  4. Set JIRA_HOME
    In terminal, from the Jira home directory, run ./bin/config.sh.
    When prompted, enter a JIRA_HOME directory path.
    I chose to create a jiraHome directory in my Google Drive directory.
  5. Create a dedicated user to run Jira
    Open system preferences, select Users & Groups, click on + to create a “Jira” standard user.
  6. Start Jira
    In terminal from the Jira installation directory, ./bin/startup.sh
  7. Run the setup wizard
    Open a browser to “http://localhost:8080”

By default, the installation will use the built-in HSQL database. This is suitable for evaluation only. If you have a MySQL database available, then I recommend that you switch to it:

  1. Create an MySQL database user (eg. jiradbuser)
  2. Create an MySQL database (eg. jiradb)
  3. If needed, copy the MySQL JDBC driver.
    It wasn’t needed during my installation.
  4. Configure Jira to use the MySQL db (./bin/config.sh)

I tried using MySQL running on my host server, but switched to using MySQL running on my Mac because it is faster and it enables me to work completely offline. Whichever your choose, be sure to keep backups.

Installing Confluence on OSX

  1. Create a “confluence” directory in your User home directory.
  2. Download and extract the Confluence zip file to that confluence directory.
    At the time I did this, the current version is 4.3.2 so I named this ~/confluence/confluence-4.3.2
  3. Edit the ~/confluence/confluence-4.3.2/bin/setenv.sh to add the line (at the top):
    export JAVA_HOME=/System/Library/Java/JavaVirtualMachines/1.6.0.jdk/Contents/Home
  4. Create a “data” directory in the confluence directory (~/confluence/data).
  5. Edit the …/confluence/confluence-4.3.2/confluence/WEB-INF/classes/confluence-init.properties file and replace the last line to indicate your install directory as follows:
    confluence.home=/Users/ronlisle/confluence/data
  6. Change the port assignment for confluence so that it doesn’t conflict with Jira.
    Edit the conf/server.xml file to set Server port=8015 and Connector port=8090
  7. Create a local MySQL database and user:
    Create database confluence;
    grant all privileges on confluence.* to ‘confluenceuser’@’localhost’ identified by ‘confluencepass’;
  8. Start confluence by running bin/start-confluence.sh
  9. Open confluence by browsing to http://localhost:8090

Accessing private methods and properties in ObjC unit tests

I’ve seen quite a few questions posted on various programming websites asking about how to access a class’s private methods from a unit test file. In Objective-C there are several ways to do this:

  1. Use performSelector in the unit test to access private methods
  2. Use Key-Value Coding to access properties and iVars.
  3. Define the methods and properties in a class extension.

I really like the 3rd approach the best. In case you aren’t familiar with class extensions in Objective-C, these are also known as anonymous categories.  The following example shows a simple class definition and implementation that includes a class extension:

// ExampleClass.h
// Public header file
#import <Foundation/Foundation.h>
@interface ExampleClass : NSObject {
}
// Publicly exposed methods
- (void)exampleMethod;
// Publicly exposed properties
@property (nonatomic, retain) NSString * exampleProperty;
@end
  
// ExampleClass.m 
// ExampleClass implementation 
#import "ExampleClass.h"   
@implementation ExampleClass 
// Properties 
@synthesize exampleProperty = exampleProperty_; 
// Methods 
- (int)exampleMethod {  
    // Do whatever this method needs to do... 
    return 3; 
}  

In this example, I’ve defined a class with an exampleMethod and exampleProperty. Both of these are declared publicly and so can be accessed easily from a unit test file as shown below:

// ExampleClass.m
// ExampleClass unit tests
#import <SenTestingKit/SenTestingKit.h>
#import "ExampleClass.h"

@interface ExampleClassTests : SenTestCase {
}
@property (nonatomic, retain) ExampleClass * testClass;
@end

@implementation ExampleClassTests
@synthesize testClass = testClass_;
-(void)testExampleMethodReturnValue {
    ExampleClass * ourClass = [[ExampleClass alloc]init];
    int returnValue = [ourClass exampleMethod];
    STAssertTrue( returnValue == 3, 
        @"Return value should have been 3 but was %d",returnValue);
}
@end

Now, what if you wanted to keep exampleMethod private, and not expose it in the public ExampleClass.h header file? As mentioned above, the unit test could use performSelector to execute the method, but this approach is limited to passing a single argument and precludes letting the compiler check your parameters, etc.

A better way is to declare exampleMethod in a class extension, and put that class extension in a separate header file. This file can then be imported into both the ExampleClass implementation file as well as any unit test files that need to access exampleMethod. This class extension header file is shown below.

// ExampleClassExtension.h
// ExampleClass Class Extension
// Declare any private methods and properties in this file.
// #import this file into the implementation file and unit test files.
@interface ExampleClass ()
- (int)exampleMethod;
@end

It’s just that simple. Using a class extension is considered a best practice for declaring your private methods and properties. Doing this makes it clear that these methods and properties are not intended for public use, otherwise they would be listed in the main header. But putting them in a class extension in a separate header file allows your unit tests to use them also. These methods and properties can be easily refactored, and will work correctly with autocompletion.

iOS Unit Testing

I’ve been knee-deep in iOS unit testing for the past few months. Xcode 4 has been a real blessing as well as a curse. Apple did a great job of integrating unit testing into Xcode 4, but so far has failed to provide much in the way of documentation. To make matters worse, things have changed drastically from Xcode 3. In the upcoming days and weeks I will be sharing what I’ve learned about unit testing in the new Xcode 4 environment.