Is pair programming worth the hassle?

I have been doing programming for over 14+ years, and from time to time I did pair programming (mostly debugging problem). Since early last year I have been doing more pairing, mostly due to the hints from above. I have mixed feeling on this, mostly along the lines of advantages of disadvantages talked about here by Mark Weldon.

Quote Mark here, “When you pair program, you’re effectively joined at the hip with your pair. You can’t pair if only one of you is there. This means that you both come into work at the same time, you both take lunch at the same time, you both take breaks at the same time, and you both leave at the same time. The work is so concentrated that you work 8-hour days (which is good). But you can’t take time off without affecting your pair. Working from home is possible, but it’s obviously not as pairy as sitting beside one another…” I have very similar feeling here. Mark is probably an experienced developer. I also did a google search, saw other people with different background shared their thoughts on pair programming (manningdigital, a CS student). Mark also talked about the personality clash, essentially one developer with strong will (or more stubborn gets her/his way), which is also echoed by other 2.

Curious about this topic, and don’t want to limit by the google, I came to quora, and searched this topic. I came up with Is pair programming worth the trade off in engineering resources and Does Pair Programming really work.

And I saw this from the famous developer Kent Beck, he suggested it works when

“The problem space is big and unknown. You don’t know what exact problem you are solving and the probability is high that any solution you find will change your understanding of the problem.
The solution space is big and unknown. You are working with technology you don’t fully understand and the chances are that any solution you find will change your understanding of what constitutes an effective solution.
You need to build relationships on a team…”

I think that’s where I agree with on pair programming at this time.

2014 Year end review on myself : family, personal finance, career, agile

I was a bit late doing this, but I think better late than never.

Family and Personal Finance
We had baby (girl) No. 2 in the summer, baby Sophia is healthy and happy for the most part. I had to be honest, having 2nd kid is not as thrilling as the 1st.

With the birth of new baby, we had some more challenges to make sure baby No. 1 is happy. We have achieved this to large extent. With some caveats (see below). It’s almost unthinkable that Serenity will start kindergarden in the fall. Time flies. Enjoy it while we can. Leave the iDevices/mac if I can.

On personal finance front, I felt stretched a bit after the cost associated with new baby (hospital bill, etc.) and the preschool tuition for my older daughter. So in Sept. I made a painful decision to transfer Serenity to the preschool at church, which will save us some money. Initially I tried to bite the bullet and started some financial engineering such as refinance the mortgage (to get some cash). But it was not enough.

Reflect on my own mistakes on personal finance, mostly on playing the stock market, and over spend on things such as organic milk. I felt not very good. But again better late than never. I started shopping more on Aldi’s and try to control the discretionary spending. Also, for the stock market part, noticing the fall of oil and the DRIP (dividend re-investing program), I decided to put some money in Exxon Mobile Drip program. I also think about the performance of my self managed IRA account vs. the other 401k/Rollover IRA accounts managed passively (all mutual funds managed by professional money managers).

Career
I did not change job in the last year, hopefully I can stay at current place longer than past few years (change job almost yearly). Another important thing to consider is the feel of being challenged and learn new things, plus work/life balance.

Another interesting point is, since my wife seeing the benefits of the programmer job, and she is taking care of baby No. 2 full time now, she is thinking about learning java in her spare time. So hopefully we will have another IT professional in our household soon :-)

Continue reading

Moving wordpress from shared host to aws ec2

I did an experiment recently trying to move my wordpress website from a shared hosting site to Amazon aws ec2 micro instance (t1). The migration was mostly successful, I did not make the move eventually due to some technical and non-technical reasons. Nonetheless, I would like to share some of the lesson I learned from this process. I followed this blog post form smashmagazine as a blueprint for “moving wordpress”. Note I already have ubuntu installed on ec2, and has setup keys for my laptop.

1) Setup wordpress on new host. This is the link I followed to setup wordpress on ubuntu on my aws ec2. Another useful article is here.

2) Upload files: I used FileZilla (SFTP) for uploading the files. Here is the link regarding setup keys. Note the file permission is also very important to make wordpress work, which is especially important when moving the sites. More on this later.

3) File permission, one thing I noticed quickly is I don’t have any writing privilege after moving, e.g., update plug-ins etc. Did google quite a bit, and tries to change the file permissions using FileZilla. No luck. Eventually I read this from wordpress official doc. Quote:…(a) file ownership: all of your WordPress files must be owned by the user under which your web server executes. In other words, the owner of your WordPress files must match the user under which your web server executes. The web server user (named “apache”, “web”, “www”, “nobody”, or some such) is not necessarily the owner of your WordPress files…

