Wednesday, May 14, 2008
Looks like I'll be speaking on Continuous Integration in theory and practice at next month's meeting of the Software Process Improvement Network.  Details are here.  If you are interested in CI, come on down.

Wednesday, May 14, 2008 5:18:08 PM (Pacific Daylight Time, UTC-07:00)  #    Disclaimer  |  Comments [0]  | 
 Friday, April 25, 2008
My new book Code Leader: Using People, Tools, and Processes to Build Successful Software is now available and in stock at Amazon and hopefully soon at stores near you.  The initial outline for the book came from a post I did a while back, This I Believe, the developer edition.  Writing up that post got me thinking about a lot of things, and I've continued to expand on them both in the book and in presentations since then. 

There is a lot of content in the book about working with tools like SCC, static analysis, and unit test frameworks to build better software more efficiently.  I think if I were to sum up the focus, it is that we as developers owe it to our project sponsors to work efficiently and effectively, and there are lots of incremental changes that can be made to the way we work, both in terms of tools and processes to make that happen. 

The reality of modern software development (mostly) is that since the physical constraints like CPU time and memory/disk space have largely fallen away, the goal of any development project (from a technical standpoint) should be optimized for developer productivity.  That includes a wide array of factors from readability of design, how clear developer intent is to future readers, and how resillient our software is to future change to reducing barriers to developer productivity like implementing a good CI process.  Working together as a team across disciplinary and physical boundaries is at least as big a challenge as writing good code. 

I agree very much with Scott that the why and how of software development are often just as important (and harder to get right) than just the what.  I hope that I have something to contribute to the discussion as we all figure it out together...

Friday, April 25, 2008 6:31:59 PM (Pacific Daylight Time, UTC-07:00)  #    Disclaimer  |  Comments [2]  | 
 Thursday, April 10, 2008
If you are doing anything even remotely involving Ajax or client side script, and you like Firefox like I like Firefox, go and get a copy of Firebug.  I quite literally don't know what I would do without it.  Firebug provides very comprehensive script debugging, allowing you to set breakpoints in your JavaScript, step through it, etc.  It also shows you all the requests and responses for all your post-backs, and lets you examine HTML, CSS, and script as well as the client side DOM at "run-time".  It's been invaluable in helping me figure out how ASP.NET Ajax is supposed to work and what's wrong with the JavaScript I'm writing (it's been a while). 





Good stuff.

 |  | 
Thursday, April 10, 2008 5:56:03 PM (Pacific Daylight Time, UTC-07:00)  #    Disclaimer  |  Comments [0]  | 

First, there was a few ideas rattling around in my head, then there was a blog post, and now you can buy the book. :-)


The most difficult challenges facing most of us these days are not about making code work.  That's relatively easy, compared to making code that you can work on and maintain with other people.  I've tried to bring together a bunch of issues and practical solutions for writing code with a team, including defining contracts, creating good tracing and error handling, and building a set of automatic tests that you can rely on.  In addition, there's a bunch in here about how to work with other developers using source control, continuous integration, etc. to make everyone's lives easier and more productive.
Thursday, April 10, 2008 5:41:33 PM (Pacific Daylight Time, UTC-07:00)  #    Disclaimer  |  Comments [1]  | 
Thanks to one of the other SoftSource guys here (yay, Ben!) we got the problem resolved.  Turns out if was also a problem under VS 2005, but only sometimes and nobody noticed.  Huh.  Anyway, there was a bit in the base page that was creating a control dynamically and inserting it into the control hierarchy.  In order to find out where it was supposed to go, it was recursively traversing the control hierarchy looking for the right one, before LoadViewState.  This causes the repeater to be created too early, and when ViewState comes along, it sees the control has already been created and so does nothing. 

This goes to show once again, just don't mess with the control hierarchy.  Nothing good can come of it.  Even better, just don't use repeaters and come up with a better way of doing things.  I'm finally doing some "real" Ajax using client side JavaScript to make asynchronous callbacks.  Sooooo much better than using update panels.  Yes, it requires writing JavaScript (of which I'm mildly scared) but it turns out to be pretty easy, and the pages are not only much more responsive, but much more deterministic in their behavior.  We're now essentially only rendering the full page once, then making all the changes client side.  The programming model is a bit harder, but the results are worth it.

Thursday, April 10, 2008 5:32:49 PM (Pacific Daylight Time, UTC-07:00)  #    Disclaimer  |  Comments [0]  | 
 Tuesday, March 25, 2008
Yes, once again repeaters and ViewState are the bane of my existence... 

