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.

Zen Templates Development Journal, Part 2

Having my concept complete (see Part 0) and my simple test case working (see Part 1), I was ready to start on my moderate-complexity test case. This would use more features than the simple test case, and more pages. I really didn't want to have to build a complete site just for the proof of concept, so I decided to use an existing site, and I happened to have one handy: rogue-technologies.com.

The site is currently built in HTML5, using server-side includes for all of the content that remains the same between pages. It seemed like a pretty straightforward process to convert this to my template engine, so I got to work: I started with one page (the home page), and turned it into the master template. I took all of the include directives and replaced them with the content they were including. I replaced all of the variable references with model references using injection or substitution. I ID'd all the elements in the master template that would need to be replaced by child templates. I then made another copy of the homepage, and set it up to derive from the master template.

I didn't want to convert the site to use servlets, since it wasn't really a dynamic site; I just wanted to be able to generate usable HTML from my template files. So I created a new class that would walk a directory, parse the templates, and write the output to files in an output directory. Initially, it set up the model data statically by hand at the start of execution.

All was well, but I needed a way for the child template to add elements to the page, rather than just replacing elements from the parent template. I came up with the idea of appending elements, using a data attribute data-z-append="before:" or "after:", to cause an element to be appended to the page either before or after the element from the parent with the specified ID. This worked perfectly, allowing me to add the Google Webmaster Tools meta tag to the homepage.

With this done, I set to work converting the remaining pages. Most of the pages were pretty straightforward, being handled just like the homepage; I dumped the SSI directives, added some appropriate IDs and classes, and all was well. However, the software pages presented some challenges. For one thing, they used a different footer than the rest of the site. It was time to put nested derivation to the test.

I created a software page template, which derived from the master template, that appended the additional footer content. I then had the software pages derive from this template, instead of deriving from the master template and - by some stroke of luck - it worked perfectly on the first try. I wasn't out of the woods yet, though.

The software pages also used SSI directives to dynamically insert the file size for downloadable files next to the links to download them. I wasn't going to reimplement this functionality, however, I was prepared to replace these directives with file size data stored in the model. But I wanted to keep the model data organized, so I needed to support nesting. The software pages also used include directives to include a Google+ widget on the pages; this couldn't be added to the template, as it was embedded in the body content, so it seemed like a perfect case for snippets - which meant I needed to implement snippet support.

Snippet support was pretty easy - find the data attribute, look up the snippet file, parse it as an HTML fragment, and replace the placeholder element with the snippet. Easy to implement, worked pretty well.

Nested properties I thought would be a breeze, as I had assumed it was natively supported by StrSubstitutor. Unfortunately it wasn't, so I had to write my own StrLookup. I decided that, since I was already doing some complex property lookups for injection, I'd build a unified model lookup class that could act as my StrLookup and could be used elsewhere. I wanted nested scope support as well, for my project list: each project had an entry in the model, that consisted of a name, latest version, etc. I wanted the engine to iterate this list, and for each entry, rather than replacing the entire content of the element with the text value of the model entry, I wanted it to find sub-elements and replace each with an appropriate property of the model entry. This meant I needed nested scoping support.

I implemented this using a scope stack and a recursive lookup. Basically, every time a nested scope was entered (e.g., content injection using an object or map, or iteration over a list), I would push the current scope onto the stack. When the nested scope was exited (i.e., the end of the element that added the scope), I popped the scope off. When iterating a loop, at the start of the iteration, I'd push the current index, and at the end of the iteration, I'd pop it back off.

This turned out to be very complex to implement, but after some trial and error, I got it working correctly. I then re-tested against my simple test case, having to fix a couple of minor defects introduced there with the new changes. But, at last, both my simple and moderate test cases were working.

I didn't like the static creation of model data - not very flexible at all - so I decided to swap it out with JSON processing. This introduced a couple of minor bugs, but it wasn't all that difficult to get it all working. The main downside was that it added several additional dependencies, and dependency management was getting more difficult. I wasn't too concerned on that front though, since I was already planning for the real product to use Maven for dependency tracking; I was just beginning to wish I had used Maven for the prototype as well. Oh well, a lesson for next time. For now, I was ready for my complex test case - I just had to decide what to use.


Zen Templates Development Journal, Part 0

Zen Templates is based on an idea I've been tossing around for about six months. It started with a frustration that there was no way to validate a page written in PHP or JSP as valid HTML without executing it to get the output. It seemed like there had to be a way to accomplish that.

I started out looking into what I knew were global attributes, class and id. I did some research and found that the standard allows any character in a class or id; this includes parens and such, meaning a functional syntax could be used in these attributes, which a parser could then process to render the template.

