The State of PC Upgrades

I’m not the first to point this out, but PCs have really reached the point of diminishing returns recently in many respects. While technological progress marches on, there’s not a tremendous subjective difference between this year’s hottest CPU and a mid-range part from two years ago. In particularly intensive applications, sure, you’ll notice it; but for the majority of users, there’s not much incentive to upgrade. For the rest, there’s likely to be one or two parts that will really get you a big benefit, while you’ll be happy with the rest of the system being 2-3 years old, and those parts will likely satisfy you at least 2-3 years more.

I used to operate on a two-year upgrade path: every other year I’d build a new machine, and in the years between, I’d make some individual upgrades (additional RAM, additional disks, faster GPU). Now I’m looking more at a 5-year path, with individual upgrades every year or two between. I really think that, at this point, anyone with a machine built in the last 3 years has little to benefit from a total overhaul. There are a few areas where everyone is likely to see real improvements:

  • Operating system: if you don’t have Windows 7, get it, along with any upgrades required to meet the minimum specs. I can’t recommend Windows 8 for any user for any purpose at the current time.
  • RAM: if you have a 32-bit system (unlikely if it’s less than 3 years old), you should have 4GB of RAM. If you have a 64-bit system, you should have 8GB; possibly 16GB for computer audio, video, or graphics professionals, or users running intensive virtual machines.
  • SSD: you should have an SSD. Honestly. If you don’t have one, get one. They’re getting cheaper by the day, and will give you a real, noticeable performance improvement across the board. Your SSD should host your OS and applications, at the least. Let Windows 7 handle optimizing system configuration for the SSD; just do a clean install onto the SSD and let it do the rest. Ignore all the “SSD tuning tips” that require changing OS settings or disabling services. 99% of them are wrong, and the other 1% are debatable.
  • Display: IPS displays are a world away from your typical bargain LCD, and they’re getting cheaper constantly. You can now get a name-brand, 24″ IPS display for under $300. If you’re a computer professional, you probably want at least two.
This is, of course, a generalization, and depending on how you use a PC, you will have different needs. Audio professionals will obviously see benefits from discreet audio hardware. Imaging and video professionals will want a fast CPU. 3D graphics professionals will want a fast CPU with as many cores as they can get, as well as a fast GPU. 3D gamers will want the fastest GPU they can get – possibly upgrading GPU every year to 18 months.
My system is two years old now. So far I’ve upgraded from 4GB of RAM to 8GB, and I’ve added a 256GB SSD drive. I’m planning on replacing my single 23″ TN LCD with dual 24″ IPS LCDs soon. In another year or two I’ll probably upgrade the GPU, and in three years or so I might be in the market for a total replacement – or I might not. I wouldn’t be shocked to find that, three years from now, brand-new hardware doesn’t put enough distance between itself and what I’ve already got to make it worth the money. Only time will tell.

Video Game Business Models

I see an opportunity, particularly for indie game developers, in developing new business models for sellings games. There are currently three predominant business models in the gaming industry:

  1. The major retail model: release a game for $60 in major retail outlets, with a huge marketing push, looking for a big launch week payout. Steadily lower the retail price by $5 or $10 a couple of times a year as it ages, until it eventually ends up in the $10 bargain bin. In the meantime, release DLC or expansions to try to get more money out of existing players, and raise the total cost for those buying the game late for $20 at retail up to or above the original $60 price tag.
  2. The subscription model: the game itself is cheap or free, but players must pay a monthly fee (usually around $15) to play the game. This is most common in the MMO genre, but can be seen elsewhere as well.
  3. The “freemium” model: the game itself is free, but players pay for in-game items, bonuses, avatars, skins, or other unlockable content, on a per-item basis. This is most commonly done with a points system, where players buy points with cash, and then spend the points on in-game items. This is particularly popular with mobile games, but is fairly widespread in general.
