Showing posts with label iOS Development. Show all posts
Showing posts with label iOS Development. Show all posts

Monday, 11 February 2013

Kata2 Binary Search

I did my second Kata this morning. I thought I'd tackle the binary search problem in following with http://codekata.pragprog.com
The idea here is that you have some huge, but sorted, list and you need to find a single element within that list as efficiently as possible. As lists grow in size just traversing through the list element by element can take a really long time for higher numbers.

The binary search solution basically means you start in the middle continually divide the list in half until you find your element. For huge lists it's excellent because it doesn't matter where the desired element is in the list, it will always find it quickly, one drawback though it will more often than not, take several searches to locate the element. So you need to weigh the efficiency lost against the efficiency gained. 

I'm quite proud of my attempt. I've tested it with a list of 50,000,000 integers and it never takes more than 26 searches to find any element. It'll support an array of any size and it should support any data type, but I'll need to test that at a later time. This is a recursive approach as it was the approach that comes most naturally to me. I'm going to have a look at an iterative at a later time.

This was developed using TDD, kind of. I had to test this from a few different directions at once, namely efficiency and accuracy. I couldn't work out a good way of testing for them both at the same time so I'm leaving what test code I did end up with out of this post.

 -(NSNumber*)binarySearch:(NSArray*)array forInt:(NSNumber*)anInt {  
   int numberOfSearches = 1;  
   int min = 0;  
   int max = array.count;  
   int searchingFor = [anInt integerValue];  
   int indexOfGuess = [array indexOfObject:[array objectAtIndex:(max + min) / 2]];  
   int guess = [[array objectAtIndex:indexOfGuess] integerValue];  
   NSLog(@"%d searches", numberOfSearches);  
   while (searchingFor != guess){  
     if (max - min <= 2){  
       return [NSNumber numberWithInt:-1];  
     }  
     if (searchingFor < guess){  
       max = indexOfGuess;  
     }  
     if (searchingFor > guess){  
       min = indexOfGuess;  
     }  
     guess = [[array objectAtIndex:(max + min) / 2] integerValue];  
     indexOfGuess = [array indexOfObject:[array objectAtIndex:(max + min) / 2]];  
     numberOfSearches++;  
     NSLog(@"%d searches", numberOfSearches);  
   }  
   return [NSNumber numberWithInt:indexOfGuess];  
 }  

Monday, 4 February 2013

Bruising the Ego

I've learned quite about managing your ego when it comes to development. Every programmer has an ego, don't listen to what they might tell you otherwise. We all consider ourselves the poets of the computing world, thinking up beautifully elegant solutions to impossible problems.

I have a huge ego, I freely admit this. I don't handle criticism well and I'm a sore loser. I constantly aim to blow peoples minds with my genius and when that doesn't happen I fall into pits of self loathing and depression. It's a constant struggle for me.

Two of my apps have received bad reviews recently. I've got another app that I'd written for a client that seems to have given up on me all together, bought my app and immediately reporting a bug and requesting all sorts of changes. I fixed the bug right away and then spent a month re-writing the app. Now they won't respond to my emails, nor have they updated the app. My natural pessimism tells me that they've written me off all together, but I just don't know.

Being that two people have chosen to be vocal about their dislike of my apps, demographically I know that there are a percentage of others out there that feel the same way and have just chosen not to speak up. I spent a lot of time and energy on those apps and I'm very proud of them and their success so far. These were my ideas, my creations, my products and I want everyone to love them.

Now in my defence neither of these two users appear to have read the description of the apps before purchasing, which is their mistake. And the things they're complaining about are actually restrictions put in place by Apple, nothing to do with me. But these are still my app reviews. There is also information within the apps and on the app store that would allow a displeased customer to get in touch with me of there's a problem. But they haven't tried to reach me. I take some solace in knowing, from experience, that there are customers out there that just want to complain about anything that they can. You can't please everyone right, so why don't all those that like my apps post good reviews and make me feel better about it. I'm sat here looking at dissatisfied customers and poor reviews and I'm powerless to do anything about it.

I suppose that I could look at it as there's being an opposing percentage of those that are very happy with my app. There is one good review as well, so that's something.

Monday, 21 January 2013

My First TDD Kata - Objective C - Xcode 4.5 - OCUnit - ARC

Ok, so I've taken the entire day to work on a programming Kata using TDD.

I started with the same exercise that I was given during an interview for an industrial placement a few weeks ago http://codekata.pragprog.com/2007/01/code_kata_one_s.html just so that I had an idea of where to start.