We have several pages that follow essentially the same pattern:  we have repeaters that include text boxes/check boxes, etc.  We need to retrieve the values from those controls in order to get feedback from the user.  To do that, the controls themselves are set to AutoPostBack=true.  (To make things more complicated, these repeaters are sitting inside an ASP.NET Ajax UpdatePanel.) When the post back happens, we grab the updated values from the repeater items, save them, then re-databind the repeaters.  This is less than optimal, I have come to see, but it worked.  That's worked, past tense.  As soon as we moved the project to VS 2008, it completely fails to work.  I'm pretty sure that ViewState is involved, since essentially we were relying on the repeaters being populated from ViewState before being databound.  That seems to no longer be the case.  To make matters worse, when I tried to code up a trivial example to demonstrate the problem, it works fine.  Curses! 

I'm down to two possibly explanations, neither of which I've been succesful proving so far.  Either something in the page is touching those repeaters before LoadViewState, thus screwing up the object creation, or the new 3.5 version of Ajax is passing ViewState differently on Async PostBacks.  Either way, we're working around it right now, but it would still be nice to know what happened.

My key learning from this whole experience?  Repeaters are the work of the devil, and writing HTML by hand wasn't such a bad idea. :-)

Tuesday, March 25, 2008 5:43:11 PM (Pacific Daylight Time, UTC-07:00)  #    Disclaimer  |  Comments [0]  | 
I'll be speaking at next month's InnoTech Oregon conference, at the convention center April 16th and 17th.  The session is entitled "The Code is the Easy Part".  I'll be speaking on practical steps you can take to improve your software project, specifically around making it easier and more effective for developers to work together as a team.  Specific topics include starting a Continuous Integration process, effective use of source control, and using tests as a means of expressing developer intent.

It looks like there's a little something for everyone at the conference, including some stuff on development practices and "agile" methodologies.  Should be fun.

Tuesday, March 25, 2008 5:34:33 PM (Pacific Daylight Time, UTC-07:00)  #    Disclaimer  |  Comments [0]  | 
 Friday, March 14, 2008
Once again I'll be teaching at the Oregon Institue of Technology this coming Spring term.  This time around the topic is building an application using C# in Visual Studio 2008.  We'll be covering an entire application lifecycle, including design, coding, test, build and deploy.  We'll go into detail about effective use of source control, how to set up a Continuous Integration process, how to write good unit tests, etc.  Along the way we'll be covering some of the new .NET 3.5 features like LINQ and all that entails.

Spread the word, and come on down if you are interested.

The official course title is .NET Tools with C# (CST407) and it will be Wednesday nights at the Hillsboro campus.

Friday, March 14, 2008 6:02:43 PM (Pacific Daylight Time, UTC-07:00)  #    Disclaimer  |  Comments [0]  | 
 Tuesday, January 22, 2008
I've been poking around a bit with the new ASP.NET MVC stuff, and so far I am very favorably impressed.  Sure, there are some things to work out, but I think they represent exactly the right level of abstraction for getting serious work done.  One of the things I've noticed lately since I've been doing lots of ASP.NET work is that the "classic" (if that works here) ASP.NET postback model is very very good at making the trivial case trivial.  If all you want is a simple form that pretends to have button click events, it's super easy.  Unfortunately for many of us, however, it is also very very good at making less trivial cases really hard.  At some point (and relatively quickly, I think) we spend a lot of time fighting the ASP.NET model rather than taking advantage of it.  I have spent hours trying to deal with the fact that ASP.NET is trying to make me code like I was writing a windows forms application when what I'm really writing is a web app.  I shouldn't have to worry about whether or not I need to handle some bit of rendering in OnInit or OnPreInit.  I know what HTML I want, but ASP.NET can make it hard to get there.

The new MVC model is the level of abstraction I'd like to work at.  I know I'm writing a web app, so better to embrace that fact and deal with requests and responses rather than trying to pretend that I have button click events.  The MVC model will make it very easy to get the HTML I want without having to fight the model.  I haven't logged enough time to have found the (inevitable) rough edges yet, but so far if I was starting a new web project I'd definitely want to do it using the MVC model.  The fact that it is easy to write unit test code is an added bonus (and well done, there!) but what really strikes me as useful is the model. 

If you want a web app, write a web app!

Tuesday, January 22, 2008 9:38:41 PM (Pacific Standard Time, UTC-08:00)  #    Disclaimer  |  Comments [0]  | 
 Wednesday, December 26, 2007
A while back I was having a problem with getting events to fire from a drop down list inside a repeater.  In that case, I turned off ViewState for the Repeater control, and everything worked fine after that.  Well, last week I came upon a situation (much to complicated to go into here) where that just wouldn't work.  I needed the ViewState to be on, and knew there should be a reasonable way to make it work.  To make a (much too) long story short, after talking it through with Leo I discovered the error of my ways.  I was populating the items inside the drop down list during the Repeater's ItemCreated event.  Apparently that's bad.  I took exactly the same code and moved it to the handler for ItemDataBound, and everyone was happy.  Now I can leave ViewState on, correctly populate the items in the list, and actully get the SelectedIndexChanged event properly fired from each and every DropDownList. 

