Archive for the 'Programming' Category

Follow this category with a feed.

Reinventing the Wheel: How to Average Numbers

Other the past week I’ve been writing some code for work that has to happen periodically and then re-schedule itself so it can happen again. We never want two of this process running, and we want the process to automagically expand its time window if it takes longer than we think it should, because arbitrary magic numbers are a Bad Thing™.

So I keep track of each time we run and keep an average of how long the job takes every time. But I don’t want to keep around every run time, so all I do is keep around the average, and how many times the job has actually run. From those two numbers plus our current run time I can approximate a new average and use that to schedule the next run. I came up with a nice little algorithm that pushes the average around whenever a new number comes in. It works great:

def find_new_avg(old_avg, old_count, new_number)
  weight = (new_number.to_f - old_avg.to_f)/(old_count+1)
  old_avg + weight
end

But in my tests, I noticed something; this doesn’t just approximate the average. It actually calculates the average. It’s right all the time.

I did few quick Google searches and checked Wikipedia couldn’t find anything. I looked at it again. I pared down the code to the above (it used to be a bit more complicated). I tried more tests. It still worked.

I asked my friend Nick if he had ever heard of this algorithm. He hadn’t. He pushed some numbers at it and decided it did work. We did a video conference over Skype and worked out the algebra, and we proved that it did work. I said: “It just seems insane that I could have invented–by accident– a new way to average numbers that uses less space than any other way I’ve ever seen.”

I searched online again, and finally found it. It’s from The Art of Computer Science, Volume 2, by Donald Knuth.

Knowing that I’m not the first one to discover this algorithm restores my faith in how much research has been done in the past (although my faith in Google’s capabilities was somewhat shaken), but the fact remains that, not knowing about it beforehand, I discovered a reliable algorithm that does what I need in a fraction of the space it could take. And that makes me happy, even if I did reinvent the wheel.

Getting TracRedirect to work with Trac 0.11rc1

I’m a big fan of Trac, and I use it for project management when I’m given the choice. It has a few issues, but nothing a little plugin magic can’t fix. On of my favorite plugins is TracRedirect, which allows me to make one page point to another and make the browser redirect there, so “Customers” points to “Customer”, and I can be lazy when I’m typing other pages and use whichever one makes the most sense.

But TracRedirect does not play nice with the latest version of Trac, 0.11. In fact, it makes 0.11 die. This is bad.

I don’t really know Python. I mean, I can get by, but I don’t really know it. So the prospect of patching some code for a plugin in a language I don’t know for a project whose code I’ve never seen is at once intimidating and exciting. The reason I’m a programmer is because the exciting won, and I fumbled around until I got it working. The diff between the latest svn code and my own is after the jump; it’s mostly just updating IWikiMacroProvider to take the new args 0.11 passes its way, but there’s another little fix to include the redirect stylesheet using the new method, as the old method didn’t seem to work reliably.

Read the rest of this article »

Centering a Window Via AppleScript

John Siracusa recently lamented the loss of one of his classic OS add-ons; the ability to center the current window onscreen via a global key combo.

Well, the global key combo can be had in any number of ways, but here’s an AppleScript that’ll do it for you. It finds the screen size using the technique Craig Hockenberry showed to John Gruber, then finds the current frontmost window and resizes it. Saved as a Script into my Script Menu, it seems to work fine.


on run
	tell application "System Events"
		set fma to first process whose frontmost is true
	end tell

	tell application (name of fma)
		set fmwBounds to bounds of first window
	end tell

	tell application "Finder"
		set desktopBounds to bounds of window of desktop
	end tell

	set fmwWidth to (item 3 of fmwBounds) - (item 1 of fmwBounds)
	set fmwHeight to (item 4 of fmwBounds) - (item 2 of fmwBounds)

	set desktopWidth to (item 3 of desktopBounds) - (item 1 of desktopBounds)
	set desktopHeight to (item 4 of desktopBounds) - (item 2 of desktopBounds)

	set newX to (desktopWidth / 2) - (fmwWidth / 2)
	set newY to (desktopHeight / 2) - (fmwHeight / 2)

	set newBounds to {newX, newY, newX + fmwWidth, newY + fmwHeight}
	tell application (name of fma)
		set bounds of first window to newBounds
	end tell
end run

Lazy Decision Making

