Tag Archives: HackerNews

F#, Mono, Agile, Architecture, DevOps

Several people have asked online lately, “Can you really write production code in F# and mono?”, “How are you doing architecture now that you’ve switched completely to F#”, and “Aren’t you doing some kind of weird thing now that doesn’t work with interactive websites?”

I usually don’t do coding blogs, because, frankly, after a while it all gets pretty boring. Same old bytes, just new bells and whistles on top. But my approach to architecture has changed in a major way over the last five years. Might as well document it.

Description of Problem Domain. For our sample project, let’s take Newspaper23. It’s a production system with a small number of users that’s been running for a few years and has evolved through my change in philosophy.

Newspaper 23 exists for one reason: I have a very short attention span. Websites are always trying to get me to hang around, click on related stories, sign-up for things, and so on. I find this very distracting. It’s very easy for me to spend a lot of time online that’s unproductive. So a few years ago I had an idea: since the news I consume is all from a dozen or two sites, why don’t I just harvest the titles and links from those sites and put them in a big list? Then I’m choosing what content to consume based on the site brand and the title of the article, not social cues or any other nonsense.

So I got out my credit card, went over to Amazon AWS, and fired up the site.

The Old, Old Way of doing things. The first time through, I did this in a “classic” manner. I sketched out a domain model, I elaborated a bit on a database model, I built a database model in MySQL, and I created a new C# app in Visual Studio and wrote a program to do everything that was needed — get some links, save the data about them, create a page with the links, do some “other stuff”.

The problem was, I was never really clear what the program should do. Should I collect the votes the article had from reddit? Don’t know, so I’ll throw that in there and save it. Might need it later. Should I provide the ability to comment, or vote? Don’t know. I’ll add space — after all, space is cheap — and if I need it, it’s there. Should there be some kind of authentication? Beats me. (Decided to skip that one)

Don’t get me wrong; none of this was a heavyweight or Big Design Up Front process. I’m only talking about an hour or two of doodling around with things. And the beauty of modern tools is that it really doesn’t matter whether your table has 5 fields or 10. Unless you’re writing the code to do something with the data, it’s just “out there”.

It did make the “link sucking” process a little more complicated, because with different sites I had to get different pieces of data. Fair enough.

What happened. After a couple of weeks of off-and-on coding, I got the program up and running, along with a unique system for identifying data on a web page to harvest. (It was a recursive RegEx language. Please, no “but you can’t use Regex on html!” It looked good.) The code base consisted of a data tier, some controller logic on top, and it seemed to work fine.

For a while.

But over a period of just a few days or weeks, it seemed like there were always these weird edge cases, both in the sites, and more disturbingly, in the tool version, setup, and configuration. Site X would change their format, and I’d be in the code changing the way I received links. Yes, I had hard-coded in the parameters for each site, but how difficult was it to change some hard-coded values once or twice a year? Except the more source code there was, and the more I touched the code, the more errors I got. And it seemed like for one reason or the other with this way of programming there was a boatload of code to wade through and I was always horsing around with it. [insert discussion here about TDD]

By using a MVC paradigm, I had written one piece of software that I could easily lay a bunch of different controllers down on. In fact, as we all know, I could develop a “controller library” over time that would take the data and do all sorts of wondrous and amazing things. That’s the beauty of a good model — it facilitates many different solutions.

I still think this might be the way to go, assuming 1) you use good testing practices, and 2) you’re going to constantly be under the hood in the code for a long time. But it introduced all kinds of problems related to having everything pass through one executable and code base. Did I really want to horse around with the code that grabbed links, for instance, simply because I was fixing the code that wrote the web page? Why was I putting all of my eggs in one basket? OOP is a great way of doing things, but it introduces a freaking huge amount of hidden interdependencies. Some times I wonder if 90% of the problems development teams have with programming is based on the fact that in the developer’s mind there is separation of model and controller, but that in the wiring itself, things can be all hooked together in completely insane ways, usually for what seemed like good reasons at the time. The black box of OOP has a lot of very sharp edges.

The Old Way of doing things. The first thing I did was ditch C#. It’s a great language, a better Java than Java, but it was the wrong paradigm for me. The second thing I did was start to build the app from the ground-up. Programming functionally required me to write functions that did things. This sounds blazingly obvious, but it’s actually a much different way of looking at things from creating a model and adding controllers on top. I still used the MySQL datastore — had to put stuff somewhere — but my code was a LOT smaller.

It also needed much less tweaking. Remember: this is personal programming. Instead of sitting on top of a model that could do many things and having to choose what to implement, which might cover calls all over the place, my code did a few things, and there was a clear path to the data for the things it did.

What happened. There was still that problem with everything running through one spot. If I wanted to tweak anything, anywhere, I’m opening up the entire codebase to make a change.

Interestingly, since this was revision 2, the code ran for much longer without needing tweaking. This meant that when I did get around to tweaking it, I had forgotten the build setup! So I’d have a 2-line change that would require screwing around with re-remembering the build-deploy environment. That might take several hours. Plus the sites were still hard-coded. The output was hard-coded. As much as I loved data-driven programming, why was everything so coupled?

Along this time I built HN Books, a social book site for hackers. It was all static. I found I could do a lot with static web pages and JSON files. Much more than most web programmers would believe.

Hmm. Fuctional programming. Static pages. Hmmm.

The way I do things now.