It's the little things...

Wednesday, December 26, 2007 8:13:48 PM (Pacific Standard Time, UTC-08:00)  #    Disclaimer  |  Comments [0]  | 
 Thursday, December 06, 2007
I happened to meet a woman the other day who grew up speaking Swiss German, and she said that one of the hardest bits of American slang for her to get the hang of was our use of "whatever" (usually with an !) to mean "that's the stupidist thing I've ever heard, but it's too trivial for me to take the time arguing with you about it".  That translation is mine, not hers.  Just look at how many works are saved with that simple but idiomatic usage.

So when I find that someone has changed the name of one of my variables (in several places) from "nextButton" to "nextBtn" causing me two separate merge conflicts, I'm glad we have that little word.

Whatever!

Thursday, December 06, 2007 10:56:06 PM (Pacific Standard Time, UTC-08:00)  #    Disclaimer  |  Comments [1]  | 
 Monday, December 03, 2007
My SoftSource compatriot Leo makes some good points about the overuse, or at least overreliance on unit testing.  I absolutely agree that you have to be clear about what the point of unit testing is.  Unit testing is for exercising all the possible paths through any given code, and verifying that it does what the author of that code thought that it should do.  That doesn't mean that it does what it is supposed to do in the context of a larger application.  That's why we have integration or functional tests.  It's up to whoever writes your functional tests (hopefully professional testers with specs in hand) to verify that the code does what the user wants it to do.  Integration tests will tell you if your code does what the developer in the cube next to you thinks it should. 

It's all about context.  It is folly to think that running a bunch of unit tests guarantees that the application will do what it should.  In fact, I'm working on a web project right now, and it is entirely possible for every unit test to pass with raging success and still not have the ASP.NET application start up.  That's a pretty clear case of the application not even running, even though all the tests pass.  The tests are still useful for what they provide, but there's a lot more to even automated testing than just validating that the code does what the author intended.

Tuesday, December 04, 2007 12:48:27 AM (Pacific Standard Time, UTC-08:00)  #    Disclaimer  |  Comments [1]  | 
If you are following a continuous integration strategy, breaking the build should be a big deal.  Most of the time, if the build is broken it's because someone forgot to check in a new file, or because they didn't update before committing their stuff.  Those are both pretty easily avoided.  One strategy that helps with missing files is to do your work in a task-specific branch, get everything checked in the way you think it should be, and then check out that branch to a separate location on your local system.  If it builds there too, then you probably aren't missing any file.  If you are, you'll know about it before you break the integration branch. 

As far as not updating before committing, there are a couple reasons why that might happen more than you would like.  If the build is constantly breaking, then people will be less likely to want to update before committing, since if the build is broken they won't be able to validate their changes, and will have to put off committing.  If your build process takes too long (more than 10 minutes including unit tests) then updating and building before committing will be painful, and people won't do it.  Of couse, sometimes it's simple laziness, but that just needs to be beaten out of people. :)  The other things are fixable with technology, which is easier than getting people to do the right thing most of the time.

To make the process easier for everyone, don't commit any changes after the build breaks unless those changes are directly related to fixing the build.  If they aren't, then those additional commits will also cause failing builds, but now the waters have been muddied and it is harder to track down which changes are causing failures.  If the build breaks, then work on fixing it rather than committing unrelated changes that make it harder to fix the real problem. 

Monday, December 03, 2007 10:44:06 PM (Pacific Standard Time, UTC-08:00)  #    Disclaimer  |  Comments [1]  | 
 Thursday, November 15, 2007
I know it's been a bit quiet hereabouts of late.  I'm in the middle of a writing project, as well as a (relatively) new work situation still, and trying to catch up from the fact that my knowledge of ASP.NET basically consisted of "there's code behind" before.  So far my feelings are mixed.  Sometimes I think ASP.NET if pretty darned clever.  Other days I find myself longing for the days of CGI, when at least it was easy to understand what was supposed to happen.  Those days usually have something to do with viewstate. :-)  Anyway...

I've also been learning about the ASP.NET Ajax goodies, and ran into an interesting problem.  If you are using UpdatePanel, you absolutely cannot mess with the control hierarchy after the update panel has been created.  If you do, you'll be presented with an helpful error that basically reads "you've screwed something up!".  It took a while to get to the root of the problem given that input.  Turned out that the update panel was in markup for my page, but somewhere between when it got created and OnInit for the page, the control hiearchy was being changed.  I won't go into detail about how, but suffice it to say stuff in the page got wrapped with some other stuff, thereby changing the hierarchy.  Nobody else seemed to mind, except for the updatepanel.  Too make a potentially very long story only slightly long, as long as all of the screwing around with the controls is done in or prior to OnPreInit for the page, all is well.  Once that change was made everything was happy, and the update panels work fine. 

The page lifecycle is possibly one of the great mysteries of our time...