We recently cleaned out my parents’ garage so that it could be torn down to make room for an intergalactic expressway a storm drain. Amongst the millions of childhood memorabilia was this book, which was the first taste I got of computer programming.

It taught us Apple BASIC, and we used it to program our Apple IIc that had one external drive. We had a bunch of floppies, a few of which we loaded ProDOS onto and toiled away.

If I recall correctly, my older brother was the one who had actually purchased the book (or convinced my parents to buy it for him) so it was ostensibly his, and he assuredly read through the thing quicker than I did, and understood more of it that I did even when I had read most of it. I was, after all, 8 at the time.

But with that book and that computer we set about to write our own games. I still believe that every programmer of my generation gets into computers for the games. I wrote a little game where you could run through computer systems a la Shadowrun, breaking ICE and finding valuable files. I tried to do HiRes graphics, which was why the game never got finished.

This was before I understood anything about design. Not that you could design in BASIC, but still.

What I did was try to figure out everything I would ever need to do, I wrote it down in a big list, and then I started at the top of the list. I wrote the main screen. I wrote the login. I wrote the first bit of navigation into the fake computer system. I got overwhelmed and never returned.

I was following what is now called the Waterfall model, where you spend a whole lot of time figuring out what you’re going to do, and then you write it all down in excruciating detail and make sure that it covers everything, then you check again. Then you check again and start programming.

This model was invented when you programmed with punch cards and had to make sure that everything worked reasonably well the first time. If it didn’t, you’d have to change something, and changing things was nigh impossible, because you can’t just insert a new row on the punch card: it’s cardboard. So you do proofs and flowcharts and loop invariants and whatnot, trying to make sure that when you go to the trouble of making the punch cards, everything works out.

Contrast that with what most programmers do today, which is sometimes referred to as Extreme Programming, XP, Agile Development, or simply Iterative Development. Whatever you call it, you figure out only what the next step is and you program that. Then you test it. Ideally, you write a test for it so that the test can be run by an automated process. Then you move on to the next step.

Developers like this method because they get immediate results (and they do a lot less paperwork). Managers like it because they get lots of feedback (and they do lots less paperwork). Customers like it because it allows the developers to respond to feedback, which means the customer gets something he actually wants, instead of something he kind of wants.

Iterative Developement is part of a larger trend in the computing world toward deciding things later, because later you will have more information with which to make the decision. It’s called Lazy because you make the decision only when you need to, as opposed to Eager decision making, when you make a decision when you think of the question.

Static typing is eager decision making. You have to decide everything up front when you don’t know enough information, and if you change it later, you’re screwed.

This is one of the reasons why the trend in computing is toward dynamically typed languages, and away from static typing. It allows you to make decisions later (at runtime), when you have more information. That allows you to be freer in your programming because you’re not making decisions based on guesswork. But most of all, it allows you to skip an entire step of development (laying out a class hierarchy) that will inevitably cause you pain in the long run when class A doesn’t inherit from class B, and neither implements interface C. This step becomes a much looser and more manageable hurdle when you can just make sure that the right methods are there, or better yet just mix in a module you already have.

The obvious next question is: what other decisions are we making too early? I wouldn’t be surprised if there are some huge ones out there. Paul Graham is fond of pointing out that the startups he funds often create a completely different product than they set out to create, and that seems like a pretty large decision to make lazily.

Alan Kay’s ‘97 OOPSLA Keynote

JavaScript is the new Smalltalk:

Regular readers are quite tired of me pointing to this video, Alan Kay: The Computer Revolution hasn’t happend yet. Keynote OOPSLA 1997, but I think it’s quite fundamental to understand that Alan Kay had a vision for the web, and though his understanding of the role of HTML in the world of 1996 was flawed, it seems the collective web has spent the last ten years building exactly what he described, with HTML/SVG being the display substrate and JavaScript being the code to drive that display.

(Via BitWorking.)

I admire Alan Kay for a lot of the things he did, but this video is one of the slowest, most meandering talks I’ve ever listened to. He is talking about incredibly important things that I’m genuinely interested in, but it’s really hard to plow through.

He is very obviously whip-smart and well-read. He cites academic papers and historical incidents with ease. He uses things like cystic fibrosis as metaphors. It all makes perfect sense, but the pacing and the delivery are so deadpan that my attention is wandering.