All three have found great success with the big game publishing houses, and the last one has found a good deal of success for indie game developers. But that last option doesn’t work with all game types, and has two possible outcomes: either all the purchasable content is purely aesthetic, and doesn’t seem worth paying for, or it offers real in-game advantages, and gives players the option to “pay to win”, leaving those who can’t or don’t pay feeling unfairly handicapped.
I think there’s another option waiting in the wings, however; I call it the value model, for lack of a better term, and it works something like this: release a game at a very low price point, and do the exact opposite of the major retail model. Players can purchase the game at any time and gain access to all content, past, present, and future. As content is added through updates and expansions, the price goes up accordingly with value. This has several effects on the sales dynamic:
  • For indie developers, releasing at an initial low price point can help to boost sales when a large marketing budget is unavailable, and help to fund further development. It’s also easier to sell a game at a lower price point before it gets popular, and easier to set a higher price point as popularity increases.
  • For players, it helps to avoid feeling like they’re being swindled, or continuously squeezed for more money; they know up front what they’re paying, they know what they’re getting right away, and if it’s worth it, then whatever content (which is free for them) is a welcome bonus.
  • From a marketing perspective, it gives the opportunity for a reverse discount: if you announce ahead of time that new content will be released (and therefor the price will be going up), it can push people to make the purchase (to lock in the lower price while guaranteeing the upcoming content) the same way a true discount would, without actually having to lower the price. The price is effectively reduced because prospective buyers are aware that the price is about to increase.
Does anyone know of any examples of such a model being used for games? I’ve seen it occasionally in game content (e.g. Unity assets and the like), but I don’t think I’ve seen it for a public game release. I’d be happy to hear thoughts on the subject in the comments!

Convenience Languages

I’ve come to see the uncertainty of untyped and interpreted languages as something of a curse. In a strongly typed, compiled language, you know ahead of time that the code is at least trying to do what you want it to; you know you didn’t typo any variable, function, method, or class names. You know you didn’t misuse or misunderstand a function, passing one type when another is required. Sanitizing inputs and returns is a matter of checking bounds, not types. Type-safe comparison is a non-issue.

After working with PHP and JavaScript extensively, as well as dabbling in Perl, Python, and Ruby, I miss the basic assurance you get from a language like C/C++, C#, or Java that if it compiles, nothing is completely wrong. Even in HTML, you can validate the markup. But in PHP or JavaScript, you probably don’t know about even a major, simple error until run-time testing (unit or functional).

To me, that’s a nightmare. I miss knowing. I miss that little bit of certainty and stability. With an untyped interpreted language, you may never be 100% certain that you’ve not made a silly but fatal mistake somewhere that your tests just didn’t happen to catch.

These are languages of convenience: easy to learn, quick to implement small tasks, ubiquitous. But they just aren’t professional-grade equipment.

Developing software is both an art and a science. I make an effort every day not to just be a coder, but to be a code poet. That’s hard to do on the unsure footing of a dynamic language. I won’t argue that these languages let you do some neat tricks; on the other hand, I also won’t discuss the performance issues. My concern is purely quality.

Is it possible to write quality code in a dynamic language? Absolutely. Unfortunately, it’s harder, and far more rare – not just because it’s challenging. It’s mainly temptation. Why would the language offer global variables if you weren’t supposed to use them? Why have dynamic typing at all if you aren’t going to have variables and function return values that could have various types depending on the context? Even with the best intentions, you can commit these Crimea against code accidentally, without even knowing it until you finally track down that pesky bug 6 months down the road.

Using (and abusing) these sorts of language features makes for messy, sloppy, confusing, unreadable code that can be an extraordinary challenge to debug. Add to that the fact IDEs are severely handicapped with these languages, unable to offer much – if any – information on variables and functions, and unable to detect even the simplest of errors. That’s because variable types and associated errors only exist at runtime; and while an IDE can rapidly attempt to compile a source file and use that to detect errors, it can’t possibly execute every possible code path in order to determine what type(s) a variable might contain, or function might return.

I know most of this has been said before, and every new language will inspire a new holy war. I’m writing this more because all of the above leads me to wonder about the growing popularity of dynamic languages like Python, Ruby and JavaScript, and the continued popularity of PHP. Anyone care to shed some light on the subject in the comments?