Thursday, November 15, 2007 6:24:37 PM (Pacific Standard Time, UTC-08:00)  #    Disclaimer  |  Comments [2]  | 
 Wednesday, October 17, 2007
OK, I'm the first to admit that when it comes to writing ASP.NET I'm a complete newbie.  Before I started on the project I'm currently working on I'd probably written less than 10 ASP.NET pages.  So maybe this is obvious to the set of all people not me.  But I think maybe not.

I've got a repeater inside a form.  Each item in the repeater is composed of three DropDownList controls.  Those dropdowns are populated via databinding.  When the user has made all of their selections using the dropdowns, the hit the "go" button and a PostBack happens.  I spent the last full day (like since this time yesterday) trying to figure out why no matter what I tried I couldn't retrieve the value the user selected after the form posted back.  Gone.  Every time I got the post back, all of the dropdowns has a selected index of -1. *@!~#!!

I was pretty sure I had the overall pattern down right, since just the day before I made this work in another page that used textboxes instead of dropdownlists.  See the dent in my forehead from the keyboard?  Sure, initially I had some other problems like repopulating the data in the drop downs every time, etc., but I got past that.

Google proved comparatively fruitless.  Lots of people couldn't figure out how to databind the list of items to the drop down, but nobody was talking about posting back results.  The lightening struck, and I found a reference to someone having problems with events not firing from drop down lists if the repeater's ViewStateEnabled == true.  Granted, I'm not hooking up the events, but you never know. 

That was it. 

<asp:Repeater ID="medicationRepeater" runat="server" EnableViewState="false">

Now the PostBack works just like I would expect.  Why this should be is completely beyond my ken.

Anyone?
              