This seemed practically ideal; I could inject content directly into the document, identifying the injection targets using these custom classes. I toyed with the idea of using this exclusively, but saw a couple of serious shortcomings. For one, sometimes you want to insert dynamic data into element attributes, and I didn't see a good way to handle that without allowing a substitution syntax like that of JSP or ASP. I decided this would be a requirement to do any real work with it.

I also saw the problem of templates. Often each page in a dynamic site is called a template, but I'm referring to the global templates that all pages on a site share, so there is only one place to update the global footer, for example. I had no good solution for this. I started thinking about the idea of each page being a template and sharing a global template - much akin to subclasses in object oriented programming, one template derives from another.

I started batting around different possibilities for deriving one template from another, and decided on having a function (in a class attribute) to identify the template being derived from, with hooks in the parent template to indicate which parts the "subtemplate" would be expected/allowed to "override".

I let the idea percolate for a while - a few weeks - as other things in life kept me too busy to work on it. Eventually it occurred to me that all these special functions in class attributes were pretty messy, and a poor abstraction for designers. It could potentially interfere with styling. It would produce ugly code. And I was on a semantic markup kick, and it seemed like a perfect opportunity to do something useful with semantic markup.

So I started rebuilding the concept and the current Zen Templates was born (and the name changed from its original, Tabula Obscura.) As I committed to maximizing the use of semantic markup and keeping template files as valid, usable HTML, I reworked old ideas and everything started falling into place. I remembered that the new HTML5 data attributes are global attributes as well, and would give me an additional option for adding data to markup without interfering with classes or ruining the semantics of the document.

I ironed out all the details of how derivation should work; it made semantic sense that a page that derived from another page could be identified by class; and, taking a page from OOP's book, it made sense that an element in the subpage with the same ID as an element in the parent page would override that element, making any element with an ID automatically a hook; somewhat like a subclass overriding methods in the superclass by defining a method with the same signature.

I sorted out the details of content Injection as well, thinking that, semantically, it made sense that an element of a certain class would accept data from the model with an identifier matching the class name. Even better, I didn't need a looping syntax; if you try to inject a list of items into an element, it would simply repeat the element for each item in the list. This simplified a lot of syntax I've had to use in the past using JSP or Smarty.

I also wrote out how substitution should work, using a syntax derived from JSP. Leaning on JSP allowed me to answer a lot of little questions easily. I would try to avoid the use of functions in the substitution syntax, because it does make the document messier, and forces more programming tasks on the designer. I conceded that some functions would likely be unavoidable.

When I felt like I had most of the details ironed out, a guiding principal in mind, and a set of rules of thumb to help guide me through questions down the road, I was ready for a prototype. Stay tuned for Part 1!

Zen Templates Development Journal, Part 1

Once my concept was well documented (see Part 0), I was ready to start developing my prototype. I had many questions I needed to answer:

  • Is the concept feasible, useful, and superior in some meaningful way to existing solutions?
  • What kind of performance could I expect?
  • How would derivation work in real-world scenarios? What shortcomings are there in the simple system described in my concept?
  • Ditto for content injection and substitution.
  • How would I handle model data scoping?
  • Would it be better to parse the template file into a DOM Document, or to parse it as a stream?
I started with an extremely simple use case: two templates, one deriving from the other; a couple of model data fields, one of them a list; use of basic derivation, injection, and substitution, with no scope concerns. I built the template files and dummy model data, such that I could quickly tell what was working and what wasn't ("this text is from the parent template", "this text is from the child template", "this text shouldn't appear in the final output", etc.) I also build a dead-simple servlet that did nothing but build the model, run the template renderer, and dump the output to the HttpServletResponse.

With this most basic use case in place, I started to work on the template renderer. I started with the state, initialization, and entry point. For the state, I knew I needed a reference to the template file, and I needed a Map for the model data. For initialization, I needed to take in a template file, and initialize the empty model. For convenience, I allowed initialization with a relative file path and a ServletContext, to allow referencing template files located under WEB-INF, so that they couldn't be accessed directly (a good practice borrowed from JSP.) I created accessors for adding data to the model.

The entry point was a function simply named "render". It was 5 lines long, each line calling an unimplemented protected method: loadTemplate, handleDerivation, handleInjection, handleSubstitution, and writeOut. These were the five steps needed for my basic use case.

