The true test for Amazon

Leave a comment

I recently had a very interesting conversation with a former employee of Amazon. I love talking to people from iconic companies like this because I love getting insight and perspective of what it’s actually like to work there.

This is what I learned.

Amazon has among the strongest company culture anyone has every seen in the world. It’s pervasive in everything.

Recruitment. Your phone. Meetings. How you interact. You can ask anyone what the company’s core values are and they’ll be able to tell you.

Obsession on the customer.
Disagree and commit.

I am sure their are others, but it was disagree and commit that I found most interesting.

You can disagree with a decision, but once the decision is made you have to commit. There is no passive aggressiveness at Amazon because once the machine decides, it goes.

Most times it goes right. And produces amazing products. Other times it goes wrong, and it takes the market to correct (Amazon Phone).

What this means is if you are going to work at Amazon, you should expect conflict. And lots of it. This can be draining. This can be tiring. But that’s the culture and that’s how things work.

There is lots of turn over. In warehouses and the office. ‘Next man up’ is the term they use whenever someone gets burned out. They just feed the machine with another person.

This will work, I am told, so long as two things continue.

  1. Jeff Bezos is leading.

Jeff is a force of nature, and so long as he is driving, expect the company to be radical and do incredible things.

  1. The stock continues to rise.

Amazon stock has done very well. And so long and it keeps doing well, people will sacrifice their happiness for the golden handshake that is understood to be waking for them at the end of the rainbow.

The true test for Amazon will be when either Jeff stops leading, or the stock starts heading sideways. As soon as that happens, that’s when Amazons staying power will truly be contested.

There are lots of examples of companies falling off when the original founders leave (Apple and Sony). I don’t know what’s going to happen with Amazon. I guess we’ll just have to wait and see.

Objective-C – How to stub out an NSError unit test

Leave a comment

#import <XCTest/XCTest.h>

#import "Player.h"

// Mocking somethings (like NSError's) can be tricky in OCMockito.
// One alternative, if your mocks get too complex, is to simply manually stub.

// create a test class for the behaviour your want to stub,
// override the methods
// and then inject that into your SUT

// For example

// Test class we want to stub
@interface FakeHandler : Handler
- (BOOL)playTrack:(NSString *)track error:(NSError **)errorPtr;
- (BOOL)playAlbum:(NSString *)album error:(NSError **)errorPtr;
@end

@implementation FakeHandler

// Method / behaviour we want to override
- (BOOL)playTrack:(NSString *)track error:(NSError **)errorPtr {

    NSString *domain = @"com.MyCompany.MyApplication.ErrorDomain";
    NSString *desc = NSLocalizedString(@"Unable to connect to network.", @"");
    NSDictionary *userInfo = @{ NSLocalizedDescriptionKey : desc };

    *errorPtr = [NSError errorWithDomain:domain
                                         code:-101
                                     userInfo:userInfo];

    return NO;
}

- (BOOL)playAlbum:(NSString *)album error:(NSError **)errorPtr {
    return NO;
}

@end


// Now we can use all of this in our test.

@interface PlayerStubTest : XCTestCase
@property (nonatomic, strong) Player *player;
@property (nonatomic, strong) Handler *fakeHandler;
@end

@implementation PlayerStubTest

- (void)setUp {
    [super setUp];
    self.fakeHandler = [FakeHandler new];
    self.player = [[Player alloc] initWithHandler:self.fakeHandler]; // Dependence inject our stub
}

- (void)testNetworkFailure {
    // Now when we call our play method, we can expect a failure and test that it bubbles up
    NSError *expectedError;
    [self.player playURL:@"track.xxx" error:&expectedError];
    XCTAssertNotNil(expectedError);
}

@end

How to throw and test exceptions in Objective-C

Leave a comment

PlayerTest.m

- (void)testInvalidUrl {
    XCTAssertThrows([self.player playURL:@"foobar" error:NULL], @"Invlaid url.");
}

Player.m

- (BOOL)playURL:(NSString *)url error:(NSError **)errorPtr {
    if ([url containsString:@"track"]) {
        return [self.handler playTrack:url error:errorPtr];
    } else if ([url containsString:@"album"]) {
        return [self.handler playAlbum:url error:errorPtr];
    } else {
        [NSException raise:@"Invalid url" format:@"%@ must be a track or an album.", url];
    }
    return NO;
}

Dealing with Errors in Objective-C

Leave a comment

A reminder to myself around where and when to use NSError vs throwing exception in Objective-C.

This article gives a nice summary

https://developer.apple.com/library/content/documentation/Cocoa/Conceptual/ProgrammingWithObjectiveC/ErrorHandling/ErrorHandling.html

Use NSError for Most errors

When things go wrong in your app, due to

x network connectivity
x database been down etc

Use NSError and pass errors by reference.