Simplicity, Flexibility, and Agility

Agile programming is supposed to be about flexibility in the face of changing requirements. It’s supposed to be about rapid development and iteration. But all too often it ends up being like classical methodologies in many ways. Many agile methodologies drown developers in process, taking time away from development. Test-driven development is a brilliant concept, but it puts more time between planning and iteration, making it more difficult to deal with changing requirements, not easier, and increasing the burden of change and the cost of refactoring.

Every developer wants carefully, precisely defined requirements. Developers often try to handle changing requirements by developing for flexibility, but flexibility often comes at the cost of added complexity. Trying to write-in endless flexibility to allow for changing requirements is very much akin to premature optimization. You end up doing a whole lot of work to make some code “better” – more flexible in this case, versus more performant in the case of optimization – when you don’t yet know which code really needs it and which code doesn’t.

“There are two ways of constructing a software design: One way is to make it so simple that there are obviously no deficiencies, and the other way is to make it so complicated that there are no obvious deficiencies.” –C. A. R. Hoare 

Often the best way to maintain flexibility is through simplicity. A program that meets its requirements with the simplest possible implementation is one that will be naturally flexible, maintainable, stable, and manageable.Of course, intelligent development plays a major role; making appropriate use of design patterns can do a lot to improve both flexibility and simplicity. Key design tenets like DRY, YAGNI, separation of concerns, and avoiding premature optimization (including overarchitecting for flexibility) help keep complexity down and productivity up.

What if requirements change? What if the simplest possible solutions isn’t as extensible? Good news: having invested in the simplest possible solution, you’ve lost little in development. You haven’t built anything that wasn’t strictly necessary. The new solution will still aim for simplicity, still reap the same rewards. By keeping things simple, you’ve kept down the cost of change.

Software development is a learning process by nature; you’re building something that’s never been done before, or at least building something in a way that’s never been done before. Innovation is at its heart, and learning is the personal experience of innovation. That being the case, every iteration has value in what’s learned, even if the code is later removed or replaced. The experience of writing it adds value to the team, and the team defines the value of the end product.

Many readers may think of targeting simplicity as a given, but it truly isn’t; while simplicity is often a goal, all too frequently it takes a back seat to other concerns, or is abandoned altogether because simplicity becomes far more difficult to achieve with many of the popular frameworks and libraries available today. Frameworks have to aim for maximum flexibility in order to be successful; in order to be general-purpose, they can’t make many assumptions, and they have to account for a whole host of different usage scenarios and edge cases. This increases the complexity of the framework, and accordingly, the complexity of any implementation using the framework. The fewer assumptions the framework can make, the more effort a developer has to put in just telling the framework what she’s trying to accomplish.

I can’t count how many implementations I’ve seen that are drastically more complex than necessary, simply because they have been forced to apply the conventions required by their chosen framework; and even following those conventions, they’re still left managing arcane configuration files, and tracking down bugs becomes an epic undertaking requiring delving deep into the inner workings of the framework and libraries. All too often, the quick-start “hello world” app is far more complex with a framework than without it, and adding functionality only makes the situation more bleak.