It does have some kickin’ quotes in it, though:

  • I made up the term object-oriented, and I can tell you that I did not have C++ in mind.
  • There is no idea so simple and powerfule that you can’t get zillions of people to misunderstand it.
  • At the very least, every object should have a URL.
  • It’s very easy to grow a baby six inches. They do it a couple dozen times in their life and you never have to take them down for maintenance.
  • One of the reasons why this meta stuff is going to be important… is this whole question of how do we really interop over the internet five and ten years from now?
  • Let’s not do it in Smalltalk; that’s too slow. Well let me tell you something: there’s nothing more inefficient than spending ten years on an Operating System that never works.

All told, it is a strong argument against “Worse is Better.” His point is similar to extreme programming, whereby you build a small thing (Smalltalk) that works, then use that to bootstrap the system and slingshot yourself forward. But he comes at it from a classic “MIT approach” of figuring out a good design for the bootstrap, and then using incremental development from there. That all sounds perfectly great– and indeed it seems to be what the web has ended up as (as Joe Gregorio was pointing out)– but it sure as heck didn’t work for the things Mr. Kay was trying to do it with. Why is that?

Are Features The Enemy?

The Software Conspiracy:

If a computer magazine publishes a roundup of word processors, the central piece of that article will be the “feature matrix,” a table showing what word processing programs have which features. With just a glance, the reader can quickly see which word processors have the richest sets of features, and which have the least features.

(Via Coding Horror.)

The next time I write a review of something, I’m going to make a feature matrix that looks like this:

  Windows   Macintosh   Linux
Did the job X X x
I liked it   X X
Would not kill development team if I met them   X X

Simulating HttpContext with Sessions and POSTs for ASP.NET

Here’s a little something I’ve been hacking together at work, so that we can do some unit testing on my current project. It’s largely based on this post by Phil Haack, but adds support for using Sessions (by assigning to the Session property) and doing Http POSTs as well as GETs, both of which are necessary for our tests, and were requested in the comments on Phil’s post.

As you can see, the Session support is bare-bones at the moment, because what’s there satisfies my needs for now. If you wander outside just stashing stuff in the session, you’ll get a handy exception to tell you that you’ve surpassed what the code can currently do.

Hope it helps you!

namespace ElectronicFieldBook.Tests
{
    /// <summary>
    /// Allows us to set the HTTP context with a valid simulated request
    /// From <http://haacked.com/archive/2005/06/11/Simulating_HttpContext.aspx>
    /// </summary>
    public static class WebRequestSimulator
    {
        public class WithoutSession
        {
            public static HttpContext Get()
            {
                return Get(“localhost”, “”, string.Empty);
            }

            public static HttpContext Get(string host, string page, string query)
            {
                SimulatedHttpRequest req = new SimulatedHttpRequest(“GET”, host, page, query);
                return HttpContext.Current = new HttpContext(req);
            }

            public static HttpContext Post(string host, string page, string query, string body)
            {
                SimulatedHttpRequest req = new SimulatedHttpRequest(“POST”, host, page, query);
                req.Body = body;
                return HttpContext.Current = new HttpContext(req);
            }
        }

        public static HttpContext Get()
        {
            return AddSessionState(WithoutSession.Get());
        }

        public static HttpContext Get(string host, string page, string query)
        {
            return AddSessionState(WithoutSession.Get(host, page, query));
        }

        public static HttpContext Post(string host, string page, string query, string body)
        {
            return AddSessionState(WithoutSession.Post(host, page, query, body));
        }

        public static HttpContext AddSessionState(HttpContext context)
        {
            IHttpSessionState ssn = Session;
            if (ssn != null)
            {
                SessionStateUtility.AddHttpSessionStateToContext(context, ssn);
            }
            return context;
        }

        private static IHttpSessionState session;
        public static IHttpSessionState Session
        {
            get { return session; }
            set { session = value; }
        }

        /// <summary>
        /// Used to simulate an HttpRequest.
        /// </summary>
        public class SimulatedHttpRequest : SimpleWorkerRequest
        {
            private string verb;
            private string host;
            private string body = string.Empty;
            public string Body { get { return body; } set { body = value; } }

            public SimulatedHttpRequest(
                string verb,
                string host,
                string page,
                string query)
                : this(“/”, AppDomain.CurrentDomain.BaseDirectory, verb, host, page, query, null)
            { }

