in

 

Chad Myers' Blog

Department of Problem Prevention

February 2008 - Posts

  • On Knightly Duty and Suffering

    I've been reading "The story of King Arthur and His Knights" by Howard Pyle to my son in the evenings recently.  It's filled with various stories of knightly prowess, victory and defeat, triumph and humiliation, etc. Overall, I'd recommend it and I think my son got a lot out of it, even if the language (Ye Olde English) is somewhat difficult to parse (we just came off of the classic The Adventures of Robin Hood, so he was used to the language).

    Anyhow, at the very end of each unit is a kind of 'Moral of the Story' and the last one was very inspiring.  This isn't really my situation right now, but I've been in situations like this and I'm definitely going to keep this one handy for when it arises again (any emphasis or highlighting is mine):

        Such is the story of Sir Gawaine, and from it I draw this significance:  as that poor ugly beldame appeared unto the eyes of Sir Gawaine, so doth a man's duty sometimes appear to him to be ugly and exceedingly ill-favored unto his desires.  But when he shall have wedded himself unto that duty so that he hath made it one with him as a bridegroom maketh himself one with his bride, then doth that duty become of a sudden very beautiful unto him and unto others.

        So may it be with ye that you shall take duty unto yourselves no matter how much it may mislike ye to do so.  For indeed a man shall hardly have any real pleasure in his life unless his inclination becometh wedded unto his duty and cleaveth unto it as a husband cleaveth unto his wife.  For when inclination is thus wedded unto duty, then doth the soul take great joy unto itself as though a wedding had taken place betwixt a bridegroom and a bride within its tabernacle.

        Likewise, when you shall have become entirely weedded unto your duty then shall you become equally worthy with that good knight and gentleman Sir Gawaine; for it needs not that a man shall wear armor for to be a true knight, but only that he shall do his best endeavor with all patience and humility as it hath been ordained for him to do.  Wherefore, when your time cometh unto you to display your knightness by assuming your duty, I do pray that you also may approve yourself as worthy as Sir Gawaine approved himself in this story which I have told you of as above written.

    How foreign these words sound today in our culture...

  • I find your lack of tests disturbing.

    Found this here: {|one, step, back|} and I had to cry chuckle.

  • SQL is the assembly language of the modern world

    This isn't a new idea, it's been mentioned before, so I'm not taking credit for it, but it's still worth pointing out... again... for the umpteenth time. So I'm gonna pick up the baton-of-flames and try the argument again:

    I really would like to challenge the conventional wisdom that stored procedures are the best and/or that hand-crafted SQL is the only way to achieve good performance.

    I once heard someone say that "SQL is the assembly language of the business application world" and I totally agree with this (I linked to Jett Attwood's post above, but I heard it somewhere else first and my Google-fu is failing me tonight).

    If you read the discussions on USENET back in the day when C++ and later Java were coming into popularity, there were a bunch of die-hards who held the conventional wisdom that C++ and Java compilers couldn't possibly ever generate machine code that would achieve the super high performance of lovingly hand-crafted assembly language.  Add into that the bytecode interpreting of Java and the Garbage Collector and their heads nearly exploded.

    Now, the same kinds are arguments are being made about not using stored procedures and instead using generators or even the inconceivable: Object/Relational Mappers.

    While the arguments of the assembly-language advocates were mostly true: Compilers can't create the mostly highly optimized code, it turns out that modern runtime environments, processors, and operating systems can account for this and actually do a better job of managing the complexities of runtime performance optimizations better than a human assembly language writer could ever hope to achieve.  The system now tunes itself on the fly based on the current reality of the operating environment as it stands right now. 

    SQL Server is now getting to the point where it's able to better tune itself based on the kinds of queries coming in and the volume and type of data it's returning. It's getting to the point where hand-crafting SQL may actually be self-defeating. We're not quite there yet, and there are still scenarios where hand-crafting SQL makes sense. Coincidentally, there are still situations where, in C#, it's appropriate to use the unsafe() keyword, or even use unmanaged code or even assembly language!

    I don't think we'll ever be able to get away from hand-crafted SQL, but I think it should be our goal to standardized on a set and sytle of SQL generation and let the tools like Linq2SQL, NHibernate, etc work with tools like SQL Server and let them work together to optimize your intentions.

    Our goal should be to get out of the SQL crafting business and get back into the data access business.

  • Austin TDD CodingDojo Homework

    A few folks have been working on some of the stories and code we were talking about at the Austin TDD CodingDojo earlier this month.  Joe Ocampo, Ray Houston, and I have been discussing it and Joe even did a cool spike/prototype to get things moving (I've looked at it Joe, I haven't had a chance to write back my thoughts or merge the code in yet, sorry man).

    Gregory Long was another attendee and he recently posted on his blog and worked out some of the model as some minimal up-front design to kick off the testing and implementation.

    Has anyone else done anything else with the code yet? Let me know in case I've missed it. I was thinking of doing a spike myself and comparing notes with everyone.

  • The first 2 hours of TDD are the most painful

    Quick Background

    I admit, I've had a lot of failures with TDD. Mostly they were solo projects and I didn't have the discipline and self control enough to stick with it. I ALWAYS regretted not sticking with it. However poorly I was doing it, it always gave SOME value and saved me from several bugs (earning its keep and paying back with dividends all the time I spent on it).  And the successes with TDD I have had have been rocky, at best.  I usually felt ashamed and embarrassed by this, seeing how there's all these noted luminaries and successful practitioners on my Blog Roll talking about optimizing, tweaking and even redefining the style of TDD as BDD.

    In my selfish desire to find out their secret, I worked with Ray Houston to try to trick a bunch of really good software developers (many of whom already had lots of TDD experience) to see if I could get them to teach me their secret ways so that I might become more proficient and successful at TDD. I didn't expect it to work very well. BOY WAS I WRONG.

    I was kind of down on the CodingDojo in my last post on the subject. I was bummed because some people came from great distances and left with less than I had hoped they would. I was bummed that I didn't serve them better.  But, there were some really great things that came out of it. It did spurn a bunch of people to get more serious about what they were doing and take a second look at how they were doing it. But more importantly, it re-instilled confidence in people (including me) who had been wavering and unsure of where to go or how to do TDD more effectively.

    It was truly great to see people whom I thought had TDD down cold, experience some of the same problems I have been having and not have a quick answer for it.  This reminded me the most important thing about TDD...

    TDD is not a solved problem, yet.

    You cannot minor in TDD at college. Heck, you cannot take a graduate level course on TDD at college.  TDD is not a fully solved problem. It's a practice which has been proven, through experience of many, to be a useful, worthwhile, and valuable tactic for achieving higher quality, more agility (through change confidence), and measured, disciplined design.

    Armed with this reassurance that I wasn't totally a heel, I really started to get into the discussions, the debates, and, above all, the code at the Dojo.  I started jotting down some of the questions that were being raised and not answered all that great in the hopes that I could spend some time thinking about them.

    I plan on writing more about these things as the weeks/months go on (especially when I start on with Jeremy and get to practice them more thoroughly and have more substance to write about).  But in the mean time, I thought I'd do a thought dump and see if anyone had any good rules of thumb, concrete advice, or even 'laws' to go by. I'll be updating this post with any interesting comments that appear so that you don't have to go hunting through them to find any gems (of course, all the comments are gems -- except for Anonymous Blog Coward ones -- but some are worth bringing to the top).

    (P.S.- I'm trying to keep the BDD style questions out of here, that will probably be another post)

    TDD Practice Questions

    • How much up-front design do you tolerate? How do you know when to stop (i.e. 'when algorithms start getting discussed, it's testing time')?
    • What about certain "I just know we'll need this" type stuff (i.e. putting a try/catch{Console.WriteLine(ex);} in your console main() method?)
    • When writing a test, in order to even get it to compile, you have to build an interface or two, a concrete class with some NotImplementedExceptions in it, etc. How far do you allow that to go?
    • If, during the middle of testing on a story, you realize that your up-front design wasn't correct, do you stop and discuss with your pair right then, do what you need to do and proceed, or do you pull back and go back to full pre-test design mode on that story?
    • When proceeding to a new story, you discover that a test you wrote for a previous story no longer reflects the requirements. Do you refactor that test immediately, mark it as ignored until you finish the current story and cycle back to the ignored one? Something else?
    • If the new story's requirements involve a slight tweaking to an existing test, do you tweak it, or make a new one and discard the old one (i.e. 'No changing existing tests!' or 'Only change if it's a minor compiler issue, but otherwise don't change it')?
    • If you're, say, building up your model and it passes tests, but you're seeing that it's infantile and that the next few upcoming stories will produce significant changes to produce a new emergent model, is it appropriate to step back and consider a larger refactoring, or do you keep plugging and make the changes into the existing model even if it could benefit from some housekeeping that is otherwise out of scope?

    TDD Style Questions

    • Assert.That(x, Is.EqualTo(y)) or Assert.AreEqual(y,x)?
    • How many asserts/test? Any caveats?
    • How do you know what to put in the SetUp method?

    TDD Mechanics Questions

    • Is a refactoring tool absolutely necessary?
    • If so, what is the bare minimum features that the tool would need to facilitate decent TDD?
    • Integrated IDE test runner or a background source-watching auto-runner?

    That's most of what I wrote down with a few extra thrown in for good.  I'd love to hear some of your thoughts on these questions.

  • Guiding Principles 101

    As a answer-in-part to my own Call To Blog More, I'd like to make an entry.  I'd like to talk about some of the guiding principles of design we should all be thinking about and re-enforcing in each other.  These principles require discipline and it's VERY easy to not use them and still achieve decent results (at the cost of looming, expensive problems down the road).  You owe it to yourself and your fellow co-worker developer to be familiar with these, at least, and to make an attempt to practice them on a daily basis.

    Rather than me repeating documentation on various principles which is already abundantly available on the web, I'm going discuss two things:  1.) The ObjectMentor site which has a collection of well-written documents (in PDF, *ugh*) and 2.) Discuss a somewhat newer principle which I call 'Framework Ignorance Principle' and which Ayende recently dubbed 'Infrastructure Ignorance [Principle].'

    Wealth of OO Design Principle Knowledge

    http://www.objectmentor.com/omSolutions/oops_what.html

    This has a breakdown of each and every principle (plus more) that I was planning on talking about here.  That kinda stole my thunder, actually.  It's hard to top 'Uncle' Bob Martin when it comes to OO design principles, so I'm not going to attempt it.

    It is definitely worth your time to spend a few nights browsing through the PDF's on that page.

    NOTE: If you ever plan on interviewing with me for anything more than a junior level developer position, you better be able to give a sentence or two on at least 5 or 6 of these principles and discuss, at length at least one of them.

    I'd like to call out one principle, in particular that I think would probably benefit everyone the most. It's one of the simplest concepts, though hardest in practice to maintain and requires a good team discipline to maintain:

    Single Responsibility Principle

    "There should never be more than one reason for a class to change"

    - Robert 'Uncle Bob' Martin

    If you have a communications class that has methods like 'Open()' and 'Close()' as well as 'Send()' and 'Receive()', you're violating SRP.  Connection management and data transfer are separate concerns and should be isolated.

    Framework Ignorance Principle

    This one isn't really a new concept and is instead really an amalgam of several other principles. It's worth pointing out and promoting to the level of a 'virtual' first-class principle, in my opinion.

    When working with various frameworks, there is a propensity for that framework to become pervasive at all levels of the code.  Without rigid discipline, the temptations and weakening arguments such as 'Well, we're joined at the hip to FrameworkX, might as well make my life easier and give up the pretense that I'm NOT going to use it' will gain in frequency and intensity until there is a collapse of discipline.  Depending on what your framework does, this line of reasoning will trigger a set of events that will lead to a quick or gradual decline in your projects maintainability, testability, and overall agility. It's a self fulfilling prophecy. If you give up the discipline of keeping the framework segregated by saying that you're already in for a penny, you will quickly be in for a pound.  While it's probably true that you may not be migrating from NHibernate any time soon, you will most likely be migrating from NHibernate 1.0 to 1.2, or better yet, 1.2 to 2.0 which could be a much larger issue. At that point, you're very close to adopting a new framework anyhow. Sure, the API is very similar, but the guts could be very different and there is tons of new functionality that may make you rethink certain design decisions -- forcing rewrites of part of your app.  Maintaining the ignorance to the last possible moment will greatly ease this refactoring or rewrite.  If you made the mistake of allowing ICriteria or ISession references bleed up into your UI or Web layer, making the switch from 1.2 to 2.0 will likely be very painful.

    Another case study here is log4net.  Over the years, I had grown so accustomed and trusting of log4net and relied on it's snail-like release schedule (or lack thereof), that I allowed log4net to bleed into all parts of my app. "It's a logging framework, how much could it possibly change?" I found myself saying.  Well, then log4net 1.2.9 came out. Sure, the API was exactly the same, but they changed the key signature for the DLL which broke assembly linkage all over the place and was irremediable due to the fact that you cannot do assembly versioning redirection in .NET when the key signature changes.  Yet another time that a lack of framework ignorance discipline bit me hard in the rear.

    I'm not advocating you go out and write abstraction layers for all your frameworks (*ahem* I've tried that, it's not pretty). You may have to in certain circumstances, but avoid it as much as possible. You will create a potentially brittle change resistance layer that can slow down your refactoring in the future and also mask useful features in the underlying framework (the 'least common denominator' problem).  I would, however, advocate that you try to leverage the framework to it's fullest, but do it in a way that works around and among your primary code and not in the middle of it.  Attempt to make use of IoC containers for injecting or wrapping functionality. Look

    A perfect example of this technique is how NHibernate mapping files are separate from the domain entity objects themselves. The mapping files explain to NHibernate how to persist and retrieve these objects from a relational data store. There are no mapper objects, no adapters, no attributes on the entities themselves, no code-generated partial classes, etc.  To stop using NHibernate or to switch to a new version, you simply stop using it or start using the other version. There will be a few places in your code that will have a reference to NHibernate, but these will be minimal and self-contained, allowing for quick refactor.

  • Don't take encryption and hashing lightly

    A word to the wise for framework and product-shipping designers: Don't take encryption, signing, and hashing lightly. Also, choose your cryptographic algorithms well and even consider making the cryptographic algorithm choice a configurable item.

    We were using a licensed 3rd party component that used RijndaelManaged for encryption of some sort (relating to the license key) and it turns out that our servers have the FIPS algorithm policy requirement enabled.  This means that when we deployed our code, we got the following somewhat cryptic error message: "This implementation is not part of the Windows Platform FIPS validated cryptographic algorithms."

    I later found out that the RijndaelManaged symmetric encryption cryptographic algorithm used (hard-coded) by the 3rd party component vendor is not among the list of FIPS-certified cryptographic algorithms and is, therefore, disabled by Windows and .NET when the FIPS policy is enabled.

    As you can imagine, this is cause for a lot of concern and consternation among the developers here as we try to find a suitable work around.

    Moral of the Story: Use FIPS-certified algorithms or provide a special build that uses FIPS-ceritifed algorithms in case one of your customers runs into this problem. 

     

  • You need to blog. Now.

    Seriously. No, I know. Stop it. Stop whining. Yes, they will care what you have to say. No, it hasn't all been said before. Yes, seriously. Do it. YOU, YES YOU!

    The most common excuse for not blogging I hear (including from myself) is "It's all been said, what can I possibly add?"

    While that may be mostly true, what you're missing is that not everyone is hearing it!  But there are still some gaping voids of content that aren't adequately covered.

    Here's a few blog ideas I've been kicking around and I'll share them with you so that you can take some of these and run with them. PLEASE GRAB ONE AND GO!  As you blog them, I will link them to you and cross 'em off the list. I'm going to be doing some of them too, but it's not enough. I need your help. I need differing views. I need conflicting, but useful information to further discussion and stimulate progress.

    I'm even going to go so far an pull rank on you and go Catholic:  If you have even the slightest knowledge of these things you have a professional obligation to share that knowledge with as many people as you can. Yes, even if you're wrong on parts. Yes, even if you're not sure (just prefix with 'not sure about this').  I'd rather have a bunch of 80% right posts out there that we can discuss and critique and further knowledge from than 0 0% right posts out there (which is a lot of what we have right now).

    • Guiding Principles 101:  Single Responsibility Principle, Dependency Inversion Principle, Liskov Substitution Principle, Framework Ignorance Principle, (and others I'm not thinking of right now 'cause it's late)
    • Dependency Injection 101: Talk about c'tor injection, setter injection, when it's good, when it's bad. Talk about the need for interfaces and how they help with this.
    • Inversion of Control 101:  Talk about how to take DI to the next level and automate a lot of it (or push the burden elsewhere).  Use StructureMap, Windsor, or roll your own super-simplistic one to show how things work and then add in one of the big frameworks.
    • Unit Testing 101:  Most people know what unit testing is, but they don't know that there are xUnit frameworks that make it a lot easier. Pick one (NUnit, MBUnit, MSTest) and start from scratch and go through a few dirt simple scenarios
    • Mocks 101: "I just bought this iMac and now I want to know how to use Rhino Mocks" -- the absolute start-from-zero low-down on why mocking and how to use Rhino Mocks (or any other framework for that matter). Many posts out there assume that you have the basic understanding of what Mocks are for and why'd you use them. The vast majority of the .NET developer community has no idea what mocks are for in the first place, let alone how you go about using them. This is a tragedy and we must correct this soon.
    • Unit Testing 201:  Test naming, test file/class/method structure, what to assert, when, and how, etc.
    • Mocks 201: Talk about when to use CreateMock vs. DynamicMock vs. Stub. When to use Expect.Call() vs. SetupResult.For... maybe you might give 'em a glimpse at constraints

     

    That should get you started. I'll be cooking up some more ideas, but this should be enough to show you that there's a WEALTH of stuff upon which to blog. Do it now!

  • Austin TDD CodingDojo Complete

    On Saturday morning, February 9th, 2008, on the frozen tundra of Lambeau Field, 20+ geeks descended to explore what TDD was all about. Ok, it wasn't frozen, nor tundra, nor Lambeau Field, but it was Feb. 9th and we were all geeks and it was good.

    Overall, I'd like to say: The event was a great success, but the CodingDojo was a failure. We talked a lot about TDD, we actually got a few minor things accomplished via code, clarified a lot of concepts that were a little cloudy in people's minds (like mine), and opened a few people's eyes who hadn't been experience to a lot of TDD -- especially the style we used.

     

    We started out -- late, in true geek fashion -- by doing some introductions and what our experience was with TDD and what we hoped to get out of this event.  Then, the project was revealed: Mathinator.  A dirt-simple command-line based basic math flash card app.  We had a few user stories to kick things off, then spent some time discussing the requirements, clarifying, and expanding on concepts.  We then went right to the code.  This turned out to be a mistake, unfortunately. We should've, at this point, spent more time talking about an up-front design.  I felt that things were late already and we had spent a lot of time not talking about TDD or code and that people's time was being wasted. It turns out that they probably would've appreciated spending more time up front talking about design. Mistake #1.  In the future, we should get started quicker and spend more time on design before jumping into code.  The socialization is definitely important, but I think we could've spent the whole time talking about various topics (including TDD) and never ended up writing a single line of code.

    We drew names from a basket and, I swear it wasn't rigged, I was one of the first ones.  Tim Hardy of the Fellowship Tech crew (they drove down from Dallas to be there at 8am! God bless 'em!) was also chosen.  We started out discussing the mechanics of ping-pong pairing.  He told me he wasn't an expert, but he picked up real quick and we were off coding.

    And then the discussions started... These were awesome, but they ended up totally blowing the whole 'CodingDojo' part of the event. Many in the crowd commented, asked questions, and many good conversations happened -- simultaneously. It was glorious and terrible at the same time. Lack of self control on my part (#1) and crowd control (#2) led to a generally rowdy event where many discussions happened -- all of which were wonderful and necessary and thought provoking, but totally confusing to anyone there trying to get serious about learning TDD.  Mistake #2.  Someone is going to have to be 'Mr. ***' next time we do this to keep the thing focused and try to offline or break out these stellar conversations so that the event stays on track, but that the conversations and ideas don't get lost forever.

    I think most people there would agree with me when I say: I wish I could have attended both events going on there that day, simultaneously.  We need to have an event where all we do is just discuss TDD, BDD, design, and such and have a computer near-by just in case it comes to down to JSMTFC. Then we need to have an event where we practice some of the outcomes of the previously mentioned event and we will have (hopefully) got all our arguments shaking out of us and we're down to fingers-on-keyboard.

    I'm seriously thinking of hosting a discussion event, panel, whatever you want to call it on TDD and get these folks together for a bigger discussion on TDD practice and theory. And I'd like to try to do that soon while it's still fresh in people's minds. I'd like to get people more familiarized with these concepts so that the next CodingDojo, we can maybe spend more time on the ground running.

    I might consider doing a TDD 101 the day before the next CodingDojo for folks who'd like to get up to speed quickly and join the fray with at least one feather in their cap. Would this be useful to anyone?

    Anyhow, thanks for everyone who attended/participated/contributed, sorry for everyone who couldn't. Below are some links from the event in case you were curious:

Copyright Los Techies 2007. All rights reserved.
Powered by Community Server (Commercial Edition), by Telligent Systems