Annotation Done Right

Or, think carefully about your APIs

This is such a common design pattern we’ve probably all done it one way or another. We have some data stream — likely XML or JSON or just plain old text — and we want to wrap it inside another element. For example, taking a name like “Zac” and turning it into “<name>Zac</name>” like so:1

var s = s"<name>$firstName</name>"

Of course if you do this enough, you start thinking it would be nice to have a function on hand:

def wrap(s: String, w: String): String = s"<$w>$s</$w>"

What’s wrong with that?

That’s all well and good, but after a while we realize a couple of problems with this very simple API:

  1. I’d say the API itself is pretty bad. I would love to have a syntax that feels more, well, functional… like "Zac" wrap "name".
  2. It’s not really “wrapping” the text string — it is in fact “XML’ising” the text string. There’s more going on here than just bracketing a string with another string.
  3. It’s not much of a stretch to see how this generic wrap() function could end up getting in the way (either confusing someone about its true purpose, or getting in the way of other string-oriented functions).
  4. And, why limit this handy little function? What happens if we want to wrap something that’s not a String?

Let’s tackle these one at a time. The first limitation is elegantly managed by introducing infix notation with an implicit class in Scala.

implicit class EnrichedString(s: String) {
  def wrap(w: String) = s"<$w>$s</$w>"
}

"thing".wrap("foo") // the usual syntax
"thing" wrap "foo"  // or using infix notation

When you try to call the wrap() function, the implicit class essentially gives the compiler a hint about where to look for the function. Since it isn’t on the String class itself, it starts to search implicit scope. The compiler finds the EnrichedString class, realizes it can convert a standard String to an EnrichedString, and gains access to the wrap() function.

One possible negative side effect of this is boxing. The source string, in our case “Zac”, will get boxed into EnrichedString("Zac") so the compiler can call wrap(). Depending on how you feel about this, you can get around it by using AnyVal instead:

implicit class EnrichedString(val s: String) extends AnyVal { ... }

A thoughtful API

That’s a nice way of improving the usability of our API, but it’s still a pretty bad API. I still haven’t addressed most of the problems I brought up:

  1. We want to wrap strings with an opening and closing XML element. We should create an API that accurately describes this.
  2. By drawing on the desired goal of avoiding boxing, we could pretty easily apply this to just about any type. So, why not? Who’s to say we might not want to wrap an Int?
  3. We should also consider other possible uses of our API. What if I wanted to ask a question in Spanish — ?Justo como esto¿
  4. Finally, I don’t know about you but I always do BDD, so we should have a test harness to make sure our API does the right thing.

Let’s start with the test harness. I love starting here, because I’m thinking about what I want the API to do, not what the code is doing. Let’s think up a test that fits all of our goals (a good API, asymmetric tokens, and a functional style):

def annotationWorksAsExpected = {
  "foo" wrap ("[", "]") === "[foo]"
  "foo" wrap (("[", "]")) === "[foo]"
  1 wrap "?" === "?1?"
  "foo" + "bar" wrap Some("...") === "...foobar..."
  "foo" + "bar" wrap Some(("<", ">")) === "<foobar>"
  "foo" + "bar" wrap None === "foobar"
  "foo" + "bar" wrap(("?", "¿")) === "?foobar¿"
  "foo" makeElementOf("around") === "<around>foobar</around>"
  "foo" + "bar" makeElementOf(("start", "end")) === "<start>foobar</end>"
  "foo" + "bar" makeElementOf((1, 2)) === "<1>foobar</2>"
  "foo" + "bar" makeElementOf("enclose") === "<enclose>foobar</enclose>"
  500 makeElementOf(0) === "<0>500</0>"
  500 makeElementOf("int") === "<int>500</int>"
  500 + " tiene razón" wrap(("?", "¿")) === "?500 tiene razón¿"
}

The === is a specs2 matcher that specifies equality. So, I defined every case I could think of, within reason, that someone might expect of my API. I’ve separated out the idea of “wrapping” and “XML’ising” a string — and while I’m at it, I decided it shouldn’t be limited to strings. I also introduced the idea of asymmetric tokens, such as “start” and “end” and “?” and “¿” (in this case, by using a tuple to represent a pair of opening and closing tokens). I also threw in an Option to give some flexibility while coding.

After sitting back and thinking about it, I feel like this is an API that won’t offend or get in too many people’s way. Now, to make my tests pass:

implicit class EnrichedAny(val s: Any) {
	def wrap(y: Option[Any]): String = y match {
		case Some(y: Tuple2[Any, Any]) => s wrap(y._1, y._2)
		case Some(y: Any) => s wrap y
		case _ => s.toString
	}

	def wrap(y: Any): String = y.toString + s + y.toString
	def wrap(y: Tuple2[Any, Any]): String = y._1.toString + s + y._2.toString

	def makeElementOf(y: Any) = s wrap(s"<${y}>", s"</${y}>")
	def makeElementOf(y: Tuple2[Any, Any]) = s wrap(s"<${y._1}>", s"</${y._2}>")
}

Hopefully the basic pattern is recognizable, but now with a few much needed improvements:

  1. We abstracted the entire function to work over Any so I’m no longer limited to String instances.
  2. I added support for Option, really just trying to be functional and think of likely use cases here.
  3. By adding support for a Tuple2 I can now use asymmetric tokens, like “start” and “end.”
  4. And I’ve separated the idea of wrapping from “XML’ising.”

I think the outcome is pretty good. We have a wrap API that does pretty much what you would expect — it puts an unmodified wrapper around another object. And we have my original goal, an XML-oriented API that puts properly formed starting and ending elements around an object. More important, it’s general enough that I won’t have to reimplement exactly the same thing on different types. And of course, it’s all tested to make sure it does what we expect.

We could probably take it a little further, perhaps using generics or a bit of recursion to support tuples of any size… but I’ll leave that as an exercise for the reader…

The real point here is to think about your APIs carefully when designing them. Don’t build an API that is limited, or confusing, or obfuscated. Look at your code in the context of the entire ecosystem you work in — and build something that fits well in that ecosystem.

  1. Obviously, if you are really doing a lot of XML specific work, you might just want to look at a library like Rapture (there are many options out there).

You’re Testing It Wrong…

I really like test driven development. It lets me be lazy. I don’t have to worry about my software quality, or that something I did broke some other thing. And with good dependency injection to make sure every component is working right, “it just works.” Now I code using TDD (writing my tests first, then coding to fulfill them), and I focus our QA efforts on making sure we have great test plans, and great coverage.

Closed System
A closed system wants to be tested.

So, when one of my project teams kept telling me they couldn’t write tests because the database wasn’t ready I got worried. Our team had been immersed in TDD for months — and every single engineer had nodded vigorously when I set expectations. The team leader recited the definition of “dependency injection,” just to drive home how ready they were to embrace it!

But when I asked to see the what was wrong, I knew we had a problem. The team’s tests were not injecting mock objects the right way. The idea behind dependency injection is to replace the smallest component possible in a closed system with another object, a “mock.” That mock can then monitor the system around it, inject different behaviors, and create desired results.

For example, let’s say we have a program that connects to a gizmo — your home thermostat. The thermostat itself is a separate component that lives outside your program. We can expect the thermostat to behave like a thermostat should… reporting the current temperature, and letting the home owner enter a desired room temperature. Pretty straight forward.

So the first step is to write a program that talks to the thermostat. We can wire up a real thermostat, but we’ve got a problem right off the bat. We want to know how our program behaves as the ambient temperature changes — 65 degrees, 32 degrees, or 100 degrees. But a real thermostat is only going to report the actual room temperature, and making the room frigid or boiling just isn’t going to be very comfortable or practical.

Not Mocking
Faking is not mocking.

This is where dependency injection comes in — wouldn’t it be great if we could inject a new gizmo, one that behaves according to our test plan?

It turns out that my team had been taking the wrong approach — but one that is pretty easy to make if you’re new to the idea of mocking and dependency injection. Unfortunately, it meant that they weren’t really testing the application. The were testing something else entirely.

Once we walked through the system, the mistake was clear. During application start up, it created a connection to a database. My team’s approach had been to add a “mocking” variable to the application. In effect, it created a test condition; if the application was in “mocking mode” it would only simulate database calls. If the application was not in “mocking mode” it sent real requests to a real database. Sounds great, right?

But it’s all wrong. Here’s the problem: The application was faking real world behavior. That is, throughout the program there were dozens of little tests, in effect asking, “if we are mocking, then don’t check the database for a user record, instead just return this fake user record.”