I then went to work on building out each of the steps. The easiest was loading the template file from disk into a DOM Document using Jsoup (since XML handlers don't deal well with HTML content). At this point I added two Documents to the renderer's state, inDoc and outDoc. inDoc was the Document parsed from the template file, outDoc was the Document in memory being prepared for output. I followed a basic Applications Hungarian Notation, prefixing references to the input document with "in" and references to the output document with "out".

Since I needed to be able to execute derivation recursively, I decided to do it by creating a new renderer, passing it the parent template, and running only the loadTemplate and handleDerivation methods; then the parent renderer's outDoc became the child's starting outDoc. In this way, if the parent derived from another template, the nested derivation would happen automagically. I would then scan the parent document for ID's that matched elements in the child document, and replace them accordingly. Derivation was done.

Next up was injection: I started out by iterating over the keys in my model Map, scanning the document for matching class names. Where I found them, I simply replaced the innerHtml of the found element with the toString() value of the model data; if the model data was an array or collection, I would instead iterate the data, duplicating the matched element for each value, and replacing the cloned element's innerHtml with the list item's toString() value. This was enough functionality for my simple test case.

Reaching the home stretch, I did substitution ridiculously simply, using a very basic regex to find substitution placeholders (${somevariable}) and replacing each with the appropriate value from the model. I knew this solution wouldn't last, but it was enough for this early prototype.

Last up was writing the rendered output, and in this case, I allowed passing in an HttpServletResponse to write to. I would set the content type of the response, and dump the HTML of my final Document to the response stream.

I ran it, and somehow, it actually worked. I was shocked, but excited: in the course of a little over an hour, I had a fully working prototype of the most basic functions of my template engine. Not a complete or usable product by any means, but an excellent sign. I made a few tweaks here and there, correcting some minor issues (collection items were being inserted in reverse order, for example), but it was pretty much solid. I also replaced my RegEx-based substitution mechanism with the StrSubstitutor from commons-lang; this was pretty much a direct swap that worked perfectly.

Time for the next test, my moderate complexity test case.

The Development Stream

I was reading today about GitHub's use of chat bots to handle releases and continuous integration, and I think this is absolutely brilliant. In fact, it occurs to me that using a chat bot, or a set of chat bots, can provide an extremely effective workflow for any continuous-deployment project. Of course, it doesn't necessarily have to be a chat room with chat bots; it can be any sort of stream that can be updated in real-time - it could be a Twitter feed, or a web page, or anything. The sort of setup I envision would work something like this:

Everyone on the engineering team - developers, testers, managers, the whole lot - stay signed in to the stream as long as they're "on duty". Every time code is committed to a global branch - that is, a general-use preproduction or production branch - it shows up in the stream. Then the automated integration tests run, and the results are output to the stream. The commit is deployed to the appropriate environment, and the deployment status is output to the stream. Any issues that occur after deployment are output to the stream as well, for immediate investigation; this includes logged errors, crashes, alerts, assertion failures, and so on. Any time a QA opens a defect against a branch, the ticket summary is output to the stream. The stream history (if it's not already compiled from some set of persistent-storage sources) should be logged and archived for a period of time, maybe 7 to 30 days.

It's very important that the stream be as sparse as possible: no full stack traces with error messages, no full commit messages, just enough information to keep developers informed of what they will need to look into further elsewhere. This sort of live, real-time information stream is crucial in the success of any continuous-deployment environment, in order to keep the whole team abreast of any issues that might be introduced into production, along with when and how they were introduced.

Now, what I've described is a read-only stream: you can't do anything with it. GitHub's system of using an IRC bot allows them to issue commands to the bot to trigger deployments and the like. That could be part of the stream, or it could be part of another tool; as long as the deployment, and its results, are output to the shared stream for all to see. This is part of having the operational awareness necessary to quickly identify and fix issues, and to maintain maximum uptime.

There are a lot of possible solutions for this sort of thing; Campfire looks particularly promising because of its integration with other tools for aggregating instrumentation data. If you have experience with this sort of setup, please post in the comments, I'd love to hear about it!


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.


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.

Driving Algorithm

Yes, I drive by algorithm. I'm a programmer, and generally have an analytical mind. I can't help it. Here's what goes on in my head when I'm behind the wheel.

My top priority is awareness. I may drive like it's a video game, but I do realize it's the sort of game in which you only get one life. I'm constantly looking around as if I'm about to make a lane change. I try to have a picture in my head of where every car is, and how they're moving in relation to each other and myself, so I can predict where they'll be. If a car appears where I didn't expect it to be, I've already failed.