            public SimulatedHttpRequest(
                string appVirtualDir,
                string appPhysicalDir,
                string verb,
                string host,
                string page,
                string query,
                TextWriter output)
                : base(appVirtualDir, appPhysicalDir, page, query, output)
            {
                if (string.IsNullOrEmpty(verb))
                    throw new ArgumentNullException(“verb”, “Verb cannot be null nor empty.”);
                if (string.IsNullOrEmpty(host))
                    throw new ArgumentNullException(“host”, “Host cannot be null nor empty.”);

                this.verb = verb;
                this.host = host;
            }

            /// <summary>
            /// Gets the name of the server.
            /// </summary>
            /// <returns></returns>
            public override string GetServerName()
            {
                return host;
            }

            /// <summary>
            /// Maps the path to a filesystem path.
            /// </summary>
            /// <param name=”virtualPath”>Virtual path.</param>
            /// <returns></returns>
            public override string MapPath(string virtualPath)
            {
                return Path.Combine(this.GetAppPath(), virtualPath);
            }

            public override string GetHttpVerbName()
            {
                return verb;
            }

            public override byte[] GetPreloadedEntityBody()
            {
                return new UTF8Encoding().GetBytes(Body);
            }

            public override int GetPreloadedEntityBodyLength()
            {
                return GetPreloadedEntityBody().Length;
            }

            public override string GetKnownRequestHeader(int index)
            {
                bool isPost = verb == “POST”;
                if (!isPost) return base.GetKnownRequestHeader(index);

                if (index == HeaderContentType)
                {
                    return “application/x-www-form-urlencoded; charset=utf-8″;
                }
                else if (index == HeaderContentLength)
                {
                    return GetPreloadedEntityBodyLength().ToString();
                }

                return base.GetKnownRequestHeader(index);
            }
        }

        public class SimulatedHttpSessionState : IHttpSessionState
        {
            private IDictionary objects = new Dictionary<object, object>();

            private bool isAbandoned = false;
            public bool IsAbandoned
            {
                get { return isAbandoned; }
                set { isAbandoned = value; }
            }

            public void Add(string name, object value)
            {
                objects.Remove(name);
                objects.Add(name, value);
            }

            public void Clear()
            {
                objects.Clear();
            }

            public int Count
            {
                get { return objects.Count; }
            }

            public System.Collections.IEnumerator GetEnumerator()
            {
                return objects.Values.GetEnumerator();
            }

            public void Remove(string name)
            {
                objects.Remove(name);
            }

            public void RemoveAll()
            {
                Clear();
            }

            public void RemoveAt(int index)
            {
                throw new Exception(“The method or operation is not implemented.”);
            }

            public object this[int index]
            {
                get
                {
                    throw new Exception(“The method or operation is not implemented.”);
                }
                set
                {
                    throw new Exception(“The method or operation is not implemented.”);
                }
            }

            public object this[string name]
            {
                get
                {
                    return objects[name];
                }
                set
                {
                    Add(name, value);
                }
            }

            public void Abandon()
            {
                isAbandoned = true;
            }

            public int CodePage
            {
                get
                {
                    throw new Exception(“The method or operation is not implemented.”);
                }
                set
                {
                    throw new Exception(“The method or operation is not implemented.”);
                }
            }

            public HttpCookieMode CookieMode
            {
                get { throw new Exception(“The method or operation is not implemented.”); }
            }

            public void CopyTo(Array array, int index)
            {
                throw new Exception(“The method or operation is not implemented.”);
            }

            public bool IsCookieless
            {
                get { throw new Exception(“The method or operation is not implemented.”); }
            }

            public bool IsNewSession
            {
                get { throw new Exception(“The method or operation is not implemented.”); }
            }

            public bool IsReadOnly
            {
                get { throw new Exception(“The method or operation is not implemented.”); }
            }

            public bool IsSynchronized
            {
                get { throw new Exception(“The method or operation is not implemented.”); }
            }

            public System.Collections.Specialized.NameObjectCollectionBase.KeysCollection Keys
            {
                get { throw new Exception(“The method or operation is not implemented.”); }
            }

            public int LCID
            {
                get
                {
                    throw new Exception(“The method or operation is not implemented.”);
                }
                set
                {
                    throw new Exception(“The method or operation is not implemented.”);
                }
            }