This meant that the real program — the actual application logic that would be deployed to the real world — was never tested. Instead, an alternate branch of logic was tested — a fake program, if you will. So two things happened:

  1. We weren’t testing the real program, we were testing something else altogether.
  2. The program itself became terribly complicated because of all the checks to find out “are we mocking?” and the subsequent code to do something else entirely.

And all of that is why my team said they couldn’t really test the system, because the database wasn’t up and running.

So what does real dependency injection look like? It’s simple: You want to change the actual gizmo, but change it in the most subtle way possible — and then you want to put that actual gizmo right back into your program.

Mocking
Real mocking doesn’t affect the original program flow.

Getting back to the thermostat example, an ideal solution would be to modify a real thermostat. You could crack it open, remove the temperature sensor, and add a little dial to it that lets you change the reported temperature. Then you plug the “mock thermostat” into your program, and you change the temperature manually! A potentially better approach would be to change the software that talks to your thermostat, and instrument it so that you can override the actual reported temperature. Your program would still think it’s talking to a real thermostat, and the connecting software could change the actual temperature before handing it off to your program.

In our case, the right solution could be injecting a simple mock component at the just the right point in our program.

For example, lets say our application uses an Authenticator object to log in users. The Authenticator checks the validity of a user in the database, and then returns a properly constructed User object. We can use dependency injection to substitute our own test data by overriding the single function we care about:

object fakeAuthenticator extends Authenticator {
    override def getUser(id: Int): Option[User] = {
        Some(User(id: -1, name: &quot;Fake User&quot;))
    }
}

On line 2, we replace the real Authenticator’s getUser function. The overridden method returns a hard-wired User object (in this case, one that clearly doesn’t represent a valid user account). By overriding the Authenticator in the test package only, the original program is not altered — all that’s left is to inject our altered Authenticator into the program.

The old fashioned way of doing injection is still reliable: Don’t tell, ask. Use a factory object to ask for the Authenticator. Given a factory in the application (let’s call it the AuthenticatorFactory) we can override what the factory actually returns in our test case only:

AuthenticatorFactory.setAuthenticatorInstance(fakeAuthenticator)

A slightly more modern approach is to use a dependency injection framework, but the underlying principle is exactly the same.

Likewise we can take the concept of mock objects further by using frameworks such as Mockito (a framework that works wonderfully with specs2). Mockito makes it easy to instrument real objects with test driven behavior. For example, Mockito will produce a mock object that acts just like a real object, but fulfills expectations (such as testing to make sure that a specific function is called a certain number of times).

Whatever tools and frameworks you use, test driven development has proven itself over the past decade. My own experience is the same: Every TDD project has produced more predictable results, has better velocity, and has been more reliable overall. It’s why I don’t do any coding without following TDD.

How To Go Global

How do you learn to “go global” and take your product, and your company, to an International scale?

Hi, I’m Zacharias Beckman, President of Hyrax International. I founded this company because I believe that American businesses, in particular, are really embracing the global economy. That means learning how to adapt products to different cultures around the world; changing a business’s internal culture in order to be compatible; changing how projects are managed, because the traditional Western management style that most of these American businesses employ, those styles are not going to work in Asia or South America or the Middle East. So, American businesses need to start to adapt.

Adapting To “Global”

A new level of business cultural awareness is needed. We need to understand how to communicate with each other, how to adapt to each other’s way of thinking about time, how to manage people with a different concept of power distance or the separation between a boss and an employee. It’s a complex landscape.

Taking a product into another country means adapting that product so that it fits well with the culture there. For example — lets say you wanted to take a product that was a four pack of golf balls, here in the United States, and sell it in Japan. It’s probably not going to work — because the word for “four” in Japan sounds very much like the word for “death.” So taking that product and simply slapping a new label on it in Japanese and shipping it over there — that’s not going to work.

This is why we created the Global Project Compass (see our six-part article on the Compass). It’s a map that takes 27 different project management verticals, things like quality assurance; time estimation; acceptance testing, and it maps them to business cultural preferences. And we see how, for example, communication is going to change each one of these 27 different project management disciplines.

We are global project experts. We understand the technical execution and we understand the cultural implication. Our programs will make sure that you succeed taking your products overseas and building a multinational organization.

How Business Culture Affects Your Business

Hi, I’m Zacharias Beckman, President of Hyrax International. We get a lot of questions about how business culture affects business on a day to day basis.