Wednesday, October 17, 2007 8:25:06 PM (Pacific Daylight Time, UTC-07:00)  #    Disclaimer  |  Comments [1]  | 
Refactoring is cool.  Really cool.  It also means something very specific.  There's a book and everything.  If you haven't read it, you should. (Hint: it's by Martin Fowler)

Refactoring means reducing code smells by making small, incremental, orderly, and very specific changes to existing code.  Make such changes (one at a time) allows one to improve the structure of existing code without changing its functionality.  Always a good thing.  Refactorings have very specific names like "extract method" or "encapsulate field" or "push member up".  Again, there's a book.  You can look them up.

Where is this going?, you might ask.  I already know this, you say.  Cool.  Then let's move on to what refactoring (Refactoring?) isn't.

Refactoring doesn't mean changing code because you think your way would have been better.  It doesn't mean rewriting things from scratch because you have a different opinion.  It doesn't mean starting over again and again in pursuit of the perfect solution to every coding problem. 

Those other things have names (which I won't mention here for the sake of any children reading this), but "Refactoring" isn't among them.  There's a tie-in here with another term we all love, "Agile".  Refactoring fits into an "agile" process after you've made everything work they way it should (i.e. passes the tests) to make it easier to work with the code on the next story/backlog item/iteration.  The point of agile development (IMHO) is to write as little code a possible to meet your requirements.  It doesn't mean redoing things until you end up with the least possible amount of code, measured in lines.  Again, that has a different name. 

Sometimes code needs to be fixed.  More often than we'd like, in fact.  But if you are (re)writing code in pursuit of the most bestest, don't call it Refactoring.  It confuses the n00bs. 

Wednesday, October 17, 2007 7:22:00 PM (Pacific Daylight Time, UTC-07:00)  #    Disclaimer  |  Comments [0]  | 
 Thursday, September 20, 2007
This came up at work this week, so I thought I'd disgorge my views on the issue.  The question at hand is whether or not every method needs to validate its input parameters. 
For example, if I have a method

    public class Example

    {

        public int DoThingy(SomeObject obj)

        {

            return obj.GetImportantValue();

        }

    }


This method depends on the value of obj not being null.  If a caller passes a null, the framework will, on my behalf, throw a NullReferenceException.  Is that OK?  Sometimes it might be, and we'll come back to that.
The alternative is for me to validate my input parameters thusly:

        public int DoThingy(SomeObject obj)

        {

            if (obj == null)

                throw new ArgumentNullException("obj");

 

            return obj.GetImportantValue();

        }


The discussion we got into was wether this was really necessary or not, given that the Example object only got used in one place, and it would require extra code to validate the parameters.  The assertion was made by more than one person that the NullReferenceException was just fine, and that there was no need to do any validation. 
My $.02 on the matter was (and is) that if you don't do parameter validation, you are not upholding and/or communicating your contract.  Part of the contract implied by DoThingy() is that you have to pass a non-null SomeObject reference.  Therefore, in order to properly communicate your contract, you should throw an ArgumentNullException, which informs the caller exactly how they have violated there half of the contract.  Yes, it's extra code.  No, it may never be necessary.  A whole different subject is whether of not "fewest possible lines of code" is a design goal.  I'm going to avoid going there just now.

That said, there are obviously mitigating circumstances that apply.  If the object in question is really only called in one place, upholding the contract is less of a concern, since you should be able to write tests that cover the right cases to make sure the caller never passes null. Although that brings up a separate issue.  If the method only had one caller, which is it in a separate object at all?  Again, we'll table that one.  In addition, since in this particular case the DoThingy() method only takes one parameter, we don't have to wonder to hard when we get a NullReferenceException where the culprit is. 

The other issue besides contract is debugging.  If you don't check your input, and just let the method fail, then the onus is on the caller to figure out what the problem is.  Should they have to work it out?  If the method took 10 parameters, all reference types, and I let the runtime throw NullReferenceException, how long will it take the consumer to find the problem?  On the other hand, if I validate the parameters and throw ArgumentNullException, the caller is informed which parameter is null, since the onus was on me to find the problem. 

One last reason...  If I validate my input parameters, it should leave me with fewer failure cases to test, since the error path is potentially much shorter than if the runtime handles it.  Maybe not much of a savings, but it's there.

Thoughts?

Thursday, September 20, 2007 11:10:41 PM (Pacific Daylight Time, UTC-07:00)  #    Disclaimer  |  Comments [11]  | 
I was having some issues with using a straight keyboard and regular old mouse, since I've been using only trackballs and trackpads for years now, so I got hooked up with some new gear.  It's only been a few days, but so far I'm pretty impressed.  I got the Microsoft Natural Ergonomic Keyboard 4000, and the Evoluent VerticalMouse 3.  The keyboard is very comfortable (as I type this) and has an optional support that props up the front of the keyboard, which keeps your hands flatter.  I wasn't sure about the lift at first, but now I'm sold.  It's quite comfy, although it did take me a day or two to get used to it.  The buttons are laid out very nicely, with a real inverted T arrow key setup.  My only complaint so far is that the spacebar clacks.  But since I usually work with headphones on, it will only really annoy my neighbors. :-)
The most is also quite comfortable, although I think I still need to get my chair adjusted a bit to deal with the desk height and the new mouse.  The VerticalMouse is just that.  It's a nice optical mouse, but oriented vertically instead of horizontally, so that you hold your hand perpendicular to the desk, rather than on top of it.  It seems like a much more natural hand position.  The buttons have a nice feel, as does the scroll wheel.  Because of the layout, the third button has to be pressed with the pinky (at least for me) which seems a bit awkward, but I'm sure I'll get used to it. 
Oh, yeah.  And I got a new car.  My Durango finally gave up the ghost after 9 years and over 230K miles.  RIP.  I got a 2007 Subaru Outback 2.5i, and so far I'm loving it.  Very comfy, handles nice.  About twice the mileage of the Durango.  We'll see how it does pulling a trailer.  The hitch goes on today, with luck.
Fall seems to be the season of change for me this year.  And it seems to have come early.  It's started getting much chillier at night just over the last week or so.  OK, now I'm rambling. 

 | 
Thursday, September 20, 2007 5:15:43 PM (Pacific Daylight Time, UTC-07:00)  #    Disclaimer  |  Comments [0]  | 
 Friday, September 07, 2007
We're looking for well qualified and excited individuals for positions in engineering, QA, and project management.  If you like working on a wide variety of projects, come and join our merry band!  Check out the SoftSource site for more details.

Friday, September 07, 2007 5:39:26 PM (Pacific Daylight Time, UTC-07:00)  #    Disclaimer  |  Comments [0]  | 
 Thursday, September 06, 2007
The project I'm working on right now uses SourceGear Vault for SCC, and I must admit, I'm not digging it.  It's like using a slightly more performant version of VSS.  Except that you can set it in "CVS mode" which means it doesn't do exclusive locks.  It seems very difficult to deal with adding new files (if you aren't integrating with VS.NET, which we aren't) and updates seem unreasonably slow, although that may just be me.  It is a pretty big project.  Doing a "Show history" on the whole tree takes over a minute to return any results at all.  It does do change sets, at least, so that's a big plus over VSS. 
In short, I can see tha market here (for people that are comfortable with VSS, but don't want Access databases for their backend) but I'd rather be using Subversion.  I guess I'm just spoiled.

Thursday, September 06, 2007 10:26:07 PM (Pacific Daylight Time, UTC-07:00)  #    Disclaimer  |  Comments [1]  | 
 Friday, August 31, 2007

For the last week (at my new gig) I've been using ReSharper 3.0, and I must say I'm pretty darned impressed.  I hadn't looked at ReSharper since the very early versions, and had sort of written it off in favor of CodeRush/Refactor, but ReSharper 3 has some pretty compelling features...

  • ReSharper parses your code outside of the compiler, and therefore knows stuff the compiler couldn't, like when you reference something in another namespace without the proper using directive in place, and ReSharper figures out which namespace you mean, and asks if you'd like to add the reference.  Slick.
  • Inline suggestions.  ReSharper parses your code and offers up both errors (in an easier way the VS.NET, IMHO) and suggestions, such as "you really could make this field readonly".  These errors and suggestions are also displayed in a sidebar next to the scroll bar as red, green or yellow lines, so you can scroll the the problems quickly.  Nice.
  • Integrated NUnit support.  I love the way ReSharper handles NUnit integration.  You get little buttons in the right hand sidebar (where your breakpoints show up) that allow you to run or debug individual tests or the whole fixture.  The results get put in a custom results pane, much neater than the text based report you get from TestDriven.NET.  If you happen to have JetBrains profiler, that's integrated as well. 
  • Clever autocompletion.  I know I probably shouldn't be so impressed with this one, but just this morning I wrote a line that returned an IEnumerable, then on the next line typed foreach, and it completed the whole block, figured out the right types, etc.  Very clean.
  • Nice refactoring support.  I haven't had too much time to play with this yet, but it looks like it supports a goodly number of refactorings.  Cool.

I'm looking forward to playing with it more in the days to come.

Friday, August 31, 2007 4:49:06 PM (Pacific Daylight Time, UTC-07:00)  #    Disclaimer  |  Comments [1]  | 
 Wednesday, August 22, 2007

Things have been a bit quiet here lately, largely due to a lot of change and a lot of heads down work.  The end result is that today marks my final day at Corillian Corp. (now a part of CheckFree).  It's been a great almost 4 years of working to improve the lives of people building (and hopefully using) online banking sites, but it's time for a change.  I'm going back to consulting after a 6 year hiatus in the product world.  Come Monday morning, I start work at SoftSource Consulting where I'm hoping to continue to build cool stuff, one customer at a time. 

In the mean time, I'm off for the woods.  Hopefully I'll have some good pictures to post on Monday.

Wednesday, August 22, 2007 9:44:25 PM (Pacific Daylight Time, UTC-07:00)  #    Disclaimer  |  Comments [1]  | 
 Tuesday, August 14, 2007

You all know this.  I (in theory) know this.  However, just to remind everyone (and apparently myself)...

When debugging anything related to WCF, there are a set of problems that are IMPOSSIBLE to discover without looking at the service trace logs.  In particular (this is the one that bit me) for very good reasons, nothing security related gets as far as application code.  You pretty much get "something bad happened". 

Anyway, after beating my head against the keyboard for a good solid day, I remembered this little maxim, and checked the logs.  There was the problem, plain as day.  Doh!  Turned out that I'd changed the namespace of a particular class, and failed to propagate that change to my .svc file.  There is absolutely no indication that this was the problem at the app level, but on looking at the logs, it's right there. 

Hopefully I'll remember that one next time.

 | 
Tuesday, August 14, 2007 9:20:17 PM (Pacific Daylight Time, UTC-07:00)  #    Disclaimer  |  Comments [0]  | 
 Wednesday, July 18, 2007

I decided a while back that I had too much extraneous junk running on my development machine and it was time to scale back.  Fist to go were Google Desktop, and Microsoft Desktop Search, both of which had been competing to see who could eat the most cycles and thrash my drives the worst.  Next on the list was TortoiseSVN.  Tortoise's cache seemed to be eating an awful lot of CPU time.  "How ever will I manage to deal with SVN without it?", I found myself wondering.  The reply came back "have you become completely feeble in your old age? Once you lived by PVCS, before there was such a thing as a decadent SCC GUI!". 

So I figured I'd give it a go.  The results have been pretty good so far, although it has taken me a while to get used to the svn.exe command set.  On the up side, it seems much faster than Tortoise, with updates in particular taking much less time.  The thing I find myself missing the most if the commit dialog, where you can uncheck stuff you don't want to commit right now.  Living without that makes for some extra typing, but overall it's still worth it.

The one thing that's a major hassle is browsing the repository.  If I have to figure out where someone shoved something in which repository, I've been falling back on another machine with Tortoise installed.  Lame?  Possibly.  I couldn't find anything approximating a non-Tortoise GUI SVN repository browser.  Maybe there is one, and I just haven't heard. 

So overall, I'm not quite ready to go back to edlin for text files, but the svn command line is treating me pretty well.  We'll see if I ever come to some watershed event where I decide to go back to the GUI.  That day may well come, but it's not on the horizon just yet.

Wednesday, July 18, 2007 5:57:58 PM (Pacific Daylight Time, UTC-07:00)  #    Disclaimer  |  Comments [10]  | 
 Monday, July 09, 2007

Lately we've been experiencing one of the downsides of all the tooling we've put into our continuous integration practice.  It's fragile.  Trying to get all your tools lined up with versions that all get along is tricky, and hard to keep balanced.  Particularly when two of them (NCover and TypeMock) both try to register themselves as profiles, and have to be chained to keep the tests running while gathering coverage information.

I think we've just about got everybody moved up to the right versions, but there's been lots of "it works on my machine" the last week or so. 

The price you pay, I guess.

Monday, July 09, 2007 9:15:03 PM (Pacific Daylight Time, UTC-07:00)  #    Disclaimer  |  Comments [0]  | 
 Tuesday, June 26, 2007

A while back I posted about how we're implementing denials using AzMan.  This week, a helpful reader pointed out that with a little extra math, I could save a call into AzMan (with all the attendant COM interop, etc.).

So, instead of my previous

 

object[] grantOps = new object[] { (object)1, (object)2, (object)3, (object)4};

object[] denyOps = new object[] { (object)100001, (object)100002, (object)100003, (object)100004 };

 

 

object[] grantResults = (object[])client.AccessCheck("check for grant", scopes, grantOps, null, null, null, null, null);

object[] denyResults = (object[])client.AccessCheck("check for deny", scopes, denyOps, null, null, null, null, null);

 

for (int i = 0; i < grantResults.Length; i++)

{

    if(((int)grantResults[i] == 0) && ((int)denyResults[i] != 0))

        Console.WriteLine("Grant");

    else

        Console.WriteLine("Deny");

}

 

I can do it in one call like so

object[] allOps = new object[8];

grantOps.CopyTo(allOps, 0);

denyOps.CopyTo(allOps, 4);

object[] allResults = (object[])client.AccessCheck("check for grant and deny", scopes, allOps, null, null, null, null, null);

for(int j = 0; j < grantOps.Length; j++)

{

    if (((int)allResults[j] == 0) && ((int)allResults[j + grantOps.Length] != 0))

    {

        Console.WriteLine("Grant");

    }

    else

        Console.WriteLine("Deny");

}

 

It does mean you have to be a little careful about getting the indexes straight, but that's probably worth the savings you'll get by not making the extra COM call. 

Every little bit helps...

 | 
Tuesday, June 26, 2007 4:12:39 PM (Pacific Daylight Time, UTC-07:00)  #    Disclaimer  |  Comments [3]  | 
 Friday, June 15, 2007

I think I've come across a better solution (or at least one that I'm happier with) to this problem.  Turns out that the KnownType attribute can take a method name instead of a type.  The type it's applied to then has to implement a static method with that name that returns an array of Type.  That method can then decide which types to return.  So I could do something like this

[DataContract]

[KnownType("CheckForConfiguredOverrides")]

public class UserBase

{

    [DataMember]

    public string FirstName;

    [DataMember]

    public string LastName;

 

    public static Type[] CheckForConfiguredOverrides()

    {

        List<Type> result = new List<Type>();

 

        string thisTypeName = typeof(UserBase).FullName;

        string overrideType = System.Configuration.ConfigurationManager.AppSettings.Get(thisTypeName);

        if (!string.IsNullOrEmpty(overrideType))

        {

            Type type = Type.GetType(overrideType);

            if (type != null) result.Add(type);

        }

 

        return result.ToArray();

    }

}

Then in the config file (this ultimately will use our distributed configuration service) I add

<appSettings>

  <add key="UserBaseType.UserBase" value="UserBaseType.BankUser"/>

</appSettings>

 
To return the right type.  Everybody is happy!  As a side benefit, this allows me to limit "overridability" to only those types I apply the attribute to.  That lets me (as the designer) decide which types are OK to subclass and which aren't (obviously I could use sealed here as well, but that's a separate issue) using this KnownType attribute.  I think this will work out much better than marking up base classes with specific types.

 | 