This code has taken me all day but for good reason.
Firstly I've never used TDD before, nor do I have any idea of how to use OCUnit. I have quite limited experience in programming generally so this was all a bit of a learning curve for me.
Secondly, this paradigm is basically the opposite of the way in which I've learned to program. I find it very, very difficult to think this way.

I'm actually quite pleased with the result. As applications go it's functional, seems robust and the design isn't far off from what I would have designed otherwise. It will be interesting to come back to this Kata later and see what differences there are.

What did I learn?

TDD is a concept, I could hear the criticisms screaming out at me as I did it but once I got going it actually started to come really naturally.

Two problems.
From time to time a tricky change comes up. For example in my application I made the decision to change from scanning in Strings to scanning in item objects. Looking back now I can see how I maybe could have handled this differently and maybe made things a little bit easier on myself. But still there was a lot of time spend pondering this, while outside of TDD the change would have been a no-brainer, just change an argument here and a return type there an done. TDD meant that I wound up writing a whole new function for it to save failing the older tests. I'm hoping that some more practice in TDD will help me to handle this type of situation in the future.

There was a real sense of fragility when programming. When implementing the BOGOF feature I found myself tip-toeing around the code trying to change as little as possible as not to fail my older tests, again I hope that experience will take care of this but I'm not so sure.

The design comes from the refactoring stage really. Refactoring seems to be the time to do a little bit of 'Crystal Balling' a little bit and try to introduce some good code and design practices.

Oh and if you're wondering about the weird way I've worked with NSNumber, well I can't really explain myself, I just had a really hard time with it and the primitives. I may do my next kata in a different language.

My Code.
Tests

 -(void)testCheckOut {  
   NSNumber *expected = [NSNumber numberWithDouble:0.0];  
   NSNumber *result = [scanner checkOut];  
   STAssertEquals([expected doubleValue], [result doubleValue], @"Expected %g, but returned %g", [expected doubleValue], [result doubleValue]);  
 }  
 -(void)testScanItem {  
   NSNumber *expected = [NSNumber numberWithDouble:0.60];  
   [scanner scanItem:(@"apple")];  
   NSNumber *result = [scanner checkOut];  
   STAssertEquals([expected doubleValue], [result doubleValue], @"Expected %g, but returned %g", [expected doubleValue], [result doubleValue]);  
 }  
 -(void)testScanningTwoItems {  
   NSNumber *expected = [NSNumber numberWithDouble:1.20];  
   [scanner scanItem:(@"apple")];  
   [scanner scanItem:(@"apple")];  
   NSNumber *result = [scanner checkOut];  
   STAssertEquals([expected doubleValue], [result doubleValue], @"Expected %g, but returned %g", [expected doubleValue], [result doubleValue]);  
 }  
 -(void)testScanningAnItemWithADifferentPrice{  
   double expected = 0.7;  
   [scanner scanItem:@"banana"];  
   double result = [[scanner checkOut] doubleValue];  
   STAssertEquals(expected, result, @"Expected %g, but returned %g", expected, result);  
 }  
 -(void)testScanningTwoItemsWithDifferentPrices {  
   double expected = 0.7+0.6;  
   [scanner scanItem:@"apple"];  
   [scanner scanItem:@"banana"];  
   double result = [[scanner checkOut] doubleValue];  
   STAssertEquals(expected, result, @"Expected %g, but returned %g", expected, result);  
 }  
 -(void)testScanningMultipleItemsObjectsOfVaryingPrice {  
   Item* apple = [[Item alloc] initWithDescription:@"apple" andPrice:[NSNumber numberWithDouble:0.6]];  
   Item* banana = [[Item alloc] initWithDescription:@"banana" andPrice:[NSNumber numberWithDouble:0.7]];  
   Item* orange = [[Item alloc] initWithDescription:@"orange" andPrice:[NSNumber numberWithDouble:0.5]];  
   double expected = 0.0;  
   [scanner scanItem:apple.description];  
   expected += [apple.price doubleValue];  
   [scanner scanItem:banana.description];  
   expected += [banana.price doubleValue];  
   [scanner scanItem:orange.description];  
   expected += [orange.price doubleValue];  
   [scanner scanItem:apple.description];  
   expected += [apple.price doubleValue];  
   double result = [[scanner checkOut] doubleValue];  
   STAssertEquals(expected, result, @"Expected %g, but returned %g", expected, result);  
 }  
 -(void)testScanningItemAsObject {  
   Item* apple = [[Item alloc] initWithDescription:@"apple" andPrice:[NSNumber numberWithDouble:0.6]];  
   double expected = 0.6;  
   [scanner scanObject:apple];  
   double result = [[scanner checkOut] doubleValue];  
   STAssertEquals(expected, result, @"Expected %g, but returned %g", expected, result);  
 }  
 -(void)testScanningMultipleObjects {  
   Item* apple = [[Item alloc] initWithDescription:@"apple" andPrice:[NSNumber numberWithDouble:0.6]];  
   Item* banana = [[Item alloc] initWithDescription:@"banana" andPrice:[NSNumber numberWithDouble:0.7]];  
   double expected = apple.price.doubleValue + banana.price.doubleValue;  
   [scanner scanObject:apple];  
   [scanner scanObject:banana];  
   double result = [[scanner checkOut] doubleValue];  
   STAssertEquals(expected, result, @"Expected %g, but returned %g", expected, result);  
 }  
 -(void)testBOGOFWithTwoOfTheSameItem {  
   Item* apple = [[Item alloc] initWithDescription:@"apple" andPrice:[NSNumber numberWithDouble:0.6]];  
   double expected = apple.price.doubleValue;  
   [scanner scanObject:apple];  
   [scanner scanObject:apple];  
   double result = [[scanner checkOut] doubleValue];  
   STAssertEquals(expected, result, @"Expected %g, but returned %g", expected, result);  
 }  
 -(void)testBOGOFWithMultipleVaryingItems {  
   Item* apple = [[Item alloc] initWithDescription:@"apple" andPrice:[NSNumber numberWithDouble:0.6]];  
   Item* banana = [[Item alloc] initWithDescription:@"banana" andPrice:[NSNumber numberWithDouble:0.7]];  
   double expected = 0.0;  
   [scanner scanObject:apple];  
   expected += apple.price.doubleValue;  
   [scanner scanObject:apple];  
   [scanner scanObject:banana];  
   expected += banana.price.doubleValue;  
   [scanner scanObject:banana];  
   [scanner scanObject:banana];  
   expected += banana.price.doubleValue;  
   double result = [[scanner checkOut] doubleValue];  
   STAssertEquals(expected, result, @"Expected %g, but returned %g", expected, result);  
 }  