I did “ps -ef|grep httpd” at my ubuntu server, and find the user for apache web server (not “root”). And changed the file owner to this user (via “chown” command).

4) MySQL server crash: I found this happens quite often (as often as once every 3 days). Turns out to be a memory problem for the t1 micro instance and apache web server and mysql fights for the memory, eventually mysql lost. The solution I found is add virtual memory to the system, and reduce the memory requirement for mysql in config file. Eventually I was able to have mysql run as long as 13 days without shutting down. Not idea, but meaningful improvement. Another idea, people talked about is use a lightweight http server such as this one.

5) MySQL database migration. Found out for large database, php export will not complete, and will end up with some junk html in the database file (.sql), it will fail during import. The workaround is do the export and import in the mysql command line. But I still have one problem with database, it appears the Chinese character got lost during this process. This problem along with the mysql server problem mentioned above, and the relative higher cost of AWS compared to shared host, made me decide to not switch at this time.

Other links:
Setup php/mysql, and phpMyAdmin.

Some tips for submit updated app to iTunes store post iOS8

With (before) the release of iOS8, I noticed the iTunes Connect web interface has also been changed. But today is the first time I submit my app (update) to the store for last few months. There are some changes.

1) First, there is no “ready to submit app” button in the iTunes Connect, instead we just create a new version at ITC;

2) After that, we load the app to the app store, I used good old Xcode 5.1.1, which is the minimum version Apple requires now. Now here is a tip when submit from Xcode organizer, when I run “validate” before submit, it says I could not change “bundle” number, which I have not. Looking more carefully, it appears the good old Xcode 5.1.1 got confused with which app profile to use, and it picked the wrong one all the time. So I manually corrected it. After that I was able to upload the binary.

3) There is one more step, the actual “submit for review”, in the past the step 2) is sufficient. Now there is this extra step. In this step, it will ask questions similar to the questions being asked when we do “ready to submit” in the ITC in the past (before this change). In my case, since the app has “iAd”, it insists me check the Ad identifier selection, and after I check that, it let me submit (note I will try couple times, eventually I started over). But it appears not let me check “no” in the Ad section. This appears to be a glitch, I was able to submit my other 2 apps without any problem when checking no for the Ad identifier. There is another glitch though, that is I have to quit the app, before pick the newly added build, and submit for review. In summary, it appears ITC web page needs some work.

I will report more when/if I find anything new next time I submit app update. I noticed there is new marketing collaterals such as the preview video, and screenshots for 4.7/5.5 inch screen. My gut feeling is those will be required after this transition period. So hurry up if you have some app or update to release :-)

(PS, 09-28-2014) One more thing, I noticed if I wanted to reject a binary (a build in new term), I need to create a new version. In the past, I could upload a newer binary with same version number. I think it’s probably a good idea to limit this back and forth. Note Apple added testFlight capability too. It should help app testing.

Set up Apple TV with AT&T u-verse

It seems the wifi router comes with AT&T u-verse does not work with Apple TV. Apple TV could not find the wifi network from the build in u-verse wifi router. I found one workaround, that is to turn off the build in Wifi, use an old wifi router (D-Link DI-524) for Wifi instead. But there is still problem with the mirroring from iPad to Apple TV. Since I still have my previous LinkSys wrt54g router, I set it up as second router behind the DI-524, and connecting both the Apple TV and iPad to wrt54g. That worked. Another side benefits is wrt54g is a newer/more powerful router, and could broadcast wider range. So in a summary the architecture from internet to apple TV is something like below.

u-verse modem (wifi off) => D-Link DI-524 router => LinkSys wrt54g router => Apple TV/iPad

You may wonder why I add this extra D-Link DI-524 old router. The problem was I could not easily connect LinkSys wrt54g (the newer router) to u-verse modem. So I used the old router as a bridge. If someone has idea to make it work without this extra router, please let me know. (Email: minjie DOT xu AT gmail DOT com; or twitter @stlplace)

There is another problem with setup AT&T u-verse which is not related to Apple TV. The problem is when creating new account at their web site, they prompt for secret question/answer, it appears they don’t take any space in the answer. It was a programming error (web page text field validation) in my opinion, since I have done some web programming lately. The workaround is not to type any space. Simple enough.

This is also after using cable internet for about 8 or 9 years, I am switching to AT&T. I was using their DSL before switching to cable. The main reason is their service is cheaper, another factor is the cable had some connection issues lately.

