Also see the list of articles, none to be taken seriously.

Developer talk follows. XCode 4 removes the PowerPC compiler, breaking package installers that try to build universal libraries.

When building most Python packages that incorporate native code, setup fails with an error like the following:
> pip install keyring
    /usr/libexec/gcc/powerpc-apple-darwin10/4.2.1/as: assembler (/usr/bin/../libexec/gcc/darwin/ppc/as or /usr/bin/../local/libexec/gcc/darwin/ppc/as) for architecture ppc not installed
    Installed assemblers are:
    /usr/bin/../libexec/gcc/darwin/x86_64/as for architecture x86_64
    /usr/bin/../libexec/gcc/darwin/i386/as for architecture i386
    keyring/backends/osx_keychain.c:117: fatal error: error writing to -: Broken pipe
    compilation terminated.
    lipo: can't open input file: /var/tmp//cdXmPvrV.out (No such file or directory)
    error: command 'gcc-4.2' failed with exit status 1

That was from pip, but distutils, setuptools, easy_install, and "python setup.py install" should all fail with a similar error.

To fix it, tell the compiler explicitly not to bother with PowerPC. Prefix the build or installation command line with this:

ARCHFLAGS="-arch i386 -arch x86_64"
If the install command needs to start with sudo, insert the above bit of text immediately afterwards, like this:
sudo ARCHFLAGS="-arch i386 -arch x86_64" pip install keyring
If installation doesn’t need sudo (for instance, installing into a virtualenv), you can enter the following command line once and the effect will last across multiple builds or installations for the remainder of the terminal session.
export ARCHFLAGS="-arch i386 -arch x86_64"
Read and Post Comments

How (not) to write Factorial in Java will hit home for any software developer who’s had to deal with over-engineered code.

I’ve come to view layers of abstraction as costing technical rent. It’s a concept worth distinguishing from technical debt. Rather than pushing a cost into the future, technical rent involves paying a manageable up-front cost by building the abstraction in code, and then needing to pay a similar cost each time programmers revisit the code, by rebuilding the same abstraction in their heads.

The worst part is when the layer of abstraction is justified as an intervention against potential technical debt: a small cost now to avoid interest payments in the future. In reality, the small cost has to be paid over and over, even if it turns out that the requirements never change in the particular direction that the abstraction anticipates.

You could call it defensive abstraction. The logic hides several assumptions:

  1. The requirements in that area will change.
  2. The abstraction, out of all possible abstractions, will happen to be the right one to cover the change.
  3. Adding a new case to the abstraction is simpler than changing the caller(s).
  4. At that future time, the programmer will choose taking on technical debt over adding the abstraction as needed. (This mainly applies if the requirements can change while the callers can’t, the practical likelihood of which varies with the situation.)
  5. The mental cost of rebuilding the abstraction, paid repeatedly throughout the life of the codebase, is outweighed by the interest paid on the technical debt, paid only until it’s corrected.

Occasionally the abstraction does actually provide enough benefits to outweigh its future costs, but failure to recognize the existence of those costs leads to poor decisions.

[Expanded from a comment I made on Hacker News.]

Read and Post Comments