Application

 -(PriceScanner*)init {  
   self.total = [NSNumber numberWithDouble:0.0];  
   self.list = [[NSMutableArray alloc] init];  
   return self;  
 }  
 -(void)scanObject:(Item*)item {  
   [self.list addObject:item];  
 }  
 -(void)scanItem:(NSString*)item {  
   if ([item isEqualToString:@"apple"]){  
     self.total = [NSNumber numberWithDouble:[self.total doubleValue] + 0.6];  
   }  
   if ([item isEqualToString:@"banana"]){  
     self.total = [NSNumber numberWithDouble:[self.total doubleValue] + 0.7];  
   }  
   if ([item isEqualToString:@"orange"]){  
     self.total = [NSNumber numberWithDouble:[self.total doubleValue] + 0.5];  
   }  
 }  
 -(void)applyBOGOF{  
   double newTotal = [self.total doubleValue];  
   NSMutableSet *tempSet = [[NSMutableSet alloc] init];  
   for (Item* i in self.list){  
     if ([tempSet containsObject:i.description]){  
       newTotal -= [i.price doubleValue];  
       [tempSet removeObject:i.description];  
     } else {  
       [tempSet addObject:i.description];  
     }  
   }  
   self.total = [NSNumber numberWithDouble:newTotal];  
 }  
 -(NSNumber*)checkOut {  
   double newTotal = [self.total doubleValue];  
   for (Item* i in self.list){  
     newTotal += i.price.doubleValue;  
   }  
   self.total = [NSNumber numberWithDouble:newTotal];  
   [self applyBOGOF];  
   return self.total;  
 }  

Tuesday, 15 January 2013

Test Driven Development: Prologue.

I'm putting down, for the record, that I'm going to endeavour to do more testing in my software. I plan to do this by means of Test Driven Development. While I plan to do as much work as possible in Xcode probably using GHUnit or OCUnit, visual studio is proving inescapable so I'll probably be using NUnit as well.

What I already know.