Friday, June 15, 2007 7:43:46 PM (Pacific Daylight Time, UTC-07:00)  #    Disclaimer  |  Comments [0]  | 

This may have been understood by the set of all people not me, but I didn't realize that the KnownType attribute doesn't seem to work on a MessageContract.  The KnownType attribute is supposed to tell the data contract serializer that there might be some extra types it needs to know about when serializing your objects.  It's equivalent to the XmlInclude attribute used by the XmlSerializer.  If I have some code that looks like this...

[MessageContract]

public class UserRequest

{

    [MessageBodyMember]

    public string UserName;

    [MessageBodyMember]

    public bool SendExtended = false;

}

 

[MessageContract]

public class UserResponse

{

    [MessageBodyMember]

    public string Message;

    [MessageBodyMember]

    public UserBase User;

}

 

[DataContract]

public class UserBase

{

    [DataMember]

    public string FirstName;

    [DataMember]

    public string LastName;

}

 

[DataContract]

public class BankUser : UserBase

{

    public BankUser() : base() { }

 

    [DataMember]

    public int TupperwarePoints;

 

}

In my server side implementation, if the "SendExtended" flag is true in the UserRequest, the object returned in the "User" property of the UserResponse is a BankUser, not a UserBase object.  If the code runs like this, that fails horribly, since the data contract serializer is set to serialize a UserBase, not a BankUser. 