So now I have a new philosophy:

  • Third time through, I decided I write small programs. As small as I can. Instead of one big honking system, my system has four programs: GetLinks, UpdateArticleLibrary, CreateSelectedArticleList, and FormatSelectedArticleList. There’s a bonus utility, CheckXPath, which lets me check out XPath strings against websites to make sure they work (in case the site layout changes). I use as few external libraries, tools, or frameworks as possible. Over the years, I’ve found that every tool I picked up had 40 tons of features, of which I only needed 3. That meant that whenever I needed to do something simple that I had never done before, I had to wade through all sorts of forums, hearing about all sorts of arcane switches and other stuff. Screw that. I do not need to buy and operate a nuclear attack sub to go fishing from the pier. So — no Visual Studio, no MySQL, no complex dependencies at all. (Having said that, I actually dumped my custom link-sucking system and went with HtmlAgilityPack. I mean heck, once it’s installed, it’s just XPath. Time spent learning XPath is not as completely sunk as time spent learning WhizBang 7). Simplify.

  • My files read and write data on the local storage. I’m not doing transactions, therefore I don’t need a transactional datastore. It’s functional coding. Things come in, things go out. The O/S already has a wonderful tool for storing things. It’s called a file system, and unless I’m going to be moving around tens of thousands of these things, it’ll work just fine, thank you. Simplify.

  • I use the O/S to schedule when the programs run and to move things around. Instead of having one program that runs once a day, split the work up into a “pipeline” and have the O/S manage the pipeline. It’s already good at managing processes — it has all kinds of tools for it. Use them. Simplify.

  • I don’t “interact”. I process things at certain times. In the old days, I’d have an instance of my program spun up in Apache, waiting around in fastCGI for a client to come and connect. Then the program would do all sorts of things depending on which client it was, what the request was, and so on.

    After many, many years of coding like this, I had to ask myself: why? Why the hell am I doing it this way? 9 times out of ten I’m delivering the same content. 9 times out of ten the client is just reading stuff. 9 times out of 10 I’m creating database connections, cursors, and all sorts of other cruft — just to send the same stuff back down the wire as I sent 2 seconds ago. For the huge majority of the use cases I can imagine, even for interactive sites, there’s no difference at all to the user between a program that sits waiting for connections and a series of programs that updates data every few seconds. This is stupid. Don’t do this any more. Decouple. Simplify.

  • I write simple queries to monitor how things are moving through the pipeline. Quite frankly, the system is running so well I don’t need to monitor it, but if I did, I’d simply monitor how things flow through the pipeline. I could even make a nice html page with graphs. Don’t need to, but it’s an easy option. In fact, I’d argue that the only things interesting to me as a owner/maintainer would be things visible at a system level, not a programming level. Huge win here: no programming skill required to look at CLR innards, just O/S skills. Simplify.

  • Nothing exists as hard-coded data. It’s all either config files or command-line parameters. Right now as I bring up the page, I can see that Hacker News isn’t returning any data. If I wanted, I could probably figure out what the problem was and fix it (assuming it was fixable on my end) in about 10 minutes. No programming required. All I need is a shell. I AM re-coding the system, kinda. I decided that since I have 10-15 functions that are the same across each executable, it would make sense to create one Visual Studio solution and share a couple of library source files. Welcome back to the days of shared C header files! I’m also making the logging more robust. Right now I log everything. (I don’t read the logs, but they are there.) This is using up too much disc space. Every few months I have to clean it out. So a more fine-tuned logging system would be nice. Maybe. Maybe not. Simplify.

  • TDD? TDD? We don’t need no stinking TDD. With purely functional programming, there are only 3 mistakes I can make: Failure to break down transforms into understandable atomic units, failure to describe the transform correctly, and failure to validate the data. If I do all three of those correctly? There’s nothing to test. It’s like trying to test an SQL select statement. The idea doesn’t make sense. Simplify.

It’s very nice. Here’s the main function for the first program in the chain, GetLinks, that gets links from sites (duh):

Code Snippet
  1. [<EntryPoint>]
  2. let main argv =
  3.     try
  4.         let opts = parseCommandLineArgs (Array.toList argv)
  5.         if opts.verbose >= Verbosity.Normal then
  6.             printfn "Options Selected:"
  7.             printfn "%A" opts
  8.             printfn ""
  9.         let config = getConfigData opts
  10.         let outputDataHolder = {
  11.             outputSections = new System.Collections.Generic.Dictionary<string, outputSection>()}
  12.         let outputData = ripLinks opts config outputDataHolder
  13.         printfn "Processing Complete for %A" opts.siteUrl
  14.         let numberOfDataPointsMatchMessage =
  15.             if outputData.outputSections.Count>0
  16.             then
  17.                 let max = outputData.outputSections |> Seq.maxBy(fun x->x.Value.outputList.Count)
  18.                 let maxCount = max.Value.outputList.Count
  19.                 let min = outputData.outputSections |> Seq.minBy(fun x->x.Value.outputList.Count)
  20.                 let minCount = min.Value.outputList.Count
  21.                 if maxCount = minCount
  22.                 then
  23.                       maxCount.ToString() + " links with " + (outputData.outputSections.Count-1).ToString() + " pieces of additional information about each link gathered."
  24.                 else "Number of links, titles, and other Data DOES NOT MATCH.\r\n" + max.Key + "  has " + maxCount.ToString() + "entries while " + min.Key + " has " + minCount.ToString() + ".\r\nCheck your configuration file or run this program with the verbose option set /V"
  25.             else
  26.                 "\r\n\r\nTHERE WERE NO SECTIONS OUTPUT.\r\nPlease check your configuration file.\r\nTry running this program with the /V option"
  27.         System.Console.WriteLine(numberOfDataPointsMatchMessage)
  28.         0 // return an integer exit code
  29.     with
  30.         | :? UserNeedsHelp as hex ->
  31.             System.Console.WriteLine("You'd like help")
  32.             System.Console.WriteLine("Good luck with that")
  33.             System.Console.WriteLine("/V for verbose output")
  34.             System.Console.WriteLine("/S:<url> to set the target site url")
  35.             System.Console.WriteLine("/C:<filename> to set the config file used. Config file is expected to have Windows line returns \r\n")
  36.             System.Console.WriteLine("/O:<filename> to set the output file created/overwritten")
  37.             System.Console.WriteLine("/N:<integer> number of links desired")
  38.             System.Console.WriteLine("")
  39.             0

This is 50 lines of code. But it’s really only 4, lines 204-207. It gets the configs passed in. It creates a new container to hold the output data, it processes the link, and then it saves the data (which happens in the ripLink function. Should be down in this one. Ugh.) The rest of it is logging and help system stuff.

I could show you ripLinks, but it’s the same deal: 50 lines of code which are really about 10. It gets the links from the page using the “ripLinksOnAPage” function (clever naming, eh?), then it processes the links according to the config file.

Let’s look at how it breaks up.


As you can see, there are really only 5 functions, ripLinks, http, loadHtml, recBuildLinksUp, writeLinksOut, and ripLinksOnAPage. The rest is either library calls or a few small helper functions. Take out the logging and some of the other broilerplate, and there’s maybe 50 lines of “real code” here.

We’ve done something simple, easily describable, and concrete. We took stuff from the file system, read a webpage, wrote stuff to the file system. Logged as we went along. That’s it. No need to solve world hunger. It has value.

This code has been running for more than a year with no modifications. I expect it to continue running forever. I’m done. Isn’t that nice?