Sarah, a project manager here in America, is very successful at what she does. She’s got a lot of successful projects under her belt. But right now she’s having problems. It looks like the project that she is working on is going to ship late. There are lot of quality problems with it.  It’s over budget, it’s behind schedule, and Sarah is very frustrated. All of the techniques that she’s been using in the past aren’t working for her now. She feels like she is  not getting the feedback from her team that she’s used to getting. For example, she proposed some changes to quality assurance system and instead of getting feedbacks, there’re silence, delays and  then finally the team agreed to implement what she had proposed.

In a typical Western style, she is expecting very clear communication from her team.  Direct, critical feedback on the project and on the proposed changes that she is making. The problem is, her team is in Asia and they don’t think  that she knows she is doing. She asks too many questions. She doesn’t demonstrate the authority and the wisdom necessary for the team to feel like she’s in charge of the project.  They are not accustomed to this kind of management.

Sarah’s run into a couple of business cultural preferences. She’s experiencing power distance, which is the separation between a boss  and a subordinate, and how they ‘re allowed to communicate because of cultural constraints. And she’s also experiencing differences in communication style — the low context, direct communication of the West versus the very high context, rich and subtle communication of the East.

Sarah’s solution in this case is to get business cultural training and understand how her management style differs from what her team is used to and then adapt  her management program, her project management technique, to work well with her team is Asia.

Check our website for more information on both of these business cultural preferences. I’ve blogged about them quite a bit in the past.

And if you are managing an International multicultural team, it’s really important to understand how much business cultural preferences will affect your project and your management style. You need to be sure that the project management methods you’re putting into play, are going to work with your multinational team.

Start Outsourcing The Little Things

Many small businesses don’t understand the benefits of outsourcing or where to get started. There are plenty of opportunities to lower your stress levels by hiring an outside contractor. Here are some tips on how to get started, and how to successfully engage an outsourcing company.

Hi, I’m Zacharias Beckman, President of Hyrax International and I wanted to talk a little bit more about successful strategies for outsourcing. We recently had our client of us ask how they could be more successful with their outsourcing and stay focused on what they do really well. Outsourcing helps us focus on our core competency, by taking all these distractions and letting somebody else worry about them. And for larger firms, outsourcing will reduce costs, streamline operations and quite often get us to market faster.

We don’t hesitate to outsource legal services and accounting, so, why not other things? Services like Ziptask, oDesk and Elance, make it very easy to outsource a lot of services. For example, you can outsource a personnel assistant, or web research, data entry, SEO operations for your website. You can even have an entire website designed for you very easily.

All of these services –- oDesk, Ziptask, Elance –- they provide quick work, fast turn around, low prices, but a recurring problem is getting quality work. So, here are few strategies.

Number one, don’t take the first cheapest bid that you get. Instead, take your time, review the bids, look for the most literate bids and look for well reviewed respondents. Also, make sure that your contract, your work order, is very explicit and detailed in what it is you want.

You can also test out each respondent with a little bit of piece work before you actually give them the entire contract. Make sure they can do the work before you make a big commitment.

And finally, use project management services. Ziptask and oDesk both offer a managed level of support where they will provide an English speaking Project Manager to run the project for you and make sure the quality is there.

Also, don’t be too trusting and rush right into a deal. For example, if you are doing a new product development, you might consider outsourcing the product development and construction to one firm, but outsource the quality assurance to another firm. By separating these concerns the two firms essentially become check and balance to against each other.

Tell me three times: The importance of quality assurance

Tell me three times

The earliest military applications of quality control came about from needing to send messages with reasonable confidence. The protocol was simple: Send every message three times. This triple-redundancy provided a checksum against failure, and could be used to correct broken messages. Any difference between the three copies would usually only show up in one, so the remaining two could be treated as accurate. The incorrect third could be discarded. In time, of course, advances in technology and process made it possible to introduce far more advanced — and secure — methods of communication. But the principle still lives on today in formal quality assurance: By introducing a redundant check on a program or process, we improve our chances of success.

As an industry, software folks have invested a huge amount of time toward figuring out what goes wrong with most projects. The root cause is complexity and our ability to accurately manage that complexity. Finding a method that enables reliable and repeatable results is a tough problem, especially given the variables involved in every project: Changing business environments, customer demands, technical capability and understanding, and team makeup are just a few of the factors that affect every project in a multitude of ways.