I would have thought that I could mark up the UserResponse, like so

[MessageContract]

[KnownType(typeof(BankUser))]

public class UserResponse

{

    [MessageBodyMember]

    public string Message;

    [MessageBodyMember]

    public UserBase User;

}

Turns out this totally doesn't work.  I get the same serializer error, despite the KnownType attribute.  If I make UserResponse a DataContract instead of a MessageContract, it works fine, and the appropriate BankUser object is received on the client side. 

However, in my actual code, I need the MessageContract.  The alternative is marking up the UserBase class itself, like this:

[DataContract]

[KnownType(typeof(BankUser))]

public class UserBase

{

    [DataMember]

    public string FirstName;

    [DataMember]

    public string LastName;

}

This works just fine, but from a design standpoint it's teh suck.  This means that I have to tell my base class about all it's derived types, thus defeating the entire point of inheritance.  That's why I never used the XmlInclude attribute.  I might have to rethink how the messages are composed and see if there's a better way to encapsulate things.

On a slightly unrelated note, it seems that my ServiceHost takes much longer to start up when the Request and Response are defined as MessageContract than when they are straight DataContracts.  I haven't tested this extensively, so it's anecdotal, but interesting nonetheless. 

 | 
Friday, June 15, 2007 5:37:14 PM (Pacific Daylight Time, UTC-07:00)  #    Disclaimer  |  Comments [2]  | 