            public SessionStateMode Mode
            {
                get { throw new Exception(“The method or operation is not implemented.”); }
            }

            public string SessionID
            {
                get { throw new Exception(“The method or operation is not implemented.”); }
            }

            public HttpStaticObjectsCollection StaticObjects
            {
                get { throw new Exception(“The method or operation is not implemented.”); }
            }

            public object SyncRoot
            {
                get { throw new Exception(“The method or operation is not implemented.”); }
            }

            public int Timeout
            {
                get
                {
                    throw new Exception(“The method or operation is not implemented.”);
                }
                set
                {
                    throw new Exception(“The method or operation is not implemented.”);
                }
            }
        }
    }
}

Twelve Benefits of Writing Unit Tests First

Twelve Benefits of Writing Unit Tests First:

How do you solve a software problem? How do they teach you to handle it in school? What’s the first thing you do? You think about how to solve it. You ask, “What code will I write to generate a solution?” But that’s backward. The first thing you should be doing— In fact, this is what they say in school, too, though in my experience it’s paid more lip-service than actual service— The first thing you ask is not “What code will I write?” The first thing you ask is “How will I know that I’ve solved the problem?”

(Via Coding Horror.)

I’ve written a lot of code. And recently, I’ve been trying this whole test-first thing out, and I’m really happy with the results. Everything they say in the article is true, and it makes a lot of sense, but I think the real benefit is far simpler:

Writing tests for code that doesn’t exist yet means that you come at the design from the point of view of a user with a specific problem, instead of the normal point of view of a coder trying to make his Brilliant New Solution™ that is both a dessert topping and a floor wax.

This plays into one of the other ideas XP expounds: Do the Simplest Thing That Could Possibly Work. Instead of trying to solve all the problems you might ever have, you tackle the problem at hand right now by writing a test that is the problem at hand right now, and deal with the rest later. Sometimes later is in a few minutes, sometimes it’s in a few days, and sometimes it’s never, but Test-First Programming lets you split those tasks down into more manageable chunks, and that’s huge.

Back when I worked at ParaSoft and was peddling Unit Test software, one of the biggest problems we found was this huge string of dependancies most code has built into it. In order to test class X, you need to create an instance of class Y to pass into the constructor. And Y, of course, needs a Z. But you can’t make a Z without an A and a B, which requires this environment property set just so. This seems insane because it is insane: no one sets out to write like this but every company I visited had code that looked exactly like this.

And it’s because they were trying to bolt unit tests on at the last minute. If they had tested first, they would have thought “This is insane. We didn’t set out to write like this” and they’d be right, and they’d fix it, and (key point) their architecture would benefit because they had to think it through before writing the code and “unit testing” with the compiler.

That’s the power of test-first: it makes you see the code from the vantage of the programming who’ll have to make use of it instead of the one creating it, and that’s the seat you’ll be occupying for most of the class’ lifetime, anyway.

Larry Gonick Math Cartoons

Larry Gonick, Cartoonist of Awesome Stuff:

Gonick Cartoon

Larry Gonick, creator of the various Cartoon History of the Whatevers, has a series of mathematical cartoons that explain things like warp drives and chaos theory. Great stuff.

(Via Coding Horror.)

Operator Overloading

Something that had been bothering me for a month just clicked in my brain and I had to write it down before it wandered off somewhere. No one who regularly reads this blog will understand, but here goes.

C++ has operator overloading that leads to code that no one understands. If I define a class Car and a class Tire, I can override some random math operator like, say, += on Car, and make it so that that sets the Tire of my car.


Car myCar = new Car();
myCar += new Tire(); //calls my "+=" operator, but this code is unreadable

C# has properties, which means that I can define a class Car that has a property Tire, so now I can define the relation between the car and the tire, and write code like this:


Car myCar = new Car();
myCar.Tire = new Tire(); //calls Car's property code for "Tire"

But Ruby has operator overloading of a different sort than C++, which gives it a lot of the clarity that C# properties exhibit, so in Ruby I write:


myCar = Car.new();
myCar.tire = Tire.new(); //calls Car's "tire=" method

C++ has operator overloading, but not in a way that makes sense; you can create the relations your class has with those classes you happen to know about when you write your class, but there are no relationships, which is what programming in large projects is all about.