To combat the problems of complexity different best practices have become popular — some good, and some abysmal. The more successful techniques have a common theme: The idea that we can manage all this complexity by introducing multiple checkpoints.

Quality assurance and checkpoints

This is what quality assurance and structured software testing is all about — and yet, at least in the commercial industry — there’s always pressure to cut quality assurance or testing budgets. Take, for example, a recent project that ran about 18 months, involved well over 25 people, and launched to huge success (and zero defects in the product). The immediate aftermath of this successful effort? One might imagine kudos were in order. How many times do 18-month long, multi-million dollar projects get out the door without major problems? Instead, the project sponsors criticized the cost of development and, rather arbitrarily, said the team had “spent too much on quality assurance.” The reasoning behind this was simply that, since there were no bugs in the finished product, all that money spent on quality must have been wasted.

Management then demanded the quality assurance budget be cut dramatically — In fact, insisting they would not spend another dime on quality assurance. It was one of the most counterintuitive situations I’ve ever encountered.

The unfortunate consequence of this is an antagonistic relationship between project team and project sponsor. It brings into question how much visibility the sponsor should have when it comes to internal project budgets, and that’s a dangerous line to tread. At the same time, taking the position that QA will not be funded is crossing the line between budgetary management and meddling with technical process — and in this case, a process that had worked with stellar success.

The politics of management

Visibility should not be compromised. The project sponsor needs to know where costs are, and most project sponsors are not going to be happy with a single budgetary line item for “project development.” However, it is equally important that project teams and their organizations maintain a uniform front defending what works.

Stated another way, when you have something that works, treat it as a whole product that cannot be “sliced and diced.” Software development, at least those processes that work, cannot be subject to arbitrary and partial budget cuts. Cutting just the quality assurance department alters a working process. In this case, we had an unreasonable project sponsor that was not interested in understanding the complexity of building a product.

I held a firm line with our sponsor. We could not run a project with arbitrary cuts to parts of the program. Our compromise ended well enough. I was able to tell the sponsor that we would cut the budget across the board, not just in one department. At the same time we came to a mutual understanding: The sponsor was really just concerned with the big picture, the total number of dollars spent. As such, we agreed he would not see another line item labelled “quality assurance.” Future budget reports had a single line item for the total engineering cost, all inclusive of quality-related expenses.

The team, and the project manager, need to defend a system that does a good job. The sponsor needs to be informed that budget cuts cannot arbitrarily target specific program components: Instead, the right way to tackle this problem is for the sponsor to cut the overall budget and let the project organization decide how that cut will be implemented. Most likely, cuts will need to be applied equally across the project — thereby reducing overall output, but not messing with a process that works.

Unfortunately, everyone needs to recognize that this can lead to losing a client or canceling a project. The question is, would keeping the project alive be worth the long-term headaches, knowing that cost will be a constant challenge? You might gain near-term budget cuts, but the problem will come back ten-fold when poor quality and schedule slips lead to unhappy customers.

Once you have a working program and methodology, don’t compromise on what it takes to deliver a project right. It’s better to decide it’s too expensive and walk away, rather than put everyone through the mess of a poorly run project.

Managing with blinders on

Most managers today have blinders on when it comes to solving the problems of complex projects: They are lost among the trees, and can’t see the forest for what it really is. In a recent discussion in the popular Project Management forum of LinkedIn, one moderator posted the question, “what is the most common mistakes of project managers?”

During the ensuing discourse respondents from around the world posted not less than 18 different answers to this question.

Among the responses were answers such as “having poor stakeholder involvement,” “not enough project planning,” “poorly documented requirements,” “the budget being too small or poorly estimated,” and “the [project] goal is not consistent.” To be sure, many of these 18 answers are highly relevant to the success of a project — and yet, every single answer was wrong. None of the 18 responses identified the single, most common mistake of project managers.

In fact, each answer emphasizes the root of the problem: Too many project managers are focused on the day-to-day problems of the project and have lost sight of their overall strategy. They are thinking tactically, putting out fires, rather than strategically — making sure the fires never happen in the first place.