Check out the latest Hanselminutes to hear Scott and I chatting with Carl about the latest language features in Visual Studio 2008 ("Orcas"), static vs. dynamic languages, and whatever else came up.

There are some very cool features coming up in C# 3.0, which while they are there mainly to enable LINQ, provide a number of opportunities for reducing the amount of extra code we write, and enabling a closer link between code written and developer intent.  Pretty exciting stuff.

 | 
Friday, June 15, 2007 4:34:34 PM (Pacific Daylight Time, UTC-07:00)  #    Disclaimer  |  Comments [1]  | 
 Friday, June 08, 2007

I finished up the day yesterday with Kathy Kam's talk on Acropolis, and watched the irrepressible Ed Pinto and Kenny Wolf describe WCF internals (which involves juggling, apparently).  The Acropolis talk was too short, and could have included a lot more detail.  It felt like brochure-ware.  Ed and Kenny's talk packed more detail than one human being could absorb in 75 minutes about the channel stack, and how behaviors can be used to influence it, as well as other gooey details about the inner machinations of WCF.  Very useful.  I think it'll take me a few hours with the slides to let it all sink in fully. 

Last night's party was a blast as usual.  I now know that the only think more fun that riding rollercoasters with drunk nerds is riding rollercoasters with drunk nerds in the pouring rain.  :-)  They shut down the rides for quite some time due to lightning, but I did squeeze in a few hair raising trips on the 'coasters, as well as plenty of general carousing.  A good time was had by all. 

Now it's time to head home and sleep for a few days.  There's nothing like sitting through 4-5 technical presentations and walking 3-4 miles a day for a week to wear a body out.

 | 
Friday, June 08, 2007 2:01:32 PM (Pacific Daylight Time, UTC-07:00)  #    Disclaimer  |  Comments [1]  | 
 Thursday, June 07, 2007

I went to a more detailed (possibly too detailed) presentation on the ADO.NET entity model this morning.  This is pretty exciting stuff, although obviously people will have some reservations.  It's easy to dismiss EDM as just another in a long line of O/R mapping attempts, and while that's a valid criticism, I think there are some interesting and instructive differences.  Because EDM is built on top of support all the way down at the ADO.NET provider level, it's more than just an O/R map.  You can define entities (this is done using XML files for now) that span multiple tables, or otherwise hide complex structures in the underlying data store, as well as defining relationships between those entities that express a higher level relationship than a relational foreign key.  These relationships can be navigated at a much higher level, without having to deal with complex joins, etc.  Because that the Entity Model actually passes down to the data provider is an expression tree, the data provider is free to optomize into its native dialect as best it can.  So when you are taking advantage of complex relationships in your entity model, you aren't just fetching a bunch of objects and then making them relate to one another.  That relationship is handled at the provider level in ways that can be optimized, so that you aren't bringing back any more data then necessary. 

Plus, because of the deep support at the provider level, you can specify a query using the simplified entity syntax, but still return a forward only dataset for best performance, skipping the object translation step all together. 

Granted, they still have quite a bit of work ahead of them to improve the tooling, and make it as transparent as possible, but I think there's a lot of value to be had here. 

I'm looking forward to taking some time with the bits and trying out some different scenarios, so hopefully I'll have some good examples later.

 | 
Thursday, June 07, 2007 6:22:39 PM (Pacific Daylight Time, UTC-07:00)