ryanmccuaig.net

piatti del giorno 77

Tue 19 Aug 2014

Things finally settling down to some semblance of normalcy.

piatti del giorno 76

Mon 26 May 2014

Had a great time at Polyglot 2014 on the weekend, but oof. Brain full.

piatti del giorno 75

Mon 12 May 2014

More time on compsci fundamentals and CAD programming lately, so living the dream.

piatti del giorno 74

Tue 15 Apr 2014

Man, these links really build up when you’re swamped for a month.

piatti del giorno 73

Fri 14 Mar 2014

danah boyd: “That’s one of the things that teenagers struggle with about Facebook: how to deal with multiple contexts simultaneously. Usually we address context collapse using alcohol in face-to-face environments, like at weddings. Online we don’t have that, so we have to deal with a lot of awkwardness.”

piatti del giorno 72

Tue 11 Mar 2014

Finally getting to play with the shiny new Python scripting engine in Vectorworks. (See ya, Pascal. It’s been real).

Meet the new boss

Fri 28 Jun 2013

Today, I wind up eight years working as a project architect for Acton Ostry Architects. As of tomorrow, 29 June 2013, my full-time employer is The Office of Ryan McCuaig. We1 make software for architects, engineers and contractors.

The provisional motto is “Computing for making better buildings.”

Like most fields right now, building design and construction has never before had so much data available, and such an uneven distribution of skills and tools that might let us make sense of it and free our thinking for higher-order problems. Even if it were tenable now (i.e., it isn’t), is only becoming less so to waste brainpower on tedium better handled by these infernal yet stupendously amazing machines.

I’ve been an architect-in-training and then registered architect on the sharp pointy end of getting buildings built since 1999, and–along with having earned a degree in computer science–I’ve worked hard to become a skilled web, Mac/iOS and CAD plugin developer alongside that. So, I’m thinking I know a thing or two about the intersection of buildings and computers.

If you also care deeply about making buildings, know we could be doing it better and want to talk about the possibility of working with ORM, please get in touch.

I want to end with a thank-you to Mark Ostry, Russell Acton and my talented colleagues at AOA, and to my former employer Bruce Carscadden, for the opportunities, support, trust, banter, mentorship, cameraderie, and for showing me what relentlessness in pursuit of design excellence really looks like.

  1. Well, yeah, a ‘royal we.’ For the moment.

Feeling democratic

Wed 12 Jun 2013

I’m confused by the high-profile venting going on from within the iOS design community about the UI overhaul of iOS 7.

So, yeah. It’s not perfect.

My own major beef is that it fails the squint test. Badly.

But a few things are making my excitement outweigh my minor misgivings:

The intellectual rigour is a great gulp of fresh air

There’s a system now: grids, type scale progressions, palettes, a philosophy of how the spatial layers overlap and maintain place, and a devotion to simulating how real objects feel instead of mainly how they look.

The absence of a system and too-shallow realism is what bugged me about Corinthian leather and the book edge in iBooks. Leather was wholly arbitrary. The page edge didn’t get thinner relative to the number of virtual pages remaining.

I grant that the new system may be imperfectly applied. But it’s definitely more coherent and makes clear what needs to be fixed, and who thinks that the low-hanging fruit won’t get fixed as we report problems?

We can be as expressive with ‘feel’ effects as ‘look’ effects

The frameworks for providing parallax effects based on the gyroscope and adding physics to enhance the illusion that you’re manipulating real objects are incredible. Motion effects and dynamics are now very easy to apply and play with, which democratizes them and makes it possible for the less technically-inclined among us to participate in building up the relatively uncharted design language around them.1

The closest comparison I can think of is the effect the LaserWriter had on print design. I expect the same period of taking things way too far and backing off. But the LaserWriter completely transformed print design. And I expect the same here.

The best interfaces will outdo Apple’s anyway

In the end, UIKit defaults and system apps, like IKEA, establish direction and are meant to raise the average case. Because I love analogies, I’ll bring up Renzo Piano and LEED. LEED is a points-ranking system for measuring how sustainable a building is. It’s a blunt instrument that fails to consider a lot of subtle design issues and architects like to grumble about it. A lot. Piano has been one of the foremost ‘green’ architects since the 1970s. To my knowledge, he refuses to consider participating in LEED certification because (among other reasons) his obviously-sustainable approaches are too subtle to get much credit within the general-purpose system. He doesn’t need the system, though. And on balance, it helps the less skilled among us make greener buildings.