Common objections.

It’s re-inventing the wheel. In most cases, I don’t need a wheel. I need a lug nut. Yes, I know what the wheel looks like, but the cognitive load of buying a big stack of wheels and carrying them around when I just need a couple of lug nuts? Tell you what. If I start thinking about round things to fit on cars, I’ll get a wheel. Otherwise I’m fine.

It’ll never scale. The funny part about this objection is the opposite is true: the more complex your stack, the more difficult and nuanced it is to scale. I can take this app and scale it out as far as I like. Heck, copy it to a CDN. We’re done. And for those of you thinking interactivity, think long and hard whether you need immediate feedback for the user or just something that changes every few seconds or once a minute. You could be spending a huge number of processor cycles worrying about concurrent clients when you really don’t need it.

It’s poorly-thought-out. My datastore? Line-delimited text files. Code complexity? Nothing more than a few hundred lines of code. Is there anything it can’t do? Not really. But (and this would be the objection I would have made several years ago) what if you want it to do something that required the data to change? Wouldn’t you have to re-jigger every piece of code in the pipeline?

Not really. First, because I’m using name-value pairs, I can always add data and not use it. So really, what would happen if I wanted some cool new feature would be 1) I’d change the data representation where it was created, 2) I’d add the code to store it, and 3) I’d add the code to use it. If you’ve worked in a functional environment, this is the way you make changes anyway. Nothing new here.

It’s not as cool as X. Probably not.

The deployment process is brittle. Actually, although I’m not continuously deploying what I write — there’s no need to automate it when it’s just me — I’m integrating DevOps directly into the solution. There’s no one part of this solution that’s “programming” and another part that’s “deployment”. It’s all integrated together. Instead of good coupling and cohesion at the function level, I have good coupling and cohesion at both the function and the executable level. Very cool stuff.

Continuing to add features. The very next thing I’m going to do is add/adjust the logging. Having to clean out the logs once every 3 or 4 months is a chore. Next up in my quest to eliminate distractions, I’ll probably go to the target site and rip the plain text and store it here. I’ve thought about adding voting and commenting, but it’s a personal site.

None of this will require a major change or a re-think of how the architecture works. Mostly the system just works and I don’t have to mess with it. O/S updates handle updating security and scaling problems. I worked a bit to make the solution, and now the solution works for me. And isn’t that the entire idea?

If you've read this far and you're interested in Agile, you should take my No-frills Agile Tune-up Email Course, and follow me on Twitter.

Startup Standup Startup

standup-iconsI’ve been coworking at a nearby town and a couple of us decided to try to help encourage each of us in our startups.

Being a startup junkie and an Agile Coach, I thought, “Why not a startup standup?” Each week we meet in person. There, each of us announces what they accomplished in the last week, what they’re planning in the next week, and what they’re number one problem is. No classes, no group-gropes, no fluff. Immediately after the ten-minute standup we can each help each other if one of us has an obstacle that we know about. Plus we can help each other position our work mentally in order to focus more on the right stuff and less on the wrong stuff.

So how to describe what we should be talking about?

I pulled down a couple PG essays, a blog on the Lean Startup concept, and some notes Derek Sivers made while reading the Lean Startup book. But heck, it was still too much verbiage. Put together, it was WAY too much to expect noobs without context to plough through. I decided to cut a bit. So here’s an effort to make a crash course in what you should know and talk about during a weekly report of your activities in a startup. I liberally edited for clarity and brevity.

1. What is a startup? (From PG’s 2012 essay)

Not every company is a startup. Millions of companies are started every year in the United States. Only a tiny fraction are startups. Startups are companies that make something people want that have the ability to scale rapidly. They may or may not involve technology.

For a company to grow really big, it must (a) make something lots of people want, and (b) reach and serve all those people. Barbershops are doing fine in the (a) department. Almost everyone needs their hair cut. The problem for a barbershop, as for any retail establishment, is (b). A barbershop serves customers in person, and few will travel far for a haircut. And even if they did the barbershop couldn’t accommodate them.

Writing software is a great way to solve (b), but you can still end up constrained in (a). If you write software to teach Tibetan to Hungarian speakers, you’ll be able to reach most of the people who want it, but there won’t be many of them. If you make software to teach English to Chinese speakers, however, you’re in startup territory.

Most businesses are tightly constrained in (a) or (b). The distinctive feature of successful startups is that they’re not.


2. Do you need a cool idea?

No, you do not.

3. What are you concentrating on and talking about while you are developing your startup? You are creating and testing value and growth hypothesis. A value hypothesis is a concrete way to determine what you are doing has value to your customer. A growth hypothesis is a concrete way to determine how you gain new customers. These are both measurable, and you have to have real results that indicate success or failure for your hypothesis. That means heavy, direct interaction with the people you are supposed to be making things that they want. More Lean Startup goodness from Sivers’ notes:

Startups are human institution designed to create new products and services under conditions of extreme uncertainty.

The stories in the magazines are lies: hard work and perseverance don’t lead to success. It’s the boring stuff that matters the most.

Startups exist to learn how to build a sustainable business. This learning can be validated scientifically by running frequent experiments.

The goal of a startup is to figure out the right thing to build – the thing customers want and will pay for – as quickly as possible.

Too many startup business plans look more like they are planning to launch a rocket ship than drive a car. They prescribe the steps to take and the results to expect in excruciating detail, and as in planning to launch a rocket, they are set up in such a way that even tiny errors in assumptions can lead to catastrophic outcomes.

The customers failed to materialize, the company had committed itself so completely that they could not adapt in time. They had “achieved failure” – successfully, faithfully, and rigorously executing a plan that turned out to have been utterly flawed.

Instead of making complex plans that are based on a lot of assumptions, you can make constant adjustments with a steering wheel called the Build-Measure-Learn feedback loop. Through this process of steering, we can learn when and if it’s time to make a sharp turn called a pivot or whether we should persevere along our current path.

Validated learning is the process of demonstrating empirically that a team has discovered valuable truths about a startup’s present and future business prospects. It is more concrete, more accurate, and faster than market forecasting or classical business planning.

Learning is the essential unit of progress for startups. The effort that is not absolutely necessary for learning what customers want can be eliminated. I call this validated learning because it is always demonstrated by positive improvements in the startup’s core metrics. As we’ve seen, it’s easy to kid yourself about what you think customers want. It’s also easy to learn things that are completely irrelevant. Thus, validated learning is backed up by empirical data collected from real customers.

