I went back today and filled in most of the missing major operations that Tangent was missing. At the moment, it's mildly stable as far as half-assed toy languages go. I'm considering polishing off a new nagging issues (escape sequences come to mind) and making a release for people to fiddle around with it.

The benefits will be that I'll get experience doing a release, I'll be forced to provide semi-coherent documentation, forced to get some source control/bug tracking implemented and I get the pressure to not look like a moron. And of course there's the feedback/suggestions/questions, though I suspect limited interest and limited intelligent feedback. I'd expect questions ('how's this work?','why's that not done?','what kind of idiot made that decision?') to be the most helpful bit there. See what people use/want.

The downsides are that nobody'll use it, the few bug reports I get will be of known bugs or dumb things I missed or 'works as designed' bugs, and that it'll be a bit of work for stuff that isn't making more stuff work. Plus it can't yet work with .NET types, so nobody will be able to do anything interesting.

I'll think about it over the weekend, and prolly aim to clean up the escape sequences since that needs to get done anyways. By the way, here's the current status of what is there and works:

Job hunting continues without progress. Moe work has all but ceased due to job hunting and motivational issues. In the meantime, here's a screenshot, and links to people actually doing some work.

[edit: by the way, I've never understood peoples' fascination with bitmaped fonts. They're tons more work, and often look terrible. It's not as though you're going to get your artist to make the millions of characters you'll need if your game ever leaves Romance language states... I'm sure I'm missing something, or just started after the advent of nice truetype font libraries like d3dxfont. So what is it? ]