The new iOS 7 design defaults will do the same for app design. If you’re not a designer who needs it, go custom and do better, just like most of the ADA winners do now.

  1. (Someone needs to write the motion-effects peer of the exquisite The Elements of Typograhic Style and pronto. We now have not one but two extremely subtle forms of design expression to master).

Hello, Lagrangian

Mon 4 Mar 2013

You should be testing your code. As should you be flossing. My prolific friend Rob Rix of RXCollections fame is seeking to give you one less excuse on the testing front, anyway. His theory: writing tests inline with the code under test reduces drag and encourages one to write more tests.1

His Lagrangian test framework (L3 for short) brings inline tests to Objective-C.2

Using some clever preprocessor hacks, the inline tests are stripped out of production builds. Set the -DDEBUG=1 compiler flag, and some even more clever preprocessor hacks will turn the test macros into a web of test objects and blocks, lying latent in the binary. Shine a black light on it by handing the binary to the test runner, and you’ll know if this specific binary is passing its tests.

We have no separate test classes (that you generated, anyway), no separate test files, and no separate test bundle.3

We’ll walk through testing “Hello World,” so you can get the flavour of how to get started.4 You’ll need Mac OS X 10.8, Xcode and git.5

Here are the steps we’ll follow from the shell:

  1. Clone the sample project and build the executable.
  2. Add inline tests.
  3. Add the L3 framework.
  4. Show a test failure.
  5. Get to green.

1. Clone the sample project and build the executable.

Our test application is a Foundation command-line tool that looks like this:

#import <Foundation/Foundation.h>

int main(int argc, const char * argv[])
{
  @autoreleasepool {
    NSLog(@"Hello, Lagrangian");
  }
  return 0;
}

Ok, so. Not the most technically-challenging program for modern hardware. Start by cloning the sample project from Github, building an executable and running it:

$ git clone -b start git://github.com/rgm/hello-lagrangian
Cloning into 'hello-lagrangian'...
remote: Counting objects: 52, done.
remote: Compressing objects: 100% (45/45), done.
remote: Total 52 (delta 3), reused 51 (delta 2)
Receiving objects: 100% (52/52), 152.34 KiB, done.
Resolving deltas: 100% (3/3), done.
$ cd hello-lagrangian
$ make
clang -fobjc-arc -framework Foundation -o hello main.m
$ ./hello
2013-03-03 09:43:15.349 hello[36100:707] Hello, Lagrangian

(Note that this checks out the start branch. Switch to the master branch to see what the project should look like when we’re done).6

2. Add inline tests.

We’ll need to define at least (a) a single suite, and (b) a single test within that suite. These are defined at the top, outside of any function or method. We’ll also need to add (c) a hook for the test runner within the top-level autorelease pool.

For religious reasons, the test we’ve added must first fail, then we’ll fix it.

#import <Foundation/Foundation.h>

@l3_suite("main");                       // (a) suite declaration
@l3_test("this test should succeed") {   // (b) test case
  l3_assert(YES, l3_equals(NO));
}

int main(int argc, const char * argv[])
{
  @autoreleasepool {
    l3_main(argc, argv);                 // (c) test runner hook
    NSLog(@"Hello, Lagrangian");
  }
  return 0;
}

Now we’ve broken make. Let’s fix it.

3. Add the L3 framework.

We need to tell the compiler about @l3_suite(), @l3_test() and l3_main() syntax by including a header file, and linking against the L3 library. It can currently be built as an iOS static framework, OS X dylib or OS X framework. I prefer the OS X framework for our purposes: it includes the headers and it’s easy for the compiler to find them.

Add this line to main.m below the Foundation include:

#import <Lagrangian/Lagrangian.h>

You can either build the framework from the L3 source and copy it into the project folder, or pull a prebuilt one from the project repo:

$ curl -L -O https://github.com/rgm/hello-lagrangian/raw/master/Lagrangian.tgz && tar zxf Lagrangian.tgz

Edit the executable target in Makefile to add the framework and enable DEBUG:

hello: main.m
  clang -fobjc-arc -F . -framework Foundation -weak_framework Lagrangian -DDEBUG=1 -o hello main.m

Now make and run the executable. If all went well, you should see the same log output as step 1.

We haven’t actually run the tests yet. But, because we set the DEBUG flag, they’re in the executable, lying in wait. Note that the Lagrangian framework gets weak-linked; none of the test code will be run nor the framework loaded unless asked to by the test runner.