Learn to see every startup in any industry as a grand experiment. The question is not “Can this product be built?” In the modern economy, almost any product that can be imagined can be built. The more pertinent questions are “Should this product be built?” and “Can we build a sustainable business around this set of products and services?” To answer those questions, we need a method for systematically breaking down a business plan into its component parts and testing each part empirically.

One of the most important lessons of the scientific method: if you cannot fail, you cannot learn.

A true experiment follows the scientific method. It begins with a clear hypothesis that makes predictions about what is supposed to happen. It then tests those predictions empirically. Just as scientific experimentation is informed by theory, startup experimentation is guided by the startup’s vision. The goal of every startup experiment is to discover how to build a sustainable business around that vision.

A minimum viable product (MVP) is simply the fastest way to get through the Build-Measure-Learn feedback loop with the minimum amount of effort. The goal of the MVP is to begin the process of learning. Its goal is to test fundamental business hypotheses.

Most entrepreneurs approach a question like this by building the product and then checking to see how customers react to it. I consider this to be exactly backward because it can lead to a lot of waste. First, if it turns out that we’re building something nobody wants, the whole exercise will be an avoidable expense of time and money. If customers won’t sign up for the free trial, they’ll never get to experience the amazing features that await them. Even if they do sign up, there are many other opportunities for waste. For example, how many features do we really need to include to appeal to early adopters? Every extra feature is a form of waste, and if we delay the test for these extra features, it comes with a tremendous potential cost in terms of learning and cycle time. The lesson of the MVP is that any additional work beyond what was required to start learning is waste, no matter how important it might have seemed at the time. [Which may include actually building anything at all]

(Dropbox:) To avoid the risk of waking up after years of development with a product nobody wanted, Drew did something unexpectedly easy: he made a video. The video is banal, a simple three-minute demonstration of the technology as it is meant to work. It was all he needed at first to test a value hypothesis. Many entrepreneurs refuse to spend any time in development at all until some initial value and growth hypotheses have been tested in the real world and they have real metrics from the tests. (Anecdotes, like “I showed it to twenty people and they liked it” are not real metrics)

MVP can seem like a dangerous branding risk. Easy solution: launch the MVP under a different brand name. Experiment under the radar and then do a public marketing launch once the product has proved itself with real customers.

Prepare for the fact that MVPs often result in bad news.

The solution to this dilemma is a commitment to iteration. You have to commit to a locked-in agreement – ahead of time – that no matter what comes of testing the MVP, you will not give up hope.

A startup’s job is to
(1) rigorously measure where it is right now, confronting the hard truths that assessment reveals, and then
(2) devise experiments to learn how to move the real numbers closer to the ideal reflected in the business plan.

The failure of the “launch it and see what happens” approach should now be evident: you will always succeed – in seeing what happens. Except in rare cases, the early results will be ambiguous, and you won’t know whether to pivot or persevere, whether to change direction or stay the course.

Entrepreneurs need to face their fears and be willing to fail, often in a public way. In fact, entrepreneurs who have a high profile, either because of personal fame or because they are operating as part of a famous brand, face an extreme version of this problem.

I recommend that every startup have a regular “pivot or persevere” meeting.

Remember that the rationale for building low-quality MVPs is that developing any features beyond what early adopters require is a form of waste. However, the logic of this takes you only so far. Once you have found success with early adopters, you want to sell to mainstream customers. Mainstream customers have different requirements and are much more demanding. A pivot is required.

Startups don’t starve; they drown.

Startups have to focus on the big experiments that lead to validated learning. The engines of growth framework helps them stay focused on the metrics that matter.

Companies using the sticky engine of growth track their attrition rate or churn rate very carefully. The churn rate is defined as the fraction of customers in any period who fail to remain engaged with the company’s product. The rules that govern the sticky engine of growth are pretty simple: if the rate of new customer acquisition exceeds the churn rate, the product will grow. The speed of growth is determined by what I call the rate of compounding, which is simply the natural growth rate minus the churn rate.

Focus needs to be on improving customer retention. This goes against the standard intuition in that if a company lacks growth, it should invest more in sales and marketing. This counterintuitive result is hard to infer from standard vanity metrics.