Take, for example, a few of the more common issues raised in this discussion:

  1. Poor stakeholder involvement. Let’s assume for a minute that we have a solution to this problem — perhaps, for example, a project manager has correctly identified all the stakeholders, put together a great communication plan to keep the stakeholders informed, and succeeds in building a collaborative environment with the stakeholders “at the table” on a regular basis. If this solves the problem of stakeholder involvement, does it actually save most of the projects that go off the rails?
  2. The budget was too small. Again, let’s assume that the right process was used to estimate the project from the start, and that the project manager uses a solid method for measuring performance, cost, and schedule (say, Performance Based Earned Value). Certainly, budget overrun is a common problem, but would this actually solve most project problems?
  3. Poorly documented requirements. In my experience, every requirement is poorly documented to start with — so, let’s assume that the right approach is taken to turn poor requirements into great requirements. Quality assurance is involved early, a full-circle approach ties requirements to work product to acceptance, excellent change management is used, and stakeholders provide a final consensus. Will producing great requirements really save more projects than any other strategy?

The list, of course, goes on quite a long ways — and that’s the point. The list is long, and every single item raised is a valid concern for project managers. But with 18 different root causes on the table, could any one of them really make that much difference is the overall landscape?

These are all tactical solutions to specific project problems. So what’s the big picture? What is the one thing that would actually make the biggest difference, that would actually address many, perhaps even most of these 18 different issues?

Let’s take another look at KPMG’s survey of 252 organizations, and their subsequent findings. According to the study, inadequate project management implementation constitutes 32% of project failures, lack of communication constitutes 20%, and unfamiliarity with scope and complexity constitutes 17%. Taken together, 69% of project failures ultimately trace back to poorly implemented project management practices. What this means is simple: Project managers need to step back from the tactical, day-to-day fire fighting, and take a more strategic view. Adopting the right project management strategy will address most of the problems at hand.

How so? Let’s reconsider those first three project issues above.

  1. Poor stakeholder involvement. A thorough project plan, adopted out of an appropriate project management methodology that is fit for the purpose, will place the right emphasis on stakeholder involvement. It will also provide the right tactical tools make sure stakeholders are involved, and appropriate measures should stakeholder involvement begin to fail.
  2. Budget problems. A correctly selected project management methodology will put the right emphasis on budget analysis, and will provide the right tools to stay on top of the budget. The project manager may need to look outside his or her own skill set to manage to those requirements — but the methodology will establish the goals, the tools, and the metrics from which deviation triggers a red flag.
  3. Poor requirements. The right project management plan will include appropriate methods, probably mandated as part of a technical requirements standard, for developing strong requirements. The plans will include adequate validation and verification of requirements — possibly through strong quality assurance measures. Again, all of these tactical solutions will become part of the project and solve the overarching problem.

So, the root cause of project failure — in fact, of 69% of project failures, according to KPMG’s study — is failing at the strategic level to identify and implement appropriate project management practices.

This means choosing the right standards and methodologies for the project. For instance, if tight quality and budget is a concern, more rigorous controls in this regard are needed. That probably means shunning simple methodologies such as lightweight, agile methods in favor of something that uses more ceremony and process (such as that defined in the PMBOK® and other classical project management approaches). It also means sticking to your guns and making sure the methodology is applied. Showing the methodology to the team and putting it on a bookshelf won’t cut it. Application is the key, and that means recognizing that the standards, practices, and procedures are there for a reason — don’t take shortcuts, because doing so means introducing risks to your project’s health.

Do hackers make the best testers?

Recently, I was asked “what makes a good software tester,” and as a subtext, whether hacking and testing share a similar mindset, and how wide a skill set testers need to have.

I think the most valuable asset a Software Tester can have is an attitude of gleeful problem discovery. Someone that loves to break systems, discover their imperfections, and explore their weaknesses makes a great tester. I haven’t met many people that really enjoy and excel at this, but it’s probably is an attribute that is common with Hackers as well.

It’s also wonderful to have a tester that really cares about the quality of the product. It’s absolutely essential for someone that wants to excel as a tester. That means having the patience and desire to work closely with the Quality Assurance group, to understand what a “good customer experience” means, and to really grasp things like quality of services, user experience, and customer needs.

Part of being a good tester means enjoying running down the rabbit hole. Where the hole leads is a mystery. Perhaps testing discovers problems stemming from poor UI design, SQL injection problems, performance issues caused by heavy loading, or playing the clueless user that always clicks the wrong thing and triggers a logic error.