Beyond that, it's very much like a video game, in several different ways. Like many games, I need to assess my fellow players: who is being aggressive? They're likely to accelerate suddenly, and take advantage of small openings to make lane changes. I need to be careful around them and keep an extra close eye on them, but I also know they're not a bad person to be behind. Who is being cautious? They're likely to drive slower and leave more following distance. I don't want to be behind them, but I know their habits mean that they'll provide ample safe lane change opportunities in front of them. Who's being reckless, or not paying attention, or not maintaining lane? They're a hazard, and I need to keep my distance and pay close attention to them. I also pay attention to what they're driving: I know a sporty car is going to accelerate more quickly than an older car, a large truck, or a minivan.

I also need to know the map: is there an on ramp people will be merging from? Is there a lane that ends or becomes turn only? People will be leaving that lane, possibly suddenly if they aren't familiar with the area. Is there a lane that backs up due to people turning? That lane will be slower, and people are likely to dodge into the next lane to get around the traffic. Any situation with a split, where one lane goes one way and the next lane goes another way (a fork, a turn-only lane, an exit-only lane, etc.)? Both of those lanes will be slower the closer they get to the split, because of people making last-minute maneuvers when they realize their lane doesn't go where they want to be.

I also need to maintain tactical awareness. If a lane is slower, is there a reason? A slow driver or a big truck that's slow to accelerate? If a lane is faster, is there a reason for that? Is there genuinely less or faster traffic, or will the lane slow to the same speed after a few hundred feet? If two lanes are moving the same speed, will one become faster or slower? Maybe many people are leaving that lane, or entering that lane. One lane could have more gaps between cars; as those gaps close (I think of this as the traffic compressing), the lane will advance further than a lane without large gaps. One lane could also end up being slower, if there's a large truck, or a stalled vehicle, or an accident.

Generally, I try to avoid changing lanes unless there's some reason that the lane I'm moving to will end up being faster than the lane I'm moving from. All things being equal, I try to be in the lane I'm going to need to be in for my next turn/exit/etc. If I'm going to make a lane change, I'm going to take all of the above factors into account: will the lane actually end up being appreciably faster? Is there an opportunity to make a lane change, or will there be soon? Will there be an opportunity to get back into the lane I need to be in, by the time I need to be there? Or, if I'm moving into a lane that ends, will I be able to get out before it does? Would I be getting behind a slower driver that will keep me from advancing, even if the lane itself should be faster?

If I'm trying to get around one or two particularly slow vehicles, I try to plan the entire maneuver: getting out of my lane, getting ahead of them, and getting back into the lane once I've passed them. This requires awareness of my lane and the passing lane, and being able to line up both the lane exit and re-entry maneuvers.

Generally, in light traffic, knowing the other drivers and their cars tends to be the most important, because they have the biggest impact on speed of travel in each lane. In moderate traffic, all three factors are fairly equal, but map awareness has a bigger impact in general. In very heavy traffic, situational awareness becomes more important, in order to know which lane is (or will be) the least bogged down.

Yes, I honestly think this way while I'm driving. Also, I tend to sing along to the stereo. Be glad you don't have to hear it.


HTML5 Grid Layouts

I have to take issue with the swarm of "responsive grid layout" systems that have been cropping up lately. Yes, they're great for wireframes and prototypes. No argument there. And yes, they take care of a lot of the legwork involved in producing a responsive layout. Great. But in the process, they throw semantic markup and separation of concerns out the window.

The idea of semantic markup is that your document structure, IDs, and classes should describe the content of the document. Separation of concerns, in HTML and CSS, means using classes and IDs to identify what something is (not how it should appear), and using CSS to identify content and determine how it should appear; this allows you to change content without having to change appearance, and vice versa: the concerns of document structure and appearance are kept separate.

That means, as far as I'm concerned, as soon as you put a 'class="two column"' into your HTML, you've lost the game. You've chained you structure to your presentation. Can you change your presentation without modifying the markup? Not any more. All we've achieved in this is bringing back the days of nested tables for layout, with a pretty CSS face on it. With one dose of "clever" we've traveled back in time 15 years. Only this time, there *are* other ways to do it. There's no excuse. It's just plain laziness.

Is building a truly semantic, responsive, attractive layout possible? Absolutely. Difficult? Yes. Is it worth the effort? In the long run, I think it is - except for those cases mentioned above, prototypes and wireframes, code that's meant to be disposable. But any code that has to be maintained in the future will be hamstrung by these systems.

Web development has made tremendous strides over the last 10 years. It's amazing how far we've come in terms of what can be done and how. Don't take all those advances and use them to regress all the way back to clunky old table-based layouts. Try using them to do something new, and interesting instead. There's no reason the idea of software craftsmanship should be missing from the web design world.



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.