4. So formulating and reporting on hard metrics resulting from direct user contact that prove or disprove our value and growth hypotheses is what we should focus on. Once we do that, what are some common mistakes? (From PG’s 2005 essay)

  • Release Early. get a version 1 out fast, then improve it based on users’ reactions. By “release early” I don’t mean you should release something full of bugs, but that you should release something minimal.
  • Keep Pumping Out Features. I don’t mean, of course, that you should make your application ever more complex. By “feature” I mean one unit of hacking– one quantum of making users’ lives better. [Which should directly come from your hypotheses testing results]
  • Make Users Happy. There are two things you have to do to make people pause. The most important is to explain, as concisely as possible, what the hell your site is about. How often have you visited a site that seemed to assume you already knew what they did? The other thing I repeat is to give people everything you’ve got, right away. If you have something impressive, try to put it on the front page, because that’s the only one most visitors will see. Though indeed there’s a paradox here: the more you push the good stuff toward the front, the more likely visitors are to explore further.
  • Fear the Right Things. Most visible disasters are not so alarming as they seem. Disasters are normal in a startup: a founder quits, you discover a patent that covers what you’re doing, your servers keep crashing, you run into an insoluble technical problem, you have to change your name, a deal falls through– these are all par for the course. They won’t kill you unless you let them.And in any case, competitors are not the biggest threat. Way more startups hose themselves than get crushed by competitors. There are a lot of ways to do it, but the three main ones are internal disputes, inertia, and ignoring users. Each is, by itself, enough to kill you. But if I had to pick the worst, it would be ignoring users. If you want a recipe for a startup that’s going to die, here it is: a couple of founders who have some great idea they know everyone is going to love, and that’s what they’re going to build, no matter what.
  • Commitment Is a Self-Fulfilling Prophecy. I now have enough experience with startups to be able to say what the most important quality is in a startup founder, and it’s not what you might think. The most important quality in a startup founder is determination. Not intelligence– determination. [In fact, intelligence, like funding, can be counter-indicative of success.]Time after time VCs invest in startups founded by eminent professors. This may work in biotech, where a lot of startups simply commercialize existing research, but in software you want to invest in students, not professors. Microsoft, Yahoo, and Google were all founded by people who dropped out of school to do it. What students lack in experience they more than make up in dedication. You can lose quite a lot in the brains department and it won’t kill you. But lose even a little bit in the commitment department, and that will kill you very rapidly.
  • There Is Always Room. So for all practical purposes, there is no limit to the number of startups. Startups make wealth, which means they make things people want, and if there’s a limit on the number of things people want, we are nowhere near it. I still don’t even have a flying car.
  • Don’t Get Your Hopes Up. This is another one I’ve been repeating since long before Y Combinator. It was practically the corporate motto at Viaweb.Startup founders are naturally optimistic. They wouldn’t do it otherwise. But you should treat your optimism the way you’d treat the core of a nuclear reactor: as a source of power that’s also very dangerous. You have to build a shield around it, or it will fry you.The shielding of a reactor is not uniform; the reactor would be useless if it were. It’s pierced in a few places to let pipes in. An optimism shield has to be pierced too. I think the place to draw the line is between what you expect of yourself, and what you expect of other people. It’s ok to be optimistic about what you can do, but assume the worst about machines and other people.This is particularly necessary in a startup, because you tend to be pushing the limits of whatever you’re doing. So things don’t happen in the smooth, predictable way they do in the rest of the world. Things change suddenly, and usually for the worse.

    Shielding your optimism is nowhere more important than with deals. If your startup is doing a deal, just assume it’s not going to happen. The VCs who say they’re going to invest in you aren’t. The company that says they’re going to buy you isn’t. The big customer who wants to use your system in their whole company won’t. Then if things work out you can be pleasantly surprised.

    The reason I warn startups not to get their hopes up is not to save them from being disappointed when things fall through. It’s for a more practical reason: to prevent them from leaning their company against something that’s going to fall over, taking them with it.

  • Speed, not Money. The way I’ve described it, starting a startup sounds pretty stressful. It is. When I talk to the founders of the companies we’ve funded, they all say the same thing: I knew it would be hard, but I didn’t realize it would be this hard.So why do it? It would be worth enduring a lot of pain and stress to do something grand or heroic, but just to make money? Is making money really that important?No, not really. It seems ridiculous to me when people take business too seriously. I regard making money as a boring errand to be got out of the way as soon as possible. There is nothing grand or heroic about starting a startup per se.So no, there’s nothing particularly grand about making money. That’s not what makes startups worth the trouble. What’s important about startups is the speed. By compressing the dull but necessary task of making a living into the smallest possible time, you show respect for life, and there is something grand about that.

I could probably tighten this up a lot further given some more time, but it’s definitely decreased in size from the 50 pages it started out as!


So 1st, definition of a startup: http://www.paulgraham.com/growth.html

Here are some notes from the book Lean Startup. Good stuff in here. http://sivers.org/book/LeanStartup

Value Hypotheses. http://thesquigglyline.com/2012/03/05/creating-and-testing-a-leanstartup-value-hypothesis-creating-and-testing-a-leanstartup-value-hypothesis/

Finally, some common mistakes. http://www.paulgraham.com/startuplessons.html

If you've read this far and you're interested in Agile, you should take my No-frills Agile Tune-up Email Course, and follow me on Twitter.

The Copycats at HackerNews

I’ve been a regular on a site called HackerNews for a few years now. It’s supposed to be a place where technical folks can talk startups, but mostly it’s kind of evolved into a sharing place for stuff that interests hackers.

But damn, the place has grown. From just a few hundred members, the site regularly gets hundreds of thousands of people viewing per day.

Over all this time I’ve noticed one clear trend: the rise of the copycat. Whatever you do or say that might be popular, there are hundreds if not thousands of people ready to jump on the bandwagon.

About 18 months ago I got tired of having to create lists of books for people to share on HN. Lots of new folks wanted to know what the best thing to read was. So I thought: why not make a site where we list only the best hacking books and people can create and share lists of them? hn-books.com was born.

But it wasn’t alone. I spoke about my intentions online while I was building it. Within the next month there were a dozen book sites spawned by the members of HackerNews.

I’m not saying it was my original idea, simply that once it was mentioned there were a zillion deployments of the same idea.

At first this was really cool. When the community discussed the need to have some app to strip websites of all the annoying visual garbage on them, wham! A bunch of different really cool sites do that now. (Which I think is awesome.)

But it has a dark side. The problem here is that while ideas are cheap, having 100 people all trying the same idea puts an extra amount of time pressure on an entrepreneur that normally isn’t there. Everything that is mentioned is copied a hundred or a thousand times. It’s as if you, a non-painter, decided to paint a picture of a house. So you set up your easel and get out your paints in front of a nice-looking house and start to puzzle over how to start. Suddenly 500 other people all arrive — some of them who actually know how to paint — and set up all around you. Not only is it annoying, it’s also distracting. And it can lead to a kind of herd mentality where everything is attempted, but nothing is really tried. Next week all the same noob painters are all setting up around a nice-looking barn. Repeat and rinse.

It’s gotten so bad that mentions of a specific business strategy on HN have become counter-indicative of the prospects of your successfully trying it out. The more directly-instructive an article was, the more folks that were going to go out and follow the directions, especially if there’s no cost involved.

It took me a while to figure this out. I finally understood it by observing what was not being done: founders were not giving specific details of their business model execution at the level where others could actually use it. So you’d get a great blog article about how some guy made his startup, and how awesome it was, but somewhere in his actual business would be a few tricks he used that he’d never mention. After all, who wants a thousand people all using your tricks? You’d be crazy to publish that stuff.

It actually happened to me once. About three years ago I came across something very unique: a step-by-step guide on how to set up an internet business online that was written by somebody who was not trying to sell me something. I found it on some obscure user’s group online — I don’t even remember the search terms. At the time, I was willing to try anything. What could a month or two trying this hurt? So I tried it.

Did it work? Yes and no. I learned something very useful from this exercise. Whatever you do for a startup is going to take a long, long time. Take however long you are willing to work, then multiply it times three. It requires a lot of dedication and attention to detail that I (and most others) probably don’t have. As it turns out, getting good at painting is more about the attention, dedication, and mentoring you receive in your work, and not so much about the house you choose to paint. But good luck learning that the first time out. Most folks never learn it.

Most of us are great at thrashing around for a few months! Tell us an idea about an app that mines Facebook data and makes money and there will be a hundred guys tomorrow firing up their code editors. Sure, in a few months most will be gone, but expect to see everybody and his brother coming out with the same idea in a short amount of time.