Moral of the story: shortcuts that make your code less readable are only short until you have to re-read your code, which may be tomorrow or may be next year. It’s generally best to avoid such “shortcuts,” which go by such names as “C++ operator overloading,” “assignments in conditions,” and “Perl.”

The Other Side of the Podium

When I was at ParaSoft, I did a number of trainings when I went to some company and showed them how to use whatever product they had purchased. We did one-day tutorials all the way up to five-day classes, where we would use our product with the customer’s code.

This week I am attending a training for Microsoft C#, and it’s interesting to be the one out in the audience with a computer in front of me, and not the one in front with a projector screen behind me.

One thing I noticed pretty early on is how hard it is to type and listen at the same time. When we’re writing code– or even copying code from a book– whatever our instructor is saying might as well be Swahili. But I also know from experience that some people will type 78,000 words per minute, and then talk loudly to their neighbor, or start checking email, or whatever. With developers especially, you can lose them to whatever problem they were tackling back at their cube before they were told to attend your meeting.

Another thing is that I notice little presentation tricks I used to use. For instance, our trainer has been talking non-stop about some small annoyance that causes a slowdown when your web service is running the first time, when IIS is compiling your code. And he’s doing it over and over, because he knows that there’s a simple fix, and when he reveals it we’ll all think “well, it’s a good thing that’s not a problem anymore.” It’s not REALLY a problem now, but it sure seems like one when it’s mentioned every hour. We used to do something similar to talk up flaws in developer processes that are, technically, flaws, but that no one really cares if they’re fixed. But it sure looks great when you can point to it and say “we fixed that.”

Bottom line: don’t believe everything a trainer tells you.

Windows Is So Slow, but Why? - New York Times

Windows Is So Slow, but Why? - New York Times:

“And Apple had the advantage of building on software from university laboratories, an experimental version of the Unix operating system developed at Carnegie Mellon University and a free variant of Unix from the University of California, Berkeley. That helps explain why a small team at Apple has been able to build an operating system rich in features with nearly as many lines of code as Microsoft’s Windows.”

It’s a great little thing called industry standards. It took Apple a long, long time to find them, but they are like strapping a rocket booster to development.

At work I program in Java, and one of the most recent things I did was implement our report system. It works like this:

  1. A user makes an HTTP request to a web page.
  2. A Java Servlet gets the request.
  3. The servlet makes a series of SQL calls to a database.
  4. The servlet then marshalls that data into XML.
  5. The XML is then transformed in XHTML using XSLT.
  6. The user gets a normal-looking web page that they can print, save, or whatever.

Each step in that process is an open standard of one form or another. That entire system took me a little less than a month to make, while I was doing other tasks. If I had had to start from the beginning and do all of this by myself, it would take forever. And I would have to return to my boss and tell her that our ship date would have to be pushed back. Repeatedly. Which is what the Windows guys are having to do. Repeatedly. Because Microsoft doesn’t follow standards unless it was one of the guys at the standardization table. They’re doing better with RSS and Atom, but they have a ways to go before they realize that there’s a lot of projects out there that they can leverage, if only they’d try.

Tim and Tiger

Tim Bray isn’t so sure he likes Tiger. And I’d agree, but with enough caveats that I thought a blog post would be worthwhile.

OS X has gone through five major revisions since I’ve been using it. It had more before, but since I didn’t use them I don’t really know about them, and won’t comment about them here.

The first release was Public Beta. This was a developer’s release: it was slow and had some bugs and everyone knew that it wasn’t a finished product. That was part of the name.

Release two was Mac OS X 10.0, which was the real deal. It was the ‘come and get it release’ that was supposed to signal that normal, everyday people could now run UNIX on their desktop and it would be pretty and they wouldn’t have to use UNIX just to use UNIX. This was UNIX for the rest of us: this was an end-user release.

Next came 10.1, which was for everybody, because the one feature in 10.1 was speed. If you’re keeping track at home, you can almost declare this as a non-release: this is what 10.0 was supposed to be, but for reasons of compiler– and press– release cycles couldn’t be.