Why new Apple smart watch is not called iWatch?

Here is my theory. Years ago I heard people in China mentioned “Apple Phone” (苹果手机), for iPhone. This is particularly true for older generation as their grasp of English is not as good as younger generation. So this time they decided just go with Apple Watch 苹果手表.

Note this is also their fourth main product category innovation since year 2000 : iPod, iPhone and iPad. If they stick with iWatch, the name will be too predicable. But this is secondary compared to the reason above, which is use their Apple logo, and name. Both are well known all over the world.

PS, saw this disturbing video about people lining up at Apple store for iPhone just for resell.

Calling restful POST PUT and DELETE methods in AFNetworking 2.0

Some example code here. For GET methods and AFNetworking 2.0 using a php web service, raywenderlich.com has an excellent tutorial. One problem I saw when I did this exercise is the service was expecting “application/json” for “Content-Type” (note the default is text/html, if we don’t specify in request serializer).


// POST method
-(IBAction)addBook:(id)sender
{
    // 1, note this is the base URL, typically it's the end point of REST web service
    NSURL *baseURL = [NSURL URLWithString:BaseURLString];
    NSDictionary *parameters = @{@"title": @"One Flew Over the Cuckoo's Nest",
                                 @"author": @"Ken Kesey",
                                 @"read": @false};
    
    // 2
    AFHTTPSessionManager *manager = [[AFHTTPSessionManager alloc] initWithBaseURL:baseURL];
    manager.requestSerializer = [AFJSONRequestSerializer serializer];
    manager.responseSerializer = [AFJSONResponseSerializer serializer];
    
    [manager POST:@"/book" parameters:parameters success:^(NSURLSessionDataTask *task, id responseObject) {
        self.title = @"Book added";
        _textView.text = [[NSString alloc] initWithFormat:@"Response JSON: %@", (NSDictionary *)responseObject];
    } failure:^(NSURLSessionDataTask *task, NSError *error) {
        NSLog(@"\n============== ERROR ====\n%@",error.userInfo);
        
        UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:@"Error adding book"
                                                                message:[error localizedDescription]
                                                               delegate:nil
                                                      cancelButtonTitle:@"Ok"
                                                      otherButtonTitles:nil];
        [alertView show];
    }];
}

- (void)setupForRemoveAndUpdateBook:(AFHTTPSessionManager **)manager_p bookIdString_p:(NSString **)bookIdString_p
{
    NSURL *baseURL = [NSURL URLWithString:BaseURLString];
    
    [_textField resignFirstResponder];
    
    int bookId = [_textField.text intValue];
    
    *bookIdString_p = [NSString stringWithFormat:@"/book/%i", bookId];
    
    *manager_p = [[AFHTTPSessionManager alloc] initWithBaseURL:baseURL];
    (*manager_p).requestSerializer = [AFJSONRequestSerializer serializer];
    (*manager_p).responseSerializer = [AFJSONResponseSerializer serializer];
}

// DELETE method
- (void)remove_book
{
    NSString *bookIdString;
    AFHTTPSessionManager *manager;
    [self setupForRemoveAndUpdateBook:&manager bookIdString_p:&bookIdString];
    
    [manager DELETE:bookIdString parameters:nil success:^(NSURLSessionDataTask *task, id responseObject) {
        self.title = @"Book deleted";
        _textView.text = [[NSString alloc] initWithFormat:@"Response JSON: %@", (NSDictionary *)responseObject];
    } failure:^(NSURLSessionDataTask *task, NSError *error) {
        NSLog(@"\n============== ERROR ====\n%@",error.userInfo);
        
        UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:@"Error deleting book"
                                                            message:[error localizedDescription]
                                                           delegate:nil
                                                  cancelButtonTitle:@"Ok"
                                                  otherButtonTitles:nil];
        [alertView show];
    }];
}

-(IBAction)removeBook:(id)sender
{
    [self clear:nil];

    if (_textField.text == NULL || _textField.text.length==0) {
        UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:@"Book ID required"
                                                            message:@"Please input the book ID"
                                                           delegate:nil
                                                  cancelButtonTitle:@"Ok"
                                                  otherButtonTitles:nil];
        [alertView show];
    }
    else {
        [self remove_book];
    }
}