I get a lot of SEO spam on the blog and in emails. Some of it is automated, but I actually get a lot of people following me because I’ve dealt with SEO in the past. For most all of these people, SEO is a shortcut to riches. Write some crap, make a landing page, then script up enough code so that you generate links back and start making conversions. Sure, Google might shut you down in a few months, but you’ll be thousands of dollars richer and will have used fake credentials anyway.

It’s the ultimate in ADHD money-making. Crap + Code + Conversions = money.

Here’s the crux of the matter: there are people who actually invent an iFart and make hundreds of thousands of dollars in a month, there are people who sit down to paint and make something that sells right away, but odds are overwhelmingly that you aren’t that guy. Odds are you will generally develop as most other startups develop; over a long period of time as you assemble these various business execution ideas into something workable that supports some grand idea (what the grand idea is — not important. The less you focus on that the better.)

We’d all would like step-by-step instructions on how to make a million dollars in a month. But if somebody published it, guess what? Everybody would be doing it and it wouldn’t work. The system is rigged so that the easier it is to connect effort to money, and the more that know how to do it, the less likely it is for a newcomer to make it happen.

That’s not saying that short projects are a waste of time. I love short projects that stand on their own and compete for my attention. Do something for 2-4 weeks and then be done with it. Move on. But don’t expect to see any results for a few years, if ever. What I learn from these exercises is being able to repeat the entire span of startups: idea, execution, business model, marketing channel, and so on. If you ask me, anybody who wanted to teach startups would have people actually learning all of these things with “practice” ideas, over and over. As they gain competence through trial and error and repetition, they’ll develop a voice and style that will carry over to a working business.

So if you want to be a copycat, fine. Go for it. But pick your poison: pick one idea and stick with it for a year or two, or do the micro-startup idea thing I did for a while where you develop something new every couple of weeks. Whatever you do, don’t fall into the death zone. Don’t “fall in love” with an idea, screw around with it for 4-6 months, then give up. That’s the worst of both worlds: you’ve picked something and stayed with it long enough to get really emotionally attached, yet you haven’t given it the attention it needs to actually grow (or die). Then when you finally switch to something new, it comes as a failure.

And whatever you do, don’t follow along with some idea mentioned on a popular website like HackerNews — unless you like learning through pain. The only thing that’s going to happen is that you’re going to be reading about somebody else who tried the same thing and is now living the high life — without telling you exactly what they did that you missed out on. That’s not a learning experience, that’s self-torture.

tl;dr: because of both the mixed messages we send and the size of the HN audience, we’ve actually created something we didn’t mean to: an environment where lots of copying goes on, but not many are really working in a way that generates good learning about startups. Instead it’s much more of a copycat, cool-for-a-day, chase-the-herd atmosphere.

That hurts. Don’t do that.

If you've read this far and you're interested in Agile, you should take my No-frills Agile Tune-up Email Course, and follow me on Twitter.

Stop Creating Content You Evil Bastard

Over the last few years, I’ve been somewhat of an internet startup/content junkie: I’ve bought dozens of domains and developed sites that do all sorts of things. Some are webapps. Some are targeted niche content. Some are a mix. Some are aggregation sites. I’ve tried to get a feel for most all the different ways to create content on the web. As I’ve tried these ideas, usually I post my experiences over on HackerNews to get some feedback from the technical community.

And do I have news for you. Whatever kind of content you create on the web, you’re an evil bastard. There’s just no getting around it.

Surprised? Here are a few ways you are unknowingly nefarious:

Registrar selection. Stay away from GoDaddy. Aside from having the morals of used-car salesmen, they’ll turn off your site in an instance if they get any complaints from the feds — even if you’re doing nothing wrong.

User cookies (third party and others). If you own several web properties, surely you’re not going to keep track of the same user across them, will you?

Javascript. Scripting is the gateway to insecurity. Sites who use scripting could be trying to break into your system. Your site should not rely on Javascript.

Email collection. Don’t even think of asking for an email address, because all email lists are always just spam tools.

Content ads. The average content ad on the average blog makes something like 3 pennies a month. But to hear readers tell it, you spent 2 hours writing that blog entry just so you can pitch iPods at them. They have no idea of how web value is created, so they are suspicious of anything that’s associated with money.

Source cloaking/reader customization. Like to put up one banner for folks visiting from Reddit and another for folks visiting from HN? Be very careful. Search engines and the public distrust sites that change their text based on visitor properties (although I think if instead of calling it an article you called it an app that would work?)

Blog spam. I used to be a freelance writer back in the late 80s. We’d read stuff, do some work, then publish other stuff. This was called writing. Sometimes you only read one other article, then you created a news story from it. Sometimes you read ten articles and did three interviews. Sometimes you might watch a TV report and write an article. It all depended on your deadline and the nature of the topic.

Nowadays if you read a couple of current news stories on Apple and then write that same kind of piece, it’s called “blogspam”. If you read a couple of stories on Apple, one story on interface design back in your college days, and the Steve Jobs biography last week, then write a story, it’s called original. The premise is that style counts for shit. It’s all facts If you are adding no new facts from what appeared in some other source (say Wikipedia), you’re spamming. To hear some tell it, the internet is a collection of facts all having authoritative/original sources that should be respected. Nobody cares about your unique way of looking at current news or idiomatic way of explaining facts we all know, especially if you have, gasp, ads on your site. You can post an asinine and ill-informed rant about Apple or Microsoft on your blog, we might love that, but don’t dare just tell us the same thing we could find out reading TechCrunch in your own style. Very bad.

Niche writing. My editor used to talk to his advertisers, read the demographics of his audience, and then assign me things to write about. Sometimes they seemed pretty trite or boring. But he was always joining up the audience, the advertising money, and interesting content. My job was to make it work. Today if you do the same thing, you’re somehow being dishonest or a sell-out. Writing in the same fashion that I spent years putting food on the table is considered a modern-day form of slavery for English majors (admittedly the rates are much lower, but I’m not sure that has anything to do with the way the topics and content are created.)

Link spam. Spend some time googling for blog articles that cover things you care about, then make informed and interesting comments on them, linking back to your site? (I don’t do this much at all, by the way) This is a terrible thing to do. You are actually visiting and reading somebody else’s content simply as a way to help yourself!