I went for an interview for an industrial placement at a software company that uses Extreme Erogramming with TDD for all of their software. Now, I'm a big fan of XP and this has proven hugely successful for this company so I paid attention to their processes.

  1. Write the test. Make sure you give it a name that describes what the test is for.
  2. Fail the test. This was really important, especially as the application starts to grow, because new tests won't always fail, but they should. If you skip this step you can end up wasting a lot of time trying to fix a problem that isn't there.
  3. Get the test to pass as quickly as possible. This is also very important because it stops you spending hours trying to implement the most ideal solution and losing scope of what you're trying to do. Literally just throw in whatever you can to get that test to pass.
  4. Refactor. Make it look nice, now is that time to maybe think about the ideal implementation, but not too much.

This approach gets a lot of criticism from people saying that it promotes bad design, or poorly written code. But the idea behind TDD is that you're focussing on a single problem at a time. So when you start, yeah you have a bunch of really inflexible code and virtually no design in place. But as the number of tests grows and likewise the application, better design falls right into place and you end up with a very robust piece of software.

Anyway, I'll see how I get on. It may be a bit naive of me to just be saying All my products will be TDD from now on but I'm going to give it a go and see how far I get.

Sunday, 15 July 2012

Cleverlist


Presenting my latest creation, Cleverlist. 

This is a shopping list app that I wrote for my wife. She designed the interface and everything else and I developed it. This app learns your shopping habits and tries to predict what item in the store you're going to arrive at next. The more you use this app, the more accurate it becomes. 

Monday, 26 March 2012

Sprint 4 Demo and Reflection

Sprint 4 Demo and Reflection

Implementation of the wind grid went much smoother than I expected, the grid is simply an array of points and a wind force value, each frame the position of the ship is tracked through those points and the corresponding wind value is applied in a specified direction. Currently the wind force is set to a value that increases as the ship gets further away it's an excellent proof of concept. With a little more work the colour values from a perlin noise image would replace the wind force values and create a much more realistic and dynamic game experience. Currently the array is 2D but would easily update to 3D.

Implementing the 3D perspective is still proving to be a challenge.  I'm going to do another sprint dedicated to it's implementation.




What I would do differently?
Nothing. I'm happy with the use and result of this sprint.

What did I learn?
I'm putting the success of this sprint down to the design. The trouble I had implementing the gravity was likely the result of a lack of good design. With the wind implantation I had a good clear design.

Sunday, 18 March 2012

Sprint 4 Planning

It's time to start with the wind model.
This is actually the initial idea behind the project and it was looking like I wasn't going to be able to manage any aspect of it, which would have been a shame.

So I'm starting small. I'm going to get the grid working. This will be a simple grid in which the ships position will be tracked. Each element of the grid will have effects of the wind assigned to it.

It all seems very straight forward so hopefully it will be.

While I'm at it I'm going to try to complete the 3D implementation.

Sprint 3 Demo and Reflection

The investigation has gone better than I hoped. With only a little work I was able to implement a 3d perspective, 3 dimensional gravity and collisions.

I did come across a couple of problems that I'm going to seek advice on.
The Z frame buffer seems to be working in reverse. I've got some experience with depth checkers and I'm sure I've just got something backwards but I can't find it.

I can't figure out how to implement the chase camera. As soon as I have this I can look at implementing a better control system. I'm going to speak with my supervisor about it on Tuesday and go from there.


What I would do differently?
Nothing. I'm happy with the use and result of this sprint.

What did I learn?
A sprint aimed at research and planned experiments can be every but as productive as a sprint dedicated to implantation.

Monday, 12 March 2012

Sprint 3 Planning

Now that I'm getting a grip on this project I'm going to look at expanding into the 3rd dimension.
I'd initially abandoned the idea of doing this project in 3d due to the problems I was having using the framework. Now I'm thinking that I should give it a go.

So sprint 3 is going to be exploratory. I'm going to take a slightly XP approach and write a bunch of experimental throw-away code and see if I can't get a hold on the Z axis. I'll implement what I can and identify the things that are going to cause me trouble. Then speak to my supervisor about it all.

Thursday, 8 March 2012

Sprint 2 Demo and Reflection

I'm very proud of myself right now.

This sprint started off well but got very rocky pretty quickly.
I set off to correct by collision handling so the rocks weren't just reversing direction when they collided.
Turns out that the gravity wasn't working anywhere nearly as well as I'd hoped. Some problem with my implementation made managing collisions impossible.
So once again I found myself working on the gravity forces instead of moving on with the project.

