<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>xProgramming.com</title>
	<atom:link href="http://xprogramming.com/feed" rel="self" type="application/rss+xml" />
	<link>http://xprogramming.com</link>
	<description>an agile software development resource</description>
	<lastBuildDate>Tue, 01 Nov 2011 10:56:24 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.2.1</generator>
		<item>
		<title>Kate Oneal: What is Scrum?</title>
		<link>http://xprogramming.com/articles/kate-oneal-what-is-scrum/</link>
		<comments>http://xprogramming.com/articles/kate-oneal-what-is-scrum/#comments</comments>
		<pubDate>Sat, 29 Oct 2011 14:54:49 +0000</pubDate>
		<dc:creator>Ron Jeffries</dc:creator>
				<category><![CDATA[Articles]]></category>
		<category><![CDATA[Kate Oneal]]></category>

		<guid isPermaLink="false">http://xprogramming.com/?p=2444</guid>
		<description><![CDATA[Kate gives Dan Devlin, the company owner, an overview of Scrum.]]></description>
			<content:encoded><![CDATA[<p>Dan Devlin arrived at the coffee shop an hour before his appointment with Kate. He had email to do, and he wanted to be sure he was there when Kate arrived. Dan got his coffee, selected an out of the way table, and moved one of the chairs away to make room for Kate&#8217;s wheelchair. Then he set to work. About fifteen minutes before Kate was due to arrive, Dan made a quick pit stop and went to the counter for a refill. Glancing over at the table, he saw Kate, sitting there, smiling and giving him a wave. He pointed at the barista to see if Kate wanted something, and she pointed at the iced drink already in front of her.</p>
<p>Returning to the table, Dan greeted Kate and asked her &#8220;How do you do that?&#8221;</p>
<p>&#8220;Do what,&#8221; Kate said.</p>
<p>&#8220;Always arrive at meetings without anyone seeing you coming and going. And with your drink, even!&#8221;</p>
<p>&#8220;Well, I don&#8217;t always do that. I guess sometimes people just aren&#8217;t very observant, though with my red hair, robust figure, and sparkling attitude, you&#8217;d think I&#8217;d be hard to miss. Maybe I&#8217;m part ninja.&#8221;</p>
<p>&#8220;Robust, is that what you call it? Anyway you&#8217;re not my usual image of a ninja,&#8221; Dan said.</p>
<p>Kate laughed. &#8220;Some kind of bust, anyway. Thing is, I&#8217;m in disguise. What good is it to be a ninja if you look like a ninja?&#8221;</p>
<p>The chat continued for a while. Then Dan got down to business. &#8220;Kate, you&#8217;re doing a wonderful job at Oak River. Things are turned around there, and I&#8217;ve been able to put most of my attention on other matters. One of those is that I&#8217;m looking at acquiring another company in our line of work. They have a good customer base, but haven&#8217;t released much at all in over a year. I&#8217;m thinking a bit of your magic might help them out.&#8221;</p>
<p>Kate said, &#8220;It&#8217;s not magic, but it might help. I think what we&#8217;re doing will help any organization that does what we do. And, by the way, it won&#8217;t help anyone who doesn&#8217;t do it, the same way that a diet won&#8217;t help people lose weight if they don&#8217;t live by it.&#8221;</p>
<p>&#8220;That makes sense,&#8221; Dan said.</p>
<p>&#8220;You&#8217;d think so. But I read every day about teams who say these things won&#8217;t work, but have never really tried them. I wonder how they know.&#8221;</p>
<p>&#8220;What are you doing, anyway, Kate? Is it Scrum? What is Scrum, anyway?&#8221;</p>
<p>Kate took a sip of her drink and thought a moment. &#8220;We&#8217;re doing something like Scrum, which I&#8217;ll describe. Let&#8217;s start with what Scrum is. I&#8217;ll blather on a bit but feel free to stop me with questions if you need to.</p>
<p>&#8220;Scrum is a framework, a way for people to work, a style, you might say, for building products. I think of it as a beginning, a good starting point for building something. If a team will start with Scrum, and pay attention, they&#8217;ll see the things that are in their way and be in a position to improve. Naturally, some of the things that are in a team&#8217;s way are outside their direct control, and in those cases, management and the organization have to be responsible for removing what Scrum calls the &#8216;impediments&#8217; that are in the way.</p>
<p>&#8220;There are just three &#8216;roles&#8217; in Scrum: the Product Owner, who determines what the team will build in the next short interval or &#8216;Sprint&#8217;; the Team, who build it; and the Scrum Master, who facilitates the process and makes sure that the process, and the people, continually improve. There are four meetings, Sprint Planning, Sprint Demo, Sprint Retrospective, and Daily Scrum. And there are just three artifacts, the Product Backlog, the Sprint Backlog, and the Increment.&#8221;</p>
<p>Dan said, &#8220;So the Scrum Master is the manager, and the Product Owner is an analyst?&#8221;</p>
<p>&#8220;No,&#8221; Kate said, &#8220;Not at all.</p>
<p>&#8220;In a Scrum project, the Product Owner is responsible for delivering the best possible product within time and budget. The team builds what she says to build, and her job is to get the best possible results. She can do this because the team shows her real running product every Sprint. That is, every couple of weeks, thirty days at most. She&#8217;s in a good position to see how fast things are going, and to make the big decisions as well as the smaller ones.&#8221;</p>
<p>&#8220;So the Product Owner is the manager, then,&#8221; Dan said.</p>
<p>&#8220;No, Kate said, &#8220;Not at all. In fact, a Scrum team need not have a manager at all. In Scrum, the team is &#8216;self-organizing&#8217;. To as large a degree as possible, they manage themselves. Naturally, in large companies, or companies with a lot of &#8216;managers&#8217; running around, it is common for a Scrum team to have a manager. Frankly, this is often harmful and it is a common cause of Scrum not working very well.&#8221;</p>
<p>&#8220;But who decides things,&#8221; said Dan. &#8220;Who decides who to hire and fire, how much to pay people? Who disciplines the bad people and encourages the good ones?&#8221;</p>
<p>Kate smiled. &#8220;Good questions, and questions that Scrum really does not want to answer. Yes, in a real organization, there will be some connection to personnel, to some kind of technical management, and so on. Scrum, to me, is defined as if those things were not needed, or as if the team could do all those things. What&#8217;s interesting, of course, is that in a startup situation, the team really can do all those things. What was it like when you started Oak River Software?&#8221;</p>
<p>Dan thought back. &#8220;Well, I made some final decisions about hiring and firing. Certainly I set the budget, because it was my money. But mostly, Art Givens, who was my marketing and domain guy back then, decided what we needed to do. And I had a lead developer who decided who to hire and fire, within budget. I&#8217;d counsel with him when there were issues, and I often had to get involved because his people skills weren&#8217;t the best. But we didn&#8217;t do a lot of what I&#8217;d really call management. We worked together, figured out what had to be done, and did it.&#8221;</p>
<p>Dan paused. &#8220;You know, maybe this is the entrepreneur in me talking, but I think things were great back then. It was only later, when Art left, and I had to hire marketing and sales managers, and a real technical manager to drive the programmers, when things started to go bad. I supposed it was just part of how a startup company becomes a grownup company. Honestly, I liked the old days best.&#8221;</p>
<p>Kate said, &#8220;Let&#8217;s get back to Scrum. We&#8217;ll leave it that Scrum doesn&#8217;t talk directly about conventional management, and that it sounds a lot like what a team-focused startup might do. We can come back to what larger companies need to do after we get the full picture.</p>
<p>&#8220;Let me say a few more words about the roles. First, the team. Since the team is responsible for doing what the Product Owner asks for, the team needs to have all the skills to make that happen. It wouldn&#8217;t make sense, for example, to have a software team without testing. We couldn&#8217;t rightly hold them responsible for producing working tested features if the testing was done separately.&#8221;</p>
<p>&#8220;Wait a minute, Kate,&#8221; Dan said. &#8220;Everyone knows that developers don&#8217;t make good testers.&#8221;</p>
<p>&#8220;You might be surprised,&#8221; said Kate. &#8220;But the team isn&#8217;t just developers. The team in Scrum must have all the skills necessary to produce an increment of potentially shippable software in every Sprint. That means everything.&#8221;</p>
<p>&#8220;What if the product needs a manual,&#8221; said Dan. &#8220;Do they have to write a manual every Sprint, and keep it up to date?&#8221;</p>
<p>&#8220;In a word, yes,&#8221; Kate said. &#8220;The Product Owner determines what kind of documentation the product needs, and the team is responsible for producing it. And there are Scrum teams all over that include tech writers, who produce a draft of the manual every Sprint, just like the developers and testers produce a draft of the software.&#8221;</p>
<p>&#8220;How is that even possible,&#8221; Dan said. &#8220;They&#8217;d have to revise the manual every Sprint.&#8221;</p>
<p>&#8220;Yes, they would. However, the devs and testers have to revise the actual software every Sprint. Their stuff has to be usable, actually work, get correct answers, and so on. That&#8217;s actually harder to do than writing a manual. If a programmer leaves out a semicolon, the program won&#8217;t work. If a writer leaves one out, the document still works rather well.</p>
<p>&#8220;The proof is in the doing. As I say, there are teams all over who do this, producing more and more refined documentation as the team produces more and more refined software.&#8221;</p>
<p>Dan looked confused. &#8220;What if the Product Owner changes her mind about what the product has to do? The writers would have to change everything.&#8221;</p>
<p>Kate said, &#8220;If the PO changes her mind in some major way it is a big deal. Frankly it&#8217;s a bigger deal for the developers and testers than it can ever be for the writers. Anyway, Scrum requires the PO to decide what the product is and how to deliver working bits of it over a number of Sprints, and requires that the team be cross-functional enough to do what is needed.&#8221;</p>
<p>&#8220;What about resources,&#8221; said Dan. &#8220;Isn&#8217;t it wasteful, putting a documentation person on every team, and so on?&#8221;</p>
<p>&#8220;The team can change over time, depending on need. What is really wasteful is giving the team half a writer and two-thirds of a tester and seven sixteenths of an analyst. Scrum asks that we make some hard decisions about how to staff our projects, and our organization. Frankly, I think that&#8217;s a strength of the method: it requires us to make real decisions, not load-sharing everyone gives up fifteen percent kinds of decisions.&#8221;</p>
<p>&#8220;OK,&#8221; Dan said. &#8220;I think I&#8217;m getting the idea. You give the team everything they need, including someone who can actually decide what needs to be done, and set them loose with a budget. Seems like anyone could succeed if they got everything they needed.&#8221;</p>
<p>&#8220;Exactly!&#8221; Kate said. &#8220;Scrum starts with everything you need. A wise project creator would fund his most important projects fully, then work down the list until he ran out of people or money. Let&#8217;s face it, starving all our projects can&#8217;t possibly be a good idea. Anyway, let&#8217;s move on.</p>
<p>&#8220;Scrum relies on a fundamental notion, &#8216;Inspect and Adapt&#8217;. The whole team inspects what happens, using day-to-day events, and Sprint-to-Sprint events, to see clearly how things are going. When they see opportunities to improve, they put improvements in place. As we&#8217;ll talk about later, this is one of the places where Scrum can fail or go poorly: if you do not observe problems, or do not or cannot fix them, you can&#8217;t possibly prosper. It&#8217;s surprising how many organizations seem to forget this, instead just telling the team to soldier on.&#8221;</p>
<p>Kate made a note on a card: &#8220;How Scrum Fails,&#8221; then went on.</p>
<p>&#8220;Scrum defines four meetings. Each of these offers opportunities to Inspect and Adapt. They all fit within the big time box, the Sprint. Ideally, I think a Sprint should be no more than a couple of weeks long.</p>
<p>&#8220;Anyway, the meetings. First, there&#8217;s the Sprint Planning Meeting. At the beginning of each Sprint, everyone gets together and works out what will be accomplished in the upcoming Sprint. The PO provides &#8216;backlog items&#8217;, the things she wants, in the order she prefers them. The team considers these, and the technical means of accomplishing them. There can be some give and take, and at the end of the meeting, the team all understand what will be undertaken, and how they plan to accomplish it.</p>
<p>&#8220;Note that this is a conversation. A negotiation, if you will, but I prefer to think it&#8217;s a conversation with everyone on the same side. The team can&#8217;t do more than they can do, and it would be counter-productive if the PO were to demand more. Two weeks later, she&#8217;d get what they could do and frankly if the PO and team continue to forecast more than is accomplished, it&#8217;s evidence of undue and unrealistic pressure from somewhere.</p>
<p>&#8220;Again, at the end of this meeting, which should take a morning for a two-week Sprint, everyone on the team knows what&#8217;s going to be undertaken, why it&#8217;s the thing to do, and how they plan to get it done. Capisce?&#8221;</p>
<p>Dan said, &#8220;I think so. It seems simple enough. Every couple of weeks, they all get together, look at what the PO needs next, and figure out how much they can do and how to do it.&#8221;</p>
<p>Kate said, &#8220;Right. Now let&#8217;s look at the other end of the Sprint. The Sprint has two meetings at the end. The first is the &#8216;Sprint Demo&#8217; or &#8216;Sprint Review&#8217;. In this session, the team demonstrates to the Product Owner what they have accomplished. Everyone discusses what happened, what issues were encountered and resolved, and so on. They do a little looking into the future, based on a fresh understanding of what has just been done, preparing for the next Sprint Planning Meeting. Here, we are inspecting the product and adapting our expectations of what is to come.</p>
<p>&#8220;The second meeting is the Sprint Retrospective. Here, we look at how we worked as a team and how our process and tools supported us. We brainstorm ways to improve, and agree to specific actions that we will take in the next Sprint to improve things. Often these changes are inside the team. Sometimes, they require someone outside to take some action, in which case we plan how we&#8217;ll influence them to do what&#8217;s needed. This meeting is an inspection of the process itself, and a determination about how to adapt to improve it.</p>
<p>&#8220;All three of these meetings are mandatory in Scrum. It would be extremely unwise to drop them or give them short shrift. Are you with me so far?&#8221;</p>
<p>Dan said, &#8220;Let me refresh the drinks and get my thoughts in order.&#8221;</p>
<p>&#8220;Sure,&#8221; said Kate.</p>
<p>Dan returned with drinks and a summary. &#8220;OK, so Scrum has these Sprints, a couple of weeks long, where the Product Owner and the team get together to plan what has to be done and how, then to see how well it went and figure out how to improve. The team has all the abilities they need, and they produce a bit of product every Sprint. Right? But you said there were four meetings, didn&#8217;t you?&#8221;</p>
<p>Kate looked happy. &#8220;Yes, I think you&#8217;ve got it so far. And the fourth meeting occurs daily. It&#8217;s called the &#8220;Daily Scrum&#8217;, I guess after some ritual that takes place in a sports event. It&#8217;s very simple and very brief: in fact, usually, it is done standing up, although I choose not to do that.</p>
<p>&#8220;Basically, every team member says what they accomplished yesterday, what they will accomplish before the next Scrum, and what, if anything, is standing in the way. They don&#8217;t try to solve the issues during this meeting, but if there are issues, most teams meet together or in small groups to address them right after the Daily Scrum. So what are the Scrum meetings?&#8221;</p>
<p>Dan said, &#8220;No one told me there would be a kind of inquisition.&#8221;</p>
<p>&#8220;No one expects the inquisition but I&#8217;m sure you&#8217;ve got it,&#8221; said Kate. &#8220;Go on.&#8221;</p>
<p>Dan said, &#8220;OK, there&#8217;s the planning meeting, the daily meeting, the demonstration and the &#8212; what did you call it, retrospective.&#8221;</p>
<p>&#8220;By Jove, I think he&#8217;s got it. What else is there, Dan?&#8221;</p>
<p>&#8220;You&#8217;re asking me? I don&#8217;t know. Do they do anything besides meet? Do they build anything, write reports, or the like?&#8221;</p>
<p>Kate said, &#8220;Yes. Yes, they do. There are what we call &#8216;Scrum Artifacts&#8217;. The most important of these is what Scrum calls the &#8216;Increment&#8217;, and what I call &#8216;What have you done for me lately&#8217;.</p>
<p>&#8220;At the end of each Sprint, we demonstrate an increment of software. This software is required to be &#8216;done&#8217;, by our then-current &#8216;Definition of Done&#8217;. The definition might start out simple, such as &#8216;able to be demonstrated on the development system&#8217;. But over the course of a good project, the Definition of Done itself gets more and more stringent. &#8216;Demonstrated on the PO&#8217;s system&#8217;, &#8216;documented and demonstrated on the production servers&#8217;, and so on. Some teams actually call things done, every two weeks, only when a customer has actually paid money to use it. That&#8217;s impressive, and Oak River isn&#8217;t there yet. Our definition of done is pretty strict however. Let me quote it:</p>
<p>&#8220;An increment is done when all the PO&#8217;s defined acceptance tests run, when the system is fully integrated and running on the production servers, when all the manual pages are up to date, the code is clean and well-factored, and all the programmer tests are running green.</p>
<p>&#8220;Our Product Owners do not accept anything that doesn&#8217;t meet those criteria, even the technical ones. They don&#8217;t inspect those criteria: the development team certifies that those criteria are met. But we are all serious about meeting them, and we&#8217;ll call a feature &#8216;Not Done&#8217; before we&#8217;ll slack on them.&#8221;</p>
<p>&#8220;Wait,&#8221; Dan said. &#8220;Are&#8217;t there times when you&#8217;d prefer to get a feature out without clean code or some such techie concern?&#8221;</p>
<p>Kate said, &#8220;You&#8217;d think so, at first. Emergencies arise and so on. Truth is, if a team can release what looks like a feature faster by writing poor code, that&#8217;s major evidence that they have important things to learn about how to write software. A good professional produces software at the best pace by working clean.</p>
<p>&#8220;This means that every time we feel we &#8216;need&#8217; to push something out that isn&#8217;t really &#8216;Done&#8217;, we inspect what&#8217;s going on and decide how to improve. So if we do have to rush out a defect fix, we are all committed just as much to fixing our process to make that unnecessary. It doesn&#8217;t take long until we are able to build increments that meet our Definition of Done fully, nearly every time. And if we do stumble, we go right back to inspect and adapt and work to make sure it won&#8217;t happen again.&#8221;</p>
<p>&#8220;That seems incredibly idealistic,&#8221; Dan said. &#8220;Things never go that well. Even if you tried, it would cost a fortune to be that good.&#8221;</p>
<p>&#8220;They can, Dan, and they do. In the early days of manufacturing, products were built, inspected, and sent back to be redone if things were wrong. Manufacturing people learned that inspecting earlier and more often meant that fewer products had to go back to be redone. Small inspections and small fixes to process are immensely less costly than reworking the whole product item.</p>
<p>&#8220;Similarly for software. Debugging a fully integrated system is difficult and costly, especially if it is made up of components that are not all individually nearly bug free. So we save time and money by testing at every level. We have automated checks that things work, and we run them all the time, and add to them all the time. The result is that things almost always go well, and we get very clear indications of where we&#8217;ve messed up when we do.&#8221;</p>
<p>Dan said, &#8220;But I have been reading Eric Ries book, <em>The Lean Startup</em>. He makes the point that it can be best to go out with far less product, even with a facade, rather than build out for perfection. You learn faster.&#8221;</p>
<p>Kate said, &#8220;Yes. But the thin character of such a product should be chosen. When we write code badly, we don&#8217;t get to choose where the problems are: they show up where we least expect them and where we don&#8217;t want them. So even when we&#8217;re building a minimal product experiment, we do best to work clean. We&#8217;re not gold-plating, but we are working clean. Anyway, from the Scrum viewpoint, this is all part of the Definition of Done. If a PO wanted the Definition of Done to include &#8220;code is the most rag-tag crappy code that will barely carry the load&#8221;, that could be the definition. Scrum doesn&#8217;t care. I care, and I wouldn&#8217;t work that way. But Scrum doesn&#8217;t care.</p>
<p>&#8220;But we&#8217;re talking about the artifacts. The main one is the increment. Without the increment, we have no product. But as the main says, &#8216;Wait, there&#8217;s more&#8217;.&#8221;</p>
<p>Kate went on. &#8220;There&#8217;s the Product Backlog. That&#8217;s just the Product Owner&#8217;s current list of things that she might want in the product someday. It&#8217;s kept &#8216;ordered&#8217;, generally speaking in the order that the PO would like to have things done in. &#8216;Order&#8217; can consider a lot of concerns: how much we need to learn whatever that item will teach us; how much revenue we&#8217;ll get for it; how much pressure some stakeholder is putting on us to show him some results; and so on. What matters is that the PO and team considers and defines the order of the items.&#8221;</p>
<p>Kate took a breath, to the delight of observers near and far. &#8220;The Product Owner monitors progress in completing backlog items. She uses whatever means she finds useful, from comparing stacks of done and not-done cards, to charts showing the growth of features, even to Earned Value kinds of calculations if they&#8217;re into that sort of thing. She and the team continually &#8216;Groom&#8217; the backlog, refining items, adding new items, removing items that no longer seem important. With me so far?&#8221;</p>
<p>Dan, recovering, said, &#8220;Yes. The Product Backlog is all the stuff that needs to be done, or might need to be done. I suppose items soon to be done are well fleshed-out &#8230;&#8221; He coughed, then went on &#8220;better understood and defined than things that are further down in the order.&#8221;</p>
<p>Kate feigned confusion but couldn&#8217;t suppress a grin. &#8220;Consider it a little treat. Anyway you&#8217;re right. Then there&#8217;s the Sprint Backlog. That&#8217;s just the list of things agreed to be done in the current Sprint. and the plan for getting them done. Just as the PO monitors overall progress in terms of the backlog, the team monitors progress toward attaining the Sprint goal. And, again, this can be done in any number of ways. My favorite is to have all the items on cards, and show them moving through whatever work stages they go through, so that I can see how many cards have arrived at the &#8216;Done&#8217; station every day.&#8221;</p>
<p>Kate continued, &#8220;And that&#8217;s Scrum. Three roles, Product Owner, Scrum Master, and Team. Four meetings, Sprint Planning, Daily Scrum, Sprint Demo, Sprint Retrospective. And three artifacts, Product Backlog, Sprint Backlog, and the Product Increment. What have we missed?&#8221;</p>
<p>Dan thought a moment. &#8220;You haven&#8217;t said much about the Scrum Master, just that he facilitates and helps the team improve.&#8221;</p>
<p>Kate said, &#8220;And that&#8217;s about it. It seems like a simple job, and in sufficiently effective teams, it might even be absorbed into the team&#8217;s general operation. But truth is, there&#8217;s a lot to do and a good Scrum Master is priceless. Let me count some of the ways:</p>
<p>&#8220;The Scrum Master helps the PO do her job. He helps everyone understand how to create good backlog items, how to communicate them, how to plan an adjust in as dynamic an environment as most projects are, how to do all the things Agile teams need to do, and so on. He helps the team do their job, coaching, leading, even teaching them how to do things. He ensures that impediments are removed. He serves the organization, helping them understand Scrum, their role in it, and the impact of the things they do on the success of the Scrum team or teams. He works throughout the organization to help Scrum work. Best of all, he does this with no formal management authority.&#8221;</p>
<p>Dan said, &#8220;Sounds like a hard job.&#8221;</p>
<p>&#8220;It is,&#8221; Kate said. &#8220;Especially when you consider that you can become a Certified Scrum Master with two days of training. The range of things that may need to be done to help a team become really good, and the breadth of the organizational reach involved, can be immense. Scrum Master is either a very hard job, or perhaps not a person&#8217;s job at all. All those things need to be done, so doing them is surely a &#8216;role&#8217;. But whether that work can be done by a single person, I seriously doubt. Whether a person can be trained to do them &#8230; well, I don&#8217;t doubt. I know they can&#8217;t be. Doing everything that it takes to make a Scrum team effective requires so many skills and so much skill, that it&#8217;s a lifetime&#8217;s work.&#8221;</p>
<p>&#8220;But wait,&#8221; Dan said. &#8220;Are you saying that Scrum basically can&#8217;t work, because the Scrum Master role is too much for a single person?&#8221;</p>
<p>&#8220;Not at all,&#8221; Kate said. &#8220;Scrum can and does work just fine. Most Scrum teams get at least a reasonable amount of benefit, and teams that pay attention to removing their impediments can absolutely fly. Our teams are beginning to show that now. What needs to happen is that the team must pay attention to the Scrum Master role, and the company must pay attention to it as well. There needs to be continuing attention on improving the effectiveness of that role, and there needs to be recognition that sometimes parts of the Scrum Master role need to be done by other team members, or even people outside the team.</p>
<p>&#8220;So there&#8217;s your quick overview of Scrum. There&#8217;s much more we should talk about before you decide what to do with these new people you&#8217;re looking at. I&#8217;d suggest we get together again over the next few days to talk about how Scrum and Scrum teams can fail, about whether we at Oak River are actually doing Scrum, about other Agile approaches that are not like Scrum, about all the important technical and related practices that need to be in place, and more.&#8221;</p>
<p>&#8220;Thanks,&#8221; Dan said. &#8220;I think I&#8217;ve heard about all I can absorb for today. Let me check my schedule for the test of the week and drop you an email proposing another meeting. We can do it at the office if you like, of course.&#8221;</p>
<p>Kate reflected for a moment. &#8220;We might do that. There might be some things to talk about where some other people might be helpful. Otherwise, I like meeting here. The buzz of activity is energizing. Either way, let me know when you&#8217;re available and we&#8217;ll pick a time and place, and I&#8217;ll see you then.&#8221;</p>
<p>&#8220;Thanks, Kate,&#8221; Dan said. &#8220;I&#8217;ll just clear the table.&#8221;</p>
<p>When Dan returned from the trash bin, Kate was gone. Not even her smile remained.</p>
]]></content:encoded>
			<wfw:commentRss>http://xprogramming.com/articles/kate-oneal-what-is-scrum/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Scrum Information Base &#8212; Agile Skills</title>
		<link>http://xprogramming.com/articles/scrum-information-base-agile-skills/</link>
		<comments>http://xprogramming.com/articles/scrum-information-base-agile-skills/#comments</comments>
		<pubDate>Thu, 29 Sep 2011 15:05:47 +0000</pubDate>
		<dc:creator>Ron Jeffries</dc:creator>
				<category><![CDATA[Articles]]></category>
		<category><![CDATA[Beyond Agile]]></category>

		<guid isPermaLink="false">http://xprogramming.com/?p=2429</guid>
		<description><![CDATA[<p>Chet Hendrickson and I have offered to help the Scrum Alliance build a broad and growing base of information relating to Scrum / Agile, and to the many skills and practices that can help teams be successful. Our offer has&#8230;</p>]]></description>
			<content:encoded><![CDATA[<p>Chet Hendrickson and I have offered to help the Scrum Alliance build a broad and growing base of information relating to Scrum / Agile, and to the many skills and practices that can help teams be successful. Our offer has been accepted and we&#8217;re enthusiastic about getting started. The project will build on as many sources of ideas and practice as we can round up &#8212; including you!</p>
<p>The Scrum Alliance was the main supporter of the Agile Skills Project, and we&#8217;ll certainly be building on that model. We have also been behind the Alliance&#8217;s recent inviting of articles from Agile- / Lean- / Craft-focused experts. This is just a beginning.</p>
<p>The Agile Skills Project identified seven &#8220;pillars&#8221; of skill: Business Value, Collaboration, Confidence, Product, Self Improvement, Supportive Culture, and Technical Excellence. We&#8217;re not sure these are the right seven, or even whether seven is the right number. What we are sure of is that there are many many skills that organizations, teams, and individuals can bring to bear on making Scrum and Agile projects successful. We hope to provide an overview of these, a roadmap through them, detailed information within this project, and pointers to outside sources and experts.</p>
<p>The scope of what we &#8220;might&#8221; do is of course immense. We will be doing our best to keep our backlog public, as well as our criteria for ordering it. We will be clear about which items are being worked on, and which ones are not. Our purpose will be to deliver value quickly, and to build a space within which growth can continue indefinitely, as our community understanding grows and changes.</p>
<p>As long-term Agilists, XPers, and Certified Scrum Trainers, plus a bit of Certified Curmudgeon, we will be trying to bring a combination of independence and Scrum expertise to this enterprise. If you think we lack something in independence or expertise, we sincerely solicit your help. We would like this growing information resource to be of real value to the &#8220;world of work&#8221;. As such, if you would like to help by writing, by editing, by commenting, or in any other way, we welcome your help. We see ourselves as curators and editors, not as prophets or definers of what is good and what is bad.</p>
<p>We&#8217;re just getting started. We need to create our backlog, get it published somewhere, and to begin to find our way through the items, figuring out how to get them done.  As soon as possible, we&#8217;ll be getting sites set up where you can help. We might use the Agile Skills Project site, or someplace new. Meanwhile you can write to me at ronjeffries at acm dot org, or comment here. We&#8217;ll be much more grateful for concrete help, but welcome all advice and positive-going ideas.</p>
<p>Again: we&#8217;re just getting started. Right now, it&#8217;s just us, and we have about a week a month to put into the effort. We&#8217;ll try our best to be open and transparent and to be delivering value rapidly. Call us on it if we&#8217;re not. And help us if you can.</p>
<p>Thanks!</p>
]]></content:encoded>
			<wfw:commentRss>http://xprogramming.com/articles/scrum-information-base-agile-skills/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>The Gift &#8230; a Report and a Request</title>
		<link>http://xprogramming.com/articles/the-gift-a-report-and-a-request/</link>
		<comments>http://xprogramming.com/articles/the-gift-a-report-and-a-request/#comments</comments>
		<pubDate>Mon, 29 Aug 2011 14:02:39 +0000</pubDate>
		<dc:creator>Ron Jeffries</dc:creator>
				<category><![CDATA[Articles]]></category>
		<category><![CDATA[Kate Oneal]]></category>

		<guid isPermaLink="false">http://xprogramming.com/?p=2421</guid>
		<description><![CDATA[<h3>The Story in Brief</h3>
<p>At Agile2011, I brought along a &#8220;gift&#8221;, a nicely formatted and illustrated Kate Oneal story. I gave a copy to everyone who asked for one, and to a few people who didn&#8217;t but who I wanted&#8230;</p>]]></description>
			<content:encoded><![CDATA[<h3>The Story in Brief</h3>
<p>At Agile2011, I brought along a &#8220;gift&#8221;, a nicely formatted and illustrated Kate Oneal story. I gave a copy to everyone who asked for one, and to a few people who didn&#8217;t but who I wanted to have one anyway.</p>
<p>This was too clever by half. I made two mistakes, so perhaps it was even too clever by two-thirds. First, I tweeted about the thing only with no hashtag or #gotKate. I should have tweeted on #Agile2011. I momentarily forgot that not everyone in the world follows me.</p>
<p>Second, I made it too hard to get one. People don&#8217;t like to ask for things from people they don&#8217;t know well. Some people may have just stood near me hoping that I&#8217;d give them one &#8212; I&#8217;ll never know. Some people would come up and the conversation would go like this:</p>
<p style="padding-left: 30px;">Some One said, &#8220;Hi Ron.&#8221;</p>
<p style="padding-left: 30px;">&#8220;Hi Some,&#8221; Ron said.</p>
<p style="padding-left: 30px;">&#8220;So, I hear you have some kind of a gift for people?&#8221;</p>
<p style="padding-left: 30px;">&#8220;Yes, I have.&#8221;</p>
<p style="padding-left: 30px;">&#8220;Is it a nice gift?&#8221;</p>
<p style="padding-left: 30px;">&#8220;I like to think so&#8221;</p>
<p>This would go on at some length until Some One either figured out to say &#8220;May I have one?&#8221; or until Chet, bored with the game, would say &#8220;Ask him for one.&#8221; Once in a while I&#8217;d say &#8220;Would you like one,&#8221; but too often I was stuck in the nerd game of just answering the question logically but not usefully.</p>
<p>That was, not to put too fine a point on it, stupid, if my point was to give away as many of the things as possible.</p>
<p>I did manage to give away all that I was carrying with me every day, but never so many that I had to go back to my room and replenish early. So I&#8217;m sure there could have been more given out.</p>
<h3>You Can Get One</h3>
<p>Speaking of that, I&#8217;m willing to send a signed one to anyone who wants it, and who sends me a self-addressed stamped envelope. I will weigh the thing to see how much postage it needs, but two-ounce postage will surely do it. The booklet is 5.5 by 5 inches and you might want a stiff or padded envelope so that it doesn&#8217;t get crunched. I&#8217;ll update this paragraph when I know more.</p>
<p>If you have the thing and like it and would like a bunch to hand out, drop me an email and we&#8217;ll see what we can set up.</p>
<h3>Feedback Please</h3>
<p>Many of the people who got them expressed later that they liked them, so that&#8217;s good. Here, I&#8217;m soliciting more feedback on whether you liked it, whether you tried to get one and I never realized it, and on what should be done next.</p>
<p>I&#8217;ll tell the story of how we made the thing in another posting. In this one, I&#8217;d just like comments, offering ideas about what the thing is, how you liked it, whether I should do another one, whether you can think of some way to monetize the creation of these, and so on. Anything on the topic, really.</p>
<p>Thanks!</p>
]]></content:encoded>
			<wfw:commentRss>http://xprogramming.com/articles/the-gift-a-report-and-a-request/feed/</wfw:commentRss>
		<slash:comments>7</slash:comments>
		</item>
		<item>
		<title>Why Did You Do That, Ron?</title>
		<link>http://xprogramming.com/articles/why-did-you-do-that-ron/</link>
		<comments>http://xprogramming.com/articles/why-did-you-do-that-ron/#comments</comments>
		<pubDate>Sat, 25 Jun 2011 14:35:26 +0000</pubDate>
		<dc:creator>Ron Jeffries</dc:creator>
				<category><![CDATA[Articles]]></category>

		<guid isPermaLink="false">http://xprogramming.com/?p=2401</guid>
		<description><![CDATA[Piers Thompson sent me a good question about my recent database articles. I suspect others would like to hear the question and answers.]]></description>
			<content:encoded><![CDATA[<p>Piers Thompson sent me a good question about my recent database articles. I suspect others would like to hear the question and answers.</p>
<blockquote><p>Just discovered your blog and am enjoying it. I was struck however bythe fact that your test code would not pass muster in my team. We have more test code than non-test code, so we are equally rigorous about the quality of the test case as we are the non-test code (quality insomuch as it is likely to affect the future costs of owning the code). Therefore I consider repeating yourself in test code to be almost invariably bad practice. Yet your test code is sprinkled with repeated literals. You also have subtle repetition &#8211; a test method named ..sixth&#8230; which includes six calls to member.charge.</p>
<p>I&#8217;m sure that you have a good reason and I wonder what it is.</p></blockquote>
<p>I do have some good reasons &#8230; some that are questionable, and some that are probably not so good at all. Let&#8217;s explore the ones I&#8217;m aware of. My tabbed out comments are pretty much what I said to Piers. Tabbed in are today&#8217;s feelings about that day&#8217;s feelings.</p>
<p>First of all, the article series so far is an example of TDDing to a point early in a program. And in fact some of the things, like the literals, do get pulled out later on. The TDD cycle is red/green/refactor and one improves what one sees as one goes.</p>
<p style="padding-left: 30px;">True enough: the focus is on getting a non-DB solution. However, there are a pile of literal small integers and they do not have meaning. I did pull out the person ones (not as nicely as I might have) but the value ones are not yet pulled out. They should be, and in my current version they are. I&#8217;ll post that later.</p>
<p>Recall also that this is my first-ever published Python program. AsI comment in the second article, I was doing things (like not adhering to &#8220;standard&#8221; naming) to reduce my cognitive load. Possiblythat same focus on &#8220;how the hell do I say this in Python&#8221; caused me not to notice things that I otherwise would have.</p>
<p>And, I didn&#8217;t have anyone pairing with me to help keep me honest.</p>
<p style="padding-left: 30px;">As an <em><strong>explanation </strong></em>of how I got where I got, I buy this. I wouldn&#8217;t accept it as an <em><strong>excuse</strong></em> for being there, or for staying there. The code is not good enough for the long term, and even with a few days&#8217; experience in Python, I can see that. I don&#8217;t know the Python way of making it better but I sure as hell know some ways. Again, let&#8217;s see what the next version looks like.</p>
<p><strong>However</strong>, I actually do some of these things on purpose.</p>
<p>In the method Piers mentions, the six calls are necessary, as I&#8217;m sure you see, because I want to check that each of the six gets a correct answer, including the sixth, which is supposed to get zero. This would have been a better test, perhaps, if all the values had been different, but since TDD is a white-box activity, I wasn&#8217;t worried about getting some number other than the input or zero. It /might/ improve the tests for the long term to change that.</p>
<p>The six calls could, of course, be placed in a loop, as I did with subsequent ones. There are two reasons not to do that, one not so good and the other one more to the idea of &#8220;reasons&#8221; why I do what I do.</p>
<p>The not so good reason was that at that moment I didn&#8217;t want to figure out the looping and how to construct it. I had &#8220;call six times&#8221; in my mind and writing it out longhand was easier.</p>
<p>The better reason, however, is that doing the calls explicitly, rather than in a loop, tells a better story. The member buys something; he buys something later; he buys something later still; and so on. The &#8220;real world&#8221; events are not &#8220;the member is in a loop&#8221;, so I prefer the code written out longhand, despite the duplication.</p>
<p>However, in the later, more complex tests, with multiple members making multiple purchases, I did go to the looping, and frankly I think it makes the tests harder to understand. I could imagine some heavier refactoring, such as making</p>
<pre>    for i in range(5):
        self.assertEquals(6,member.charge(6))</pre>
<p>into something like</p>
<pre>    assert_member_makes_five_charges_at_cost(6)</pre>
<p>And one could make that (6) into (SIX_DOLLARS), and probably should.</p>
<p>Suffice to say that I like each test to tell its own story, and so I generally do not factor out duplication as aggressively as I would in the production code. This is an example of the tension between rules two and three of  Beck&#8217;s rules of Simple Code:</p>
<ol>
<li>Runs all the tests;</li>
<li>Contains no duplication;</li>
<li>Expresses all our design ideas;</li>
<li>Minimizes number of code entities;</li>
</ol>
<p>In the case of tests, I sometimes prefer more duplication to get better expression of the testing ideas.</p>
<p>For the article, this final point is also key:</p>
<p><em><strong>The point of the article is to focus on how to TDD toward a database without actually doing any database work. Thus I want the code in the article to focus on the working mechanics of the production code, and on the thought process that goes into the tests. If I were to go off on a refactoring spree on the tests, I felt that would draw attention away from the core point.</strong></em></p>
<p>That said, for longer-term life in a production system, the tests do need improvement. Here&#8217;s what I have for those same tests today:</p>
<pre>THREE_DOLLARS = 3
FOUR_DOLLARS = 4
FIVE_DOLLARS = 5
SIX_DOLLARS = 6
TEN_DOLLARS = 10

PERSON_ONE = 1
PERSON_TWO = 2
PERSON_SIX = 6

class NoDBTests(unittest.TestCase):

    def test_hookup(self):
        self.assertTrue(True)

    def test_member_charge(self):
        member = MemberRecord()
        charge_amount = member.charge(TEN_DOLLARS)
        self.assertEqual(TEN_DOLLARS,charge_amount)

    def test_sixth_one_free(self):
        member = MemberRecord()
        charge_amount = member.charge(FIVE_DOLLARS)
        self.assertEqual(FIVE_DOLLARS, charge_amount)
        charge_amount = member.charge(FIVE_DOLLARS)
        self.assertEqual(FIVE_DOLLARS, charge_amount)
        charge_amount = member.charge(FIVE_DOLLARS)
        self.assertEqual(FIVE_DOLLARS, charge_amount)
        charge_amount = member.charge(FIVE_DOLLARS)
        self.assertEqual(FIVE_DOLLARS, charge_amount)
        charge_amount = member.charge(FIVE_DOLLARS)
        self.assertEqual(FIVE_DOLLARS, charge_amount)
        charge_amount = member.charge(FIVE_DOLLARS)
        self.assertEqual(0, charge_amount)

    def test_twelfth_one_free(self):
        member = MemberRecord()
        for i in range(5):
            self.assertEquals(SIX_DOLLARS,member.charge(SIX_DOLLARS))
        charge_amount = member.charge(SIX_DOLLARS)
        self.assertEqual(0, charge_amount, "first one bad")
        for i in range(5):
            self.assertEquals(SIX_DOLLARS,member.charge(SIX_DOLLARS))
        charge_amount = member.charge(SIX_DOLLARS)
        self.assertEquals(0, charge_amount, "second one bad")

    def test_member_two_still_gets_free(self):
        members = MemberCollection()
        for purchase_from_two in range(5):
            self.assertEquals(FOUR_DOLLARS, members.member(PERSON_TWO).charge(FOUR_DOLLARS))
        self.assertEquals(0, members.member(PERSON_TWO).charge(FOUR_DOLLARS))

    def test_member_six_does_not_interfere_with_two(self):
        members = MemberCollection()
        for purchase_from_two in range(5):
            self.assertEquals(FOUR_DOLLARS, members.member(PERSON_TWO).charge(FOUR_DOLLARS))
        self.assertEquals(FOUR_DOLLARS, members.member(PERSON_SIX).charge(FOUR_DOLLARS), "six interfered")
        self.assertEquals(0, members.member(PERSON_TWO).charge(FOUR_DOLLARS), "two got no discount")

    def test_threeAtOnce(self):
        members = MemberCollection()
        for purchase_number in range(5):
            for person in [2, 6, 1]:
                self.assertEquals(THREE_DOLLARS, members.member(person).charge(THREE_DOLLARS), "improper free one")
        self.assertEqual(0, members.member(PERSON_ONE).charge(THREE_DOLLARS))
        self.assertEqual(0, members.member(PERSON_TWO).charge(THREE_DOLLARS))
        self.assertEqual(0, members.member(PERSON_SIX).charge(THREE_DOLLARS))</pre>
<p>&nbsp;<br />
Of these, I like the named literals much better than the literal literals. This was Piers&#8217; first point. As for the duplicated lines versus the loops, I find the tests with the duplicated lines easier to read by a small margin. The last one, looping over five interleaved purchases for three people, is pretty hard to decode, I think. I prefer the six in a row one to a single loop of five followed by a single call to check the freebie, but it&#8217;s hard to count the six. If it were &#8220;twelfth one free&#8221;, in line would be bad for sure.</p>
<p>So let&#8217;s see what else we can do. First of all, all those asserts have a log of duplication, and they&#8217;re all just checking that some person pays some amount, or that some person pays nothing. Let&#8217;s express that:</p>
<pre>    <span style="color: #993300;">def check_person_pays(self, members, person, amount):
        self.assertEquals(amount, members.member(person).charge(amount))

    def check_person_free(self, members, person, amount):
        self.assertEquals(0, members.member(person).charge(amount))</span>

    def test_member_two_still_gets_free(self):
        members = MemberCollection()
        for purchase_from_two in range(5):
            self.<span style="color: #993300;">check_person_pays(members, PERSON_TWO, FOUR_DOLLARS)</span>
        self.<span style="color: #993300;">check_person_free(members, PERSON_TWO, FOUR_DOLLARS)</span>

    def test_member_six_does_not_interfere_with_two(self):
        members = MemberCollection()
        for purchase_from_two in range(5):
            self.<span style="color: #993300;">check_person_pays(members, PERSON_TWO, FOUR_DOLLARS)</span>
        self.<span style="color: #993300;">check_person_pays(members, PERSON_SIX, FOUR_DOLLARS)</span>
        self.<span style="color: #993300;">check_person_free(members, PERSON_TWO, FOUR_DOLLARS)</span>

    def test_threeAtOnce(self):
        members = MemberCollection()
        for purchase_number in range(5):
            for person in [2, 6, 1]:
                self.<span style="color: #993300;">check_person_pays(members, person, THREE_DOLLARS)</span>
        self.<span style="color: #993300;">check_person_free(members, PERSON_ONE, THREE_DOLLARS)</span>
        self.<span style="color: #993300;">check_person_free(members, PERSON_TWO, THREE_DOLLARS)</span>
        self.<span style="color: #993300;">check_person_free(members, PERSON_SIX, THREE_DOLLARS)</span></pre>
<p>&nbsp;</p>
<p>I think I like that better still. We have lost my few special diagnostics, but those can readily be replaced by adding an optional argument to the check functions. Meanwhile the tests express what&#8217;s going on quite a bit better.</p>
<p>I think this is well worth doing before committing these stories to the system. And I&#8217;m still glad that we focused first on the main point, getting the database feature working without an actual database, and then looked at improving the tests.</p>
<p>What do you think, Piers? And what do you all think? Thanks!</p>
]]></content:encoded>
			<wfw:commentRss>http://xprogramming.com/articles/why-did-you-do-that-ron/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>See? We Don&#8217;t Need a Database &#8230; Yet</title>
		<link>http://xprogramming.com/articles/see-we-dont-need-a-database-yet/</link>
		<comments>http://xprogramming.com/articles/see-we-dont-need-a-database-yet/#comments</comments>
		<pubDate>Wed, 22 Jun 2011 13:32:56 +0000</pubDate>
		<dc:creator>Ron Jeffries</dc:creator>
				<category><![CDATA[Articles]]></category>

		<guid isPermaLink="false">http://xprogramming.com/?p=2391</guid>
		<description><![CDATA[Here's the current code, and some commentary, for the "But We Need a Database" article. UPDATED: Comments on Python style.]]></description>
			<content:encoded><![CDATA[<p>Here&#8217;s the current code, and some commentary, for the &#8220;<a title="But We Need a Database … Don’t We?" href="http://xprogramming.com/articles/but-we-need-a-database-dont-we/" target="_blank">But We Need a Database</a>&#8221; article. <strong>UPDATED: Comments on Python style.</strong></p>
<h3>First, the Tests</h3>
<p>Nothing new to see here. These are in the order they were written, which is my usual practice with new code. If a test suite gets large, I&#8217;d break it up, and perhaps arrange tests by topic area. As a rule, though, I like them to tell the story of how the program grew.</p>
<pre>import unittest
from membercollection import MemberCollection
from memberrecord import MemberRecord

class NoDBTests(unittest.TestCase):

    personOne = 1
    personTwo = 2
    personSix = 6

    def test_hookup(self):
        self.assertTrue(True)

    def test_memberCharge(self):
        member = MemberRecord()
        chargeAmount = member.charge(10)
        self.assertEqual(10,chargeAmount)

    def test_sixthOneFree(self):
        member = MemberRecord()
        chargeAmount = member.charge(5)
        self.assertEqual(5, chargeAmount)
        chargeAmount = member.charge(5)
        self.assertEqual(5, chargeAmount)
        chargeAmount = member.charge(5)
        self.assertEqual(5, chargeAmount)
        chargeAmount = member.charge(5)
        self.assertEqual(5, chargeAmount)
        chargeAmount = member.charge(5)
        self.assertEqual(5, chargeAmount)
        chargeAmount = member.charge(5)
        self.assertEqual(0, chargeAmount)

    def test_twelfthOneFree(self):
        member = MemberRecord()
        for i in range(5):
            self.assertEquals(6,member.charge(6))
        chargeAmount = member.charge(6)
        self.assertEqual(0, chargeAmount, "first one bad")
        for i in range(5):
            self.assertEquals(6,member.charge(6))
        chargeAmount = member.charge(6)
        self.assertEqual(0, chargeAmount, "second one bad")

    def test_memberTwoStillGetsFree(self):
        members = MemberCollection()
        for purchaseFromTwo in range(5):
            self.assertEquals(4, members.member(self.personTwo).charge(4))
        self.assertEquals(0, members.member(self.personTwo).charge(4))

    def test_memberSixDoesNotInterfereWithTwo(self):
        members = MemberCollection()
        for purchaseFromTwo in range(5):
            self.assertEquals(4, members.member(self.personTwo).charge(4))
        self.assertEquals(4, members.member(self.personSix).charge(4), "six interfered")
        self.assertEquals(0, members.member(self.personTwo).charge(4), "two got no discount")

    def test_threeAtOnce(self):
        members = MemberCollection()
        for purchaseNumber in range(5):
            for person in [2, 6, 1]:
                self.assertEquals(3, members.member(person).charge(3), "improper free one")
        self.assertEqual(0, members.member(self.personOne).charge(3))
        self.assertEqual(0, members.member(self.personTwo).charge(3))
        self.assertEqual(0, members.member(self.personSix).charge(3))

if __name__ == '__main__':
    unittest.main()</pre>
<p>&nbsp;</p>
<h3>The MemberRecord</h3>
<p>This, too, is pretty much as we&#8217;ve seen it. It may be worth mentioning that the member variable __purchaseCount is private, by virtue of the two leading underbars, and that memberNumber is public. We wanted it public so that our collection code could access it.</p>
<p>As far as I know, there is no access indicator for read but not write. If I really cared, I&#8217;d build an accessor method and use a private variable. However, I&#8217;m usually not very concerned that someone might mistakenly write into a member record. I&#8217;m used to working with teams who have an agreed approach to their code. If I were writing a library for use by outsiders, I might be more paranoid.</p>
<pre>__author__ = 'Ron'
class MemberRecord(object):

    def __init__(self, memberNumber=-1):
        self.<span style="color: #993300;">__purchaseCount</span> = 0
        self.<span style="color: #993300;">memberNumber </span>= memberNumber

    def charge(self, amount):
        self.__purchaseCount+=1
        return amount if self.__purchaseCount%6 != 0 else 0</pre>
<p>&nbsp;</p>
<h3>The MemberCollection</h3>
<p>Here, I changed the way the member(memberNumber) function works, using an explicit loop rather than my overly clever approach of filtering and then checking the result size. Note, however, that the explicit loop would be a Very Bad Idea if we were to translate it directly into a database solution. We wouldn&#8217;t want to read the database one record at a time. The filter approach might better suggest what to do to someone building the  database code. Again, my normal approach is to trust the team. YMMV.</p>
<pre>from memberrecord import MemberRecord

__author__ = 'Ron'
class MemberCollection(object):

    def __init__(self):
        self.members = []

    def member(self, memberNumber):
        <span style="color: #993300;">for mr in self.members:
            if mr.memberNumber == memberNumber:
                return mr
        newMember = MemberRecord(memberNumber)
        self.members.append(newMember)
        return newMember</span></pre>
<p>&nbsp;</p>
<h3>Better Idea</h3>
<p>Ori Peleg commented on the earlier article that there is a better way to do my member finding method, using a dictionary. When I worked on another practice program, I had more than one entry with the same (partial) key, so needed to filter or loop. Somehow that stuck in my mind and I didn&#8217;t think to use a dictionary, though I had tried one in the other location.</p>
<p>I blame my pair, Chet, for not being there. Anyway, the better way is:</p>
<pre> def member(self, memberNumber):
        if memberNumber in self.members:
            return self.members[memberNumber]
        else:
            newMember = MemberRecord(memberNumber)
            self.members[memberNumber] = newMember
            return newMember</pre>
<p>&nbsp;</p>
<h3>Comments on Python Style</h3>
<p>The code here is not in <a title="Python Style" href="http://www.python.org/dev/peps/pep-0008/" target="_blank">official Python style</a>. In particular, it seems that Pythonistas prefer send_player_to_jail over sendPlayerToJail. That said, the guide linked to above does allow for use of mixedCase where that is the prevailing style.</p>
<p>One thing you&#8217;d have to think about if adding Python to the development mix on your team is what style to follow. At the time I wrote this program, I knew that underbar_names were preferred, but because I&#8217;m used to mixedCase, I used it to keep my cognitive load down.  I was sure someone would sort me out on it, and my luck was in. Oddly enough, Python folks do use CapWords for class names but not mixedCase for methods. Curious.</p>
<p>There may be other deviations: the guide referenced above is long and detailed. If I publish more Python code, I&#8217;ll see about coming more in line with convention. Meanwhile, I&#8217;ll refactor this program just to see how easy PyCharm makes it, and to bring it more in line. I won&#8217;t trouble you with another version unless I feel the need for more feedback.</p>
<p>Thanks for your help and comments, I do appreciate them.</p>
<h3>Bottom Line &#8230; For Now</h3>
<p>There are probably more things we could change here, either to make the code look more like good Python, or to make it more clear, or for some other reason. Since my point in the previous article was just to show how I&#8217;d proceed to solve a database problem without involving the database yet, I think the point is made.</p>
<p>Your comments are welcome &#8230;</p>
]]></content:encoded>
			<wfw:commentRss>http://xprogramming.com/articles/see-we-dont-need-a-database-yet/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>But We Need a Database &#8230; Don&#8217;t We?</title>
		<link>http://xprogramming.com/articles/but-we-need-a-database-dont-we/</link>
		<comments>http://xprogramming.com/articles/but-we-need-a-database-dont-we/#comments</comments>
		<pubDate>Mon, 20 Jun 2011 13:37:04 +0000</pubDate>
		<dc:creator>Ron Jeffries</dc:creator>
				<category><![CDATA[Articles]]></category>

		<guid isPermaLink="false">http://xprogramming.com/?p=2349</guid>
		<description><![CDATA[Last week Chet and I taught a delightful XP Experience class in Delaware. As often happens--where by often I mean always--the participants ran into trouble trying to apply Simple Design ideas when it came time for the system to demonstrate the ability to store and retrieve information. Let's talk about that.]]></description>
			<content:encoded><![CDATA[<p>Last week Chet and I taught a delightful XP Experience class in Delaware. As often happens&#8211;where by often I mean always&#8211;the participants ran into trouble trying to apply Simple Design ideas when it came time for the system to demonstrate the ability to store and retrieve information. Let&#8217;s talk about that.</p>
<p>Hmm. First we have to think of an app. I don&#8217;t want to do the one we use in the class: that would make it too easy for the next vict^H^H^H^H lucky participants.  I&#8217;m at the Seattle&#8217;s Best coffee shop in Borders, so how about this:</p>
<blockquote><p>Whenever someone buys something in our coffee shop, we remember how many things they have bought, and every time they buy another five things, the sixth one is free. People and their purchases are recorded by their membership number in our Constant Caffeination Club.</p></blockquote>
<p>Clearly this requires a database. Surely we will have millions of members in the CC Club as soon as the word gets out about this fabulous deal. We can&#8217;t possibly build this system in a TDD style without using some kind of database software.</p>
<p>To make this even more difficult, we&#8217;ll build the software in Python, since I just got Python and haven&#8217;t much of an idea how to program in it. Fortunately, I also have a trial of JetBrains&#8217; PyCharm, which is very helpful. I&#8217;ll be buying that before the week is out, I think. Naturally, I begin with a hookup test:</p>
<pre>import unittest

class NoDBTests(unittest.TestCase):
    def test_hookup(self):
        self.assertTrue(True)

if __name__ == '__main__':
    unittest.main()</pre>
<p>&nbsp;</p>
<p>With great good fortune, this goes green. Now let&#8217;s TDD a class into existence. I&#8217;m thinking I&#8217;ll start with the Club member record, and &#8230; oh, let&#8217;s see &#8230; the way it works is that we get the member record and when they buy something for X dollars, we send the member record a message and it responds with the amount to charge the member &#8230; either X or zero, probably. This will take a couple of tests, or one growing test. Let&#8217;s see:</p>
<pre>    def test_memberCharge(self):
        member = MemberRecord()
        chargeAmount = member.charge(10)
        self.assertEqual(10,chargeAmount)</pre>
<p>&nbsp;</p>
<p>This ought to serve to get us going. PyCharm tells me there is no MemberRecord class and offers to build it for me. I allow that. It builds it into the current file. I can live with that for now. I expect that when I run the tests it will go red-bar on charge not existing &#8230; and it does. I will add that, as follows:</p>
<pre>class MemberRecord(object):
    def charge(self, amount):
        return 0</pre>
<p>&nbsp;</p>
<p>This gets me the next expected red-bar, namely 10 != 0, telling me that my implementation of charge() is wrong. Naturally, I fix it perfectly like this:</p>
<pre>class MemberRecord(object):
    def charge(self, amount):
        return <span style="color: #800000;">10</span></pre>
<p>&nbsp;</p>
<p>OK, there can be no doubt that this is the definitive implementation of charge. So it is time for another test. Let&#8217;s have our guy charge six things and check that the first five come back charging, and the sixth comes back free. I&#8217;m sure this is going to work.</p>
<pre>    def test_sixthOneFree(self):
        member = MemberRecord()
        chargeAmount = member.charge(5)
        self.assertEqual(5, chargeAmount)
        chargeAmount = member.charge(5)
        self.assertEqual(5, chargeAmount)
        chargeAmount = member.charge(5)
        self.assertEqual(5, chargeAmount)
        chargeAmount = member.charge(5)
        self.assertEqual(5, chargeAmount)
        chargeAmount = member.charge(5)
        self.assertEqual(5, chargeAmount)
        <span style="color: #993300;">chargeAmount = member.charge(5)
        self.assertEqual(0, chargeAmount)</span></pre>
<p>&nbsp;</p>
<p>Damn. Didn&#8217;t quite work. Turns out returning 10 was wrong. I need to return the amount sent in. Easy fix:</p>
<pre>class MemberRecord(object):
    def charge(self, amount):
        return <span style="color: #800000;">amount</span></pre>
<p>&nbsp;</p>
<p>Darn. (Not quite as bad as damn.) The first five asserts worked fine but the sixth one returned five instead of zero. What&#8217;s up with that?</p>
<p>N.B. I&#8217;m not really this stupid. I&#8217;m just having fun. Really. You can trust me on this.</p>
<p>Anyway, we need to implement the counting from one to five to make this work. Should be easy enough:</p>
<pre>class MemberRecord(object):

    def __init__(self):
        self.__purchaseCount = 0

    def charge(self, amount):
        <span style="color: #993300;">self.__purchaseCount+=1
        <span style="color: #000000;">return amount</span> if self.__purchaseCount != 6 else 0</span></pre>
<p>&nbsp;</p>
<p>Pretty big change there, but let me point out that it was mostly addition, not rewriting.</p>
<p>Now of course, I was just doing the absolute simplest thing there, and it is clear that a test of more than six purchases will fail to give any more freebies. Let&#8217;s try 12:</p>
<pre>    def test_twelvthOneFree(self):
        member = MemberRecord()
        for i in range(5):
            member.charge(6)
        chargeAmount = member.charge(6)
        self.assertEqual(0, chargeAmount, <span style="color: #993300;">"first one bad"</span>)
        for i in range(5):
            member.charge(6)
        chargeAmount = member.charge(6)
        self.assertEqual(0, chargeAmount, <span style="color: #993300;">"second one bad"</span>)</pre>
<p>&nbsp;</p>
<p>I did this in two steps to be sure that the first one still works. Sure enough, the test fails saying &#8220;second one bad&#8221;. I&#8217;m thinking I have a fix for that &#8230; I&#8217;ll do a mod check on the count. I could zero it but I think the mod is easier and a bit more flexible. I understand mod, so others might disagree. Anyway here goes:</p>
<pre>   def charge(self, amount):
        self.__purchaseCount+=1
        return amount if <span style="color: #993300;">self.__purchaseCount%6 != 0 </span>else 0</pre>
<p>&nbsp;</p>
<p>As I thought, this works just fine. We are green all the way, and I&#8217;m sure that the system is working just fine. Might be a good idea to beef up this final test just a bit, to make sure that it&#8217;s not always returning zero for some reason. Like this:</p>
<pre>    def test_twelvthOneFree(self):
        member = MemberRecord()
        for i in range(5):
            <span style="color: #993300;">self.assertEquals(6,member.charge(6))</span>
        chargeAmount = member.charge(6)
        self.assertEqual(0, chargeAmount, "first one bad")
        for i in range(5):
            <span style="color: #993300;">self.assertEquals(6,member.charge(6))</span>
        chargeAmount = member.charge(6)
        self.assertEqual(0, chargeAmount, "second one bad")</pre>
<p>&nbsp;</p>
<p>Still green, and a bit more robust. Naturally, you could have gone faster, but you&#8217;re not writing an article on how to do TDD, and you probably don&#8217;t like going down to the finest grain possible. I do. One result of that is that never once in this bit of coding did I get a surprise. (Yes, I was faking it. I wanted you to think I was having a good time.)</p>
<p>I like working with no surprises. It gives me confidence that I&#8217;m coding what I set out to code. When I do get  a surprise, I try to back out my last changes, and go in smaller steps. When I forget to do that, and start debugging instead, pretty soon I&#8217;m strewing print statements around or even going into the debugger. So far I don&#8217;t know how to work the PyCharm debugger and I&#8217;m hoping never to learn.</p>
<blockquote><p><strong>Hey! I thought this was supposed to be about databases???</strong></p></blockquote>
<p>Hey, yourself. Try to pay closer attention. This is totally about databases.</p>
<blockquote><p><strong>Why is this even remotely about databases???</strong></p></blockquote>
<p>Well, here&#8217;s why:</p>
<p>We have just defined a core element of our member database record, namely the purchase count, and made sure that it works. Now when we read a member record in from our database, we can instantiate it into our class MemberRecord and send it messages to decide what to do. This is OO here, my young padawan, and that&#8217;s how we do it.</p>
<blockquote><p><strong>Yeah, sure, old man, but what about the membership number? That&#8217;s the key, according to the story, and you don&#8217;t even have it. And isn&#8217;t there just a small matter of actually storing and retrieving these babies?</strong></p></blockquote>
<p>Patience, youngling. Each thing comes in its time. Let&#8217;s see what the next tests bring us.</p>
<p>I&#8217;m thinking we need something like this: We&#8217;ll have two members, say numbers two and six. You are number six. We&#8217;ll have them each buy some stuff, in some alternating pattern, and make sure that they each get their freebies at the right time. I&#8217;ll start with this test:</p>
<pre>    def test_twoAndSixBothGetFreeStuff(self):
        members = MemberCollection()
        for purchaseFromTwo in range(5):
            self.assertEquals(4, members.member(2).charge(4))
        self.assertEquals(0, members.member(2).charge(4))</pre>
<p>&nbsp;</p>
<p>This isn&#8217;t my complete plan, but it is enough to fail. The idea here is that MemberCollection is my database of MemberRecords, and the method member() returns the MemberRecord whose number is given. First cut solution goes like this:</p>
<pre>class MemberCollection(object):
    def member(self, memberNumber):
        return MemberRecord()</pre>
<p>&nbsp;</p>
<p>We don&#8217;t really have a collection yet: we just return a new member every time. The result of this, of course, is that we always start at zero purchases, so the sixth purchase is not free.</p>
<p>I can see at least two ways to go from here. I could save a single record and return it always. That would make it work for one person and not for the second, because their purchases would add together. I could make two records, and return the appropriate one, simulating the collection.</p>
<p>There is also a need to add the member number to the MemberRecord, which I will do by extending the constructor. I&#8217;ll have to choose between a default number, or modifying the tests. I&#8217;ll figure that out when I get there.</p>
<p>Then finally I&#8217;ll need a collection, which I can drive out with a third member, or refactor in when the current test works. It&#8217;s early days yet. I don&#8217;t mind speculating about these things, but I&#8217;m not going to do them until the time comes. I think first, I&#8217;ll just save one record. That should get this part of the test going, then I&#8217;ll extend the test, or write a new one, to break the one-record solution.</p>
<pre>class MemberCollection(object):

    <span style="color: #993300;">def __init__(self):
        self.__record = MemberRecord()</span>

    def member(self, memberNumber):
        return self.__record</pre>
<p>&nbsp;</p>
<p>That gets our current test working: the single record in the database works for for our one guy. Now I can extend this test, or write a new one. If I write a new one, this one should be renamed. I&#8217;ll do that.</p>
<pre>    def <span style="color: #993300;">test_memberTwoStillGetsFree</span>(self):
        members = MemberCollection()
        for purchaseFromTwo in range(5):
            self.assertEquals(4, members.member(2).charge(4))
        self.assertEquals(0, members.member(2).charge(4))

    def test_memberSixDoesNotInterfereWithTwo(self):
        members = MemberCollection()
        for purchaseFromTwo in range(5):
            self.assertEquals(4, members.member(2).charge(4))
        self.assertEquals(4, members.member(6).charge(4), <span style="color: #993300;">"six interfered"</span>)
        self.assertEquals(0, members.member(2).charge(4), <span style="color: #993300;">"two got no discount"</span>)</pre>
<p>&nbsp;</p>
<p>This fails as expected, &#8220;six interfered&#8221;. Member six and member two are sharing the same record. I will fix this by making two records:</p>
<pre>class MemberCollection(object):

    def __init__(self):
        <span style="color: #993300;">self.__record2 = MemberRecord()
        self.__record6 = MemberRecord()</span>

    def member(self, memberNumber):
        return <span style="color: #993300;">self.__record2 if memberNumber == 2 else self.__record6</span></pre>
<p>&nbsp;</p>
<p>And our test is green. We now have a database of records. A very small database, mind you, but it is working perfectly for our two members. What&#8217;s next? Well, we could refactor a bit, but it seems to me that we&#8217;d really be putting in new functionality. So I&#8217;ll write another test. I think I&#8217;ll process three people at once this time, number two, number six, and number one.</p>
<p>Also, while I&#8217;m thinking of it, I think I&#8217;ll create some manifest constants for those magic person numbers, as they are not showing up very well in the tests. Here goes:</p>
<pre>class NoDBTests(unittest.TestCase):

    <span style="color: #993300;">personOne = 1
    personTwo = 2
    personSix = 6</span>
    ...
    def test_threeAtOnce(self):
        members = MemberCollection()
        for purchaseNumber in range(5):
            for person in [2, 6, 1]:
                self.assertEquals(3, members.member(person).charge(3), <span style="color: #993300;">"improper free one"</span>)
        self.assertEqual(0, members.member(<span style="color: #993300;">self.personOne</span>).charge(3))
        self.assertEqual(0, members.member(<span style="color: #993300;">self.personTwo</span>).charge(3))
        self.assertEqual(0, members.member(<span style="color: #993300;">self.personSix</span>).charge(3))</pre>
<p>&nbsp;</p>
<p>Naturally, the self.personOne changes were made elsewhere as appropriate. You can look for those when I provide the final code at the end. Right now, we get the &#8220;improper free one&#8221; message, as the current implementation of the database will reuse person number six&#8217;s record when asked for person number one. (Interesting how that turned out if you were thinking of The Prisoner, but for our database it just won&#8217;t do.)</p>
<p>Now we need to build a collection that will work for as many people as we have. One way to do it, certainly, would be to build it up before the tests. We could argue that members will have to already be signed up before their purchases will be counted. Or we could add them dynamically, creating a MemberRecord for any key we don&#8217;t already have. I think I&#8217;ll go that way, mostly to learn a little more Python. With luck I won&#8217;t get in trouble. Let&#8217;s see.</p>
<p>I&#8217;ll make a collection named members, and a function findMember(memberNumber) that looks for a member. If it finds the member, it&#8217;ll return them, otherwise it will create a new one, add it to members, and return it. And I&#8217;ll need to add a memberNumber &#8220;member&#8221; to the MemberRecord. Got that? OK, here goes.</p>
<pre>class MemberRecord(object):

    def __init__(self, <span style="color: #993300;">memberNumber=-1</span>):
        self.__purchaseCount = 0
        <span style="color: #993300;">self.memberNumber = memberNumber</span>

    def charge(self, amount):
        self.__purchaseCount+=1
        return amount if self.__purchaseCount%6 != 0 else 0

class MemberCollection(object):

    def __init__(self):
        <span style="color: #993300;">self.members = []

    def member(self, memberNumber):
        memberRecordList = filter(lambda m: m.memberNumber == memberNumber, self.members)
        if len(memberRecordList) &gt; 0:
            return memberRecordList[0]
        else:
            newMember = MemberRecord(memberNumber)
            self.members.append(newMember)
            return newMember</span></pre>
<p>&nbsp;</p>
<p>The above code makes the tests green. We now have a MemberRecord that knows its member number, and a MemberCollection that can find MemberRecords by number, and add them on the fly as needed.</p>
<p>You&#8217;ll note that I named the finding method member(), not findMember(). Oversight on my part and perhaps we&#8217;ll change that now that we are green. You may be wondering how that method works. It goes like this: create a list of all the records numbered &#8220;memberNumber&#8221;. If the list has more than zero elements (by construction it can only have zero or one), return the zeroth element. If it has zero, create a new one of the desired number, add it, return it.</p>
<p>I&#8217;m not unduly fond of this method but it was the first thing I could think of that wasn&#8217;t an explicit loop. In retrospect, I may prefer the explicit loop. We&#8217;ll see.</p>
<p>You may be wondering about the lambda. That&#8217;s an inline function, returning whether x.memberNumber == (the provided) memberNumber. I think that&#8217;s how ya do that.</p>
<p>Anyway, now that we are green, let&#8217;s review what has happened. Then, time and space permitting, I&#8217;ll clean up the code a bit.</p>
<h3>Database? Why Yes, In Fact It Is.</h3>
<p>Without ever doing any SQL or other SQuirreLy database stuff, we have begun to design and implement an important record in our system, the MemberRecord. We can continue to evolve it, adding meaningful fields and behavior, as long as we want. Because the record is an object, we have at least a decent chance of encapsulating behavior in the right place.</p>
<p style="padding-left: 30px;">Speaking of that, should our collection be looking at the member number? Or should we have an &#8220;isMemberNumber(n)&#8221; method on the record? Possibly the latter but the way it is now may lead more more readily toward a database solution. Viz:</p>
<p>We have also done important design on the database &#8220;table&#8221; that contains MemberRecords. In particular, we have identified that our only needs (so far) are the ability to find a record by its number, and to add a record of a given number. This finding simplifies any actual database we may do in the future to put these records into some persistent collection. If we are the kind of people who use stored procedures, for example, we have just identified the only ones we&#8217;ll need.</p>
<p>Again, so far. As we continue to evolve this little app, we may find more. The good news is that they&#8217;ll all be nicely located in the MemberRecord and MemberCollection.</p>
<p>And its fast. Our seven tests execute in 0.122 seconds on my ancient tablet PC.</p>
<h3>But What About &#8230;</h3>
<p>Doubtless at this point you have some &#8220;what about&#8221; questions. I think you can answer them. I&#8217;m here to point the way, not drag you along the path. :) But I will take one question just to show that while I am unreasonable, I don&#8217;t want to appear that way:</p>
<blockquote><p>When we finally plug in the real database, how should we do it so that these tests don&#8217;t all break?</p></blockquote>
<p>I&#8217;d look into topics like &#8220;pluggable behavior&#8221;. I could imagine a switch inside MemberCollection that cuts it over to using the real database code, or a different class, maybe OracleMemberCollection with the same behavior but implemented in Oracle. Either way, the switch setting or use of the new class will be plugged into the system at some higher level than we presently have represented.</p>
<p>Please think about other issues, and see how you might address them. For extra credit, try working this way, and solve the issues as they arise. If you keep the objects well encapsulated, I&#8217;m sure you&#8217;ll do just fine.</p>
<h3>Final Code</h3>
<p>I think this article is more than long enough already. I&#8217;ll post the final code in a separate piece.</p>
<p>P.S. PyCharm is really nice. I am not associated with JetBrains in any way other than as a user. And I like it.</p>
<p>P.P.S. Comments are on, at least for a while.</p>
<p>Thanks for reading!</p>
]]></content:encoded>
			<wfw:commentRss>http://xprogramming.com/articles/but-we-need-a-database-dont-we/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>Kate Oneal and the Mythical Italian Restaurant</title>
		<link>http://xprogramming.com/articles/kate-oneal-and-the-mythical-italian-restaurant/</link>
		<comments>http://xprogramming.com/articles/kate-oneal-and-the-mythical-italian-restaurant/#comments</comments>
		<pubDate>Thu, 09 Jun 2011 15:25:08 +0000</pubDate>
		<dc:creator>Ron Jeffries</dc:creator>
				<category><![CDATA[Articles]]></category>
		<category><![CDATA[Kate Oneal]]></category>

		<guid isPermaLink="false">http://xprogramming.com/?p=2328</guid>
		<description><![CDATA[Kate met Dan Devlin at the coffee shop on Main Street where he had originally recruited her. They shared the lovely weather and caught up to date on their lives. But Dan had a question.]]></description>
			<content:encoded><![CDATA[<p>Kate met Dan Devlin at the coffee shop on Main Street where he had originally recruited her. They shared the lovely weather and caught up to date on their lives. But Dan had a question.</p>
<p>&#8216;Kate,&#8221; Dan said, &#8216;things are going well. Products are selling, the Marketing people are happy, quality is up, customers are happy. I just have one question.&#8221;</p>
<p>&#8220;How much of a raise do I want?&#8221; Kate said. &#8220;It&#8217;s nice of you to ask.&#8221;</p>
<p>Dan laughed. &#8220;Don&#8217;t worry about that, there&#8217;ll be a nice present in your stocking come Christmas. No, my question is, how can what you&#8217;re doing possibly work? As soon as we have a product idea even partly fleshed out, the developers are building it and have a version for us to play with. And then you just grow it from there. How can that possibly work?&#8221;</p>
<p>&#8220;Do you mean technically? We have tests, refactoring, &#8230;&#8221;</p>
<p>&#8220;No,&#8221; Dan said. &#8220;That&#8217;s your bailiwick. I don&#8217;t understand how it can work from a business viewpoint. How can we do all this without nailing down the requirements, estimating everything, and making sure people get done what they said they would do? It seems like you have everyone just winging it.&#8221;</p>
<p>&#8220;Well, it is a lot like improv,&#8221; Kate said. &#8216;Lots of preparation, practice, refining. Maybe it would help if I told you about my Uncle Guido and his Italian restaurant.&#8221;</p>
<p>&#8220;You don&#8217;t look Italian,&#8221; said Dan.</p>
<p>&#8220;True enough. I&#8217;m in witness protection, but don&#8217;t tell anyone. Anyway, my uncle Guido had an Italian restaurant, and he decided he needed a lovely mural on the back wall, to give the place a touch of class. Let me tell you what happened.</p>
<p>&#8220;Guido and his pals talked about it a bit, over some of Guido&#8217;s famous Questionable Chianti. They decided this was a great idea. They thought about what they needed and decided on a nice Tuscan look, with maybe a grape arbor showing where the Questionable Grapes were grown in the old country, and probably a picture of Great Great Aunt Sophia, sitting at a picnic table or maybe hanging out laundry. They drew pictures of their ideas on bar napkins. Unfortunately most of those were lost, because Questionable Chianti turns out to be a really good bleach.</p>
<p>&#8220;Anyway, after they had some ideas, and the headaches were mostly gone, they started to talk with local artists. They learned a lot, most of it bad news. The artists wanted &#8216;artistic freedom&#8217;, or they said that the painting would take a month to do and they needed the restaurant closed for that period. There were all kinds of problems.</p>
<p>&#8220;The good news was, this helped Guido understand his needs. He needed to keep the restaurant going, and he didn&#8217;t want a big ugly drop cloth hanging there hiding the painting, since there were doors in the wall, to the restrooms and the kitchen. At first he tried to find someone who would paint the whole thing over a weekend, but no one stepped up to that.</p>
<p>&#8220;Guido was stumped. He couldn&#8217;t have the place looking horrible, and he couldn&#8217;t close, but he really wanted his mural. Finally he met one artist who had an idea. &#8216;What if we let people see how the mural is coming,&#8217; she asked Guido. &#8216;I&#8217;ll work early mornings until you open, and folks can come in every day and see what is happening. They can give you feedback, and you can give me feedback and we&#8217;ll build the mural to best suit your ideas and budget.&#8217;</p>
<p>&#8220;Guido thought a bit and decided that if there were no poisonous fumes, this could be a good idea. He could see the thing taking shape and guide how it went. But he was worried about the budget. &#8216;How can we keep costs under control,&#8217; he asked.</p>
<p>&#8220;The artist suggested this: &#8216;Let&#8217;s set a deadline and total budget. I&#8217;ll keep you posted on how much is being spent, and of course we&#8217;ll have the picture on the wall to look at. By the time we&#8217;re about half-way through, it should be of high enough quality, and have enough picture elements, that we could stop any time. You&#8217;ll have more ideas, of course, but by then we&#8217;ll both have a sense of how fast we can progress, and you can choose the most valuable things to add or change. You&#8217;ll have total control over how the picture winds up, and if you want to, we can stop on or before the money runs out.&#8217;</p>
<p>&#8220;Guido wasn&#8217;t entirely convinced. He wanted to know how he could be sure he wouldn&#8217;t be left with a horribly ugly wall. The artist told him that she would guarantee to paint it back over and stop any time he wanted, and said she would start by working in some temporary pigment like chalk, so they could erase and change things easily.</p>
<p>&#8220;Guido decided to go ahead.&#8221;</p>
<p>Dan thought. &#8220;I can almost imagine that working. But it seems awfully chaotic. Did it work?&#8221;</p>
<p>Kate said, &#8220;Wait and see. The story goes on. Guido was a serious thinking guy, like you are. He had made a lot of notes about the mural and his needs, and many of them were not bleached away by the Questionable Chianti. His first thought was to give all his notes to the artist and have her paint away. I&#8217;ve actually seen some of those notes and they were pretty good. Here&#8217;s how I remember what he wrote about Great-great Aunt Sophia:&#8221;</p>
<blockquote><p>Sophia was a great beauty in her youth. It was said in our family that Sophia Loren took her name because she looked like our Sophia. Our Sophia had dark dark eyes, jet black hair that flowed down below her shoulders. She had curves to make men cry and she moved like a dancer despite her voluptuous figure.</p></blockquote>
<p>&#8220;Maybe you are Italian after all,&#8221; Dan said.</p>
<p>&#8220;Silence, I&#8217;m telling a story, you dirty old man,&#8221; said Kate. &#8220;Guido had written more:&#8221;</p>
<blockquote><p>The mural should show Sophia in her later years. She had rounded out a bit, as we Italians will, and somehow she seemed shorter. You could see in her aging face the beautiful girl she had been. And in her eyes you could see the memories of the many men she had conquered. After she married Francesco, she had a long happy married life and many children whom she adored.</p>
<p>The mural should show her as Grandmama Sophia, still energetic and beautiful, still ruling the family gently but firmly. It should let people see the great family heritage that comes down to us and should suggest that just as Sophia created wonderful food for her family, we will create wonderful food for our customers.</p>
<p>The picture should also show that Sophia was frugal, just as our prices are quite fair given the high quality of the food we serve. And she should look hard-working, to show that we will work hard for our customers.</p></blockquote>
<p>&#8220;Wow,&#8221; Dan said. &#8220;He asks a lot of a picture of a little old lady.&#8221;</p>
<p>&#8216;Guido was a poet at heart,&#8221; Kate said. &#8220;But tell me this: if you were an artist, could you draw a picture of Sophia at age 55 or so, and have it look like Guido&#8217;s memory?&#8221;</p>
<p>Dan only had to think a moment. &#8220;No. I get that she was a lovely lady but I have no idea what she looked like. Hey, wait! This is an allegory isn&#8217;t it? Are you talking to me about written specifications?&#8221;</p>
<p>Kate laughed. &#8220;Caught me. We have the same problem as the artist would have had with Guido&#8217;s lovely prose: it doesn&#8217;t really tell her what has to be done.&#8221;</p>
<p>&#8220;What did she do?&#8221;</p>
<p>Kate said, &#8220;First, she read all of Guido&#8217;s pages of notes. Fortunately there weren&#8217;t too many, but there were a lot of items that she made notes about:&#8221;</p>
<blockquote><p>The family had a pet mouse named Petra. The mural should have a mouse in it, but it shouldn&#8217;t look like the restaurant is infested.</p>
<p>Also, now that I think about it, a sort of Garden of Eden feeling might be good, as our restaurant is a little paradise. And our desserts are very tempting. Maybe there should be a serpent to tempt people. Maybe a Python.</p>
<p>Don&#8217;t forget the Questionable Grapes from which we get our famous Chianti.</p>
<p>The family kept goats and sheep. Maybe there could be some hills with animals playing.</p>
<p>I remember one time a wolf or something got my favorite little goat. Should there be a wolf?</p></blockquote>
<p>Kate took a breath. &#8220;Guido&#8217;s list went on and on.&#8221;</p>
<p>Dan said. &#8220;Wait. Guido wanted a python? In a restaurant mural? Of Tuscany?&#8221;</p>
<p>Kate said, &#8220;It turns out Guido was really hung up on the python. It took a lot for the artist to talk him out of it. And talking is what they did.</p>
<p>&#8220;The artist met with Guido after reading all his notes. Guido began by saying that he wanted the artist to write up her design for the mural and her detailed schedule. Fortunately, she had a better idea. &#8216;Words describing pictures don&#8217;t work very well, Guido. I suggest that I&#8217;ll draw you some sketches of what I understand. We&#8217;ll work with the sketches for a while, and then we&#8217;ll start working directly on the wall where your customers can see the mural.&#8217;&#8221;</p>
<p>Dan said, &#8220;Dammit, this <em><strong>is </strong></em>an allegory isn&#8217;t it? Your Jesuit education is showing.&#8221;</p>
<p>&#8220;No, no, this is all true, I swear it,&#8221; said Kate, holding up her crossed fingers. &#8220;It does relate to how we work on your products though.&#8221;</p>
<p>Dan said, &#8220;OK, let&#8217;s see. You start with whatever written material Marketing has, and then you sit and talk with them. And as soon as you can, you start showing them product pieces, like the artist&#8217;s sketches.&#8221;</p>
<p>&#8220;Yes, that&#8217;s right. And, as soon as possible, we get those product pieces in the hands of customers, just like the artist got things on the wall in the restaurant as soon as possible,&#8221; said Kate.</p>
<p>Dan said, &#8220;Wasn&#8217;t  there trouble along the way, like with Aunt Sophia&#8217;s looks and the bloody python?&#8221;</p>
<p>&#8220;The artist handled it pretty well. Her first move on Sophia was to ask for pictures of her at the age Guido had in mind. Naturally, there were lots of pictures in the family albums. She had him pick out his favorites, and over time, she at first sketched some samples, and then later actually did some small renditions in chalk or something. By the time Sophia went on the wall, they had a good idea what she would look like.&#8221;</p>
<p>Dan said, &#8220;Did they do everything that way, with lots of sketches first?&#8221;</p>
<p>&#8220;Fortunately not,&#8221; Kate said. &#8220;One thing that helped was that although some of their meetings had been away from the restaurant, they did have a meeting there pretty soon, because the artist wanted to look at the actual installation. Two important things came out of that.</p>
<p>&#8220;First of all, she couldn&#8217;t help noticing the two doors in the wall, which Guido had never mentioned to her in conversation or his writing. And she saw that the one led to the restrooms, and the other to the kitchen. She asked whether the mural should incorporate the doors, and if so, whether the one should seem open and inviting, and the other one closed, so people didn&#8217;t accidentally go into the kitchen. Guido agreed, of course.</p>
<p>&#8220;The artist sketched a couple of ideas &#8230; one with the door to the restroom painted to look like an inviting pathway, and one with the door to the kitchen looking like a closed gate. She also showed one with the kitchen doors painted so as to hide the fact that they were doors at all.&#8221;</p>
<p>Dan said, &#8220;You said two things. What else?&#8221;</p>
<p>&#8220;The artist noticed that there were tables near the mural wall, not for customers, but where restaurant supplies like plates and silver were kept.  The sketches they had looked at had detail all the way down to the floor, but that detail wouldn&#8217;t be visible at all. So being in the real situation had given them some important insights, one of which Guido had thought about but forgotten to mention, and the other one being new to both of them.&#8221;</p>
<p>Dan said, &#8220;OK, what&#8217;s the lesson in this, you Jesuitical minx?&#8221;</p>
<p>&#8220;Ah, Watson, you know my methods. We try to get together not just with the idea people but with the real customers for our software. In Guido&#8217;s case, they were the same person, but by putting Guido in the restaurant with the artist, new understanding came out. When we meet, not just with Marketing, but with our customers and prospects, in the presence of even sketched product ideas, better ideas come out.&#8221;</p>
<p>&#8220;OK, what happened next to your imaginary uncle Guido?&#8221; said Dan.</p>
<p>&#8220;Imaginary? Imaginary? For that you have to take me to dinner at his restaurant. Anyway, they worked with sketches for just a bit longer, and then the artist said it was time to start working on the real wall. Guido was pretty scared. He was afraid that if something really ugly went up there, customers would be turned off. The artist agreed, but she was thinking about the Python.</p>
<p>&#8220;So she asked Guido if he would prefer to look at sketches and then close the restaurant for a while while she painted the real wall. Right away Guido didn&#8217;t want to shut down, but then he realized that no matter how much work she did on the sketches, he wouldn&#8217;t have a sense of how the wall was looking until she was finished.&#8221;</p>
<p>&#8220;Unless he sat there and watched her all the time,&#8221; Dan said.</p>
<p>&#8220;Yes. And neither of them thought that would be much use, and anyway they would have used up all their time and cost flexibility on sketches. There wouldn&#8217;t be much ability to change, just ability to fail or run over.&#8221;</p>
<p>&#8220;So what did they do?&#8221; said Dan.</p>
<p>Kate said, &#8220;Just like she had suggested. The artist started coming in in the morning and chalking the mural on the wall. She blocked in big areas, and sometimes drew more detailed bits. I think she did Aunt Sophia in more detail early on, and the Questionable Grape Arbor.</p>
<p>&#8220;Guido was worried at first, but the customers loved it. They would ask what was going on, and offer comments. The whole restaurant turned into a kind of little village where people were talking among themselves, and with the staff and Guido about what was going on. A lot of people started coming in more frequently just to see what was happening to the mural.&#8221;</p>
<p>Dan said, &#8220;Did it all go smoothly into place?&#8221;</p>
<p>&#8220;Not remotely,&#8221; Kate said. &#8220;There were lots of changes, some that Guido saw, and some that the customers saw. One time, the artist sketched in the python, and people asked to be seated far away from it. I guess it was a very convincing python. Guido relented on the python at that point.&#8221;</p>
<p>&#8220;OK, so in our company, you put the product before the customers before it&#8217;s finished, and let them give you feedback about it,&#8221; said Dan.</p>
<p>&#8220;Yes, that&#8217;s right. And we build lightly enough that when we get good ideas, we can put them in without too much trouble. That&#8217;s where our testing and refactoring play in.&#8221;</p>
<p>Dan said, &#8220;What about the wall? When she started using real paint, were there still changes?&#8221;</p>
<p>&#8220;Sure, lots,&#8221; Kate said. &#8220;Many came from customers, some from Guido, some from the artist herself. In art, you just paint over the bad bits, or scrub them off and start over in some area. In software, we refactor most often, sometimes we replace whole bits. We&#8217;d rather refactor, because it&#8217;s less expensive, but sometimes we just get it wrong.&#8221;</p>
<p>Dan said, &#8220;But isn&#8217;t that wasteful? If you had planned better, you wouldn&#8217;t have all that rework!&#8221;</p>
<p>Kate smiled. &#8220;Nice try. But the issue isn&#8217;t in planning. No number of words would get the right look on Sophia&#8217;s face. Guido had to see it on the wall. In fact he had the artist change it several times before she caught his vision of this saintly but still sexy older woman. It kept getting better, and they went back to sketches a few times, but things on the wall look different than in sketches.</p>
<p>&#8220;I believe that Guido made some important tradeoffs to get things right. The artist was insistent that they stop on time and on budget. By now, Guido was in the throes of creativity and might have gone on refining Sophia forever. The artist brought him back to earth by reminding him of the schedule. At one point, he actually backed off on some of the animals in the field to get a little more done on Sophia.&#8221;</p>
<p>Dan said, &#8220;That&#8217;s what Susan does, isn&#8217;t it? I remember her briefing me one time that she had deferred my favorite feature to get another feature stronger. She had a hard time convincing me but was pretty insistent. In the end, I realized I had given her authority and let her go ahead. Turns out everything went just fine, and she put in my feature in an update later.&#8221;</p>
<p>&#8220;Exactly,&#8221; Kate said. &#8220;Building the best possible product in the time and money we have isn&#8217;t easy. Sometimes we have to make hard decisions, and sometimes we&#8217;ll even make them wrong. No one is perfect. What our approach does is keep everything visible: the product as it grows, the budget as it is spent, the time as it runs out. And we keep the picture on the wall at all times, so when it&#8217;s time for the big party, the picture is ready.</p>
<p>&#8220;And the mural was ready for Guido&#8217;s big party as well. His daughter Amelia decided to get married, rather suddenly I&#8217;m told, and Guido threw the biggest party imaginable, at the restaurant. It was just a few days after the original deadline, and of course lots of people came in who had never seen Guido&#8217;s place at all. They had a wonderful time and everyone loved the mural. As far as I know, no one asked why there wasn&#8217;t a python in the picture.&#8221;</p>
<p>Dan thought a moment. &#8220;I think I get it. You just work as close to real product as you can, evolving your understanding and the product at the same time. And you make decisions as you go, doing the best you can, and making sure you&#8217;re always ready for the next party &#8212; I mean ready to ship. Sounds easy.&#8221;</p>
<p>Kate smiled. &#8220;Pretty close. One thing: it&#8217;s not easy. You have to be willing to work in public, with all the good stuff and all the bad stuff right out there to be seen. You have to be willing to make decisions, and to remake them, and you have to work so as to to make change easy. This stuff isn&#8217;t really easier than the older ways. It&#8217;s just much better.&#8221;</p>
<p>&#8220;It is much better,&#8221; Dan said. &#8220;When we first talked, I thought we would have to close the company. Now we have a steady flow of new product and a steady flow of happier customers. Thanks for the story about how you do it, wrapped up in the Mythical Guido&#8217;s Restaurant story.&#8221;</p>
<p>&#8220;Mythical?&#8221; Kate said. &#8220;Wait until you taste Guido&#8217;s veal piccata at the dinner you&#8217;re going to buy me. It won&#8217;t seem mythical then. And the restrooms? They&#8217;re through that door that looks like a hedged pathway into a private part of the garden.&#8221;</p>
]]></content:encoded>
			<wfw:commentRss>http://xprogramming.com/articles/kate-oneal-and-the-mythical-italian-restaurant/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Ends of Some Things, with Regret &#8230; and Beginnings?</title>
		<link>http://xprogramming.com/articles/ends-of-some-things-with-regret-and-beginnings/</link>
		<comments>http://xprogramming.com/articles/ends-of-some-things-with-regret-and-beginnings/#comments</comments>
		<pubDate>Tue, 10 May 2011 15:18:44 +0000</pubDate>
		<dc:creator>Ron Jeffries</dc:creator>
				<category><![CDATA[Articles]]></category>
		<category><![CDATA[J Language]]></category>

		<guid isPermaLink="false">http://xprogramming.com/?p=2323</guid>
		<description><![CDATA[It is with some regret that I'm discontinuing my articles about J and about iLua on the iPad. Here's why. Also, I have a question.]]></description>
			<content:encoded><![CDATA[<p>It is with some regret that I&#8217;m discontinuing my articles about J and about iLua on the iPad. Here&#8217;s why. Also, I have a question.</p>
<h3>J Language</h3>
<p>J language just isn&#8217;t paying off enough for me to invest more time in it. I see no possibility that I&#8217;ll be building any real software in J, and the learning curve is a rough one. You pretty much can&#8217;t do anything without having a large number of verbs and adverbs at your fingertips.</p>
<p>I regret this, because it is clear that J causes you to think in some interesting ways about your problem and its solution. The J community is interesting as well. I&#8217;ve encountered some very helpful people, and it seems that everyone wants to help you get it. This is great. Perhaps one day soon I&#8217;ll get to sit down with a J expert and pair on something. If I do, I&#8217;ll sure let you know.</p>
<h3>iLua System</h3>
<p>The iLua system is an interesting little language on the iPad. As my articles have shown, you can actually build little programs that do real things. The language allows you to construct things like objects very readily, using its very interesting internal primitives. It has been fun playing with it.</p>
<p>However, Apple has made it clear, by rejecting certain upgrades from the iLua people, that they will not permit the language ever to get very useful. For example, there was a very simple window/dialog capability put in, and Apple made them take it back out. It appears that Apple intends to enforce their policy that there will be no real software development for the iPad on the iPad.</p>
<p>I&#8217;m sad for the iLua people, and I&#8217;m sad for myself. But the fact remains that if I&#8217;m to build things for the iPad, this is not the way to do it.</p>
<h3>What&#8217;s Next?</h3>
<p>I&#8217;m not sure. I&#8217;ve had nearly six months off waiting for a new knee and then getting used to it. (Very fine, thanks. I recommend it to anyone who doesn&#8217;t mind being felt up in airports.) So I&#8217;m looking for things to do that will be fun and, if not lucrative, at least not get in the way of supporting my limited needs.</p>
<p>One thread of that might be some kind of development for mobile platforms, just for the fun of doing it. I attended a very interesting talk at Philly ETE, about using HTML, CSS, and JavaScript to build mobile apps. It looks to me as if this could become a better and more portable way of doing it. So I would like to learn more about that area. If you know of a course relating to it, or want to drop by and pair with us, let me know.</p>
<p>Another thread has to do with coaching and training. Chet and I will still be offering our highly-rated CSM course, and the Agile Skills course. At the same time, these are both aimed at entry-level and near entry-level folks, and I&#8217;d like to do a bit of work with more impact that that. Maybe deeper impact is what I mean. I&#8217;d like to work with people who have their feet solidly on the ground in Agile, and who want to excel.</p>
<p>So here&#8217;s a question to you: what kind of course or workshop might Chet and I offer that would entice you to attend, even if you or your company had to pick up the tab for course and travel?  What could Chet and I bring to the table that few others might? What would the session be like? How long would it go on? What would be really great?</p>
<p>Crazy ideas welcome &#8230; thanks!</p>
]]></content:encoded>
			<wfw:commentRss>http://xprogramming.com/articles/ends-of-some-things-with-regret-and-beginnings/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>On-Web Hashtable &#8230; What I&#8217;m Up To</title>
		<link>http://xprogramming.com/articles/on-web-hashtable-what-im-up-to/</link>
		<comments>http://xprogramming.com/articles/on-web-hashtable-what-im-up-to/#comments</comments>
		<pubDate>Tue, 10 May 2011 14:56:41 +0000</pubDate>
		<dc:creator>Ron Jeffries</dc:creator>
				<category><![CDATA[Articles]]></category>

		<guid isPermaLink="false">http://xprogramming.com/?p=2319</guid>
		<description><![CDATA[Need a little help getting some data in and out of Second Life. World's most rudimentary scripting language, world's most ignorant scripter.]]></description>
			<content:encoded><![CDATA[<p>I tweeted a bit about a need for a &#8220;hashtable&#8221; on the Web. My needs are so constrained that it was hard to give me good answers. (Unless you were all just trying not to give me good answers. (No, that&#8217;s not possible. You&#8217;re nice people. Must be my fault.)) So here&#8217;s a bit more about what I&#8217;m up to.</p>
<h3>The Constraints</h3>
<p>I&#8217;m trying to build a little script in Linden Scripting Language, LSL, the scripting language for Second Life. LSL brings new meaning to the word &#8220;rudimentary&#8221;.  There is a very limited built-in library of calls, mostly aimed at making things in Second Life move or talk or such. As for web connections, you can send and receive short emails, and you can make an http request. This request has a URL, a few parameters, and a body. Parameters include HTTP_METHOD (GET, POST, PUT, DELETE), HTTP_MIME_TYPE (text/* and apparently application/x-www-form-urlencoded), HTTP_BODY_MAXLENGTH (not supported, locked at 2048), and HTTP_VERIFY_CERT.</p>
<p>The x-www&#8230; MIME type will let you URL encode a body with var=value&amp;var2=value2 kinds of strings.</p>
<p>I want to use an existing on-line service, such as Amazon S3 or one of the hosted CouchDB or MongoDB services. Free usage at low volumes is a plus. Low cost usage at low volumes is a must.  Access using this rudimentary capability is, of course, a sine qua non.</p>
<p>I&#8217;m just messing around, so do not have the time or inclination to build something on my own site to host it and respond to a language of my own invention. Something out of the box is what I&#8217;m looking for.</p>
<h3>The Problem</h3>
<p>It should go without saying that a scripting language this limited also has limited storage. What I&#8217;d like to do is to store a moderate number (around a thousand) strings, by key. The key will be some unique string, the value another string. Keys around 20 or 30 characters, values around 200 or 300.</p>
<p>The script needs to be able to get a value string from the Web system, using the key, to put one back giving the key and value, and to delete a key. Simple hashtable kind of function.</p>
<p>The LSL language has an http_response &#8220;event&#8221; that will receive any response headers and the response body. My guess is that the content type of the body must be a string. I know for sure that LSL will not receive XML, JSON, Atom, RSS, or PLS content types.</p>
<p>Once the string is back, one can do reasonable parsing of it. Imagine what you could do with simple string functions: pretty much anything if you have the time.</p>
<p>So I&#8217;m looking for something on the Web, free or cheap, working with simple get, put, delete by key, storing a fairly small number of fairly short string objects, that can be accessed via a very simple text-focused URL request, returning a text-like response.</p>
<h3>But I&#8217;m Very Dumb &#8230;</h3>
<p>It does look to me as if S3 or MongoDB or CouchDB can probably do what I want. But since I have zero tools available in LSL, and little time to play on my PC to try to figure out what the URLs have to look like for get, put, and delete, I&#8217;m looking for a system whose docs show what the requests and responses actually look like, or for some examples that do the same.</p>
<p>Very lazy, I know. This is a tiny little hobby, and I can&#8217;t be investing hours and hours in it.</p>
<p>Got advice or ideas? Comments are open. Thanks!</p>
]]></content:encoded>
			<wfw:commentRss>http://xprogramming.com/articles/on-web-hashtable-what-im-up-to/feed/</wfw:commentRss>
		<slash:comments>11</slash:comments>
		</item>
		<item>
		<title>Kate Oneal: Handling Defects</title>
		<link>http://xprogramming.com/articles/kate-oneal-handling-defects/</link>
		<comments>http://xprogramming.com/articles/kate-oneal-handling-defects/#comments</comments>
		<pubDate>Mon, 11 Apr 2011 14:25:37 +0000</pubDate>
		<dc:creator>Ron Jeffries</dc:creator>
				<category><![CDATA[Articles]]></category>
		<category><![CDATA[Kate Oneal]]></category>

		<guid isPermaLink="false">http://xprogramming.com/?p=2311</guid>
		<description><![CDATA[<p>A few minutes before 9, the team was in the coffee room.</p>
<p>&#8220;What time&#8217;s the meeting?&#8221; said Gil. &#8220;Is she here?&#8221;</p>
<p>&#8220;Nine sharp,&#8221; said Susan. &#8220;I just went by her office. She&#8217;s not there.&#8221;</p>
<p>&#8220;Carl and I have been working&#8230;</p>]]></description>
			<content:encoded><![CDATA[<p>A few minutes before 9, the team was in the coffee room.</p>
<p>&#8220;What time&#8217;s the meeting?&#8221; said Gil. &#8220;Is she here?&#8221;</p>
<p>&#8220;Nine sharp,&#8221; said Susan. &#8220;I just went by her office. She&#8217;s not there.&#8221;</p>
<p>&#8220;Carl and I have been working in here since 8,&#8221; Gil said. &#8220;She hasn&#8217;t been here for a Diet Coke.&#8221;</p>
<p>&#8220;This is the day,&#8221; Carl said. &#8220;She&#8217;s late. Let&#8217;s go!&#8221;</p>
<p>When the team came into her office, Kate was by her window. She spun her wheelchair and scooted to her usual spot at the table.</p>
<p>&#8220;How do you do that?&#8221; said Gil.</p>
<p>&#8220;It&#8217;s easy. To spin, push one wheel, pull the other. To go forward, push both. To turn, grab one. To stop, grab both.&#8221;</p>
<p>&#8220;No, how do you always get to meetings right on time?&#8221;</p>
<p>Kate smiled. &#8220;That&#8217;s easy too: you leave wherever you are as many minutes as it&#8217;s going to take to get wherever you&#8217;re going.&#8221;</p>
<p>Carl said, &#8220;You have a Diet Coke.&#8221;</p>
<p>&#8220;Yes. Yes, I have.&#8221;</p>
<p>&#8220;It must be warm.&#8221;</p>
<p>Kate felt the can. &#8220;No, it&#8217;s nice and cold. The machine is working just fine.&#8221;</p>
<p>&#8220;I mean, how did you get it? Did you bring it to work with you?&#8221;</p>
<p>&#8220;Standard way. Put coins in slot, press the button. I suppose I could have thrown the coins across the room into the slot and tossed my exercise ball against the button, but I&#8217;d still have to go get the can.&#8221;</p>
<p>&#8220;No one could do that,&#8221; said Gil.</p>
<p>Kate smiled. &#8220;Maybe no one ever tried. What&#8217;s this meeting about?&#8221;</p>
<p>On his way to the coffee pot, Carl said, &#8220;We want to talk about what to do about bugs.&#8221;</p>
<p>&#8220;Great,&#8221; Kate said. &#8220;Let&#8217;s not have any.&#8221; She clapped her hands. &#8220;Meeting over?&#8221;</p>
<p>Susan laughed. &#8220;As Product Owner, I&#8217;m good with that. Move to adjourn.&#8221;</p>
<p>&#8220;Not so fast,&#8221; said Gil. &#8220;There are always going to be bugs. We have to handle them.&#8221;</p>
<p>&#8220;I knew it couldn&#8217;t be that easy,&#8221; said Kate. &#8220;What about these defects?&#8221;</p>
<p>Gil said, &#8220;Well, should we put them into a database? How should we decide which ones to fix?&#8221;</p>
<p>Kate said, &#8220;Who decides what features you work on?&#8221;</p>
<p>Gil said, &#8220;Susan, as you well know.&#8221;</p>
<p>Kate laughed. &#8220;Yes, as we all well know. So &#8230; who should decide which broken features to fix?&#8221;</p>
<p>Gil said, &#8220;Susan?&#8221;</p>
<p>&#8220;Good idea. Susan.&#8221;</p>
<p>Carl, having returned to the table, interrupted. &#8220;Oops. I forgot sugar. Sugar, please.&#8221;</p>
<p>Kate dipped two fingers into the bowl of sugar packets, and pulled one out. &#8220;Don&#8217;t move,&#8221; she said, and flicked the packet at Carl. It hit him in the chest and dropped into his shirt pocket.</p>
<p>&#8220;How did you do that?&#8221;</p>
<p>&#8220;Easy. Your nerd pack pulls your pocket open.&#8221;</p>
<p>Everyone laughed.</p>
<p>Carl frowned. &#8220;You never know when you might need a pen. Or a marker. Or a drawing pencil. Or another pen &#8230;&#8221;</p>
<p>&#8220;True that,&#8221; Kate said. &#8220;So what else about these defects?&#8221;</p>
<p>Susan said, &#8220;Well, we need to decide just how to handle the scheduling, how to count velocity, and things like that. And if there are a lot of them, how should we keep track of them?&#8221;</p>
<p>Kate said, &#8220;How do you schedule things now?&#8221;</p>
<p>Susan grinned. &#8220;Why do you ask questions you know the answers to? I write a short description on a card. If I need help deciding what to write, or need to be sure the idea makes sense, I talk about it with the team. Also, I meet with the testers to work out the correctness checks. We do that about once a week. Then at the planning meeting, I bring enough cards and checks to fill the week, we talk through each one, figure out how many the team can take on, and commit to the work.&#8221;</p>
<p>Kate paused, then said,&#8221;Why do I ask questions I know the answers to?&#8221;</p>
<p>Susan stared. Then, &#8220;Oh. If I want a bug fixed, I could write it on a card and bring it to the meeting?&#8221;</p>
<p>&#8220;Sure could,&#8221; said Kate. &#8220;But you mentioned something else that you bring.&#8221;</p>
<p>&#8220;The checks,&#8221; said Susan. &#8220;The testers and I could bring in some checks for the bug. They always figure out a way to reproduce it anyway.&#8221;</p>
<p>Kate smiled. &#8220;Sounds good to me. But isn&#8217;t there something special about these defect checks?&#8221;</p>
<p>Everyone looked confused. Finally, Charlie, a tester, spoke up. &#8220;Oh. We should have provided those checks the first time. We screwed up by not having them.&#8221;</p>
<p>Kate said, &#8220;I&#8217;m not into blame, and anyway we can&#8217;t go back on our own time line and edit the past. But we do have a good learning opportunity. What can we do to take advantage of that?&#8221;</p>
<p>Carl said, &#8220;The retrospective. We should look at the defects discovered and see how to do a better job of creating checks for them.&#8221;</p>
<p>&#8220;Good idea, Carl, and well put,&#8221; said Kate. &#8220;I noticed that you said &#8216;we&#8217;. Why did you put it that way?&#8221;</p>
<p>&#8220;Well, we programmers are in those story meetings too, and we help with the examples. Often a bug &#8230;&#8221;</p>
<p>Kate said, &#8220;Defect.&#8221;</p>
<p>&#8220;&#8230; yes, defect. Often a defect comes out in some odd coding case that a programmer might foresee and a tester might not. Anyway, we&#8217;re all in this together, so let&#8217;s all learn.&#8221;</p>
<p>Gil said, &#8220;There&#8217;s another chance to learn, sooner. That&#8217;s as soon as the bug &#8212; defect &#8212; is found. The testers usually grab a programmer right away, to be sure they understand the situation, and maybe to figure out how to reproduce it.</p>
<p>&#8220;Often, we see right away what is going on. That&#8217;s the moment to start learning.&#8221;</p>
<p>&#8220;Yes! Good point, Gil.&#8221; Kate looked delighted. &#8220;Now you said something about velocity?&#8221;</p>
<p>Susan said, &#8220;Yes. How should we handle velocity for bu &#8230; defect cards.&#8221;</p>
<p>Kate said, &#8220;Here&#8217;s a question I know the answer to: how do you use velocity?&#8221;</p>
<p>Susan said, &#8220;I use it in my product burn chart, to get a sense of how much we&#8217;ll have by the final ship date.&#8221;</p>
<p>Carl said, &#8220;And we use velocity to estimate how much work we can take on in the Sprint.&#8221;</p>
<p>&#8220;OK,&#8221; said Kate. &#8220;Two reasons: know how many features we&#8217;ll have by the ship date, and know how much work to take on in the Sprint. Do defects take time to fix? Can we estimate that time for the Sprint?&#8221;</p>
<p>Carl grinned. &#8220;They do, unfortunately, and we can usually estimate them pretty well. Sometimes we need to take some time to dig in a bit before we know.&#8221;</p>
<p>&#8220;If you don&#8217;t know how long a fix will take, what do you do?&#8221;</p>
<p>Carl went on. &#8220;Often we just guess how much time it&#8217;ll take or how many we can do. That works pretty well. If it&#8217;s a really weird one, we usually ask Susan to authorize a time-boxed exploration.&#8221;</p>
<p>&#8220;A spike,&#8221; Kate said.</p>
<p>&#8220;Yes. Then we usually know how long the thing will take. In fact, quite often we actually find and fix it inside the spike timebox.&#8221;</p>
<p>&#8220;OK,&#8221; Kate said, &#8220;it sounds like you&#8217;re totally on top of estimating defects into the Sprint. What about planning toward the release, Susan?&#8221;</p>
<p>Susan frowned a bit. &#8220;Defects are really a hassle. Usually they&#8217;re important, and I have no choice but to fix them. But they don&#8217;t fit into my planning at all.&#8221;</p>
<p>&#8220;Why not?&#8221;</p>
<p>&#8220;Well, even if I knew how long they take &#8212; and I think they probably average out well enough &#8212; I don&#8217;t know how many there are going to be.&#8221;</p>
<p>Kate said, &#8220;Couldn&#8217;t we just take that average as well? Like if you&#8217;re fixing five defects a Sprint, we just assume that if we have ten Sprints left, we&#8217;ll have fifty defects to fix?&#8221;</p>
<p>Susan said, &#8220;Well &#8230; we could &#8230;&#8221;</p>
<p>&#8220;So then,&#8221; Kate went on, &#8220;we could factor the defect fix time right into the planning and tracking. We could bump up the burn chart by fifty, and track the defects just like stories.&#8221;</p>
<p>Susan said, &#8220;We could, but that makes me feel kind of dirty. Defects are bad. Yes we can learn from them. For example, I learn how to say more clearly how things have to work, and I work closer with Charlie and the rest of the team coming up with examples that help us be sure things work. And I know the programmers are learning how to do their tests better, and better ways of designing things. But &#8230;&#8221;</p>
<p>&#8220;But what?&#8221; said Kate.</p>
<p>&#8220;I don&#8217;t want defects! When I have to schedule a defect fix, even when I can see it&#8217;s because of a test that I should have seen, I just don&#8217;t get the same thrill I do when I see the gang finish one of my features.&#8221;</p>
<p>Gil said, &#8220;You just want to punish us, or yourself, for making mistakes. Bugs are inevitable. They just happen.&#8221;</p>
<p>Kate said, &#8220;Hold on a second. Maybe some defects are inevitable. But aren&#8217;t you all learning ways to avoid them and make them less likely?&#8221;</p>
<p>Gil said, &#8220;Well, yes. Carl and I learned a new way of testing without going to the database last week, based on something Carl read about. That makes it a lot easier to write tests, and much faster to run them. I can identify a bug that I&#8217;m sure we would have had two weeks ago, avoided now because we can test better. But still, bugs will happen.&#8221;</p>
<p>Kate said, &#8220;They will. One reason I like to say &#8216;defect&#8217;, though, is to remind myself that whenever I look back at a &#8216;bug&#8217; in the system, I can almost always find something concrete that I, or someone on the team, or all of us together, could have done to prevent it. Saying defect reminds me that most of them are up to us to avoid or prevent.&#8221;</p>
<p>Gil said, &#8220;There will always &#8230;&#8221;</p>
<p>Kate said, &#8220;Yes. There will always be defects. But do this for me. The next time one shows up that was absolutely unpreventable, bring it to a meeting with me. I&#8217;ll bet that by the time the meeting is over, we&#8217;ll know a way we could have prevented it &#8230; and a way that isn&#8217;t even all that costly. Meanwhile, let&#8217;s pretend that they are all preventable: most of them clearly are.&#8221;</p>
<p>Susan said, &#8220;So what does this say about planning?&#8221;</p>
<p>&#8220;Way to keep us on track, Susan. You&#8217;re right to feel bad about defects. There are two kinds of demand for work, according to the Lean and Systems Thinking people. Who knows what they are?&#8221;</p>
<p>Silence. Then, Susan said, &#8220;I don&#8217;t know the words, but there are the things our customers actually want and the things I have to do because the software isn&#8217;t right.&#8221;</p>
<p>Kate clapped. &#8220;Exactly right. The words they use are &#8216;value demand&#8217; and &#8216;failure demand&#8217;. Value demand is the demand for what customers actually want. Failure demand is work we have to do because we are imperfect &#8230; because we have room for improvement.</p>
<p>&#8220;So I think you&#8217;re on the right track, Susan. I would suggest that you should not bump up your target by some expected number of defects, and you should not count defect fixes as features on the burn chart. If you do that, and there are defects, what will happen?&#8221;</p>
<p>Susan thought a moment. &#8220;My progress line won&#8217;t grow so fast. Each defect we fix takes away that much work on a feature. The chart will show us slowing down to the extent that we work on defects.&#8221;</p>
<p>&#8220;Right!&#8221;, said Kate. &#8220;Defects do slow us down, and in an unpredictable way. So it makes sense to me not to track them on your chart as if fixing them were a good thing. It&#8217;s more of a necessary evil.&#8221;</p>
<p>&#8220;But wait!&#8221; Carl, this time. &#8220;Those bugs can be hard to fix. We put in real work on those. We should get credit for that work.&#8221;</p>
<p>Kate grinned. &#8220;Remember the story lady? She comes in every Friday, looks on your shelves for features, and buys what you have, putting dollars in your pockets and lattes on your desks? What&#8217;s that beautiful redhead going to say when she finds a defect fix on the shelf? Am I going to pay for it?&#8221;</p>
<p>Carl smiled back. &#8220;I guess not. You&#8217;re going to say that you already paid for that feature and you want the fix for free.&#8221;</p>
<p>Kate said, &#8220;That&#8217;s right. Making me pay for defects ain&#8217;t workin&#8217;. I won&#8217;t pay money for nothin&#8217;. I want my fix for free.&#8221;</p>
<p>Everyone groaned.</p>
<p>&#8220;Welcome to my earworm. So, do we have a plan? Estimate for the Sprint as usual, don&#8217;t put defects on the Product Burn Chart, either in the target or in the progress?&#8221;</p>
<p>Everyone agreed.</p>
<p>&#8220;Great,&#8221; Kate said. &#8220;Meeting adjourned. Thanks for stopping by.&#8221;</p>
<p>As they started to leave, Carl turned. &#8220;One more question, Kate?&#8221;</p>
<p>&#8220;Sure?&#8221;</p>
<p>&#8220;Could you really throw your exercise ball and hit the Diet Coke button?&#8221;</p>
<p>&#8220;Is there money riding on it? Come over to the Bombay some evening and play a game of darts with me. Then we can talk about the exercise ball &#8230; and the coin slot.&#8221;</p>
]]></content:encoded>
			<wfw:commentRss>http://xprogramming.com/articles/kate-oneal-handling-defects/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