Pictures. I have a site where I tag and share my funny picture collection. (I started collecting interesting/funny images a couple of years ago. The collection got so big I had to do something with it.) Best I can figure, any sharing of pictures is terrible — except with your friends on Facebook, G+, or Twitter. You’re not crediting the photographer (good luck finding him/her), you’re not creating things yourself, only sharing, you’re not adding a bunch of detailed new material, only curating other people’s stuff. And so on.

Self-promotion. Mention and pump something you did, like I just did with my funny picture site above? Stand-by to be accused of being a self-promoter. On some aggregation sites, it’s even a bad thing to do to submit your own material. Heaven forfend! My youngest son Jack got a Facebook account a few years ago. When he posted things, he always clicked he liked them. It struck me as odd, but then I thought “Why not? Why would you post things you didn’t like?” But of course the faux pas he made was in actually saying something nice about his own contribution to the universe. That should only be done by others.

Fake user accounts. A large number of the major sites you use on the web have used fake user accounts some time in the past in order to make the site look more busy than it was. This is because nobody wants to use an empty site. (Good luck getting the actual numbers on this. Nobody will talk about it.)

It’s gotten to the point I could look at any site on the Internet and start making a list of how they’re not to be trusted and are screwing over the public — if I wanted to.

And let me assure you, there’s no feeling in the world like spending a week or two carefully and lovingly creating a site in order to do something nice for folks — only to have somebody online treat you as if you just knocked over a liquor store.

My internet friend Swombat recently tweeted something like “Hey! I got my first hate mail! Must be doing something right.”

He has a point: the problem here is that you can’t stay away from being declared immoral once your audience is big enough. It’s impossible. If you garner enough eyeballs, people will snark at you — your motives are poor, your methods are low, and your values are sick. If you keep getting more popular, people will start actively making arguments that you’re the devil. Hell, they’ll start following you around.

One of the first lessons I learned as a blogger is the high number of readers to participants on a blog article. You might have 100 people read, and only 1 will upvote it on an aggregation site or make a comment. The same thing is at work here. I’d guess somewhere around 1-in-1000 consumers of your content will be pissed at you. Maybe they had a bad day, maybe they misunderstood your purpose, maybe their puppy died, maybe they’re 12 and don’t understand what you’re saying, maybe they didn’t even read the article, maybe they just don’t like the cut of your jib. And here’s a huge list of reasons they can pull off the shelf to use when they vent. We’re just getting started. There are lots more.

The bigger you are, the badder you’re going to be.

(In defense of the people making critiques, many of these technicques have been overused and/or smeared by people on the web who have taken them too far and acted in poor taste. It’s reached the point that, in some consumer’s eyes, any use of these things is very suspicious. They don’t trust anybody. That’s a throw-out-the-baby-with-the-bathwater kind of thinking, but all too prevalent, sadly.)

If you've read this far and you're interested in Agile, you should take my No-frills Agile Tune-up Email Course, and follow me on Twitter.

A Christmas Failure

Now that the gifts are unwrapped, the glow is gone, and the snow is falling, I was sitting here alone Christmas morning sadly thinking of how my mom and dad died this year and how I’ll never see them or hear from then again. How much I miss them. But instead of dwelling in melancholy, I thought it might be a good time to take a look at who got any benefit from my Christmas present I made for folks this year.

A few weeks ago I had an idea: why not write a free program for people as a Christmas present? It was a huge pain in the butt to write, but in the end I had an app that stored lists for folks. Nothing super or fantastic, just an app that stored lists.

After finishing a few days ago, I set about trying to tell as many people as I could about my gift, asking myself the question: just how many people can I give a present to, anyway?

And now we have the answer. In the last few days, from the logs, the results are:

Total visitors 587
Total data entry attempts 45
Lists entered 35
Lists retreived 42
New users created 22

Only 22 users! And 3 of those were guys trying a SQL injection attack.

But it gets worse. I immediately started counting up the failures of the experiment. Out of 150 Facebook friends I messaged to tell about my gift, 25 of them dumped me for simply messaging them and telling them I had made a Christmas present. That’s about 16%. Out of the almost 600 people visiting, only 20 or so signed up. That’s only 1 in 30. And out of a dozen or so startup/submit-your-idea sites, only a couple of them even bothered to write back or post a link telling folks about my app.

What a total distaster.

Or was it?

Continue reading

If you've read this far and you're interested in Agile, you should take my No-frills Agile Tune-up Email Course, and follow me on Twitter.

The HN Heartbeat

Tired of coding today, so I thought I’d look over some server stats and make some observations based on the data. Perhaps my thinking aloud can help other bloggers.

server statistics graph for last 90 days

Average traffic is passing through 80K visits per month. This puts the blog in sort of a transitional space — not really anything to be tremendously interested about, but a little more than just a hobby.

HN Traffic is a big part of that growth. This makes sense, as HN is really the only place I post my articles. Been doing it like that for years. That’s not as a promotional tool — I just like hearing what my fellow HN’ers feel about what I’m writing.

Traffic is very spikey. That’s because the HNers have sort of become a huge herd of elephants, running from site to site The vast overwhelming majority don’t like or dislike my site per se, they’re just along for the ride. It’s also because I only publish 5-7 articles a month. Most of them aren’t that good, and what’s there to read in the intervening days? I’ve also noticed with my other sites that internet traffic in general is much more spikey than you would think, although there are long-term trends.

The danger here — as it has always been with blogging — is that I start writing articles as a way to keep the heartbeat going. I love writing. I love putting my thoughts down on paper (or in a blog). And I can’t describe the feeling to you of writing what you know is a good article and then watching something like forty-thousand people come by to read it. It’s freaking incredible. But the minute I start thinking in terms of “what can I write for the HNers so a lot will come visit today?” is the minute I start writing crap. Must remember.

As an observation, as the HN traffic firehose grows ever larger, the temptation is there for a lot of people to become “HN hangers-on” — people who provide marginally useful apps and services just for the HN audience. HN is like its own city by now — very strange. While I played around with this idea a bit in my site hn-books.com, really the idea for that site was to see if I could put together a multi-page targeted site with lots of functionality without a backend server. The HN gang were just my guinea pigs. (Plus I love books and respect their opinion). If it’s difficult for me to separate writing for myself and writing to suck up to the HNers, I imagine it’s going to be impossible for a lot of people. Expect to see a LOT more HN-stuff sites and services being pumped over on HN. They mean well. But it’ll get noisy. I guess nothing lasts forever, right? Sigh. Much better that than the endless supply of nerd-drama that seems to fill the front page.

So what are people reading?