So, what does all this add up to? Here’s the bullet-point version:

  • If you’re aiming for agility – the ability to adapt quickly to changing requirements – don’t invest too much time on nailing down requirements. Get as much detail as you can, and start iterating. If you’re planning for requirements to change, go all the way – assume that your initial requirements are wrong, and think of each iteration as an opportunity to refine the requirements. All code is wrong until proven right by user acceptance.
  • Use interface mockups (for software with a UI) or API documentation (for libraries and services) as a tool to give stakeholders a chance to revise requirements while looking at a proposed solution and thinking about using it in real-world scenarios.
  • Don’t choose flexibility or modularity over simplicity. Choose a framework that won’t get in your way; if there isn’t one, then don’t use a framework at all. Don’t write what you don’t need. Don’t turn a piece of code into a general-purpose API just because you might need to use it again. If you need it in multiple places now, separate it out; otherwise, you can refactor it when it’s appropriate.
  • Think about separation of concerns early in the game, but don’t sacrifice simplicity for the sake of compartmentalization. Simple code is easier to refactor later if refactoring turns out to be necessary. Overarchitecting is the same sin as premature optimization, it’s just wearing a nicer suit.
  • The simplest solution isn’t always the easiest. The simplest solution often requires a lot of thought and little code. Don’t be a code mason, laying layer after layer of brick after brick; be a code poet, making every line count. If a change could be implemented by increasing the complexity of existing code, or by refactoring the existing code to maintain simplicity, always take the latter route; you’ll end up spending the same amount of time either way, but will reap far more benefits by maintaining simplicity as a priority.
  • Simplicity carries a great many implicit benefits. Simpler code is very often faster (and easier to optimize), more stable (and easier to debug), cleaner (and easier to refactor), and clearer to read and comprehend. This reduces development, operational, and support costs across the board.
  • Simplicity doesn’t just mean “less code”, it means better code. SLOC counts don’t correlate directly to complexity.
  • Don’t reinvent the wheel – unless you need to. All wheels aren’t created equal; there’s a reason cars don’t use the same wheels as bicycles.
What are your experiences? What ways have you found to keep hold of simplicity in the face of other pressures? Feedback is welcome in the comments!

On New Tricks, Old Hacks, and Web Browsers

I must say, I’m a little curious why I haven’t seen mention of this before; a quick Google search didn’t turn anything up either. For the last, oh, ten years or so, web designers have been wrestling with all the different browsers, and different versions of each browser, to get their web pages to behave the same – or at the very least, behave relatively well – on all the browsers their users are likely to employ.

The whole time, the W3C has been releasing new standards and new versions of old standards to give web designers new tricks… and every time, the browsers all catch up to the new standards at different speeds, and implement different parts of the standards, or implement them slightly differently.
My question, then, is this: why is there no W3C specification for browser detection? Why can’t I use CSS selectors to target certain styles at certain browsers, without resorting to lousy hacks? Even CSS3’s new media queries allow me to check the screen size before applying styles, but not whether or not the browser supports, say, CSS3 Of course, it’ll take forever for designers to be able to count on all the browsers supporting a new feature like that, but I haven’t even seen a proposal.
Today, putting together a design involves pulling up your design in all the browsers, figuring out what works and what doesn’t, and then applying hacks specific to each browser. Life would be so much easier in the web design world if instead you could say something like, “if the browser doesn’t support CSS3 background properties, apply this style instead.”
Suddenly, I don’t need to use the hack that hides CSS from IE, and the other hack that hides CSS from everything but IE, and test it, and then find another set of hacks for the Android browser, and another for FireFox, and so on. I can apply styles logically by selecting for specific features, rather than selecting for specific browsers, then having to keep up with the features of each browser – because the features are all I really care about as a designer.
I would much rather “hack” for specific features than specific browsers because it’s more intuitive, and it’s less work to support multiple browsers and different versions of each browser. The browser makers know what features they support. If I can select for the features I want to use, I don’t have to worry about keeping up-to-date with what features are supported by what versions of what browsers.
I’m bringing it up on the W3C mailing list, but I thought I would bring it up here… I’d love to hear your thoughts in the comments!

On the "Digital Civil Rights" Movement

The Yearly Kos Conference is holding a panel on net neutrality and other issues which are more and more often being grouped under a new banner of “Digital Civil Rights”. I agree with many of the points being raised, but calling this a civil rights issue, I think, is misleading, in that they are trying to evoke ideas of the civil rights movement of the 1960’s. This has little to do with equality in treatment, and everything to do with an aging government failing to come to grips with the new, digital age.

They even tried to make it about racial equality, noting statistics that minorities frequently use the internet on mobile phones rather than on computers. This isn’t about racial equality. It’s about giving the lower classes fair access to our new, digital world. And while it’s still true that minorities are disproportionately in the lower classes, that’s a completely unrelated issue – and, in my mind, a much more important one, and one we’ve been battling for decades.

But I’m not here to talk about racial or sexual equality. I’m here to talk about the failure of our government to keep up with the fast-paced advancement of technology in the digital age. This nation invented the modern computer, and the internet, yet while we trip, stumble, and fall, other developed nations have taken this new technology and hit the ground running. The US is ranked 14th among nations in broadband penetration. Broadband here is more expensive than almost any other developed nation, it’s slower than in other developed nations, and it’s available to less of the population. Not coincidentally, the US is also the only developed nation without a national broadband deployment policy.

We have in this country the RIAA (Recording Industry Association of America) going on a vast crusade against their own customers, bringing countless illegitimate and frivolous lawsuits to bear against hundreds of people nationwide, demanding obscene compensation for infractions that, quite often, never occurred. Unfortunately, the RIAA has enough political power to keep their witch-hunt going on unchecked.

We have in this country a deeply-entrenched broadband duopoly, again with enough political weight to keep themselves in power into the foreseeable future. They have little to no incentive to reduce prices, increase speeds, or widen deployment into rural and low-income areas. Monopolies and duopolies are a free-market failure that hurt the consumer in countless ways, limiting innovation and elevating prices. And, should they decide to start bringing to bear their threats of bandwidth shaping for the highest bidder, there will be no free and neutral alternative for internet access.

Don’t think it’s an issue? Look at Japan: 50Mbps DSL is available for $35 per month, 100Mbps fiber is available for $50, and 1 Gbps service over power lines is available for $90. I’m currently paying $43 for a paltry 6 Mbps, and I’m lucky to even have such “high” speeds available in my area; the majority of DSL customers in America are limited to 1.5 or 3 Mbps service, if DSL service is available at all.

So why are things in such a sad state in the country that originated the digital revolution? It’s very, very simple: wretched companies with no concern for the consumer have far too much power, and the people have far too little. Is there a simple solution? Of course not. The unchecked political power of big corporations is a staple of American politics, and I don’t see it changing any time soon. Politicians on both sides of the aisle are on the take from Big Business, leaving voters to choose the lesser of two evils.

LAMPP and then some

I recently built Apache, MySQL, PHP, Python, SQLite, OpenSSL, Subversion , and Trac on a Mac, an Ubuntu box, and a RHEL 4 box. Don’t ask why, just see these tips:

  • Try building your own APR. Also, check what APR is being used; if you already have an APR version 0.9.x, the new APR will be named apr-1-config instead of apr-config, and likewise apu-config will be apu-1-config to get the proper version.
  • Try building Apache –with-included-apr.
  • Try using a different version of OpenSSL, even if you have to go back a version. Security holes are typically backported as a letter release to the previous one or two point releases.
  • Under linux, remember to run sudo ldconfig, make clean, make if you’re having trouble.
  • Under MacOS, if you’re building under a prefix, make sure to add the prefix to the environment variable DYLD_LIBRARY_PATH.

More tips, and maybe even a step-by-step, will be forthcoming.

Development Tactics

I recently set up an account with, because I wanted a Subversion repository more accessible & stable than the one running on my home desktop. I shopped around for a while, and decided on this place – it’s a small project, and a starter account is only $7/month, so I figure, what the heck.

My account was set up within a few minutes, even though I ordered after business hours – I’m guessing they’ve got a pretty good automation system going. I get fast, secure access for unlimited users to unlimited projects in 100M of space, plus a free Trac – not a bad deal. As far as reliability and support, well – only time will tell.

The host is all well and good, but what I really wanted to talk about is Trac. I had looked Trac up some time ago, and decided to take a pass on it – it just wasn’t mature enough at the time, and didn’t have most of the features I was looking for.

Now, however – after some time, and a few bug tracking schemes – I find myself with a free Trac page sitting around, and I figure, what the hey, I’ll give it a shot. And you know what? It still doesn’t have some of the features I was looking for. But it works so well, it doesn’t matter.

The whole thing runs on a Wiki engine. This Wiki engine identifies all CamelCase as wiki links, which I find a bit annoying, but I got used to it pretty quickly. It lets you easily link to pretty much anything, and inline, too: #123 is ticket 123, r456 is revision 456, etc. It hooks up to your Subversion repo and lets you keep an eye on changelogs and browse the repo; plus, this means if you put properly formatted notes in your commit messages (which isn’t hard), you get links in the changelog, for free.

While not quite as versatile as MediaWiki, for example, in terms of page layout and design, it’s probably easier to use – and programmers tend to go for form over function anyway. It’s a developer’s tool. Developers probably won’t spend all day perfecting page templates and macros.

The system provides for a roadmap of milestones, a list of issue tickets, the wiki, and the repository. That’s it. What’s the big deal? How insanely easy it is to wire them all together. With some really basic formatting, you can turn a simple list of milestones into this.

It’s got some rough edges, and there are definitely some huge opportunities yet to be taken advantage of – particularly, I have yet to discover decent, proper JavaDoc support, with full wiki integration. I may just have to learn enough Python to write a plugin for it. I’d also really like to see automatic backlinks added to all the internal links.

I know it’s still version “0.10.3”, but it’s pretty stable so far, and everything works pretty well. I have yet to run into any bugs or bad behavior – however, you should keep in mind that this is bleeding-edge software if you’re considering deploying it. Don’t let that scare you off though: if you don’t mind the under-heavy-development label, you really should give this little application a try and see what you think. At the very least, check out Trac’s own website to see what it can do.

Symbolic Tagging: Tags 2.0

Tagging has become extremely popular these days, and with good reason – people naturally catalog things under various categories mentally, and are able to recall them by any of those routes. So, it makes sense to use a multiple-tagging system rather than a singular system like plain categories or folders.

Combining tagging with social networking, as does, is particularly effective – a set of aggregate tags that allow a community to classify data for use by the whole. However, the problem with this is that not everyone uses the same tags to mean the same things.

The words are just symbols; tags demand meaning. It makes sense, in a simple system, to consider words and their meaning to be one and the same; however, as the system expands, it needs to understand the relationships between words and meanings. Enter symbolic tagging. Rather than making the tags the words and the words the tags, separate the two – after all, they are in fact separate.

From an architecture perspective, this means we need two constructs: the symbology (words) and the semantics (tags), with a 1..*:1..* relationship between the two. One symbol can have multiple semantics, and one semantic can have multiple symbols. As an example, let’s say two symbols, “foo” and “bar” both share a semantic X. When a user searches for “foo”, they will see all records associated with semantic X; the same when they search for “bar”. Alternately, assume the symbol “baz” is attached to two semantics, X and Y. When a user searches for “baz”, they will see all records associated with semantic X, Y, or both.

How does the system learn which symbols reflect which semantics? The same way it determines which records match which tags – community input. Take, for example, the following process for developing and refining a symbolic-semantic map.

1. As new records are added, the user adding them tags those records as they normally would. Any time a user inputs a tag that isn’t already in the map, a new symbol is created for the tag, and a new semantic is created for it as well. At initialization, the two share a 1:1 relationship.
2. The user may opt to go through a refinement process, either manually initiated, or initiated as an additional step in the new-record process. This refinement process prompts the user with a list of tags they have used, and for each tag T, lists other tags associated with records which are also associated with tag T. The user may mark zero or more of these related tags as being synonymous with the tag in question.
3. For each tag being marked synonymous, if that tag is associated with more than one semantic, the user may chose one or more semantic associations between the two tags. The semantics can be identified by the list of tags associated with them. If none of the semantic lines is appropriate, the user may choose “other” to create a new semantic and link it to the two tags being compared. If the tag in question is only associated with one semantic, that semantic is automatically used, avoiding the additional step.

This allows the system to continue its organic social self-construction, while greatly improving the quality of the tag browsing/searching system as a whole, and imparting exponentially more meaning on the dataset itself, which can be used in other areas of research – the data from one large-scale implementation could prove invaluable for semantic computing, computer linguistics, and social networking research and development.

So, – are you up to the task?