Anyway, I've revamped my gravitations, it now less resembles real gravitational forces and more resembles a very simple pursuit model. Basically all of the objects encourage the other objects to chase them at speeds calculated by their mass.
Once that was completed the collision work went relatively smoothly. I say relatively because at the level where the collision responses are being handled I only had access to one of the objects velocity, which made working out the forces pretty challenging. But what I did have was both their masses and positions. So my algorithm assumes that all colliders are moving at least a little bit, it then works out the trajectories of the collision from both object positions and combines, multiplies that by the collidee's mass and applies the result to the collider's speed with a 40% reduction to make it feel a little more real, and controlled.


It's still not perfect but it's much better than it was, I'm hoping that as I get more practice with my vector math I'll be able to more finely tune it.

What I would do differently?

Don't worry so much about getting stuck. Even if you find yourself redoing work, of course it's not ideal, but it's still a step toward completion.

What did I learn?

Smaller bites certainly works. I pretty much chose a single thing and went for it. Now here I am having completed what I wanted to right on schedule.

Monday, 5 March 2012

Sprint 2 Planning

05-03-2012

I’ve had to take a week break from project work to complete other assignments.
Planning for Sprint 2. The plan is:

Collision Detection. Get the collision forces and vectors calculated correctly.
Gravity: turn down the gravity to a slightly more realistic scale. The idea being that the gravitations might be less dramatic but more realistic and more importantly more manageable while ‘playing’ the game.

Triple all my time estimations.

While planning Sprint 2 I estimated that I’d need 13 hours to complete all the tasks I wanted to complete on this sprint. Looking at my current workload I couldn’t see how I could schedule in that many hours. So I had to push from of the tasks to a later sprint.

Friday, 24 February 2012

Sprint 1 demo and draft reflection.

It turns out that multiplying my time estimations by three wasn't even close to enough. but I've finally managed to get a grip on the framework and have created my first demonstration. I present to you... GRAVITY. It's only a 3 second clip because things get pretty crazy pretty quickly.

It's really just a proof of concept because I've not implemented the collision forces correctly, by which I mean at all. The forces just reverse upon collision. That's going to be in another sprint. But gravity works.

For those that might be interested and my own personal remembrance. Each screen object's gravitational pull is calculated using Newton's equation. The distance is measured in 1000m and the objects masses are variants of 100,000 metric tons. The ships mass is 355,000 which is the same as the USS Defiant.

What I would do differently next time?


Consider approaches more carefully.
To start with I approached the gravity all wrong. I initially set each object to gravitate toward everything around it based on it's own mass. I'm not sure why I went about it this way, I suppose I thought that it would just be easier... Anyway after 3 weeks of issues I approached things in a more accurate way and implemented the whole thing again from scratch in about 4 hours. How each object pulls every other object toward it based on universal gravitation.

Smaller bites.
This a fundamental principal of the Scrum approach. If things are taking too long, or are too hard, or if maybe you're just bored of it then the problem is too big. I spent a lot of time trying to understand very complex implementations of iOS and the game framework instead of just focusing on the little things that needed to be done. As soon as I broke the gravitation down to individual lines of code it came very easily.

What did I learn?
When it comes to gravity it's really all about the fine tuning. Pick a scale and stick too it, even if it's just to keep your head straight.

Friday, 20 January 2012

The Danger Meter

Did you realise that you could be in danger right now, if there was only some way to find out. Well now there is. Announcing the release of my third app, the Danger Meter.

It uses real statistics as well as some things that I just made up to tell you just how much danger you're in. Think of the applications, first off your safety, if you know how much danger you're in then you can plan accordingly.

Or just when you need an excuse to leave. "Sorry gotta go, I'm in danger."

You can verify certain claims made by your psychic.

The possabilities are endless.

Dangermeter is free and can be found here http://itunes.apple.com/gb/app/dangermeter/id494654553?mt=8

Wednesday, 18 January 2012

A new app.

There really will be an app for everything when I'm finished.

I'm feeling pretty proud of myself right now because I've just written an app from start to finish in about 2 hours. The only reason it took that long was because I was chasing a phantom bug in the programming, I never did find it, nor was I able to recreate the problem.

Anyway I wrote this little app that I've called FlipCards. My son is learning to read and from time to time he comes home from school with a set of new words to learn. He loves to play with my iPhone so while he watched the last half of The Lion King this evening I whipped up an app for him with all of his words so far.

It's not on the app store, for now I can't be bothered to get it approved, it can be found here instead. I might expand on it some time in the future and then get it approved... we'll see.