pages viewed in the last 90 days

Spikey traffic is probably not as important as it appears. Ah, here’s the biggest slice of humble pie: remember that “agile ruined my life” article I wrote? Folks loved that. It got 78,000 views. But coming up right behind it, with almost 60 thousand views, is an article that I wrote 18 months ago that has nothing to do with technology, management, or humor. It was just an article I wrote on a lark, to see how the internet would respond. Well, respond it did, and every month I get thousands of people coming by to look at the article about she-who-must-not-be-named-again-on-this-blog. Coming in at #7 on the list is an article I wrote three and an half years ago. Yes, spikey traffic drives the numbers and averages up, but there’s a huge component of evergreen content in blogging. If I stopped writing tomorrow, I’d still be generating tens of thousands of visits, and probably would continue doing so for a long time. Traffic might even increase over time.

Throw-away articles lead to throw-away traffic. Over the years I’ve written many kind of fun articles, like “nerdy girls in cute t-shirts” or “important online research” I don’t regret writing these articles — I write whatever I feel like — but I notice that quickie articles generate quickie traffic. People don’t stay around to read much. Whereas articles with a lot of heft drive folks to stay for a while. Six thousand people stayed an average of more than 8 minutes reading my “putting the fun in functional programming”. I don’t know a lot, but that seems like an incredible number. Most articles tank, yes, but in general the more thought I put into writing something the more in-depth value people get out of it.

People are searching my blog for web design tips. This seems like going to a bar to ask for alcohol abstention advice, but there it is, on line 17. From 10 to 20 folks a day are searching the blog for web design advice. Wish I had some to give!

Why are people visiting, anyway?

traffic sources for past 90 days

Most folks come directly here. As counter-intuitive as that sounds, even though HN gives me a big bump on the days I write something worthwhile, most of the people visiting get here because they know the site and check it out from time-to-time (probably on an RSS feed). These folks are probably going to hang around longer.

A close second is HN, and beyond that we really are getting into Google territory.

Images count a heckuva lot more for organic search than you think. People are visiting my site from search engines because, well, I like graphics and I like putting in fun images from time to time. A full 37% of my search-engine traffic visitors are visiting — and you’ll like this — because I put pictures of a teenage track star up in an article about what’s fair game on the internet. Yes, at the time I knew it might be “junk” blogging, but I was genuinely interested in what the effects would be. Well, year and a half later, thousands of pimply teenagers a month are still flocking to my blog to see the derrière of a mmse stocke (purposely misspelled) Be careful what you ask for, you just might get it. Following her up is “bikini”, “Walt Disney”, and “Pluto” (which should still be a planet. Long live Pluto!)

I really enjoy blogging, and I love numbers, but looking at stats is always a dangerous thing. I remember when I first got my blogging account; I would watch each and every visitor as they showed up. Wonder why they came? What interests them? Wonder if I put the graphic on the left if it would be better?

This type of thinking is perfectly fine for a business, but in a freeform medium it’s very easy to get the cart ahead of the horse. Blogging as an engineer has a way of sucking you up into the numbers instead of focusing on the reason for blogging. Yes, when I write thoughtful articles people spend more time here, and yes, when the folks over on HN like it there’s a huge spike, but none of that is a reason to change what I do. That was a difficult lesson to learn, but I’m glad I learned it.

If you've read this far and you're interested in Agile, you should take my No-frills Agile Tune-up Email Course, and follow me on Twitter.

Make something people hate

“Make something people want” is the first rule Paul Graham and other leaders of the startup community will tell you.

But they’re wrong. Or rather, what they say is incomplete.

Continue reading

If you've read this far and you're interested in Agile, you should take my No-frills Agile Tune-up Email Course, and follow me on Twitter.

Secret Hacker Bookshelf

I received an email two weeks ago from a guy in the Philippines. He wanted to learn how to program and didn’t know where to start. Last week I was talking to a family member — he wanted to get into computers but didn’t know where to start. This week, 2 people came up to me and asked me questions about which books to read to learn startups and marketing.

It’s a common pattern. On the forum I visit, HackerNews, every few weeks somebody asks the same question — what are the best programming books? What are the best startup books? What are the best books on marketing? There are a lot of people asking, and the same questions are asked quite frequently. A quick search on Google lists dozens of questions about programming.

So. What do hackers recommend to each other?

Frankly, it gets old having to post comments recommending the same books over and over again. I know others feel the same way. But still, I’d like to help. So I decided to take all day today and find the best books from hacker discussions and list them here. Next time somebody asks me, I can just point them to this page. Who knows, if enough folks like the list, maybe I can keep it updated and expand on it.

Caveat Emptor: reading a good book on something fuzzy, like marketing or starting a business, is like having a beer with somebody at a bar. There’s lots of great ideas and great experiences to be learned. It’s also important to note that it’s you, not the authors, who is responsible for your life. Don’t fixate on any one book or author and go off hell bent for leather on what the author said. Instead, sample broadly, compare notes, learn both sides of the argument, then figure out how to use this new information to do things you want to do.

Having said that, this is a pretty incredible list and a pretty cool bunch of recommenders. If you have time, you should follow the conversations around some of these books. Many of the people commenting and many of the people writing these books have made millions or billions of dollars and would like to help you succeed too. And they’re not the traditional get-rich-quick, business porn, or self-help books that clutter up the marketplace. Lots of value here.

These books are listed by how hackers rate them, the vote count — books appearing higher on the list were voted by hackers as better than those lower. The programming section has several sub-sections that I haven’t broken out yet, but you can easily spot where one section ends and another begins.

As for some meta advice, if I were interested in buying one of these books, I’d probably read the pro and con reviews on Amazon, taking careful note of the con reviews (many times the pro reviews are fake). I’ve had pretty good luck using this technique, especially when I get there from a recommendation from a friend. And now you just gained a thousand hacker friends :)

Continue reading

If you've read this far and you're interested in Agile, you should take my No-frills Agile Tune-up Email Course, and follow me on Twitter.

Retro Techno

I was watching the remastered versions of the old 1960s Star Trek TV show the other day, and while the new graphics were great, I couldn’t help but think how god-awful the instruments and displays were, compared what we are using today.

instrument panel from the old star trek show

But then — being the contrarian I am — I thought: Doesn’t this actually make a bit of sense?

Continue reading

If you've read this far and you're interested in Agile, you should take my No-frills Agile Tune-up Email Course, and follow me on Twitter.