- (BOOL)writeToURL:(NSURL *)aURL
 options:(NSDataWritingOptions)mask
 error:(NSError **)errorPtr;

Create an error pointer/reference and pass it to your method

NSError *anyError;
BOOL success = [receivedData writeToURL:someLocalFileURL options:0
 error:&anyError];

if (!success) {
 NSLog(@"Write failed with error: %@", anyError);
 // present error to user
}

The recover if possible and display an error to the user.

Generating your own errors

To create your own error define your own error domain.

com.companyName.appOrFrameworkName.ErrorDomain

Along with a unique error code for each error that may occur.

NSString *domain = @"com.MyCompany.MyApplication.ErrorDomain";
 NSString *desc = NSLocalizedString(@"Unable to…", @"");
 NSDictionary *userInfo = @{ NSLocalizedDescriptionKey : desc };
 
 NSError *error = [NSError errorWithDomain:domain
 code:-101
 userInfo:userInfo];

Then use as follows

- (BOOL)doSomethingThatMayGenerateAnError:(NSError **)errorPtr;

- (BOOL)doSomethingThatMayGenerateAnError:(NSError **)errorPtr {
 ...
 // error occurred
 if (errorPtr) {
 *errorPtr = [NSError errorWithDomain:...
 code:...
 userInfo:...];
 }
 return NO;
}

Exceptions are Used for Programmer Errors

- (void)testInvalidUrl {
 XCTAssertThrows([self.player playURL:@"foobar" error:NULL], @"Invlaid url.");
}

- (BOOL)playURL:(NSString *)url error:(NSError **)errorPtr {
 if ([url containsString:@"track"]) {
 return [self.handler playTrack:url error:errorPtr];
 } else if ([url containsString:@"album"]) {
 return [self.handler playAlbum:url error:errorPtr];
 } else {
 [NSException raise:@"Invalid url" format:@"%@ must be a track or an album.", url];
 }
 return NO;
}

Objective-C initializer unavailable

Leave a comment

#import <Foundation/Foundation.h>

@interface Calculator : NSObject

@property (nonatomic) double result;

- (void)pushOperand:(double)operand;
- (void)add;

- (instancetype)init NS_UNAVAILABLE;
+ (instancetype)new NS_UNAVAILABLE;

@end

How to stub a class for unit testing

Leave a comment

Here is an example of how to override an existing class and create a stub for your unit tests in objective-c.

PlayerStubTest.m

#import <XCTest/XCTest.h>

#import "Player.h"
#import "Handler.h"

@interface PlayerStubTest : XCTestCase
@property (nonatomic, strong) Player *player;
@property (nonatomic, strong) Handler *stubHandler;
@end

// overide default behavior of handler for those methds you want to test
@interface StubHandler : Handler
- (BOOL)playTrack:(NSString *)track;
- (BOOL)playAlbum:(NSString *)album;
@end


@implementation StubHandler

- (BOOL)playTrack:(NSString *)track {
 NSLog(@"Stub track");
 return NO;
}

- (BOOL)playAlbum:(NSString *)album {
 NSLog(@"Stub albumn");
 return NO;
}

@end

@implementation PlayerStubTest

- (void)setUp {
 [super setUp];
 self.stubHandler = [StubHandler new];
 self.player = [[Player alloc] initWithHandler:self.stubHandler];
}

- (void)testExample {
 [self.player playURL:@"track"];
}

@end

 

When you run this you should see ‘Stub track’ in the console.

 

OCMockito – How to handle returning NSError

Leave a comment

I find mocking pointers (specifically NSError’s) a bit of a pain in OCMockito. But here is a way I get things working if I just want to set an expectation, and have it return NULL.

Handler.h

@interface Handler : NSObject
- (BOOL)playTrack:(NSString *)track error:(NSError **)errorPtr;
@end

PlayerTest.m

#import <XCTest/XCTest.h>

#import <OCHamcrestIOS/OCHamcrestIOS.h>
#import <OCMockitoIOS/OCMockitoIOS.h>

#import "Player.h"

@interface PlayerTest : XCTestCase
@property (nonatomic, strong) Player *player;
@property (nonatomic, strong) Handler *mockHandler;
@end

@implementation PlayerTest

- (void)setUp {
    [super setUp];
    self.mockHandler = mock([Handler class]);

    self.player = [[Player alloc] initWithHandler:self.mockHandler];
}

- (void)testPlayTrack {

    // given
    [[given([self.mockHandler playTrack:anything() error:NULL]) withMatcher:anything() forArgument:1] willReturnBool:YES];

    // when
    [self.player playURL:@"spotify.track.xxx" error:NULL];

    // then
    [verify(self.mockHandler) playTrack:anything() error:NULL];
}

Older Entries

%d bloggers like this: