Showing posts with label cogitation. Show all posts
Showing posts with label cogitation. Show all posts

2015-04-12

2013 WRX Swaybar Installation

Introduction


My wife and I run a 2013 Subaru WRX hatchback at autocross and rallycross events. In an effort to improve handling and reduce tire wear, we decided to upgrade the front and rear swaybars and endlinks. We chose a 24mm two-position adjustable front swaybar and a 22mm three-position adjustable rear swaybar and adjustable front and rear endlinks, all from Whiteline. The rear swaybar comes with an additional support brace to provide a little added stiffness.

The equipment came from the good folks at Subie Autosport, who were more than happy to advise us on what would work best for our purpose. Two days after we ordered, the gear was on our doorstep.

This is the story of two people with limited mechanical ability attempting to do this installation. I have done a few oil changes and many wheel/tire swaps, but little else. My wife has done similar work on other cars but not the WRX yet.

I've read many forum posts on the subject, I've watched about a dozen videos, and I've read the included directions. My wife also read the directions and watched a couple of the install videos with me. Supposedly this is under an hour of work per swaybar; we gave ourselves the better part of a day to do it, given our collective inexperience.

Part I: Front Swaybar & Endlinks


Step 1: Remove the plastic undertray. This went smoothly.

Step 2: Remove the crossmember to gain access to the swaybar. This is where the trouble started. Ten bolts, all stuck like they were glued in. Doused everything in penetrating oil, eventually got all the bolts off using a breaker bar, which we had to run out and buy (I didn't own one). I think this is where I injured my shoulder - seems like a partially torn rotator cuff. Getting the crossmember off took about three hours, including giving the oil some time to sink in, and going to the auto parts store for the breaker bar.

Step 3: Remove the swaybar. Again, every bolt was seized. Doused them all with penetrating oil, let it sit. Got the nuts off the endlinks. Got the nuts off the D-brackets. Removing the bolts from the D-brackets, one of the bolts sheared. We tried for a while to remove the end bolt from the top but access is extremely poor. Did some research, and decided to try using an easy-out in the hope we wouldn't have to drill out and re-ream the bolt hole. We finally got the brackets off, disconnected the endlinks, and got the swaybar off. At this point it was 10pm, about five hours in to our two-hour project, and we don't own an easy-out. I loaded up on NSAIDs and iced my shoulder.

The next day, went to the hardware store and picked up an easy-out, and after a lot of drilling, finally got the bolt out. At this point my wife is doing most of the work, I'm mostly providing technical advice and the occasional third hand. Despite the package's claim of "10 seconds", this took us about an hour and the better part of an 18v drill battery. We also went to the auto parts store and got a replacement bolt.

Step 4: Remove the endlinks. Surprise, these bolts were stuck too. Penetrating oil and a lot of elbow grease finally got them off. It is incredibly difficult to hold an allen wrench while you wrench a nut off, with your hand inside the wheel.

Step 5: Install the new endlinks. The Whiteline endlinks come with nuts that have a plastic piece on the front side, which you usually see in parts where they use it as a stop so you can't over-tighten the nut. In this case, however, you're supposed to torque past it, which we found after some more research. Also, those red plastic things that are in every product picture? For protection during shipping. Remove them before installing - not mentioned in the instructions.

We get them torqued down and run out of depth in the socket. My box-end wrench set only goes up to 14mm and the nuts on the Whiteline endlinks are 17mm. It's Sunday, and the shops are closed by this time. We attach both as best we can and leave it until Monday so we can run out yet again for more tools.

Monday we get a 17mm deep socket (no 17mm box-ends to be found), and get the endlinks attached. Day 3, after 5 trips for parts and tools, we've finally got new parts installed on the car.

Step 6: Install the new swaybar. Once the endlinks were on, getting the swaybar on and the first endlink attached was relatively short work. We put them on the softer of the two settings. The new bushings are grease-less, so there really wasn't much to it.

Getting the second endlink attached turned out to be an ordeal. It seemed physically impossible for the endlink to fit. We did some research online and found some people were attaching the endlink to the swaybar first, then to the chassis, so we attempted that, which worked after some finagling.

We found a service manual online for the torque specs, and torqued everything down... except the torque wrench we have is too large to use on the endlinks, so yet another trip to the auto parts store had us a new torque wrench for smaller spaces.

Step 7: Reinstall the crossmember. Just a matter of elbow grease.

Finishing up: At last, we got everything torqued down and took it for a test drive - we were going to do the front and rear at once, but at this point we were three days in and wanted to see some results. Turn-in is much improved, and the reaction to steering input is much quicker, making all that work worthwhile. Re-torqued everything after the test drive, per the instructions.

Part II: Rear Swaybar, Endlinks and Braces


We did the rear the following weekend, so my shoulder had a chance to heal and I was back to doing my fair share. The rear went far more smoothly than the front, but we did run into some small snags.

Step 1: Remove the factory swaybar. This wasn't terribly difficult, it just required some muscle and a breaker bar.

Step 2: Remove the factory endlinks. This was a little bit harder; the lower connection point in the rear crossmember was pretty well seized. A good deal of penetrating oil and muscle on the breaker bar finally got them free.

Step 3: Install the new endlinks. Because of they way they slot into the crossmember, which is a tight fit, this took some finagling; wiggling them back and forth and applying pressure got them into the proper position. We greased the new bolts and hand-tightened them, so they could still be moved side to side to make it easier to get them into the swaybar.

Step 4: Install the new swaybar. Again, greaseless bushings make this a pretty streaightforward task... until we stripped the upper bolts for the D-brackets that attach the bushings. Both of them. I'm not sure what the issue was, but both sides did the same thing - tighten, tighten, fine, then as we tried to torque them down, just as it seemed to be getting close to the proper torque setting, they suddenly got easier to turn again - and kept turning. Not spinning free like it was totally stripped, they just never got tighter.

Since the rear of the bolt is accessible, we picked up a couple of M8 bolts, put them on the back, and torqued it down to spec without issue. Then we got the endlinks attached, putting the rear on its middle setting, and torqued those down. There was also an issue with the lower bolt on the driver's side, which was inaccessible with a socket because the exhaust is in the way; this hand to be hand-torqued. We basically just torqued the bolt on the passenger side with the torque wrench, and then torqued the driver's side with a box-end wrench so it felt the same. Certainly not perfect, but the best we had available.

Step 5: Install the braces. The most difficult part was getting the lower control arm bolt off in order to attach the braces; these seemed to be torqued far tighter than the factory-specified 59 ft-lbs. It was tight enough that we couldn't do it with a breaker bar using a 1/2"-to-3/8"-drive adapter, and had to run out for a 1/2"-drive socket set. A lot of penetrating oil, patience, and torque finally got them off. We attached the braces, which connect the lower attachment point of the D-bracket to the inner attachment point of the control arm.

Finishing up: We torqued everything down and took it for a test drive; all good. The steering is solid and stable, roll is vastly reduced, turn-in is better, steering is significantly more responsive, and much more neutral, with just a hint of oversteer. We lift it back up and torque everything down again per instructions.

A week later, we torqued it all down one last time; you're supposed to do it after the first 100mi but we didn't have a chance until the next weekend with almost three times that. Most of the bolts were still set, a couple were off just a little.

Conclusion

All in all it took us much longer than it probably should have, certainly longer than we thought it would have, and required all sorts of equipment we didn't know we'd need. But the car is better for it, and we get the pride of knowing not only did we install it ourselves, but we were able to navigate a few difficulties along the way and surpass them to get the job done. Not to mention that our garage is a bit better equipped - we spent $5 on nuts and bolts and all the rest was on tools that will last and we'll use again.

We both learned a lot doing it - my wife commented on how far she had come just in terms of knowing the tools. At the start I had to occasionally explain here and there what some tool was called or what the differences between them were, but by the end she knew them all and had no trouble choosing the right socket set for the job out of what was available at the store when we founded we needed something we didn't have.

And you know what? Working on a car with your wife is pretty nice. It might have gone more smoothly and quickly if there was someone there who knew what they were doing, rather than two complete amateurs. But it was a shared experience, it was time spent together, and I can't imagine anyone I'd rather crawl around under a ton and a half of Japanese engineering with.

2013-10-29

Simple Entity Framework Model Structure

I'll say right up front, I don't have a lot of experience with Entity Framework, and this could either be a well-known solution or a completely foolish one. All I know is that, so far, it has worked extremely well for my purposes.

Coming from the Java world, I'm used to using DAO's to serve as an abstraction layer between the controllers and the database, with the basic CRUD methods, plus additional methods for any specific queries needed for a given entity type.

Conveniently, entity framework provides a fairly complete DAO in the form of DbSet. DbSet is very easy to work with, and provides full CRUD functionality, and acts as a proxy for more complex queries. I wanted to keep queries out of my logic, however, and in the model.

Looking at it, I didn't want to have to write an entire wrapper for DbSet, and subclassing it seemed like asking for trouble. That's when it occurred to me to use extension methods for queries. It turns out you can define extension types against a generic type with a type argument specified (e.g. this IEnumerable). This not only allowed me to abstract out the queries and keep them in the model, without having to wrap or subclass anything; but by defining the extensions on IEnumerable instead of DbSet, I have access to my queries on any collection of the appropriate entity type, not just DbSet. I can then chain my custom queries in a very intuitive and fluid way, keeping all of the code clean, simple, and separate.

For example, I have a table of tags. I've created extension methods on IEnumerable to filter to tags used by a given user, and to filter by tags starting with a given string. I can chain these to get tags used by a given user and starting with a given string. I can also use these queries on the list of tags associated with another entity, as IList implements IEnumerable, and thus inherits my query extension methods.

I don't know if this is the best way - or even a good way - but it's worked for me so far. I do see some possible shortcomings; mainly, the extensions don't have access to the context, so they can't query any other DbSets, only the collection it's called against. This means that only explicit relationships can be queried against, which hasn't been a roadblock so far in my (admittedly simple) application. I'm not sure this is really a drawback though - you can still add a parameter to pass in an IEnumerable to query against, which again offers the flexibility to pass a DbSet or anything else.

2013-10-18

Pragmatic Prioritization

The typical release scheduling process works something like this:

  1. Stakeholders build a backlog of features they'd like to see in the product eventually.
  2. The stakeholders decide among themselves the relative priority of the features in the backlog.
  3. The development team estimates the development time for each feature.
  4. The stakeholders set a target feature list and ship date based on the priorities and estimates.

The problem here is primarily in step 2; this step tends to involve a lot of discussion bordering on arguing bordering on in-fighting. Priorities are set at best based on a sense of relative importance, at worst based on emotional attachment. Business value is a vague and nebulous consideration at most.

I propose a new way of looking at feature priorities:

  1. Stakeholders build a backlog of features they'd like to see in the product eventually.
  2. The stakeholders estimate the business value of each feature in the backlog.
  3. The development team estimates the development time for each feature.
  4. The stakeholders set a target feature list and ship date based on the projected return of each feature - i.e., the estimated business value divided by the estimated development time.

This turns a subjective assessment of relative priorities into an objective estimate of business value, which is used to determine a projected return on investment for each feature. This can then be used to objectively prioritize features and schedule releases.

I've been using this workflow recently for one of my upcoming projects, and I feel like it's helped me to more objectively determine feature priorities, and takes a lot of the fuzziness and hand-waving out of the equation.

Shameless self-promotion: Pragmatic prioritization is a feature of my project scheduling and estimation tool, Rogue Prognosticator

2013-06-02

Building a Foundation

It's been said that pharmaceutical companies produce drugs for pennies per pill - except the first pill, which costs millions. Things aren't so different in the land of software development: the first usage of some new functionality might take hours, building the foundation and related pieces. But it could be re-used a hundred times trivially, and usually expanded or modified with little effort as well (assuming it was well-written to start with).

This is precisely what you should be aiming for: take the time to build a foundation that will turn complex tasks into trivial ones as you progress. This is the main purpose behind design concepts like the single responsibility principle, the Hollywood principle, encapsulation, DRY, and so on.

This isn't to be confused with big upfront design; in face, it's especially important to keep these concepts in mind in an agile process, where you're building the architecture as you go. It can be tempting to just hack together what you need at the moment. That's exactly what you should be doing for a prototype, but not for real development. For lasting functionality, you should assemble a foundation to support the functionality you're adding now, and similar functionality in the future.

It can be difficult to balance this against YAGNI - you don't want to build what you don't need, but you want to build what you do need in such a way that it will be reusable. You want to save yourself time in the future, without wasting time now.

To achieve a perfect balance would require an extraordinary fortune teller, of course. Experience will help you get better at determining what foundation will be helpful, though. The more experience you have and the more projects you work on, the better sense you'll have of what can be done now to help out future you.

2013-05-10

The Importance of Logging

Add more logging. I'm serious.

Logging is what separates an impossible bug report from an easy one. Logging lets you replace comments with functionality. I'd even go so far as to say good logging separates good developers from great ones.

Try this: replace your inline comments with equivalent logging statements. Run your program and tail the log file. Suddenly, you don't need a step wise debugger for the vast majority of situations, because you can see, in the log, exactly what the program is doing, what execution path it's taking, where in the source where each logging statement is coming from, and where execution stopped in the event of a crash.

My general development process focuses on clean, readable, maintainable, refactorable, self-documenting code. The process is roughly like this:
  1. Block out the overall process, step by step, in comments.
  2. Any complex step (more than five or ten lines of code), replace the comment with a clearly-named method or function call, and create a stub method/function.
  3. Replace comments with equivalent logging statements.
  4. Implement functionality.
    • Give all functions, methods, classes, parameters, properties, and variables clear, concise names, so that the code ends up in some semblance of readable English.
    • Use thorough sanity checking, by means of assertions or simple if blocks. When using if blocks, include logging for any failed checks, including what was expected and what was found. These should be warnings.
    • Include logging in any error/exception handling code. These should be errors if recoverable, or fatal if not. This is all too often the only logging a developer includes!
  5. Replace inline comments with equivalent logging statements. These should be debug or info/trace level; major section starts should be higher level, while mid-process statements should be lower level.
  6. Add logging statements to the start of each method/function. These should also be debug or info/trace level. Use higher-level logging statements for higher-level procedures, and lower-level logging statements for more deeply-nested calls.
  7. For long-running or resource-intensive processes, particularly long loops, add logging statements at regular intervals to provide progress and resource utilization details.
Make good use of logging levels! Production systems should only output warnings and higher by default, but it should always be possible to enable deeper logging in order to troubleshoot any issues that arise. However, keep the defaults in mind, and ensure that any logging you have in place to catch defects will provide enough information in the production logs to at least begin an investigation.

Your logging messages should be crafted with dual purpose in mind: first, to provide useful, meaningful outputs to the log files during execution (obviously), but also to provide useful, meaningful information to a developer reading the source - i.e., the same purpose served by comments. After a short time with this method you'll find it's very easy to craft a message that serves both purposes well.

Good logging is especially useful in an agile environment employing fast iteration and/or continuous integration. It may not be obvious why at first, but all the advantages of good logging (self-documenting code, ease of maintenance, transparency in execution) do a lot to facilitate agile development by making code easier to work with and easier to troubleshoot.

But wait, there's more! Good logging also makes it a lot easier for new developers to get up to speed on a project. Instead of slogging through code, developers can execute the program with full logging, and see exactly how it runs. They can then review the source code, using the logging statements as waypoints, to see exactly how the code relates to the execution.


If you need a tool for tailing log files, allow me a shameless plug: try out my free log monitor, Rogue Informant. It's been in development for several years now, it's stable, it's cross-platform, and it's completely free to use privately or commercially. It allows you to monitor multiple logs at once, filter and search logs, and float a log monitoring window on top of other applications, to make it easier to watch the log while using the program to see exactly what's going on behind the scenes.Give it a try, and if you find any issues or have feature suggestions, feel free to let me know!

2013-05-06

The Problem with Responsive Design

A huge problem I see with responsive/adaptive design today is that, all too often, it treats "small viewport" and "mobile" as being synonymous, when the two concepts are orthogonal. A mobile device can have a high-resolution display, just as a desktop user can have a small display, or just a small browser window.

Responsive designs need to design for viewport size, and nothing more. It's not mobile, it's a small display. Repeat that to yourself about a thousand times.

What's holding back single-design philosophies isn't display size, it's user interface; for decades, web designers have counted on there being a mouse cursor to generate events - mouseovers, clicks, drags. That's not how it works on touchscreen devices, and we need some facility - JavaScript checks, CSS media queries - to cater to touch-based devices as opposed to cursor-based devices.

Sanity Checks: Assumptions and Expectations

Assertions and unit tests are all well and good, but they're too narrow-minded in my eyes. Unit tests are great for, well, testing small units of code to ensure they meet the basic requirements of a software contract - maybe a couple of typical cases, a couple of edge cases, and then additional cases as bugs arise and new test cases are created for them. No matter how many cases you create, however, you'll never have a test case for every possible scenario.

Assertions are excellent for testing in-situ; you can ensure that unacceptable values aren't given to or by a piece of code, even in production (though there is a performance penalty to enabling assertions in production, of course.) I think assertions are excellent, but not specific enough: any assertion that fails is automatically a fatal error, which is great, unless it's not really a fatal error.

That's where the concept of assumptions and expectations come in. What assertions and unit tests really do is test assumptions and expectations. A unit test says "does this code behave correctly when given this data, all assumptions considered?" An assertion says "this code assumes this thing, and will not behave correctly if it gets another, so throw an error."

When documenting an API, it's important to document assumptions and expectations, so users of the API know how to work with your code. Before I go any further, let me define what I mean by these very similar terms: to me, code that assumes something operates as if its assumptions are correct, and will likely fail if its assumptions turn out to be incorrect. Code that expects something operates as if its expectations are met, but will likely still operate correctly even if they aren't. It's not guaranteed to work, or guaranteed to fail; it's likely to work, but someone should probably know about it and look into it.

Therein lies the rub: these are basically two types of assertions, one fatal, one not. What we need is an assertion framework that allows for warning-level assertion failures. What's more, we need an assertion framework that is performant enough to be regularly enabled in production.

So, any code that's happily humming along in production, that says:

Assume.that(percentage).isBetween(0,100);

will fail immediately if percentage is outside those bounds. It's assuming that percentage is between zero or one hundred, and if it assumes wrong, it will likely fail. Since it's always better to fail fast, any case where percentage is outside that range should trigger a fatal error - preferably even if it's running in production.

On the other hand, code that says:

Expect.that(numRows).isLessThan(1000);

will trigger a warning if numRows is over a thousand. It expects numRows to be under a thousand; if it isn't, it can still complete correctly, but it may take longer than normal, or use more memory than normal, or it may simply be that if it got more rows than that, something may be amiss with the query that got the rows or the dataset the rows came from originally. It's not a critical failure, but it's cause for investigation.

Any assumption or expectation that fails should of course be automatically and immediately reported to the development team for investigation. Naturally a failed assumption, being fatal, should take priority over a failed expectation, which is recoverable.

This not only provides greater flexibility than a simple assertion framework, it also provides more explicit self-documenting code.

2013-04-24

Real Sprints


Agile methodologies talk about "sprints" - workloads organized into one to four week blocks. You schedule tasks for each sprint, you endeavour to complete all of it by the end of the sprint, then you look back and see how close your expectations (schedule) were to reality (what actually got done).

Wait, wait, back up. When I think of a sprint, I think short and fast. That's what sprinting means. You can't sprint for a month straight; you'll die. That's a marathon, not a sprint.

There are numerous coding competitions out there. Generally, you get around 48 hours, give or take, to build an entire, working, functional game or application. Think about that. You get two days to build a complete piece of software from scratch. Now that's what I call sprinting.

Of course, a 48 hour push is a lot to ask for on a regular basis; sure, your application isn't in a competition, this is the real world, and you need to get real work done on an ongoing basis. You can't expect your developers to camp out in sleeping bags under their desks. But that doesn't mean turning a sprint into a marathon.

The key is instilling urgency, while moderating burnout. This is entirely achievable, and can even make development more fun and engaging for the whole team.Since the term sprint has already been thoroughly corrupted, I'll use the term "dash". Consider this weekly schedule:
  • Monday: Demo last week's accomplishments for stakeholders, and plan this week's dash. This is a good week to schedule any unavoidable meetings.
  • Tuesday and Wednesday: your 48 hours to get it done and working. These are crunch days, and they will probably be pretty exhausting. These don't need to be 18-hour days, but 10 hours wouldn't be unreasonable. Let people get in the zone and stay there as long as they can.
  • Thursday: Refactoring and peer reviews. After a run, athletes don't just take a seat and rest; they slow to a jog, then a walk. They stretch. The cool off slowly. Developers, as mental athletes, should do the same.
  • Friday: Testing. QA goes through the application with a fine-toothed comb. The developers are browsing the web, playing games, reading books, propping their feet up, and generally being lazy bums, with one exception: they're available at a moment's notice if a QA has any questions or finds any issues. Friday is a good day for your development book club to meet.
  • By the end of the week, your application should be ready again for Monday's demo, and by Tuesday, everyone should be well-rested and ready for the next dash.
Ouch. That's a tough sell. The developers are only going to spend two days a week implementing features? And one basically slacking off? Balderdash! Poppycock!

Think about it, though. Developers aren't factory workers; they can't churn out X lines of code per hour, 40 hours per week. That's not how it works. A really talented developer might achieve 5 or 6 truly productive hours per day, but at that rate, they'll rapidly burn out. 4 hours a day might be sustainable for longer. Now, mind you, in those four hours a day, they'll get more done, better, with fewer defects, than an army of incompetent developers could do in a whole week. But the point stands: you can't run your brain at maximum capacity eight hours straight, five days a week. You just can't - not for long, anyway.

The solution is to plan to push yourself, and to plan to relax, and to keep the cycle going to maximize the effectiveness of those productive hours. It's also crucial not to discount refactoring as not being productive; it sets up the following weeks' work, and reduces the effort required to get the rest of the development done for the rest of the life of the application. It's a critical investment in the future.

Spending a third of your development time on refactoring may seem excessive, and if it were that simple, I'd agree. But if you really push yourself for two days, you can get a lot done - and write a lot of code to be reviewed and refactored. In one day of refactoring, you can learn a lot, get important work done, and still start to cool off from the big dash.

That lazy Friday really lets you relax, improve your craft, and get your product ready for next week, when you get to do it all over again.

2013-04-19

Hiring the Best

A commitment to hiring the best requires a significant departure from typical hiring practices, because of the very nature of the beast: the best are rare by definition, and sought-after by nature. That means that when they're available, you have to hire them. This sounds straightforward enough, but it's harder to put into practice.

In order to have the best, you have to always be hiring, whether or not you need people. I'm not suggesting you staff up to a thousand employees when you only need ten, but you should be open to the idea of hiring people now up to the number of people you think you'll need a year or two from now. Allowing moderate over-staffing gives you the flexibility to make an excellent hire when the candidate is available, so that when you really do need them, you aren't forced to accept less than the best because you're in a time crunch.

Which brings us to the correlary: when you're hiring for a specific opening, you have to commit to not hiring people who don't meet your standards, no matter how badly you need to fill the position. That may mean that while you're searching for the perfect person, you have to outsource, hire contractors, or hire temporary workers. That may mean that your current employees have to go a little outside their comfort zone and pick up the slack until you can find someone who is a good fit. Just don't buckle: every time you lower your standards to fill a position, you're lowering the average quality for your entire operation. Don't do it.

Both of these ideas - hiring when you don't need to, and not hiring when you do need to - are somewhat counter-intuitive, can be very difficult to stick to in practice, and can be even more difficult (if not impossible) to convince management of. But if you want to have the best, the only way to get there is by hiring the best when you can, and refusing to hire anyone that doesn't meet your standards.

It's also important to understand that candidates who don't look good on paper may turn out to be rock stars of only you knew you should hire them. If you can possibly manage it, try setting up an apprenticeship program. Take on candidates that seem promising despite being apparently unqualified. Give the paperboy the chance to prove he can write code even though he never went to college. Give the mechanic the opportunity to show he's a diamond in the rough for your sales department.

The purpose of your apprenticeship program should be genuine apprenticeship - a learning experience for the prospect, and for your team as well. Don't just treat it as a temp-to-hire situation. Find out how far this person can go if you really back them up and give them the tools to succeed. If it doesn't work out, cut them loose. If it does work out, guess what? You just picked up an excellent employee that no resume search our recruiter world ever have found, and they'll likely show more loyalty to your company than an industry veteran ever would.

2013-04-17

Truly Agile Software Development


Truly agile software development has to, by nature, allow for experimentation. In order to quickly assess the best option among a number of choices, the most effective method is empirical evidence: build a proof of concept for each option and use the experience of creating the proof, as well as the results, to determine which option is the best for the given situation.

While unit tests are valuable for regression testing, a test harness that supports progression testing is at least as useful. Agile development methodologies tend to focus on the idea of iterating continuously toward a goal along a known path; but what happens when there's a fork in the road? Is it up to the architect to choose a path? There's no reason to do so when you can take both roads and decide afterward which you prefer.

Any large development project should always start with a proof of concept: a bare-bones, quick-and-dirty working implementation of the key functionality using the proposed backing technologies. It doesn't need to be pretty, or scaleable, or extensible, or even maintainable. It just has to work.

Write it, demo it, document what you've learned, and then throw the code away. Then you can write the real thing.

It may seem like a waste of time and effort at first.  You'll be tempted to over-engineer, you'll be tempted to refactor, you'll be tempted to keep some or all of the code. Resist the urge.

Why would you do such a thing? If you're practicing agile development, you might think your regular development is fast enough that you don't need a proof. But that's not the point; the point is to learn as much as you can about what you're proposing to do before you go all-in and build an architecture that doesn't fit and that will be a pain to refactor later.

Even if it takes you longer to build the proof,it's still worth it - for one thing, it probably took longer because of the learning curve and mistakes made along the way that can be avoided in the final version, and second because again, you've learned what you really need and how the architecture should work so that when you make the production version you can do it right the first time, with greater awareness of the situation.

This approach allows much greater confidence in the solutions chosen, requiring less abstraction to be built in to the application, which allows for leaner, cleaner code, and in less time. Add to that the value of building a framework that is flexible enough to allow for progression testing, and you've got the kind of flexibility that Agile is really all about.

Note: Yes, I understand that Scrum calls prototypes "spikes". I think this is rather silly - there are already terms for prototypes, namely, "prototype" or "proof of concept". I'm all for new terms for things that don't have names, but giving new names to things that already have well-known names just seems unnecessary.

2013-04-01

Assumptions

We all make assumptions. It's the only way we can get anything done. If every time you found a bug you started at the iron - testing the CPU to make sure every operation returns an expected result - it'd take you months to troubleshoot the simplest issue. So we make assumptions to save us time, when we know that the likelihood of something being the cause of a problem is far less than the time it would take to verify it.

We also make assumptions out of sheer bloody-mindedness. You can spot these assumptions by phrases like "that couldn't possibly be it" or "it's never been a problem before" or "I wrote that code, I know it works". These are the kinds of assumptions that can get us into trouble, and they're the exact reason why it's important to have developers from different backgrounds, with different perspectives, who make different assumptions.

Since we all make assumptions, the best way to challenge those assumptions is to have someone who makes different assumptions look at the issue. They'll bring their perspective and experience to the matter, challenge your assumptions where they don't make sense, and make you prove those assumptions to be accurate or not. This stands as a strong incentive to hire a team with diverse backgrounds and areas of expertise. They bring not just talent to your team, but a different perspective.

It's also a good reason to invest the time in learning different technologies, languages, and development philosophies. Getting outside of your comfort zone can open your eyes to things you might not otherwise have considered, and help you to gain new perspective on your work - helping you to challenge your own assumptions.

2012-10-14

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.

2012-09-03

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!

2012-08-01

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?

2012-07-21

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!

2010-07-06

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!

2008-04-03

My head hurts.

Falling in love is like being hit in the back of the head with a gold brick out of the middle of nowhere.

*WHACK* OW! What the fu- holy shit, that's a gold brick!

My head still hurts, but that will pass. The gold is mine for keeps.

2007-08-07

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.

2007-03-23

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.

2007-02-23

Development Tactics

I recently set up an account with hosted-projects.com, 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.