The “how” of testing is another matter though. Yes, there are well understood principles and techniques, and often tools, for testing all of these things. I have found that in most cases, good testers tend to specialize. I don’t expect to find one person that can find the flaws in the user interface, perform load testing, and also look for SQL injection vulnerabilities. To get really good at all of these things, you need a team — some of those team members will focus on the back end, some on security, some on database systems, some on the front end. Finding someone that’s great at tackling a couple of those verticals is pretty rare. That said, every tester should have an adequate, at least shallow understanding of all of these areas. In order to properly localize a problem, you need to understand what could be causing it. But having other resources to bring in to help diagnose the specialty areas is critical.

Successfully applying lessons learned

In theory, capturing lessons learned at the end of a project sounds like a great idea. Who wouldn’t want to reflect on what was done right, what could be done better, and then apply those lessons to the next project? In practice, though, it is sometimes a different story. It may be a lack of time, resources, interest, or follow-through that causes lessons learned to fall by the wayside. Or, even if they are captured they may not necessarily be implemented. So what makes successful application of lessons learned possible?

Probably the most important factor to me is accessibility. Actually capturing lessons learned is relatively easy (as long as it’s embraced by project and team leadership). Problems, issues, ideas are still fresh in people’s minds so voicing them is not the problem. Management needs to recognize this and embrace the idea that some time needs to be invested in capturing lessons learned — and not just at the end of the project, but throughout its lifecycle. In my experience, this is pretty easy to achieve.

It’s returning to the information and using it in the future where most organizations fail to follow through. 

Having a system in place that makes sure the lessons learned knowledge base is consulted and used in the future is critical. My favorite approach is a well structured, collaborative, wiki-like system. For example, Atlassian’s Confluence has proven great in the past. It offers an open information repository that anyone can contribute to. It’s rich in terms of media integration, and it has version control and sufficient security to ensure that nothing gets lost. 

But most important, the system needs to provide a ready reference library. That means an excellent search capability and well thought out keyword or classification systems. Project managers and leads need to know they can consult the knowledge base, quickly find relevant lessons learned, and apply them to their current project. 

This also means capturing a lot of information. The tool is only useful if it really has a significant knowledge base. Lessons learned need to encompass the positive as well as the negative. Project performance statistics need to be in there. Specific development problems and solutions. Having a cross-reference to your support system or ticketing system is a great idea, because the team can look up generalities and then link directly to hands-on end results from past projects. 

Building the right kind of system is critical. Think about building a reference library. What does it take to feed the library, and what does it take to make it easy to access?

Bad employees rarely quit and good ones are hard to find

Finding great employees is really hard. I don’t mean it’s difficult — I mean it’s virtually impossible to succeed in hiring great employees all the time. It’s equally hard to keep them, as it turns out. As Don Rainey recently wrote:

Good employees are really hard to find — A solid worker isn’t just difficult to find, he or she is really difficult to find. And they’re the first ones to leave. The truth is that 10 percent of the world is competent – and you’re looking for that 10 percent in every hire.

It’s hard to do consistently. And that’s why organizations that do it with frequency have such strong reputations. If you want to build a business predicated largely on finding, getting and keeping quality employees to succeed, you should understand that premise will be your greatest risk. Finding a market and profitably selling to it (usually the greatest risks) will take a back seat. Better yet, pursue a business that needs some reasonable percentage of employees to be really good.

But if that news isn’t bad enough, consider the other side of the coin — if you don’t have really great employees filling your ranks, then what do you have?

Your bad employees rarely quit — For one thing, poor performers aren’t really all that motivated to look, as that might involve actual performance. For another, no one else is likely to recruit them. Your marginal and weak employees are with you for life unless you move proactively. In many years of running businesses, the only time this wasn’t true was during the dot-com bubble. At that time, every idiot could get a 15 percent to 20 percent raise here in Northern Virginia by changing jobs. And they did. Aside from that blessed time, weak employees are your most “loyal.”

Don makes a good point, among several others (his article is 8 things I wish I knew before starting a business): Having, and holding on to, great employees is very, very hard work.

It’s also quite possibly the one sure-fire factor that’s going to push your company toward success. Consider a few of the leaders in the technology industry, such as Apple and Google. Both have stringent hiring processes and focus on the quality of the hire first, and growth second.

Let’s put it another way: Does it make sense to focus on growth if what you are growing is mediocre (or worse)?