Saturday, September 28, 2013

Cocoapods - ARGV - Returns Options as a Hash, OCMock only for Tests target.

Tonight I actually made my cocoapods objc port use cocoapods. Most of the point of this adventure is for me to deeply learn cocoapods. I initially wanted to replace some manually written stubs in my first ARGV test with OCMock, but it OCMock doesn't support stubbing -[NSObject description], so I didn't actually need it. I imagine I'll need OCMock at some point, and it was also a good exercise in learning how to setup cocoapods dependencies only for specific targets, so I left it in.
I also tried implementing the "returns options as a hash" spec, but ran out of time. Ben Chatelain suggested I use FSArgumentParser:
but I don't think that's going to work. However, FSArgumentParser depends upon CoreParse, and that looks like it'll work out great. I'll probably use FSArgumentParser as an example of how to use CoreParse for my purposes, so I think Ben's suggestion will pay many dividends. I love knowing smart people.

Friday, September 27, 2013

Cocoapods adventures

We've started using Cocoapods at work, and it seems like a really great system. However, it is written in ruby, and I hypothesize that it would get more participation from the community if it was written in Objective-C. Also, since Cocoapods is a specification as well as a system, it would benefit from a separate (though in this case not clean-room) implementation. Thus, I'm going to rewrite Cocoapods in Objective-C and blog about my journey along the way.
Thankfully, Cocoapods looks pretty modular, and it looks like it has good tests. I'm starting with CLAide, which is Cocoapods' command-line aide. This has RSpec tests, which I know nothing about, but I can generally figure out what they're doing just by reading the text.
Tonight, I just wanted to start something. I wasn't too concerned about crazy progress. I simply cloned CLAide and figured out how to run the existing RSpec tests. I found the .travis.yml file with a script command that looked promising, so I tried running that, and installed required gems (bundler, rspec) until it worked.
Next, I just converted the first two tests in the first spec (argv_spec.rb). I'm doing at least one commit for each test I convert. Also, I'm keeping all this work on a separate branch. Eventually, I'll just have a parallel Foundation command-line tool project that I'll keep up to date.
Tomorrow, I'll tackle the first real piece of parsing necessary. Hopefully, I'll have ARGV converted by Sunday night.

Saturday, June 15, 2013

All the smart kids are writing blog posts about exceptions

Since all the smart kids are writing blog posts about exceptions, I figure if I write one, I might be considered smart by association. :)

I favor automation in all things. I will happily supply metadata with my code that will allow it to be automatically verified to be correct, or at least more correct than it could be without the metadata. This colors my viewpoint on exceptions.

This all started because of Craig Buchek's tweet:
I prefer code that enumerates exactly what it will return and how it might fail via the type system. I used to prefer checked exceptions everywhere for this, but I've since changed to just returning a either a good return value or an error.
Old Java:
class Foo {
  Foo foo() throws FooException {
    if (Math.random() < .5) {
      throw new FooException();
    } else {
      return new Foo();
    }
  }
  Foo bar(Foo foo) throws FooException {
    if (Math.random() < .5) {
      throw new FooException();
    } else {
      return foo.foo();
    }
  }
  String baz() throws BazException {
    try {
      Foo foo = foo();
      Foo barFoo = bar(foo);
      return "I ran the gauntlet with " + barFoo;
    } catch (FooException f) {
      throw new BazException(f);
    }
  }
}

With this code, you can capture all your handling for common errors in one place, and because FooException is a checked exception, the compiler will happily tell you if you forget to handle your error cases. Yay!

However, errors are data just like everything else, and they don't need to be shunted off into a separate world. One might assume that if we remove exceptions, we'll end up with a lot of annoying if checks:
class Foo {
  Either<Foo, FooException> foo() {
    if (Math.random() < .5) {
      return new Either<>(new FooException());
    } else {
      return new Either<>(Foo);
    }
  }
  Either<Foo, FooException> bar(Foo foo) throws FooException {
    if (Math.random() < .5) {
      return new Either<>(new FooException());
    } else {
      return foo.foo();
    }
  }
  Either<String, FooException> baz() throws BazException {
    Either<Foo, FooException> eitherFooOrFooException = foo();
    if (eitherFooOrFooException.left()) {
      Either<Foo, FooException> eitherBarFooOrFooException = bar(eitherFooOrFooException.left());
      if (eitherBarFooOrFooException.left()) {
        return "I ran the gauntlet with " + eitherBarFooOrFooException.left();
      } else {
        return new Either<>(new BazException(eitherBarFooOrFooException.right()));
      }
    } else {
      return new Either<>(new BazException(eitherFooOrFooException.right()));
    }
  }
}

It doesn't have to be that way. Jessica Kerr describes how in detail. However, Java idioms and language limitations do make these functional styles difficult. So, if you're in Java-land, I won't look down upon you for sticking with Exceptions, as long as they're checked.