Then we move into the big cats and get Jaguar, 10.2. This was a release for the developers again: we got Quartz Extreme APIs and Rendezvous Bonjour and a significant update to most of the internals. There was much rejoicing on the mailing lists, and there was the beginning of a Renascence in the Mac Shareware world. Jaguar contained little for the end-user, but it contained a lot of springboards that the developers could launch off of and bring amazing new things to the end user.

Panther (aka 10.3) was the result of Apple using all of those springboards and launching everything in the OS up a notch. Panther was targeting at the end user again: the foundations didn’t shake much (we did get Bindings), but the world shifted: the bar moved up because it was just expected that every app would pull out all the tricks: after all, everything in the system did.

And that brings us to 10.4, Tiger, which with CoreData and CoreAudio and CoreVideo and CoreNameYourComponentHere is to my eye quite definitely a developer release. Apple is shoving more tools in the toolbox, and seeing what the community can do with them. When it’s obvious which ones are the good ideas, Apple will take them and run with it: persistent SQL stores backing the iApps? Let’s hope.

What Apple is doing is alternating between the releases for the devs and the releases for everybody. But you can’t just give the devs special builds, because the interesting part of the experiment is what gets built, and in our networked world the interesting apps are the ones that rely on the network effect of having lots of installations. Quote the Cluetrain, “Markets are Conversations,” and the conversation is more interesting the more voices speak.

I’ll also note that this theory is made even better by the fact that it cannot be proven: if Apple started admitting that every other release was developer-oriented, then non-developers would stop buying those releases, and the whole house of cards falls down.

As long as it stays up, though, it’s a neat trick. It pulls the platform forward in leaps and bounds, and it does a pretty nice job of growing the third-party developer scene: every other release, Apple is providing lots of new areas to create new apps, to make new waves, and to ride those into the sunset (which may or may not be the next major release).

But I think the best part is that it dovetails wonderfully with the quick revision cycle they’ve been peddling: Apple never appears to be behind the curve, but the developers and the platform always seem to be on the leading edge. And that’s where all the alpha geeks want to be.

MSN Virtual Earth

I have this problem with MSN Virtual Earth. It looks like this:

Virtual Earth with missing chunks

Apparently, the borg have landed in Costa Mesa, and their ship is resting at the corner of Mesa Verde and Baker.

But it’s more pervasive than that. They seem to be everywhere I look. They seem to have invaded our world quite thoroughly; everywhere from New York to Phoenix. Resistance truly is futile.

Oh, wait: maybe it’s just this:

Toolbar shows load errors

Oh, they just can’t get everything to load right. I would have thought that was an important thing to check before releasing. I guess that’s why they’re the biggest software company in the world and I’m just a smartass.

ApTel: Whither AltiVec?

So there’s talk all over the web about Apple moving to Intel processors, but one thing I couldn’t find was the fate of AltiVec. AltiVec, or the Velocity Engine, is the part of the G4 and G5 that does the heavy lifting when you need giant numbers crunched: it is the reason why G5s have been seen in a few supercomputers lately. It is one of the biggest selling points that the more recent PowerPCs had, but I couldn’t find anyone who was talking about it. What was the future of AltiVec?

Well, I finally found out from Apple’s own docs, page 53 (emphasis added):

AltiVec instructions, because they are processor-specific, must be replaced o Macintosh computers using Intel microprocessors. You can choose from these two options:

  • Use the Accelerate framework. The Accelerate framework, introduced in Mac OS X v10.3 and expanded in v10.4, is a set of high-performance vector-accelerated libraries. It provides a layer of abstraction that lets you access vector-based code without needing to use vector instructions yourself or to be concerned with the architecture of the target machine. The system automatically invokes the appropriate instruction set.
  • Port AltiVec code to the Intel instruction set architecture (ISA). The MMXTM, SSE, SSE2, and SSE3 extensions provide analogous functionality to AltiVec. Like the AltiVec unit, these extensions are fixed-sized SIMD (Single Instruction Multiple Data) vector units, capable of a high degree of parallelism. Just as for AltiVec, code that is written to use the Intel ISA typically performs many times faster than scalar code.

So the long and the short of it is that all the work you’ve put into those optimizations is effectively dead, unless you did them recently and wrote to the Accelerate framework.

This may seem like a little thing, but AltiVec was one of the big reasons why Apple was seeing an upsurge in popularity among the sciences; big pharmaceutical and biotech firms were using G5s to run their massive numbers. Can ApTel compete?