4. Show a test failure.

To see test results, we’ll run our executable within the test runner. Things are a little different with a full Cocoa app (ie. one that passes off to NSApplicationMain()), and hopefully a future tutorial will show that.

Like the library, you can either build the test runner from the L3 source and copy it into the project folder, or pull a prebuilt one from the project repo:

$ curl -L -O https://github.com/rgm/hello-lagrangian/raw/master/lagrangian-test-runner.tgz && tar zxf lagrangian-test-runner.tgz

Add a test target to Makefile. This tells the test runner where to find the L3 library and executes it, passing it the command-line invocation needed to run our executable:

test: hello
  DYLD_FRAMEWORK_PATH=. ./lagrangian-test-runner -command hello

And now, run the test target. Note that we set a DYLD environment variable to tell the dynamic linker where to nab L3 from:

% make test
DYLD_FRAMEWORK_PATH=. ./lagrangian-test-runner -command hello
Test Suite 'hello_lagrangian' started at 2013-03-03 22:58:54 +0000

Test Suite 'main' started at 2013-03-03 22:58:54 +0000

Test Case '-[main this_test_should_succeed]' started.
main.m:7: error: -[main this_test_should_succeed] : 'YES' was '1' but should have matched 'l3_equals(NO)'
Test Case '-[main this_test_should_succeed]' failed (0.000 seconds).

Test Suite 'main' finished at 2013-03-03 22:58:54 +0000.
Executed 1 test, with 1 failure (0 unexpected) in 0.000 (0.003) seconds

Test Suite 'hello_lagrangian' finished at 2013-03-03 22:58:54 +0000.
Executed 1 test, with 1 failure (0 unexpected) in 0.000 (0.007) seconds

If all went well, you’ll see a log of the test run with our (expected) failure.

5. Get to green.

And now, make the test pass by changing the assertion in main.m from

l3_assert(YES, l3_equals(NO));

to

l3_assert(YES, l3_equals(YES));

Back at the shell, rebuild the executable and start a test run:

% make test
clang -fobjc-arc -F . -framework Foundation -framework Lagrangian -o hello -DDEBUG=1 main.m
DYLD_FRAMEWORK_PATH=. ./lagrangian-test-runner -command hello
Test Suite 'hello_lagrangian' started at 2013-03-03 23:04:31 +0000

Test Suite 'main' started at 2013-03-03 23:04:31 +0000

Test Case '-[main this_test_should_succeed]' started.
Test Case '-[main this_test_should_succeed]' passed (0.000 seconds).

Test Suite 'main' finished at 2013-03-03 23:04:31 +0000.
Executed 1 test, with 0 failures (0 unexpected) in 0.000 (0.003) seconds

Test Suite 'hello_lagrangian' finished at 2013-03-03 23:04:31 +0000.
Executed 1 test, with 0 failures (0 unexpected) in 0.000 (0.007) seconds

And with that–assuming you agree there’s not much to refactor here–we’ve completed one full TDD cycle using Lagrangian.


I hope this has piqued your interest to learn more. As of this writing, L3 is barely four months old yet it’s already achieved that neat test-framework crane-building-tail-swallowing trick, and so the best place for learning more about using L3 is to look over the extensive self-tests in its own source.

(Things can change fast. If you find a broken step, I’d appreciate it if you’d let me know).

  1. (Kind of like keeping the floss in the washroom, I suppose).

  2. If, like me, you washed out of physics before getting to Lagrangian mechanics, the name is a reference to something I don’t actually understand, but that I am for the time being taking on faith is a rich and appropriate metaphor.

  3. Well, sort-of true. Yes, there’s a octest bundle target in Xcode, but that’s mainly to trick Xcode’s test machinery. This project won’t have one.

  4. Note that you wouldn’t normally do all this at the shell. I’m reducing the number of moving parts for learning purposes. Lagrangian has extensive Xcode integration, and Rob is performing yeoman’s work in keeping it working. Frustrating and mounting evidence suggests that Apple may not rely on its own unit-testing tools as much as one would hope.

  5. You could make this work with older versions of OS X or even Linux / GNUStep. For convenience, the project uses binaries pre-built against 10.8 using Xcode 4.6. You could build your own. The real prerequisite is a relatively recent version of clang, since L3 makes heavy use of blocks and ARC.

  6. git checkout master