tag:blogger.com,1999:blog-80504622024-03-06T21:53:57.509-06:00Asynchrony Community BlogThis is a blog set up for Asynchrony employees, contractors and clients. Views expressed here are not the views of Asynchrony Solutions, Inc. and are the personal expressions of their creators.Unknownnoreply@blogger.comBlogger144125tag:blogger.com,1999:blog-8050462.post-12223442379662743522009-12-29T12:51:00.002-06:002009-12-29T13:00:07.922-06:00Transitioning From Matt to Steve<a href="http://www.flickr.com/photos/fourworlds/4225450005/" title="Matt to Steve by daveelf, on Flickr"><img src="http://farm5.static.flickr.com/4059/4225450005_ff815e06a2_o.gif" width="295" height="366" alt="Matt to Steve" /></a><br /><br />Animation might take a few seconds to load.Unknownnoreply@blogger.com3tag:blogger.com,1999:blog-8050462.post-76618710800326094742009-02-13T10:20:00.002-06:002009-02-13T10:36:50.272-06:00Link Roundup<ul><li><a href="http://xprogramming.com/blog/2009/02/01/quality-speed-tradeoff-youre-kidding-yourself/">Quality-Speed Tradeoff — You’re kidding yourself</a>: Ron Jeffries on the quality vs. speed argument</li><li><a href="http://www.tecnicadelpomodoro.it/docs/francesco-cirillo/2007/ThePomodoroTechnique_v1-3.pdf">The Pomodoro Technique</a></li><li><a href="http://agileinaflash.blogspot.com/">Agile in a Flash</a>: Agile Reference in the form of flashcards, with explanations and comments</li><li><a href="http://wolfbyte-net.blogspot.com/2009/01/clean-code-developer-grades-black.html">Clean Code Grades</a>: Clean Code Developer Grade system is a graduated collection of principles, rules and practices which a software professional can use to produce "cleaner" code. It is based partly on the contents of the book Clean Code by Robert C. Martin. </li><li><a href="http://availagility.wordpress.com/2008/10/28/kanban-flow-and-cadence/">Kanban, Flow and Cadence</a></li><li><a href="http://www.adaptivepath.com/blog/2009/02/03/burndowns-and-flareups-in-agile-design/">Burndowns and Flareups in Agile Design</a><br /></li></ul>Piphttp://www.blogger.com/profile/05346094110928992431noreply@blogger.com0tag:blogger.com,1999:blog-8050462.post-58160759808681399452009-01-30T17:05:00.000-06:002009-01-30T17:09:50.307-06:00Link roundup<ul><li><a href="http://gojko.net/2009/01/26/announcing-trinidad-in-process-test-runner-for-fitnesse-wiki-pages/">Announcing Trinidad: In-process test runner for FitNesse wiki pages</a></li><li><a href="http://www.oreillynet.com/ruby/blog/2008/03/cruisecontrol_charts.html">Rake Stats</a>: How to log Rails 'rake stats' command output over time and add extensions to it into CruiseControl<br /></li><li>Clarke Ching's <a href="http://www.rocksintogold.com/">"Rocks into Gold"</a>: a biztech parable for software developers who want to Survive - and then Thrive – through the Credit Crunch.<br /></li><li><a href="http://www.cio.com/article/478106/Hiring_Software_Developers_The_Agile_Aptitude_Test">Hiring Software Developers: The Agile Aptitude Test</a></li><li><a href="http://www.information-age.com/channels/development-and-integration/perspectives-and-trends/989977/agile-payback.thtml">Agile Payback</a>: The adoption of agile programming methods has proved one of the most effective and popular strategies of the past year</li><li><a href="http://www.exampler.com/blog/2007/11/06/latour-3-anthrax-and-standups/">Anthrax and Standups</a>: Slightly old but relevant post from Brian Marick on story-based standups</li><li><a href="http://www.techdarkside.com/playgrounds-a-thought-on-testing">Playgrounds & a Thought on Testing</a></li></ul>Piphttp://www.blogger.com/profile/05346094110928992431noreply@blogger.com0tag:blogger.com,1999:blog-8050462.post-73920887094265878162009-01-29T08:00:00.001-06:002009-01-29T08:00:00.389-06:00Asynchrony honorably mentioned as Great Place to WorkSt. Louis Magazine has an article that notes something that those of us who work at Asychrony already knew: Asynchrony is a great place to work. We received an honorable mention in the publication's <a href="http://www.stlmag.com/media/St-Louis-Magazine/January-2009/Great-Places-to-Work/">January issue highlighting the area's Great Places to Work</a>. Sure, our "Employees play Halo on two 40-inch TVs," but we're got several of the other perks that other companies have, and some that they don't. Like flexible childcare, pet-friendliness, FFASHH, and, of course, the free lunches. That chinese food in the first-floor refrigerator <span class="Apple-style-span" style="font-style: italic;">was </span>for everyone, right?Piphttp://www.blogger.com/profile/05346094110928992431noreply@blogger.com1tag:blogger.com,1999:blog-8050462.post-347767032585089412009-01-28T10:00:00.003-06:002009-01-28T10:06:14.846-06:00Defense Systems highlights Asynchrony's SOA work at USTRANSCOM<a href="http://defensesystems.com/articles/2009/01/22/transcom-begins-transition-to-soa.aspx">Defense Systems magazine had a good article</a> about Asynchrony's SOA work at USTRANSCOM. Here's a snippet with a quote from Steve:<div><p></p><blockquote><p>The prescriptive architecture is due for delivery in the fall of 2009, said Steve Elfanbaum, Asynchrony’s president. But it won’t take the full length of the contract for new Web-based capabilities to come out, or for the transition architecture to be fully defined.</p> <p> </p><p>“People (in USTRANSCOM) are already clamoring for new services and want to use what we have now,” he said. “So as things come out of this process, as the various templates and standards fall out, we’ll start to use those as soon as we can.”</p></blockquote><p></p><p>That's textbook agile philosophy, providing value as soon as possible. Who says government contracts can't be done agilely (or at least more agilely)?</p></div>Piphttp://www.blogger.com/profile/05346094110928992431noreply@blogger.com0tag:blogger.com,1999:blog-8050462.post-20753198056183403422009-01-26T19:53:00.000-06:002009-01-26T19:53:00.108-06:00Link roundup<ul><li><a href="http://johnwilger.com/2009/01/13/retro-facilitation.html?disqus_reply=5107401">Retrospective facilitation</a> -- John Wilger</li><li><a href="http://www.thepmpodcast.com/index.php?option=com_content&task=view&id=220&Itemid=9">Kanban introduction</a> -- Eric Landes (podcast)</li><li><a href="http://xndev.blogspot.com/2009/01/this-is-how-we-do-it.html">"How we develop software at Socialtext"</a> (video)</li><li><a href="http://www.alistapart.com/articles/gettingrealaboutagiledesign">Getting Real About Agile Design</a></li><li><a href="http://www.flashbulbinteraction.com/WTS_opening.html">Working through Screens</a> (ebook on user interaction)</li><li><a href="http://www.codegreenlabs.com/">Agile Philanthropy</a><br /></li></ul>Piphttp://www.blogger.com/profile/05346094110928992431noreply@blogger.com0tag:blogger.com,1999:blog-8050462.post-70205543014999377582009-01-21T15:28:00.004-06:002009-01-21T15:40:08.835-06:00Environmentally friendly, reusable story cardsBesides conversation, nothing beats the tactile, low-fi index card for communicating story information. And for environmentally friendly story cards, nothing beats this invention (well, we're not really sure it's an invention in the strictest sense) by Asynchronite Dan King: The Lamindex Story Card. As the name implies, it's a laminated index card that can be used and reused for countless stories and countless projects.<br /><br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjwaYQOQBBmkVV4ys9UntGseYKumQ1c765NMM8ieRGTU0GV_nQ39mqfHEMvrJBr_zz_eCtLfD853B24WhTkmKnP-g6BSaTYziGi28SM0E6d8v-T4XxuxVBrvxW0ESa5IGbgHwCq7g/s1600-h/lamindex-wipe.jpg"><img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 400px; height: 324px;" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjwaYQOQBBmkVV4ys9UntGseYKumQ1c765NMM8ieRGTU0GV_nQ39mqfHEMvrJBr_zz_eCtLfD853B24WhTkmKnP-g6BSaTYziGi28SM0E6d8v-T4XxuxVBrvxW0ESa5IGbgHwCq7g/s400/lamindex-wipe.jpg" alt="" id="BLOGGER_PHOTO_ID_5293864862679431474" border="0" /></a><br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgHtcHBusPi12_WPzKEQj2rVS8Fhll41lp5djEH_5mT33KueytzHbUpA8OjPlEjIgUXUEfxmhsijJ-sV9sT61kOPCt8pCUrshyphenhyphenC3CDyz9uWU0AyV56eRxvCKMDR1r_dO-nAhds3hA/s1600-h/lamindex-blank.jpg"><img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 400px; height: 305px;" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgHtcHBusPi12_WPzKEQj2rVS8Fhll41lp5djEH_5mT33KueytzHbUpA8OjPlEjIgUXUEfxmhsijJ-sV9sT61kOPCt8pCUrshyphenhyphenC3CDyz9uWU0AyV56eRxvCKMDR1r_dO-nAhds3hA/s400/lamindex-blank.jpg" alt="" id="BLOGGER_PHOTO_ID_5293864777275334850" border="0" /></a><br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgMGuEJ3f8wPe-RqsD_QewQppGzKZEbXYncBwu1O3NaYEiudaUzvaKvefvm1uC8UkYLlvwG7MmPnPxat83g2M1Nv0E0ksvSOgN4dHAftKSLxShHFfNp3iinGRukl4jcEsOV3jgg2w/s1600-h/lamindex.jpg"><img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 334px; height: 400px;" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgMGuEJ3f8wPe-RqsD_QewQppGzKZEbXYncBwu1O3NaYEiudaUzvaKvefvm1uC8UkYLlvwG7MmPnPxat83g2M1Nv0E0ksvSOgN4dHAftKSLxShHFfNp3iinGRukl4jcEsOV3jgg2w/s400/lamindex.jpg" alt="" id="BLOGGER_PHOTO_ID_5293864676981335042" border="0" /></a><br />They're relatively cheap to make (just go to Kinko's if you don't have your own laminator or teacher friend), though Dan advises getting the "special kind" of laminate for easy cleaning.Piphttp://www.blogger.com/profile/05346094110928992431noreply@blogger.com1tag:blogger.com,1999:blog-8050462.post-11372381684372266822009-01-09T17:22:00.002-06:002009-01-09T17:31:09.483-06:00The Toilet Paper (Installment 25): Single-Responsibility Principle (SOLID, part 2)<span style="font-style: italic;">A class should have exactly one reason to change</span><br /><br />The Single-Responsibility Principle (SRP) helps you create classes that are resilient in the face of requirements changes. Put more simply, the SRP guides you in creating individual classes that are highly focused on a single implementation concept, so that each individual class is less likely to be affected by each requirements change. Each class is very limited in what it knows how to do and what it knows about, so an individual requirement change is less likely to affect that class. As a result, classes that change less often and accumulate less code are less likely to accumulate bugs as well. They can be tested thoroughly and raise the overall quality of your application.<br /><br />Let's look at an example. Suppose we have a Product class that models information and behavior associated with some widget we're selling. It might look something like this:<br /><blockquote><pre>public class Product {<br /> public String Name { get; private set; }<br /> public String Sku { get; private set; }<br /> public Money ShippingCharges(Destination dest) {…}<br /> public Money CalculateDiscount(Contract contract){…}<br />}<br /></pre></blockquote>Assuming that the implementations of how to calculate shipping charges and discounts are inside both of those methods, this class clearly has multiple responsibilities – three, in fact. First, it models a product, which has properties, shipping charges and discounts. But this class also charges shipping and calculates discounts. This may not seem that important, but it means that this particular class is harder to understand and changes more often than would otherwise be necessary. The biggest shortcoming, however, is that the logic for these calculations is hidden inside the Product class, making these non-trivial bits of code harder to find and harder to test independently.<br /><br />To solve this, refactor this class so that it delegates the responsibility of how doing the calculations are done to two other, more specialized classes, such as ShippingChargeCalculator and PriceDiscounter. That would leave you with three classes, each of which has one reason to change, decreasing the complexity of the system and increasing maintainability, flexibility, and testability.<br /><br />You can find much more on the SRP on Google. Try searching for "<a href="http://www.google.com/search?q=ActiveRecord+Single-Responsibility+Principle&ie=utf-8&oe=utf-8&aq=t&rls=org.mozilla:en-US:official&client=firefox-a">ActiveRecord Single-Responsibility Principle</a>" for hours of enjoyment!Piphttp://www.blogger.com/profile/05346094110928992431noreply@blogger.com1tag:blogger.com,1999:blog-8050462.post-17934229590259280582009-01-07T14:31:00.000-06:002009-01-07T14:32:07.975-06:00Link roundupProduct Ownership<br /><ul><li><a href="http://www.rgalen.com/publications.html">Becoming a Great Scrum Product Owner (eBook)</a></li></ul>Testing<br /><ul><li><a href="http://www.acceptancetesting.info/the-book/">Bridging the Communication Gap: Specification by Example and Agile Acceptance Testing</a> (book)</li><li><a href="http://jnarrate.org/">JNarrate</a>: Tool that allows you to write acceptance tests with code using a fluent API</li><li><a href="http://craftingsw.blogspot.com/">Craft of Software blog</a>: Matt Heusser's new blog for testers</li><li><a href="http://groups.google.com/group/software_craftsmanship">Software Craftsmanship</a>: Google group<br /></li></ul>Best Practices<br /><ul><li><a href="http://www.se-radio.net/podcast/2008-07/episode-105-retrospectives-linda-rising">Linda Rising podcast on Retrospectives</a></li><li><a href="http://availagility.wordpress.com/2008/08/28/kanban-and-retrospectives/">Kanban and Retrospectives</a><br /></li></ul><div>Agile</div><div><ul><li><a href="http://www.stickyminds.com/Media/Video/">“Seven Years Later: What the Agile Manifesto Left Out”</a> presentation by Brian Marick at Agile Development Practices </li></ul></div>Piphttp://www.blogger.com/profile/05346094110928992431noreply@blogger.com0tag:blogger.com,1999:blog-8050462.post-22766615384485103972009-01-05T17:03:00.009-06:002009-01-07T12:18:30.999-06:00Asynchrony Principals Aging Like Fine Wine<div style="text-align: left;"><a href="http://www.flickr.com/photos/27180696@N02/3172247272/" title="We Get Better Looking Each Day by daveelf, on Flickr"><img src="http://farm2.static.flickr.com/1016/3172247272_281da60ef1.jpg" alt="We Get Better Looking Each Day" height="500" width="365" /></a><br /></div><br /><div style="text-align: left;">First image is from around the time of our 1999 start-up. The second is the 2009 version.</div>Unknownnoreply@blogger.com2tag:blogger.com,1999:blog-8050462.post-47731797425672350322009-01-01T10:40:00.011-06:002009-01-01T11:29:40.264-06:00Using JavaScript to check if an image is loadedI had an interesting problem the other day. The project I'm on is a real estate listing website. It's very <a href="http://en.wikipedia.org/wiki/Web_2.0">Web 2.0</a>, using AJAX calls to provide the user with a rich experience. We use the <a href="http://www.prototypejs.org/">Prototype Library</a> for all our AJAX calls and DOM manipulation. <br /><br />So the problem came about with the enlarged photo browsing portion of the site. Each listing has at least one photo associated with it. If the listing has more than one photo, then the user can browse through the photo with simple NEXT & PREVIOUS links. Under the scene, when the user presses one of the links we make a simple AJAX call to load the next image and swap out the div the image belongs to.<br /><br />The problem came about when we were testing in IE. The footer would sometimes appear right over the image. IE wasn't recognizing that one of the div elements was supposed to grow to match the size of the image inside it. The simple fix was to set the Height of the problem div to the Height of the child div that is holding the image. To do this all I had to do was call this method in the "onComplete" section of my AJAX call.<br /><br />This worked in most cases but there were still times when the footer tag would appear in the middle. With the help of <a href="http://getfirebug.com/lite.html">firebug lite</a>, and Nate Young, I realized that my method was being called before the image was finished loading. The solution was loading the image and checking the <a href="http://www.devguru.com/Technologies/Ecmascript/Quickref/image.html">"complete"</a> on the image object. If the image isn't finished, just make a simple recursive call. <br /><br /><br /><pre name="code" class="js"><br />function moveFooter(){<br /> if ($('enlargedImageDiv') && $('imageContainer')){<br /> var image = <br /> new Image($('imageContainer').siblings[0]);<br /> if(image.complete) {<br /> Element.setStyle($('enlargedImageDiv'), {<br /> height:$('imageContainer').getHeight()+41<br /> });<br /> }else{<br /> moveFooter()<br /> } <br /> }<br />}<br /></pre>Eric Neunaberhttp://www.blogger.com/profile/18394319456644274008noreply@blogger.com1tag:blogger.com,1999:blog-8050462.post-16651248072224398082008-12-31T14:20:00.003-06:002008-12-31T14:27:49.108-06:00Is estimating a bad practice?<a href="http://blogs.agilefaqs.com/2008/12/25/estimation-considered-harmful/">According to Naresh Jain</a>, writing in response to a <a href="http://www.linkedin.com/e/ava/828175/37631/add-qa-disc-0Qt79xs2RVr6JBpnsJt7dBpSBA/">LinkedIn Agile Alliance discussion</a>, it is:<br /><blockquote>Estimates are a hang-over from the waterfall world. For the last 6 years, I’ve been very happy and successful building products and delivering projects without all the estimation related ab-ra-ca-dab-ra. No more real-time, ideal-time, story point, function point; non-sense. I’ve realized the key is to focus on the flow of the deliverable and not whether your are delivering according to the estimates.</blockquote>He goes on to make a pretty compelling case for the abolition of estimates (he provides some useful back-and-forth with his detractors in the comments, too). Since some of our teams have started down the kan-ban path, it would be interesting to know how much of our experience squares with Jain's claims.<br /><br />Jain also references <a href="http://submissions.agile2008.org/node/4804">Joshua Kerievsky's Agile 2008 presentation</a> on the same topic.Piphttp://www.blogger.com/profile/05346094110928992431noreply@blogger.com0tag:blogger.com,1999:blog-8050462.post-67424015509260391232008-12-30T12:33:00.003-06:002008-12-30T12:46:46.619-06:00An acceptance-test development approach by any other name would smell as sweetGaffo forwarded this snippet from the <a href="http://www.blogger.com/rspec-users@rubyforge.org">RSpec users list</a> in response to the question "Is there a difference between Behaviour-Driven-Development and Story-Driven-Development?":<br /><blockquote>Excellent question,<br /><br />I think the more common term is STDD (Story Test Driven Development). There is ATDD (Acceptance-Test Driven Development too) ;-)<br /><br />They are all variations on the same theme and only marginally different IMO. The biggest difference seems to be that different people and groups promote them and talk about them in slightly different ways, and emphasise the various techniques differently. My personal take is that BDD *is* ATDD/STDD, but with an additional emphasis on Business value and getting the words right. I'm not sure how ATDD and STDD are different.<br /><br />Maybe the best place to get a good balance of viewpoints on this topic is in a tool-agnostic forum - maybe this one:<br /><a href="http://groups.google.com/group/behaviordrivendevelopment" target="_blank">http://groups.google.com/group/behaviordrivendevelopment</a> (I don't know of any STDD or ATDD forums).<br /><br />There are good articles about ATDD and STDD here:<br /><ul><li><a href="http://testobsessed.com/wordpress/wp-content/uploads/2008/12/">http://testobsessed.com/wordpress/wp-content/uploads/2008/12/example.pdf</a><br /></li><li><a href="http://industriallogic.com/papers/storytest.pdf">http://industriallogic.com/papers/storytest.pdf</a><br /></li><li><a href="http://www.nxtbook.com/nxtbooks/sqe/bettersoftware0908/">http://www.nxtbook.com/nxtbooks/sqe/bettersoftware0908/</a> (page 24-29)<br /></li></ul></blockquote>Sounds about right to me. The most important thing is what you actually are doing, not what you call it (though that's important, too). Around here, I use ATDD, since I think it best describes the practice and people are already familiar with what acceptance tests are. And STDD sounds too much like <span style="font-style: italic;">STD</span>, which doesn't exactly foster a mindset of willing acceptance.Piphttp://www.blogger.com/profile/05346094110928992431noreply@blogger.com0tag:blogger.com,1999:blog-8050462.post-5968323836457984442008-12-23T16:47:00.002-06:002008-12-23T17:02:09.700-06:00DynamicPageList installed on wikiWe've installed the <a href="http://www.mediawiki.org/wiki/Extension:DynamicPageList">DynamicPageList extension</a> on the company wiki. The extension is:<br /><blockquote>a universal reporting tool for MediaWikis, listing category members and intersections with various formats and details ... Typically the selection of pages to be shown will be based on one or more categories. But there are many other choices for selection criteria, like e.g. author, namespace, date, name pattern, usage of templates or references to other articles.</blockquote>This allows us to dynamically generate lists, such as most-popular pages, recently-edited pages and pages edited by certain authors. I initially found the extension in my quest for a way to organize our retrospectives and let interested people see at a glance, say, the last five retrospectives for a particular project.Piphttp://www.blogger.com/profile/05346094110928992431noreply@blogger.com0tag:blogger.com,1999:blog-8050462.post-74237552542436551512008-12-22T10:27:00.010-06:002008-12-22T14:22:15.283-06:00Path to ProgrammingOver the weekend, I read <a href="http://pshaw.wordpress.com/2008/10/18/i-have-no-idea-how-difficult-my-class-is/">this article</a> along with discussions about it on <a href="http://www.reddit.com/r/programming/comments/7km8s/the_more_that_i_teach_computer_programming_the/">Reddit,</a> <a href="http://news.ycombinator.com/item?id=404009">Hacker News</a> and a related discussion on what it takes to become a talented programmer on <a href="http://radar.oreilly.com/2008/12/hard-work-and-practice-in-programming.html">O'Reilly's blog</a>.<br /><br />It got me thinking about my own path to programming:<br /><br />0. My first CS course ever was in high school. I did ok, middling at best. It was taught in C++. The Borland compiler we used marked syntax errors the line after they occurred, which caused me a lot of headaches. The final assignment, biggest grade of the class, was to create a game, any game. The brightest kid in the class wrote a poker game using ascii art to actually draw the cards. I thought I was at least as smart as him, so I made a poker game as well, but halfway through writing it, realized I couldn't figure out how to determine what hand a player was dealt, so I did what any industrious 10th grader would do. I rigged the game. Every hand dealt to the player was all hearts and it always printed out:<br /><code style="font-weight: bold;">You have a flush!</code><br />I did not go to college hoping to earn a degree in Computer Science.<br /><br />1. As a biology undergrad, though, I did have to take an introductory computer science class. It was in C. What I had learned in High School was sufficient enough that I slept through every class and aced every homework assignment. In retrospect, it probably set unrealistic expectations for courses to come.<br /><br />2. The summer after my freshman year, during a summer internship in a bio lab, I found myself spending every waking moment in the library reading technical computer books. The campus had a network of vending machines with student id card readers attached that would, when swiped, bill your student account. I noticed that they left the phone line that connected them to the campus network exposed, and was convinced that if only I knew a little bit more about TCP/IP I could send the machine someone else's student id number and get free Snickers for the duration of my internship. I never succeeded, but at the end of the internship nothing I had still to study in biology seemed as appealing as figuring out the answers to all of the questions my reading had stirred up. That fall semester, I enrolled in CS.<br /><br />3. My Operating Systems class made the most sense of any class I took as a CS major. Each assignment covered a separate system call and that system call would be printed at the top of the assignment handout, verbatim from the man page. Combined with a good specification of exactly what our program was supposed to output and how we were to deal with error conditions meant that in order to turn in a working program, all I had to do was read the assignment and the man pages enough times to put statements together in the right order. I won't even pretend that I understood how my assignment to write a primitive shell worked, I had just read the execv man page enough times that by sheer combinatorial probability it had to work.<br /><br />4. Many people in the comments on the article and in the forums noted that while initially programming may not make sense to a lot of people, sometimes, out of the blue it will "click" for a student. I actually had an "Aha" moment <span style="font-style: italic;">during</span> a final as time was being called. The last question on the last test of Computer Architecture and Assembly Programming, asked what instruction was equivalent to popping the top of the call stack. I will never accuse anyone of having a dumb, blank stare again as my slack expression betrayed that fact that somewhere inside my cranium, hexadecimal notation, the von Neumann architecture, Intel memory addressing and the 8086 instruction set were coalescing into actual understanding. Even more amazing was that my brain took those tiny electrical impulses and mechanically translated them into little carbon-graphite scratches representing a correct answer. I remember leaving the test, talking to a fellow student for whom that question had not ignited any cranial conflagrations and despite the urge to prove my superiority, I withheld my hard won answer from him, realizing that sometimes the possession of knowledge comes secondary to its acquisition.<br /><br />The common thread of my education, though, I think, was that I never really questioned why things worked the way they did or worried that I didn't have as much control over them as I wanted. In High School I never questioned why I wrote <code>int main(char* argc, char** argv)</code> even though I had no idea what those two arguments were, nor ever used them in my programs, nor (until my infamous OS shell assignment) questioned how those values would ever be populated.<br /><br />More <span style="font-style: italic;">theologically</span> inclined students wanted to know why the for loop looked the way it did or pouted when they knew that they wanted their code to be compiled, but could not properly translate that knowledge into a series of dashes and letters that gcc would understand.<br /><br />I never questioned the magical gcc incantation that was usually provided to me. Cryptic error messages, I felt deep down, were <span style="font-style: italic;">my</span> fault. It is this same suspicion that persists in me even today, keeping me from writing copious amounts of bug reports for the software I use.<br /><br />I did know I hated C++ and liked C, though I had seen the phrase C/C++ bandied about so often that I thought that they were merely two different styles of writing the same language, sort of like the distinction between which style of brace indentation you chose.<br /><br />And once, while practicing for a programming contest, competing against my advising professor, he blew my mind by writing some 4 or 5 line string function in C that I had written with 1 in Java, and like the master to the grasshopper, asked my how mine could still be slower.<br /><br />There were more classes, but I was a college student and blissfully unaware of the totality with which my life after college would be consumed with, well, life after college and I tried not to let too many more painful epiphanies erupt inside my skull. Departed from college for a handful of years, I now work with very smart people that force these epiphanies on me cruelly and with great relish. Its probably why our company has been as successful as it has been and makes me wonder just what their path to programming was.<br /><br />So, to end of this heinously long post, I completely agree with whoever it was that said "A little bit of knowledge is a dangerous thing".Natehttp://www.blogger.com/profile/13345231139427891523noreply@blogger.com0tag:blogger.com,1999:blog-8050462.post-13502423311248282642008-12-19T09:58:00.001-06:002008-12-19T10:02:05.366-06:00Link RoundupMethodology:<br /><ul><li><a href="http://leansoftwareengineering.com/ksse/scrum-ban/">Scrum-ban</a></li></ul>User experience:<br /><ul><li><a href="http://fivesecondtest.com/">Five-second test</a></li><li><a href="http://blog.gdinwiddie.com/2008/11/28/agile-usability/">Agile Usability</a>, George Dinwiddie’s blog</li><li><a href="http://www.stickyminds.com/BetterSoftware/magazine.asp?fn=cifea&ac=384">Getting Agile with user-centered design</a><br /></li></ul>Programming:<br /><ul><li><a href="http://www.stickyminds.com/sitewide.asp?Function=edetail&ObjectType=COL&ObjectId=14444&tth=DYN&tt=siteemail&iDyn=2">Reusability vs. Usability: Where to Draw the Line?</a></li><li><a href="http://evagilist.wordpress.com/2008/12/16/will-the-agile-holidays-create-discipline-debt/">Will the holidays create discipline debt?</a><br /></li></ul>Testing:<br /><ul><li><a href="http://www.stickyminds.com/s.asp?F=S14400_COL_2">Simple strategies to keep quality visible</a></li></ul>Conferences:<br /><ul><li><a href="http://www.citconf.com/msp2009/">CITCON 2009</a><span class="Title"><a name="coltop"></a></span></li></ul>Piphttp://www.blogger.com/profile/05346094110928992431noreply@blogger.com0tag:blogger.com,1999:blog-8050462.post-65903419933117490072008-12-17T14:36:00.022-06:002008-12-18T23:11:35.017-06:00Reducing authorization Redundancy in Web.configWe are developing a website that includes several pages, where user access is by page. The users are assigned to groups, which correspond to user roles, in Active Directory. Access to the various pages is based upon a member's being associated with any one of a group of roles.<br /><br />Here is an example that illustrates the situation:<br /><br />A user is granted access to the pages, "Bananas.aspx", "MonkeyMatch.aspx", and "Swingers.aspx" if (s)he is in any of the roles: "monkey a", "monkey b", "monkey c".<br /><br />A user is granted access to the pages, "JavaJabber.aspx", "RailsRules.aspx", and "CodeGuru.aspx" if (s)he is in either of the roles: "geek 0" or "geek 1".<br /><br />A user in the admin role is granted access to all pages.<br /><br />Only a user in the admin role is granted access to the page, "SpyOnGeeksAndMonkeys.aspx".<br /><br /><br />So, Web.config might look like this:<br /><!-- code formatted by http://manoli.net/csharpformat/ --><br /><style type="text/css"><br />.csharpcode, .csharpcode pre<br />{<br /> font-size: small;<br /> color: black;<br /> font-family: Consolas, "Courier New", Courier, Monospace;<br /> background-color: #ffffff;<br /> /*white-space: pre;*/<br />}<br /><br />.csharpcode pre { margin: 0em; }<br /><br />.csharpcode .rem { color: #008000; }<br /><br />.csharpcode .kwrd { color: #0000ff; }<br /><br />.csharpcode .str { color: #006080; }<br /><br />.csharpcode .op { color: #0000c0; }<br /><br />.csharpcode .preproc { color: #cc6633; }<br /><br />.csharpcode .asp { background-color: #ffff00; }<br /><br />.csharpcode .html { color: #800000; }<br /><br />.csharpcode .attr { color: #ff0000; }<br /><br />.csharpcode .alt<br />{<br /> background-color: #f4f4f4;<br /> width: 100%;<br /> margin: 0em;<br />}<br /><br />.csharpcode .lnum { color: #606060; }<br /></style><pre class="csharpcode"><span class="kwrd"><</span><span class="html">configuration</span> <span class="attr">xmlns</span><span class="kwrd">="http://schemas.microsoft.com/.NetConfiguration/v2.0"</span><span class="kwrd">></span><br /><span class="rem"><!-- blah, blah ... --></span><br /><span class="kwrd"><</span><span class="html">system.web</span><span class="kwrd">></span><br /> <span class="kwrd"><</span><span class="html">authentication</span> <span class="attr">mode</span><span class="kwrd">="Forms"</span><span class="kwrd">></span><br /> <span class="kwrd"><</span><span class="html">forms</span> <span class="attr">name</span><span class="kwrd">=".ADAuthCookie"</span> <span class="attr">timeout</span><span class="kwrd">="10"</span> <span class="attr">loginUrl</span><span class="kwrd">="login.aspx"</span> <span class="attr">defaultUrl</span>="<span class="attr">default</span>.<span class="attr">axpx</span> <span class="kwrd">/></span><br /> <span class="kwrd"></</span><span class="html">authentication</span><span class="kwrd">></span><br /> <span class="kwrd"><</span><span class="html">authorization</span><span class="kwrd">></span><br /> <span class="kwrd"><</span><span class="html">deny</span> <span class="attr">users</span><span class="kwrd">="?"</span> <span class="kwrd">/></span><br /> <span class="kwrd"></</span><span class="html">authorization</span><span class="kwrd">></span><br /> <span class="rem"><!-- blah, blah, blah --></span><br /><span class="kwrd"></</span><span class="html">system.web</span><span class="kwrd">></span><br /><span class="kwrd"><</span><span class="html">location</span> <span class="attr">path</span><span class="kwrd">="Bananas.aspx"</span><span class="kwrd">></span><br /><span class="kwrd"> <</span><span class="html">system.web</span><span class="kwrd">></span><br /> <span class="kwrd"> <</span><span class="html">allow</span> <span class="attr">roles</span><span class="kwrd">="monkey a,monkey b,monkey c,admin"</span> <span class="kwrd">/></span><br /> <span class="kwrd"><</span><span class="html">deny</span> <span class="attr">users</span><span class="kwrd">="*"</span> <span class="kwrd">/></span><br /> <span class="kwrd"></</span><span class="html">system.web</span><span class="kwrd">></span><br /><span class="kwrd"></</span><span class="html">location</span><span class="kwrd">></span><br /><span class="kwrd"><</span><span class="html">location</span> <span class="attr">path</span><span class="kwrd">="MonkeyMatch.aspx"</span><span class="kwrd">></span><br /> <span class="kwrd"><</span><span class="html">system.web</span><span class="kwrd">></span><br /> <span class="kwrd"><</span><span class="html">allow</span> <span class="attr">roles</span><span class="kwrd">="monkey a,monkey b,monkey c,admin"</span> <span class="kwrd">/></span><br /> <span class="kwrd"><</span><span class="html">deny</span> <span class="attr">users</span><span class="kwrd">="*"</span> <span class="kwrd">/></span><br /> <span class="kwrd"></</span><span class="html">system.web</span><span class="kwrd">></span><br /><span class="kwrd"></</span><span class="html">location</span><span class="kwrd">></span><br /><span class="kwrd"><</span><span class="html">location</span> <span class="attr">path</span><span class="kwrd">="JavaJabber.aspx"</span><span class="kwrd">></span><br /> <span class="kwrd"><</span><span class="html">system.web</span><span class="kwrd">></span><br /> <span class="kwrd"><</span><span class="html">allow</span> <span class="attr">roles</span><span class="kwrd">="geek 0,geek 1,admin"</span> <span class="kwrd">/></span><br /> <span class="kwrd"><</span><span class="html">deny</span> <span class="attr">users</span><span class="kwrd">="*"</span> <span class="kwrd">/></span><br /> <span class="kwrd"></</span><span class="html">system.web</span><span class="kwrd">></span><br /><span class="kwrd"></</span><span class="html">location</span><span class="kwrd">></span><br /><span class="kwrd"><</span><span class="html">location</span> <span class="attr">path</span><span class="kwrd">="RailsRules.aspx"</span><span class="kwrd">></span><br /> <span class="kwrd"><</span><span class="html">system.web</span><span class="kwrd">></span><br /> <span class="kwrd"><</span><span class="html">allow</span> <span class="attr">roles</span><span class="kwrd">="geek 0,geek 1,admin"</span> <span class="kwrd">/></span><br /> <span class="kwrd"><</span><span class="html">deny</span> <span class="attr">users</span><span class="kwrd">="*"</span> <span class="kwrd">/></span><br /> <span class="kwrd"></</span><span class="html">system.web</span><span class="kwrd">></span><br /><span class="kwrd"></</span><span class="html">location</span><span class="kwrd">></span><br /><span class="kwrd"><</span><span class="html">location</span> <span class="attr">path</span><span class="kwrd">="CodeGuru.aspx"</span><span class="kwrd">></span><br /> <span class="kwrd"><</span><span class="html">system.web</span><span class="kwrd">></span><br /> <span class="kwrd"><</span><span class="html">allow</span> <span class="attr">roles</span><span class="kwrd">="geek 0,geek 1,admin"</span> <span class="kwrd">/></span><br /> <span class="kwrd"><</span><span class="html">deny</span> <span class="attr">users</span><span class="kwrd">="*"</span> <span class="kwrd">/></span><br /> <span class="kwrd"></</span><span class="html">system.web</span><span class="kwrd">></span><br /><span class="kwrd"></</span><span class="html">location</span><span class="kwrd">></span><br /><span class="kwrd"><</span><span class="html">location</span> <span class="attr">path</span><span class="kwrd">="SpyOnGeeksAndMonkeys.aspx"</span><span class="kwrd">></span><br /> <span class="kwrd"><</span><span class="html">system.web</span><span class="kwrd">></span><br /> <span class="kwrd"><</span><span class="html">allow</span> <span class="attr">roles</span><span class="kwrd">="admin"</span> <span class="kwrd">/></span><br /> <span class="kwrd"><</span><span class="html">deny</span> <span class="attr">users</span><span class="kwrd">="*"</span> <span class="kwrd">/></span><br /> <span class="kwrd"></</span><span class="html">system.web</span><span class="kwrd">></span><br /><span class="kwrd"></</span><span class="html">location</span><span class="kwrd">></span><br /><span class="kwrd"><</span><span class="html">location</span> <span class="attr">path</span><span class="kwrd">="images"</span><span class="kwrd">></span><br /> <span class="kwrd"><</span><span class="html">system.web</span><span class="kwrd">></span><br /> <span class="kwrd"><</span><span class="html">allow</span> <span class="attr">users</span><span class="kwrd">="*"</span> <span class="kwrd">/></span><br /> <span class="kwrd"></</span><span class="html">system.web</span><span class="kwrd">></span><br /><span class="kwrd"></</span><span class="html">location</span><span class="kwrd">></span><br /><span class="kwrd"><</span><span class="html">location</span> <span class="attr">path</span><span class="kwrd">="javascript"</span><span class="kwrd">></span><br /> <span class="kwrd"><</span><span class="html">system.web</span><span class="kwrd">></span><br /> <span class="kwrd"><</span><span class="html">allow</span> <span class="attr">users</span><span class="kwrd">="*"</span> <span class="kwrd">/></span><br /> <span class="kwrd"></</span><span class="html">system.web</span><span class="kwrd">></span><br /><span class="kwrd"></</span><span class="html">location</span><span class="kwrd">></span><br /><span class="kwrd"><</span><span class="html">location</span> <span class="attr">path</span><span class="kwrd">="css"</span><span class="kwrd">></span><br /> <span class="kwrd"><</span><span class="html">system.web</span><span class="kwrd">></span><br /> <span class="kwrd"><</span><span class="html">allow</span> <span class="attr">users</span><span class="kwrd">="*"</span> <span class="kwrd">/></span><br /> <span class="kwrd"></</span><span class="html">system.web</span><span class="kwrd">></span><br /><span class="kwrd"></</span><span class="html">location</span><span class="kwrd">></span><br /><span class="rem"><!-- blah, blah, blah --></span><br /><span class="kwrd"></</span><span class="html">configuration</span><span class="kwrd">></span><br /></pre><br /><br />You can see the problem! Having the list of roles duplicated in the various location elements is definitely asking for trouble. What are the chances that someone will mess up the roles on a new page -- or even in the original configuration. As the number of roles and the number of pages increase, it gets even worse.<br /><br />It would be very nice if the path attribute of the location element could take multiple paths. Unfortunately, it doesn't.<br /><br />There are options. We could organize the structure of the site around authorization. In that case each location element would only need to reference the containing folder. Sometimes that makes sense.<br /><br />Another option is to use the configSource attribute of the authorization element. We can then write separate files that have the configuration that we need. For example, we can write these files:<br /><br /><span style="font-weight: bold;">AuthMonkey.config</span><br /><!-- code formatted by http://manoli.net/csharpformat/ --><style type="text/css"><br />.csharpcode, .csharpcode pre<br />{<br /> font-size: small;<br /> color: black;<br /> font-family: Consolas, "Courier New", Courier, Monospace;<br /> background-color: #ffffff;<br /> /*white-space: pre;*/<br />}<br /><br />.csharpcode pre { margin: 0em; }<br /><br />.csharpcode .rem { color: #008000; }<br /><br />.csharpcode .kwrd { color: #0000ff; }<br /><br />.csharpcode .str { color: #006080; }<br /><br />.csharpcode .op { color: #0000c0; }<br /><br />.csharpcode .preproc { color: #cc6633; }<br /><br />.csharpcode .asp { background-color: #ffff00; }<br /><br />.csharpcode .html { color: #800000; }<br /><br />.csharpcode .attr { color: #ff0000; }<br /><br />.csharpcode .alt<br />{<br /> background-color: #f4f4f4;<br /> width: 100%;<br /> margin: 0em;<br />}<br /><br />.csharpcode .lnum { color: #606060</style><br /><pre class="csharpcode"><span class="kwrd"><</span><span class="html">authorization</span><span class="kwrd">></span><br /><span class="kwrd"><</span><span class="html">allow</span> <span class="attr">roles</span><span class="kwrd">="monkey a,monkey b,admin"</span> <span class="kwrd">/></span><br /><span class="kwrd"><</span><span class="html">deny</span> <span class="attr">users</span><span class="kwrd">="*"</span> <span class="kwrd">/></span><br /><span class="kwrd"></</span><span class="html">authorization</span><span class="kwrd">></span><br /></pre><br /><br /><span style="font-weight: bold;">AuthGeek.config</span><br /><pre class="csharpcode"><span class="kwrd"><</span><span class="html">authorization</span><span class="kwrd">></span><br /><span class="kwrd"><</span><span class="html">allow</span> <span class="attr">roles</span><span class="kwrd">="geek 0,geek 1,admin"</span> <span class="kwrd">/></span><br /><span class="kwrd"><</span><span class="html">deny</span> <span class="attr">users</span><span class="kwrd">="*"</span> <span class="kwrd">/></span><br /><span class="kwrd"></</span><span class="html">authorization</span><span class="kwrd">></span><br /></pre><br /><span style="font-weight: bold;">AuthAdmin.config</span><br /><br /><pre class="csharpcode"><span class="kwrd"><</span><span class="html">authorization</span><span class="kwrd">></span><br /><span class="kwrd"><</span><span class="html">allow</span> <span class="attr">roles</span><span class="kwrd">="admin"</span> <span class="kwrd">/></span><br /><span class="kwrd"><</span><span class="html">deny</span> <span class="attr">users</span><span class="kwrd">="*"</span> <span class="kwrd">/></span><br /><span class="kwrd"></</span><span class="html">authorization</span><span class="kwrd">></span><br /></pre><br /><br /><span style="font-weight: bold;">AuthAllowAllUsers.config</span><br /><pre class="csharpcode"><span class="kwrd"><</span><span class="html">authorization</span><span class="kwrd">></span><br /><span class="kwrd"><</span>allow <span class="attr">users</span><span class="kwrd">="*"</span> <span class="kwrd">/></span><br /><span class="kwrd"></</span><span class="html">authorization</span><span class="kwrd">></span><br /></pre><br />The web.config location elements can now be replaced with:<br /><br /><!-- code formatted by http://manoli.net/csharpformat/ --><br /><style type="text/css"><br />.csharpcode, .csharpcode pre<br />{<br /> font-size: small;<br /> color: black;<br /> font-family: Consolas, "Courier New", Courier, Monospace;<br /> background-color: #ffffff;<br /> /*white-space: pre;*/<br />}<br /><br />.csharpcode pre { margin: 0em; }<br /><br />.csharpcode .rem { color: #008000; }<br /><br />.csharpcode .kwrd { color: #0000ff; }<br /><br />.csharpcode .str { color: #006080; }<br /><br />.csharpcode .op { color: #0000c0; }<br /><br />.csharpcode .preproc { color: #cc6633; }<br /><br />.csharpcode .asp { background-color: #ffff00; }<br /><br />.csharpcode .html { color: #800000; }<br /><br />.csharpcode .attr { color: #ff0000; }<br /><br />.csharpcode .alt<br />{<br /> background-color: #f4f4f4;<br /> width: 100%;<br /> margin: 0em;<br />}<br /><br />.csharpcode .lnum { color: #606060; }<br /></style><br /><pre class="csharpcode"><br /><span class="kwrd"><</span><span class="html">location</span> <span class="attr">path</span><span class="kwrd">="Bananas.aspx"</span><span class="kwrd">></span><br /> <span class="kwrd"><</span><span class="html">system.web</span><span class="kwrd">></span><br /> <span class="kwrd"><</span><span class="html">authorization</span> <span class="attr">configSource</span><span class="kwrd">="AuthMonkey.config"</span> <span class="kwrd">/></span><br /> <span class="kwrd"></</span><span class="html">system.web</span><span class="kwrd">></span><br /><span class="kwrd"></</span><span class="html">location</span><span class="kwrd">></span><br /><span class="kwrd"><</span><span class="html">location</span> <span class="attr">path</span><span class="kwrd">="MonkeyMatch.aspx"</span><span class="kwrd">></span><br /> <span class="kwrd"><</span><span class="html">system.web</span><span class="kwrd">></span><br /> <span class="kwrd"><</span><span class="html">authorization</span> <span class="attr">configSource</span><span class="kwrd">="AuthMonkey.config"</span> <span class="kwrd">/></span><br /> <span class="kwrd"></</span><span class="html">system.web</span><span class="kwrd">></span><br /><span class="kwrd"></</span><span class="html">location</span><span class="kwrd">><br /><</span><span class="html">location</span> <span class="attr">path</span><span class="kwrd">="JavaJabber.aspx"</span><span class="kwrd">></span><br /> <span class="kwrd"><</span><span class="html">system.web</span><span class="kwrd">></span><br /> <span class="kwrd"><</span><span class="html">authorization</span> <span class="attr">configSource</span><span class="kwrd">="AuthGeek.config"</span> <span class="kwrd">/></span><br /> <span class="kwrd"></</span><span class="html">system.web</span><span class="kwrd">></span><br /><span class="kwrd"></</span><span class="html">location</span><span class="kwrd">><br /><</span><span class="html">location</span> <span class="attr">path</span><span class="kwrd">="RailsRules.aspx"</span><span class="kwrd">></span><br /> <span class="kwrd"><</span><span class="html">system.web</span><span class="kwrd">></span><br /> <span class="kwrd"><</span><span class="html">authorization</span> <span class="attr">configSource</span><span class="kwrd">="AuthGeek.config"</span> <span class="kwrd">/></span><br /> <span class="kwrd"></</span><span class="html">system.web</span><span class="kwrd">></span><br /><span class="kwrd"></</span><span class="html">location</span><span class="kwrd">><br /><</span><span class="html">location</span> <span class="attr">path</span><span class="kwrd">="CodeGuru.aspx"</span><span class="kwrd">></span><br /> <span class="kwrd"><</span><span class="html">system.web</span><span class="kwrd">></span><br /> <span class="kwrd"><</span><span class="html">authorization</span> <span class="attr">configSource</span><span class="kwrd">="AuthGeek.config"</span> <span class="kwrd">/></span><br /> <span class="kwrd"></</span><span class="html">system.web</span><span class="kwrd">></span><br /><span class="kwrd"></</span><span class="html">location</span><span class="kwrd">><br /></span><span class="kwrd"><</span><span class="html">location</span> <span class="attr">path</span><span class="kwrd">="SpyOnGeeksAndMonkeys.aspx"</span><span class="kwrd">></span><br /> <span class="kwrd"><</span><span class="html">system.web</span><span class="kwrd">></span><br /> <span class="kwrd"><</span><span class="html">authorization</span> <span class="attr">configSource</span><span class="kwrd">="AuthAdmin.config"</span> <span class="kwrd">/></span><br /> <span class="kwrd"></</span><span class="html">system.web</span><span class="kwrd">></span><br /><span class="kwrd"></</span><span class="html">location</span><span class="kwrd">><br /></span><span class="kwrd"><</span><span class="html">location</span> <span class="attr">path</span><span class="kwrd">="images"</span><span class="kwrd">></span><br /> <span class="kwrd"><</span><span class="html">system.web</span><span class="kwrd">></span><br /> <span class="kwrd"><</span><span class="html">authorization</span> <span class="attr">configSource</span><span class="kwrd">="AuthAllowAllUsers.config"</span> <span class="kwrd">/></span><br /> <span class="kwrd"></</span><span class="html">system.web</span><span class="kwrd">></span><br /><span class="kwrd"></</span><span class="html">location</span><span class="kwrd">><br /><</span><span class="html">location</span> <span class="attr">path</span><span class="kwrd">="css"</span><span class="kwrd">></span><br /> <span class="kwrd"><</span><span class="html">system.web</span><span class="kwrd">></span><br /> <span class="kwrd"><</span><span class="html">authorization</span> <span class="attr">configSource</span><span class="kwrd">="AuthAllowAllUsers.config"</span> <span class="kwrd">/></span><br /> <span class="kwrd"></</span><span class="html">system.web</span><span class="kwrd">></span><br /><span class="kwrd"></</span><span class="html">location</span><span class="kwrd">><br /><</span><span class="html">location</span> <span class="attr">path</span><span class="kwrd">="javascript"</span><span class="kwrd">></span><br /> <span class="kwrd"><</span><span class="html">system.web</span><span class="kwrd">></span><br /> <span class="kwrd"><</span><span class="html">authorization</span> <span class="attr">configSource</span><span class="kwrd">="AuthAllowAllUsers.config"</span> <span class="kwrd">/></span><br /> <span class="kwrd"></</span><span class="html">system.web</span><span class="kwrd">></span><br /><span class="kwrd"></</span><span class="html">location</span><span class="kwrd">></span></pre><br /><br />As a result, the groups of roles are kept in one place. The Web.config file now references the appropriate authorization rules in the location elements. This is a great improvement over redundant values in the allow and deny elements.Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-8050462.post-26641394863117557422008-12-17T10:11:00.014-06:002008-12-17T16:40:12.785-06:00Acceptance testing pains converting WatiN tests to run in SeleniumFor the last year and a half we have been using <a href="http://watin.sourceforge.net/">WatiN</a> to drive our automated integration/acceptance tests for one of our projects (If you'd like some insight into our decision, see <a href="http://adamesterline.com/2007/04/23/watin-watir-and-selenium-reviewed/">Adam's blog post on it</a>), and it has worked out really well. However, lately we have been experiencing pain when it comes to running our acceptance tests, and we have considered moving our tests to run using <a href="http://seleniumhq.org/">Selenium</a> instead.<br /><br />Our first point of pain is the amount of time it takes to run our acceptance tests. We have around 500+ and they have been taking close to 40 minutes to run. I'm not sure at what point they began to take so long, but I hardly considered 40 minutes to be acceptable. One of the key ideas behind <a href="http://en.wikipedia.org/wiki/Test-driven_development">Test Driven Development</a> is the red, green, refactor principle, which requires you to run your tests often. With the acceptance tests taking 40 minutes to run, I had begun to find myself running those tests less and thus losing the security blanket that we had created by writing those tests from the very beginning.<br /><br />Another point of pain is testing the number of web browsers we are supporting. Currently we are supporting eight different browsers, Firefox 2 & 3 (Mac & PC varieties), Safari 2.0.4 & 3 (Mac only), IE 6 & 7. We are looking to add support for at least two more, Google Chrome & IE 8. One of WatiN's biggest limitations is that it only runs in IE. Our stories had to be tested manually in the other browsers to ensure they were complete and if you do this often enough it, you will loose a lot of time out of your development cycle.<br /><div><br /></div><div>We decided to reexamine using <a href="http://seleniumhq.org/">Selenium</a>, particularly <a href="http://selenium-grid.seleniumhq.org/">Selenium Grid</a> and <a href="http://seleniumhq.org/projects/remote-control/">Selenium RC</a>, in our test suite. We were hoping to a) Speed up the time it took to run out tests b) Run our test across a larger set of browsers. Knowing how the Grid works, we knew that <span class="Apple-style-span" style="font-weight: bold;">b</span> could easily be achieved, but how would the speed compared to WatiN. </div><div><br /></div><div>As a test we converted a small subset of our fixtures, about 10, over to Selenium and did some slight benchmarking. After the 10 fixtures were converted, we didn't see any initial improvement in the average test time. It was decided the advantage gained by being able to test across multiple browsers was more than enough for us to convert the rest of our tests to Selenium.</div><div><br /></div><div>It appeared the quickest way to move forward was to rewrite our tests using <a href="http://seleniumhq.org/projects/ide/">SeleniumIDE</a>. It took two developers about a week and a half to convert every test over and flush out any old tests or broken tests. After this was all said and done the Selenium tests ran about two to five minutes faster than the WatiN tests, but I feel that what we gained was well worth the effort. At the very least, we did not slow ourselves down and we can now test across multiple browsers with ease, and I like knowing that whatever changes we make will be tested and tested well. </div><div><br /></div><div><span class="Apple-style-span" style="font-style: italic;">*We were able to speed the tests up and get them to run in as little as 12 minutes. I'll share that in a later post.</span></div>Eric Neunaberhttp://www.blogger.com/profile/18394319456644274008noreply@blogger.com0tag:blogger.com,1999:blog-8050462.post-64298903959873153332008-12-16T14:08:00.007-06:002008-12-16T14:23:47.280-06:00PairamidA few teams at Asynchrony have used pairing charts as a mechanism to help us pair and change pairs frequently so that we gain the benefits of sharing knowledge, widening our understanding of the code, etc. Here's an example of something I call the "pairamid" (pun intended):<br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiTXrSSY4oBZ3_4Av6v8DfxCBUH6BdwyBrHN2tUGj0sdg47Sf8sykfXeJp46HfOEe0ILKrmXz2erq-1641bQe5b4YJ3uAmzUvuS-et_ysrc90DGRrORzfHFvSyTP1Pegr10yyzp8Q/s1600-h/pairamid.jpg"><img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 400px; height: 355px;" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiTXrSSY4oBZ3_4Av6v8DfxCBUH6BdwyBrHN2tUGj0sdg47Sf8sykfXeJp46HfOEe0ILKrmXz2erq-1641bQe5b4YJ3uAmzUvuS-et_ysrc90DGRrORzfHFvSyTP1Pegr10yyzp8Q/s400/pairamid.jpg" alt="" id="BLOGGER_PHOTO_ID_5280485431832101458" border="0" /></a>In this particular pairing chart, we put a tally for each pairing session, color-coded by day of the week. It serves as a gentle reminder in our war room that we shouldn't let one of the squares have too many more tallies than any other and that person x should try pairing with person y (which we obviously weren't doing very well that iteration!).Piphttp://www.blogger.com/profile/05346094110928992431noreply@blogger.com0tag:blogger.com,1999:blog-8050462.post-59965875350633304752008-12-10T09:02:00.004-06:002008-12-12T09:15:47.284-06:00Link roundupProduct ownership:<br /><ul><li><a href="http://www.stickyminds.com/Media/eNewsletters/Iterations/Default.aspx?eNewsletter=200812#powerbookreview"><span class="BlackTextTitle1White"></span></a><a href="http://www.stickyminds.com/Media/eNewsLetters/Iterations/Default.aspx?eNe#powerbookreview">A Product Needs an Owner</a></li></ul>Agile adoption:<br /><ul><li><a href="http://www.stickyminds.com/sitewide.asp?Function=edetail&ObjectType=COL&ObjectId=14404&tth=DYN&tt=siteemail&iDyn=2"><span class="Title"></span></a><a href="http://www.stickyminds.com/sitewide.asp?Function=edetail&ObjectType=COL&ObjectId=14404" name="coltop">Little Scrum Pigs and the Big, Bad Wolf</a></li></ul>Testing:<br /><ul><li><a name="coltop"></a><a href="http://searchsoftwarequality.bitpipe.com/data/document.do;jsessionid=CF4FA0552D08BB13F07469A0E44C4FC0?res_id=1209485432_588&src=DED_ssoftq_12_09_08">Best Practices for Implementing Automated Functional Testing Solutions</a></li><li><a href="http://testobsessed.com/2008/12/08/acceptance-test-driven-development-atdd-an-overview/">ATDD: An Overview</a><br /></li></ul>Tools:<br /><ul><li><a href="http://www.michaeldkelly.com/blog/archives/218">Choosing a code-coverage tool</a><br /></li></ul>Reference:<br /><ul><li><a href="http://rdocul.us/">RDocul.us: All Ruby Docs, always up to date!</a></li></ul>Conferences:<br /><ul><li><a href="http://www.sqe.com/ConferenceArchive/StarEast2008/">StarEast 2009</a></li><li><a href="http://parlezuml.com/softwarecraftsmanship/">Software Craftsmanship 2009</a><br /></li></ul>Piphttp://www.blogger.com/profile/05346094110928992431noreply@blogger.com0tag:blogger.com,1999:blog-8050462.post-67297071068892951602008-12-09T09:15:00.004-06:002008-12-09T09:21:36.331-06:00Hendrickson on ATDDThe prolific Elisabeth Hendrickson has posted another insightful piece on her blog, <a href="http://testobsessed.com/2008/12/08/acceptance-test-driven-development-atdd-an-overview/">an overview of Acceptance-Test-Driven Development</a>. I'll let you read it, which includes <a href="http://testobsessed.com/wordpress/wp-content/uploads/2008/12/atddexample.pdf">a .pdf with more details</a>, but I wanted to highlight a graphic from the .pdf:<br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi_rWCqFEZ15kd2Njyrbm7pCkddtwZuouJtwpPuVeN44NKscd97PIqXjvnyHyrbzWrbJEhCK9q8bpUjoNnb0XXLTfMiOM0AIZMzmiwn8KZsqiUKh-Y1-HE5RCRLVPKO6ZGFUx_Acw/s1600-h/atddcycle.jpg"><img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 400px; height: 384px;" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi_rWCqFEZ15kd2Njyrbm7pCkddtwZuouJtwpPuVeN44NKscd97PIqXjvnyHyrbzWrbJEhCK9q8bpUjoNnb0XXLTfMiOM0AIZMzmiwn8KZsqiUKh-Y1-HE5RCRLVPKO6ZGFUx_Acw/s400/atddcycle.jpg" alt="" id="BLOGGER_PHOTO_ID_5277810139880498738" border="0" /></a><br />I think we do the Discuss and Develop components well, but our weaker muscles tend to be the Distill and Demo aspects. Distilling takes a bit more time, but I think it's an example of the old saying "a stitch in time saves nine."Piphttp://www.blogger.com/profile/05346094110928992431noreply@blogger.com0tag:blogger.com,1999:blog-8050462.post-19806527966913240732008-12-05T14:37:00.003-06:002008-12-05T14:42:09.830-06:00Twitter badges now on blog sidebarI added individual Twitter badges of Asynchrony employees to the sidebar of this blog. Apparently, there's no way to aggregate multiple Twitter accounts into one badge that I've seen. If someone wants to try, let me know.<br /><br />Also, I'm using the big block flash badges because there's no easy way to display multiple individual non-flash badges on the same html page. You can <a href="http://getsatisfaction.com/twitter/topics/embed_two_twitter_accounts_onto_one_website#reply_621386">read more about it</a>.Piphttp://www.blogger.com/profile/05346094110928992431noreply@blogger.com0tag:blogger.com,1999:blog-8050462.post-62187227505066210322008-11-26T08:47:00.005-06:002008-12-05T14:42:29.454-06:00Helmkamp on Story-Driven DevelopmentGaffo noted <a href="http://goruco2008.confreaks.com/01_helmkamp.html">this very good talk</a> -- "Story Driven Development" -- by "the guy who runs webrat" (aka Bryan Helmkamp):<br /><blockquote>It really picks up about 25 minutes in for us, but the first 25 minutes are interesting because they cover Rspec and story runner (the precursor to cucumber). He's talking about a lot of the things we're currently running into and I think it will help facilitate later discussions.</blockquote>Good stuff; I second Mike's commendation.Piphttp://www.blogger.com/profile/05346094110928992431noreply@blogger.com0tag:blogger.com,1999:blog-8050462.post-31230886957100223982008-11-25T13:33:00.012-06:002008-11-26T09:00:14.326-06:00Testing Pyramid, part 2I went ahead and grabbed the actual test numbers from the build(s) -- simply the total number of assertions in each of the test levels (unit, functional, integration and UI) -- and generated a chart in Excel:<br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjQZ-rDgCqUKcJqlTXxohMsO3ytrrJtkI97aTjtsAi9EbjkF5eIVxMFEDGMtbn38TKY2deaJzw3qy4XequBJ_ugZzODNxpUYcxS6aCBDMKXB1k0zafmJBRDIEwB7HZqrpQSMWhqtA/s1600-h/it5testingtriangle.jpg"><img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 327px; height: 370px;" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjQZ-rDgCqUKcJqlTXxohMsO3ytrrJtkI97aTjtsAi9EbjkF5eIVxMFEDGMtbn38TKY2deaJzw3qy4XequBJ_ugZzODNxpUYcxS6aCBDMKXB1k0zafmJBRDIEwB7HZqrpQSMWhqtA/s400/it5testingtriangle.jpg" alt="" id="BLOGGER_PHOTO_ID_5272682500605598786" border="0" /></a><br />I posted it in our war room; we'll see what kind of conversation it sparks. It looks like we need to continue moving toward increasing the ratio of webrat (integration) tests to Selenium (UI) tests, as well as upping our base level of units. Using the actual data also corrected my anecdotal assumption that we had a lot more unit tests than we do (see my sketch in my previous post).<br /><br />UPDATE: I ran the numbers for another team. Here's their chart:<a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgL-_GZJqioDuL57elnG_CV0jrpqcH-ArXiNWySceGrV7az4X3QJvUZ-Y6aohx6_1rbBGQotBApuVZjzV6Qsm0K9ZahpZZ6EiSa1BPJRVfWe0TktyBl_91EIgxqoVmbGipkrnNyWw/s1600-h/acetestingtriangle.jpg"><img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 327px; height: 370px;" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgL-_GZJqioDuL57elnG_CV0jrpqcH-ArXiNWySceGrV7az4X3QJvUZ-Y6aohx6_1rbBGQotBApuVZjzV6Qsm0K9ZahpZZ6EiSa1BPJRVfWe0TktyBl_91EIgxqoVmbGipkrnNyWw/s400/acetestingtriangle.jpg" alt="" id="BLOGGER_PHOTO_ID_5272980346752423474" border="0" /></a><br />This team has some UI tests written in Watir, but they don't run them (so they're useless). All of their integration tests are Webrat; apparently, these can be run as Selenium tests, but the team isn't doing that (yet). This team has the fundamentals down well -- more unit tests than functional, more functional than integration. We'll see how they expand the upper levels of their triangle in the coming weeks.Piphttp://www.blogger.com/profile/05346094110928992431noreply@blogger.com0tag:blogger.com,1999:blog-8050462.post-19831334990905007022008-11-24T08:55:00.002-06:002008-11-24T09:13:37.082-06:00Constructing the testing pyramidI like Mike Cohn's testing pyramid as a guideline for test allocation, and I've mentioned it to a couple of teams around here (for more, read <a href="http://patrickwilsonwelsh.com/?p=32">Patrick Wilson-Welsh's blog</a> and/or see <a href="http://patrickwilsonwelsh.com/wp-content/uploads/2008/08/flipping-the-triangle.pdf">his Agile 2008 presentation</a>). Lately, on one team, we've been very earnest about writing Selenium tests for UATs, even doing some ATDD. But we're seeing what many have seen: Selenium tests are often (necessarily) long and slow, and occasionally brittle. I asked the team what our "testing pyramid" would look like, and it's something like this:<br /><pre><br /><div> ^^^^^^^^^^^^ (GUI/system)</div><div> ^^^^^^^^^^ (functional)</div><div> ^^^^^^^^^^^^^^^^^ (unit)</div></pre><div>That is, the majority of our tests are at the unit level (that's good), but we are top-heavy with GUI tests. So with the help of the Ace team, we're moving toward more under-the-GUI integration tests using Webrat. Now we're looking more like:<div><pre><br /><div> ^^^^^^^^^^^^ (GUI/system)</div><div> ^^^^ (integration)</div><div> ^^^^^^^^^^ (functional)</div><div> ^^^^^^^^^^^^^^^^^ (unit)</div></pre><div>The goal is to convert some of those Selenium (GUI/system) tests to Webrat (integration) and get our pyramid more in line (and help our team be more productive). There's still obviously need for the GUI-system tests, but we're just trying to be smarter about it. </div></div></div>Piphttp://www.blogger.com/profile/05346094110928992431noreply@blogger.com0