// PUT method
- (void)update_book
{
    NSString *bookIdString;
    AFHTTPSessionManager *manager;
    [self setupForRemoveAndUpdateBook:&manager bookIdString_p:&bookIdString];
    
    NSDictionary *parameters = @{@"read": @true};
    
    [manager PUT:bookIdString parameters:parameters success:^(NSURLSessionDataTask *task, id responseObject) {
        self.title = @"Book updated";
        _textView.text = [[NSString alloc] initWithFormat:@"Response JSON: %@", (NSDictionary *)responseObject];
    } failure:^(NSURLSessionDataTask *task, NSError *error) {
        NSLog(@"\n============== ERROR ====\n%@",error.userInfo);
        
        UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:@"Error updating book"
                                                            message:[error localizedDescription]
                                                           delegate:nil
                                                  cancelButtonTitle:@"Ok"
                                                  otherButtonTitles:nil];
        [alertView show];
    }];
}

-(IBAction)updateBook:(id)sender
{
    [self clear:nil];

    if (_textField.text == NULL || _textField.text.length==0) {
        UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:@"Book ID required"
                                                            message:@"Please input the book ID"
                                                           delegate:nil
                                                  cancelButtonTitle:@"Ok"
                                                  otherButtonTitles:nil];
        [alertView show];
    }
    else {
        [self update_book];
    }
}

iOS Objective-C interview questions

I just throw some technical questions out here. Note Ray Wenderlich has a series on this. BlackPixel has an article too.

life cycle of UIViewController;

NSString property copy or retain?

frame vs bounds

category vs subclass

What is protocol (Apple doc; Ry’s Objective-C tutorial)? Create a protocol for List, and how to implement the “add” method for linked list (stackoverflow)?

block (how to avoid memory issue);

To be continued…

Update sqlite database during iOS app update

We all know updating sqlite database on an existing iOS app could be tricky, esp. with any schema (table) changes. In the good old days when I was developing in-house app, I found out the app would crash when I added a column to the sqlite database, after merely updating the app. The problem was, the old database won’t get updated if we don’t explicitly do it during app start-up (after app update). So what did I tell my user to do? Delete the app, and re-install the app. Not the most user-friendly way, and what if the user has some data on it that he/she wants to keep? What if this app have many users?

I had this updating issue in my mind for a while, because one of my apps needs to refresh its data. There are a few ways to do it: 1) Use a web service to get the data; 2) Just update the sqlite database. The former has some limitations: we could get data via web service, but note we still need to manipulate the database if we need to add a column or table (this is same for both approaches). The latter is faster in terms of development. So I decided to do it. I did some research on stackoverflow and found this post as my reference. Here is my implementation, if you are interested. The following is done in viewDidLoad.

Continue reading

stlplace.com was hacked and restored, plus some thoughts

I found out this site was hacked yesterday evening, as I saw the loading of site on Safari was slower than usual. It also shows incorrect theme, more like a plain theme. With the admin link redirect to spammer site. I decided to tackle it right away. I recall about one year ago something similar happened to this site, and google webmaster tool told me about it. I was able to remove the offending files/directories, by following the recommendation set out by google and some other wordpress sites.

This time I made an almost fatal mistake, during deleting some of the files in wp-includes, I accidentally deleted all the useful php files there. Panicked, I used both the website restore tool, and the import feature of wordpress (mojo marketplace), to no avail. The symptom of the problem was I could not login, and it shows blank page when I login via the wp-admin or wp-login.php after taking my credential. And I can only see the pages at uudaddy.com (I could not log in there either).

I filed for help at the hosting company. But I still feel helpless as this site has about 9 years of my blogging and uudaddy.com has my last 4 years of blogs. Fortunately I was able to find this wordpress help page about updating wordpress, and fix internal server error by deactivating the plug-ins. The latter comes only after I gained some web dev experience lately, knowing more about error 500 :-)

So long story short, I was able to restore all the blogs (those two plus my wife’s happy mandarin.com) by the following:
1) Restore .htaccess file to avoid the redirect to spammer page;
2) Restoring the wp-includes and wp-admin page: upload zip file, extract; in the wp-content directory, I renamed plugin directory as plugin.SAV (this way it deactivates all the plugins);
3) Run the wordpress update as soon as I can log in.

I also backed up the MySQL databases for stlplace and uudaddy, and backed up those two blogs to wordpress.com (this one and this one). I understand blogging itself is a declining trend, and it’s probably not easy for small web hosting company to defend against hackers like Google/Amazon/Wordpress do. That’s why I am also evaluating whether to move to wordpress.com or Amazon EC2 (self hosting). It’s a bit emotional decision as I have hosted this site for 9 years, but I need to consider both my time, the cost of hosting, etc. I will make a decision on this shortly. Meanwhile check out the new blogging sites I mentioned above, in which I will blog both about software development and raising kids.