I had some time tonight to work on Tangent. On the menu? Infrastructure for unit of measurement types (as the clever folks might've guessed by the title). Under the hood, a Measure inherits (awkwardly) from Type. It adds a list of UnitOfMeasure, a comparator, and a few util methods for now. A UnitOfMeasure contains a Measure and an exponent (in numerator/denominator form rather than float).

Type operators already exist for the usual suspects. They need to be extended to be aware of the new subtype (did I mention this was a little awkward?). The equality and subclassing operators actually didn't need to be modified; since measure types are goose types, that works itself out. Same with tupling, and intersection. Bind and select (to bind a generic param, and select a method from a group respectively) don't really apply. Union (inheritance) is a TODO [eventually, you'll be able to inherit from classes without data fields]. So umm, not much work needed here.

But measures need a few more operators. Type operators to construct new types from the existing types. The three here are multiplication, division, and exponentiation. They have 2 key jobs. First is to do the math on the exponents of the Measures. The second is to do the type fiddling with the 'value' of the measure. int of meters/int of seconds should yield float of (m/s) for example. To do this, the operators will look at the implemented multiply and division methods for the numeric types and use that type for the determination. That might run into problems, but should be an okay way to keep the things generic enough for user numeric types.

So, for those who followed last post's link or know of the F# implementation, this is going to be a little different. Instead of float, meters will default to float (or more accurately be declared as measure meters{}) so the use of the measure will be a little less verbose/more focused. Of course a different type might be generated... say meters with a complex unit type if its manipulated that way. In general though, I want the programmer to be able to use what numeric they need; not annoy them with conversions or accommodations just to get measure safety.

Eventually I aim to get aliases into measure definitions, probably with certain names marked as singular/plural/abbreviation to generate better names, and to give the option of a terse 'abbreviation-style' name.

After looking and asking about, I made an assembla page for Tangent. Included is a release for version 0.1 and some wiki/documentation stuff. It should only require .NET 2.0, and ideally just extract from zip and run the exe.

After a not so short time spent merely abusing the forums, I have tossed in some cash for a yearly subscription. God knows I've gotten more than that in advice, and will probably save more than that in book discounts.

Unemployment continues.

I dislike large consultancies. They are perhaps the antithesis of unions. Instead of unionizing against companies for higher pay and better benefits, companies go to consultancies, which give them the cheapest worker. Since the company doesn't actually hire the guy, they don't need to provide benefits, or treat them like a proper human since he's just going away after the 6 month contract.

Perhaps I'm too paranoid.

Hobby work sort of continues. Lack of sleep and generally being bummed out by unemployment make for poor motivators. I did though manage to doodle up the beginnings of a formal design doc for moe, based off of sunandshadow's one from a recent post in game design. Hopefully I will get the basics jotted down in word and then post them here or in game design for criticism and feedback.

Alas, I doubt too much will come of it; either flames about something petty or deafening silence.

Anyways, greetings! Thanks for coming by and reading. Here's to me actually remembering to post not too infrequently...

public static void main(){ local speaker cow = new speaker; local speaker sheep = new speaker;

cow.text = "moo."; sheep.text = "bleat.";

cow(); sheep(); }

// moo. // bleat.

And again there's some polish to be had. I'm not sure how well these puppies work when inherited (should be allowed, probably works for the straightforward case) or in various combinations when they're stuffed into groups. There's also the possibility of some wonky behavior with dispatching if these things are in a group (since the 'this' parameter is the functor itself).

I hope to get the absolute path declarations or some basic .NET importing done later today.

I've finished pretty much all of the non-game specific stuff, leaving a few days in my goal to re-fit Moe. The UI stuff got less fiddling than I wanted, which will be revisited.... later. Also there's a bit of moe changes that didn't get caught in the last backup. Those two will likely delay the schedule a little, but it's better to take the time than to half-ass something and pay for it ever after.

Since I upgraded my input handling a while back I've been meaning to add the stuff it allows to my Moe menus. The main menu now changes color if the mouse is over something clickable and makes a satisfying *bloop* sound.

I also added in the end of turn order processing. Now to add the ability to create Projects [edit:done] and code for Victory Condition checking and the game will be 'playable' for the very loosest definition of the term. The skeleton of infrastructure, game rules, and communication will be there leaving just a matter of content and similar fleshing of the skeleton into something meatier.

Had a little bit of time and worked a bit on delegates tonight. Turns out they weren't terribly difficult due to some good planning on my part, and because a lot of the stuff was already there. I still need to make normal methods not assignable, and stuff might break in corner cases, and I need yet to make the default delegate initializer be a no-op, and I need to make instance binding work so a instance/instance-method pair can be pushed into a delegate, but the 'simple' stuff works:

After exceptions work, the next step is the using block. The syntax is slightly different from C#. You can't have two elements in a using block (I forgot/didn't know you could even do that). And you can't just put a single expression after the using bit. Only the actual block, or another using segment. I was lazy and didn't implement the null check in the generated code (bug #77), so don't using something and then set it to null or fubar the initialization.

Probably now I'll go for a little release to get basic Dictionary importing, exceptions and using available (even if no useful .NET disposable objects are available yet...). Then it's time for bulldozer refactoring. The organization of the code is absolute trash, even without considering all the places where it's just architected oddly.

I've had a little bit of a rough time getting to where I am. I made the mistake of not studying computer science in college. Then I made the mistake of going to college early (before I was ready as it turns out), and did not finish. Thus I spent 7 years working my way up from phone monkey to sys-admin to QA. Then I got to spend a year unemployed as a wonderful complication of these mistakes.

After that though, I applied for an entry level dev job posted for about the 60th percentile (according to salary.com) and 15k off my previous position. Got an offer for 15% less than that, and took it. After all I'd not proved anything, and was hurting for cash, and realistically I had no good way to evaluate my skills. Might as well start at the bottom, pickup some missing skills, some years on the resume.

And things went well. I picked up Java and SQL better than half the existing team, got a better grasp of cvs, and spent a good while becoming acclimated to the huge system the team works on/with. I turned around a $1m/year client from a clusterfuck, developed the financial processing for our new setup, added creditcard processing to our site, trained up 3 new guys, about 4 dozen smaller tasks, and about 1/5-1/3 of the bug/tickets.

It was about 18 months in and review time rolls around (first one due to a quirk of the company HR policies). Great work, you've really helped take care of things with no oversight, you've picked everything up so quickly... 5 of 5. Astounding! I'm one of those 'straight B' guys. Work just hard enough to do well, but not hard enough to really excel. A 5 on the performance review is just unheard of. 'The checks will be out at end of month.'

So it's end of month. I am disappointed. To say the least really... more of a speechless, vitriol spewing rage machine. So a 5 on the performance review at this place merits, that's right... 3.5%. Barely INFLATION! (depending on who you ask). It is a fucking joke. Our site has about 250 people and we get, I kid you not, 1-2 emails a week about 'so-and-so has left to persue other opportunities'. I mean, I just thought it was the crappy benefits or super shitty christmas 'bonus' (crappy stuff with the company logo on it) or generally mind-numbing work (your standard 'fiddle with stuff in a DB' operation)...

And it has to be bad business! It has to cost like $40-50k every time someone leaves. It takes 3-6 months to train them into something useful because of the system complexity (10-25k in salary alone + benefits + facilities + time taken from person answering questions + $$$ lost by screw ups + $$$ lost by people waiting on the new guy + time/effort to job-post/screen/interview). Why in the world would you skimp and pay the entirety of the programmers inflation or worse?!? (remember, I got a 5. Others got a bit less than 3.5%)

You're going to lose 1/4 of the team or so (especially since there's 3-4 other guys in my situation of being 'entry level' because of some schooling or inexperience flaw) and are going to spend $40-50k a head to replace them.

Fucking stupid.

So basically I'm owner of a payment processing webapp, a dozen smaller apps, the head IT guy for a half dozen 7-9 figure financial processing clients, and the #2 guy to go to ask about any of the backend financial processing stuff... for 50th percentile salary of an entry level programmer.

One thing that's been making the journal rounds is this link from HopeDagger's journal. 'tis an article trying to categorize developers. I don't particular agree with it or that it even vaguely represents developers, though perhaps I've just not met too many....

It did though bring up something for me to think of, which I do think about quite a bit. I worry that I am not, and won't develop into a particularly good computer programmer. Odd I suppose, given that I've been programming off and on for some 15 years and currently make my living doing it.

I'm not sure quite what it is that I'm missing (or not found yet). I've gotten to the point where syntax isn't a big deal, I don't fight the compiler or the debugger anymore, a few hundred lines written in an intellisense IDE will compile the first try and is usually bug free; program design is pretty good: utilities are reusable, separate, and not too annoying to use. I can even look upon old code without horror and disgust!

There's something though I am missing right now. I can feel it. There's still a pretty huge rift between where I'm at and even folks like HopeDagger who've got some nice stuff to show. (who in turn seem to be another step below Ravuya and dgreen, who in turn seem to be a step below a few folks [whose names I cannot remember] who're then a step below the Sneftel's of the world) [of course I might be completely wrong; I've only forum posts to go by]

I'm not sure if it's experience or some missing knowledge or missing some other developers' viewpoints. Might just be confidence or acclaim for my product. Or of course it might just be how I am wired does not suit that analytical or creative sort who're particularly gifted.

I've no idea. I don't particularly fit into any of the four stereotypes either. I'm not particularly smart I've realized, but I'm not a log either. I get all my work work done (expediently), but don't even have tetris to show off from my hobby work. That just has a bunch of infrastructure and a few unpolished half-done demos and clones.

It's a bit worrying and frustrating and disappointing all rolled up. I suppose it'll just be one of those things I'll find out when it comes just like all the other big steps taken in improving my development skills.

No. Sleep is for people that actually want to get stuff done the next day. At least after you leave college...

After getting perhaps 5 hours of sleep total Friday and Saturday nights, nothing really got done. I don't even have wonderful stories of drunken revalry, just a blanket stealing wife, a dog with a tiny bladder and the Minnesota weather report.

I realized something today. I do not learn advanced concepts well. This is a known problem. There's probably a lot of reasons why this is, and I have a decent idea about a few of them, but today I thought of a new one.

I am pretty smart. Or at least all the tests always said I was, and looking around for the past 20+ years affirms that. The key problem I've had for some time is that I might be a little too smart, and it's led to problems later in life.

I remember when I was young my father (a mainframe programmer) would get calls late at night when a program went bad. He'd sit there, right after being awoken in the middle of the night without a computer and quote line numbers to the guy on the phone regarding what code to fix. My childhood memory wasn't quite that good, but spelling tests are easy when you can recall the image of the word in the spelling book.

The other thing that made schoolwork easy was the ability to pattern match and do kind of extrapolation. A sentence's grammar is something of this type followed by a different type, followed by... fits mentally right in with algebra behaviors. And that's usually how I'd learn new things. The new thing follows this pattern, or the new thing behaves like this known thing.

So these sort of things were great in school. Most of (US, public) school is just memorizing and regurgitating things. The rest is learning pretty similar concepts in a vaguely different form.

Now as an adult, they're kind of sucky. My memory is mostly gone. I'll remember the shape of the license board in FFX or where we left off in the last D&D campaign or the ID of the user I worked on yesterday or who the Steelers quarterback was when they tied Atlanta... but not reliably anymore. And code? No way. It doesn't fit into the shape or pattern or however my memory likes it.

And as it turns out, mapping new concepts into old concepts only goes so far. It goes a hell of a long way mind you, but eventually you need (a few) new concepts to really know something different. And it's hard to get them when you've never needed to.

Perhaps more significantly, I have problems communicating certain things to people. I'll tend to describe coupling oddly for example. That the data organization should line up like a tree; just as actual personnel organizations and areas of responsibility; just as a graph of sciences and their interactions or a game's tech tree. I tend not to make any distinction between any of them, and the abstract concepts of relations, interactions, parents, 'weak' sort of ownership are all still sort of there even if they're not commonly used in that particular tree. And that leads to problems sometimes when other people just don't think of them that way.

Anyways, as I was saying, I realized something today. Another facet of learning problems I have is when people abstract stuff for me. I was looking at the wikipedia entry for Limits in category theory and my brain shut off. Not exactly surprising. But this time I realized why I hate greek lettering and the general 'blah is defined as blah op blah to blah blah blah op' that is universal to higher math resources and not a few programming language books/articles/guides. I can't conceptualize greek.

I just can't form a symbol in my head to represent the first element of the relation/equation. X is fine. I know what X looks like, what it sounds like, and reading it I can get a handle to 'some placeholder named X'. Greek? Can't do it. Things that I'm not sure are placeholders, or are some new abstract concept I don't know? Can't do it.

Further, I don't learn by taking an abstraction and specializing it to cases. I learn by taking hard examples (which give me nice solid things to use as symbols/images while thinking) and extrapolating them into the general case. So compare that wikipedia article to this haskell tutorial regarding list comprehensions. That tutorial is what kinda set off the light bulb for me today. It was the first thing I thought of after my brain rebooted. It's the same sort of math gibberish I have problems with, but it starts with an example. No problem at all learning what it is and even the mathematical notation it's based off of.

It starts with a nice set as the visual symbol and then edits it as the tutorial goes along describing what the example comprehension is/does. It describes what everything is in the example, and relates it back to the mathematical roots so that mentally I can make that footnote. It then does progressively more complex things, but always again from an initial state. It works fantastically for me; someone who starts with a known concept and maps new concepts to it, expanding or adapting the original concept as needed.

For whatever reason, the threat of financial troubles (or perhaps the frugality that it promotes) provides programming motivation. At work I'm picking up Java for a project and as a general alternative to C++. At first glance it seems to be less good than I expected. I expected C# with some nuances. While the language itself sort of fits into that regard, the ancillary stuff in the process of turning design doc into running software is not close to C# niceties. There's also the fact that C# stuff 'does what you expect' for the most part and it's nuances are a bit deeper (delegate behavior is a common one for me). Java's seem to be more shallow (string operator + does concatenation but == doesn't do value equality?!?)...

And Moe got hours of work this evening. It's nice to look back on my code and think that much of the stuff is particularly elegant rather than horrid. Wonder when that happened...

Anyways, added a test map renderer, which is still broken. It did turn up a few incomplete things. Added turn messages, added parser switching for client commands once they join the game, added a quit to the screen, changed the game to run in psuedo-fullscreen (window the size of the screen on top) by default, realized that network communication sent along create messages for new objects but did not link them up! (oops) so fixed that and added code to handle discovery, added a quit to the console, added an ascii tree dump for game objects (and linked into console).

Next small step is the test renderer, then summary screens, then extending game objects, then turn processing, project stuff; lots yet to do before it's even vaguely playable. At least you'll be able to chat freely...

So, I get an email in my resume box this morning about a contract job up in Fargo. Fargo! It's not so bad, maybe a 4 hour drive; but far more than a commute, and I certainly don't want to move to Fargo. So in the spirit of the hockey trade deadline , I reply back "sure, I'd be interested if it'd be worth my while".

Now, when does that ever work? Right. Never.

I get a reply back asking what would make me go and work in Fargo. Absurd! I think about it, and decide that the common approach would be to work the week, and drive home on the weekends to be with the wife and dog. Okay. Ask for company to cover a temporary place, and healthy pay. Very healthy.

I mean, I'd work in Fargo for 6 figures above and beyond them paying for my housing expenses there, who wouldn't? Most likely, this counter will be met with deafening silence, if not a rude email asking me never to think about dealing with their firm again.

So what happens? That's right, they counter with 6 figures above and beyond them paying for all local and travel expenses during my contract.

Those times in your life when you are left totally and hopelessly speechless are rare...

Now we'll see if the actual interview goes through well. More to come.

Fixed the bug in the op-constraints. I must've written them while sleepy, because I made the op-constraint object a mutable class. Things that get bound with types need to be immutable (and you get a new type back). This led to problems when I ran two in a row (in this case, assignment). I would bind the two types to the op constraint, and it'd check them as passed. I would bind the next two types, but there was no type-parameters left to bind to, they were already filled! So when it went to check, it saw the old 2 params, and passed that along too.

Oops. They're now nicely immutable little things that return new things when bound with types.

I decided in the past few days that the name collision and inheritance cleanup needs three parts. Part one will be converting the mix-in operator from working on well-defined types to the half-defined types during compilation. Part two will be converting type comparison to the half-defined types available at compilation. Part three will be auto-generating new types for inherited member-methods.

That will allow (respectively):

- name collisions to be resolvable for cases where the types are identical. Abstract and virtual and initializer resolution should work.

- name collisions to be resolvable (or less punt-able at least) where the types are not identical. There's likely to be some cases where it's indeterminable. This is going to be the hardest part.

- methods -> method groups, virtual dispatch, snazzy stuff.

I got part one done tonight, which also included a mechanism for block comparison and some cleanup on the built-in types. Example!:

(the multiple declarations per class is odd, but allowed for now. It simulates inheritance, which mechanically adds members from the inheritees to the bottom of the declaration [and are then consolidated to 1 per name])

This code works fine now, printing:

4 b

bar::x is consolidated into foo::x since they have the same initializer. foo::x = 4 beats out its brethren because it's not virtual (or abstract). virtual on fields implies that the initializer may be overriden. The second half of the program shows the picking if both parts of the name collision are virtual; the type doing the inheriting (or to the left of the mix operation) wins.

Daerax asked if Tangent was going to support local functions. It seems he meant anonymous delegate things, so yes. They're very useful for just little tidbits of glue code (because there's no 'bind' equivalent in C#), and pretty vital in providing snippets as strategies. Since Tangent is making an increased emphasis on functions over objects, they gain that much more importance.

I went with C# lambda style syntax, since that does tend to be cleaner and a little less ambiguous for the parser than alternatives. Unfortunately, Tangent can't (nicely) support the type inference C# allows on params and on return type. So the Tangent syntax is a bit more verbose:

( method-parameter-list ) => return-type-expression block

It kinda sucks, because the verbosity might push people away from its use. And it will likely turn away functional language advocates who like things nice and succinct. I dislike succinctness in languages, but x => x + 1; is pretty damned clear.

Making the lambdas work required only a few changes. The syntax itself is constructed of bits already used elsewhere. When the lambda's block is compiled, the lambda's scope is simply added to the stack of scopes for name resolution. The name resolution got an added snippet of code to tack on a 'use the outer scope' placeholder (for locals/params/member vars in the outer method). That placeholder then becomes a VM opcode (access outer-scope) during compilation. The lambda itself is compiled into its own VM opcode that creates the method instance and binds the outer scope (params, calling-instance, locals) with it.

This should emulate C#'s closure behavior (and it's a bug if it doesn't), such as weird stuff like this:

public static void main(){ local foo A = new foo; local foo B = new foo;

A.Conditional = (int x)=>bool{ return(x10); };

A.Action = (int x)=>void{ print "A:" x " \r\n"; };

B.Conditional = (int x)=>bool{ return(x==42); };

B.Action = (int x)=>void{ print "B!\r\n"; };

A.Process(4); A.Process(42); B.Process(4); B.Process(42); }

// A:4 // B!

Binary parameter lambdas can be used as operators (not recommended) or stored in an operator delegate (more recommended). I will be providing a mechanism for combining them (and other arbitrary methods) into a method group, which should yield the ability to do stuff akin to pattern matching found in functional languages (as well as mildly nifty polymorphism on event-handling).

Next in the queue should be Properties. Though Disgaea 3 is coming out next week. Productivity that doesn't involve joyously evil tactical role playing is likely to decline precipitously.

Interview today went well, I think. The interview was a bit different as they were testing more that I would fit into their culture than anything else.

I rather wish more peoples' journal posts would post code rather than screenshots. It's more interesting to see new approaches for problems or how people vastly more skilled implemented something... I suppose most of the interesting things are a bit larger than is feasible to read through, and most of the code isn't free to give away.

I don't know, I'm tired of being demotivated most days by work and by too much [game] design indecision. Those days that I'm not actually dead tired that is. In the coming week I'd like to get the Tile code mostly sketched out. Resources, terrain types, perhaps the mapgen infrastructure.

I dislike most people. I dislike how much effort I need to spend in not offending them, being cordial, like-able even. Worse yet, I dislike holidays which are not of my religion. It's work enough dealing with people's craziness without adding in faith. Meh. I'm glad it's over.

In better news, I snuck in a little moe work this morning. I added 'use the rest' as a sizing option for the TableLayout. It's actually fairly complicated since it involves re-tying half of the columns/rows to calculate everything except the 'leftover' one rather than just assuming they come out right.

That change allowed me to redo the border widget to use the layout rather than the hackish non-reusable layouts I was using before. It's now much shorter, much more reusable, and a bit more configurable. Yay.

I had a little time today so I fixed up member access. foo(a,b,c).bar() now will work as expected and a few other oddities around member access have been corrected. As an added bonus, the code around them is smaller, cleaner and more kickass.

I also took a few hours to knock up the worst IDE known to man. Textbox for input, textbox for output, button to compile. Woo. I'll likely need to add a little to it because I suspect Tangent to really benefit from IDE support. Stuff like knowing what that identifier actually is, what that statement really will resolve to, what the order of operations for that is going to be. Usually I expect that to be clear, but it'll be easier to write ugly/obfuscated code and I think even good coders will run into scenarios where the IDE will help.

Now I have somewhere to add that, and a practical bit of code to better judge what is required/useful.

I recently got back into playing Magic: the Gathering after some years away. The game has improved greatly since my departure, so kudos there but not what prompts a journal entry today.

Something I found out about today was this article by one of the card designers that describes the three archetypes of magic players that they've identified and catered to. Very similar to the mud/mmo paper that I hope you're all familiar with.

There is though one notable difference. The heart/spade/diamond/club paper describes mostly what people like to do in the game. It focuses on needs that the game designer must fill. The magic archetype model focuses more on what tickles certain players' fancies since each player essentially follows the same process while playing a game.

And mulling it over today, I thought that the magic article describes a fairly good model for programmer archetypes. It makes sense, since the game was originally designed to help teach certain programming concepts. For those that didn't read the article, here's the quick and dirty:

Timmy: This player likes to make a splash. They don't look at downside so much, just powerful effects, solid creatures. Swarming and going overboard are good too. A memorable victory or particularly gruesome overkill will make up for a number of losses.

Johnny: This player likes to create things. They won't ever just take a deck from someone else or the internet. Taking the various cards and creating something unique or under some odd constraints is often more fun than the game. Getting a quirky deck to beat the 'consensus pick' will make up for a number of losses.

Spike: This player likes to win. They are happy playing the same deck over and over again, as long as it wins. They're also happy to take decks off the internet or just buy their way to victory. A win is a win to these players; losses are unacceptable.

And of course these things are just stereotypes. All players fit somewhere between these extremes, with a certain mixture of each.

Each trait lines up with programmer behaviors that are beneficial, and some that become vices when taken to the extreme. Looking at programmers I've known, they too tend to fall towards these categorizations.

Timmy: The programmer that likes power. They probably got into programming to 'make the computer do things' or show off to friends. They love automating things, making flashy apps (that maybe don't work quite right). Their vices are feature creep, over-engineering, and occasionally an unreasonable tendency towards low level programming. They provide vision for a project, and at their best are the team members who just extrude useful little tools and enhancements.

Johnny: The programmer that likes creation. They probably got into programming as an artistic outlet, or as a natural expression of problem solving. They love creating new things and solving weird problems. Their vices are 'not invented here' syndrome, being too 'clever' while programming, and occasionally a lack of attention to mundane or practical concerns. They provide solutions for a projects, and at their best are the ones who solve the hardest problems and create the most elegant solutions.

Spike: The programmer that likes production. They probably got into programming as a means to an end; perhaps to make a mod or automate some task. They love getting things done, now. Their vices are disregard of usability, cutting corners with testing/maintenance, and occasionally low technical knowledge. They provide drive to a project, and at their best are the team members who pump out code and keep the rest in line with their uncompromising demand for production.

The most interesting thing I at least noticed was that an ideal team requires a mix of these sort of archetypes to keep each other in balance. Another thing I noted was that none of the archetypes was the 'perfectionist' sort. Someone who desired quality over anything else. That would mean that programmers by default don't like testing, which I'm not sure is true. It might be that there's a style of programmer missing from here. In the original article, the sort who needs to tune and refine something to the best it can be falls into the Spike archetype. Perhaps then that should be split into the 'make stuff, be proud of it' and the 'hacker' archetypes.