Random Thoughts of a Scatterbrain.
 Friday, September 21, 2007

Programmathon VII Begins!

9/21/2007 11:41:20 PM (Eastern Daylight Time, UTC-04:00)

So I'm back in Utah.  Today is day one of Programmathon VII. This time, we have two new faces, Dan and Thuy (all the ways from Vietnam!)

The highlight of any of the Programmathons are the meals and awesome sightseeing that we get to do while we're out in Utah (some trips being more memorable than others) to break up the long hours of work and occassional heated technical debates.  Of course Brad would probably disagree: the highlights of the Programmthons are really the 14 hour days we pull to get things done.

We ended up at Park City for dinner on day one.

The steak at Grub Steak was pretty good (and so was the atmosphere), but the waiter totally oversold the awesome-ness of their steaks.  7.5/10.

Luckily, I ended up with a Honda Odyssey instead of the Ford Freestar I was supposed to get.  This thing has some guts...no problem hauling 7 full grown adults up some pretty steep climbs.

Park City is a quaint little area.  The main street is lined with all sorts of eateries, expensive art galleries (expensive).  From left (above): Jim, Dave, Thuy, Me, Dan, and Brad.

More pictures with the locals.

Ice cream at Cow's.  Very good stuff.

Seems like the calm before the storm.  Only a few days left to wrap up version 1.

 Thursday, September 20, 2007

I Don't Like To Get Political, But...

9/20/2007 1:58:51 PM (Eastern Daylight Time, UTC-04:00)

A Republican leader with some balls, some heart, and most importantly, lots of humanity.

Well said, sir, well said:

Mayor Sanders: "With me this afternoon is my wife, Rana.

"I am here this afternoon to announce that I will sign the resolution that the City Council passed yesterday directing the city attorney to file a brief in support of gay marriage [with the California Supreme Court].

"My plan, as has been reported publicly, was to veto that resolution, so I feel like I owe all San Diegans an explanation for this change of heart.

"During the campaign two years ago, I announced that I did not support gay marriage and instead supported civil unions and domestic partnerships.

"I have personally wrestled with that position ever since. My opinion on this issue has evolved significantly -- as I think have the opinions of millions of Americans from all walks of life.

(Sanders with lesbian City Councilmember Toni Atkins)
"In order to be consistent with the position I took during the mayoral election, I intended to veto the council resolution. As late as yesterday afternoon, that was my position.

"The arrival of the resolution -- to sign or veto -- in my office late last night forced me to reflect and search my soul for the right thing to do.

"I have decided to lead with my heart -- to do what I think is right -- and to take a stand on behalf of equality and social justice. The right thing for me to do is to sign this resolution.

"For three decades, I have worked to bring enlightenment, justice and equality to all parts of our community.

"As I reflected on the choices that I had before me last night, I just could not bring myself to tell an entire group of people in our community that they were less important, less worthy and less deserving of the rights and responsibilities of marriage -- than anyone else -- simply because of their sexual orientation.

"A decision to veto this resolution would have been inconsistent with the values I have embraced over the past 30 years.

"I do believe that times have changed. And with changing time, and new life experiences, come different opinions. I think that's natural, and certainly it is true in my case.

"Two years ago, I believed that civil unions were a fair alternative. Those beliefs, in my case, have since changed.

"The concept of a 'separate but equal' institution is not something that I can support.

"I acknowledge that not all members of our community will agree or perhaps even understand my decision today.

"All I can offer them is that I am trying to do what I believe is right.

"I have close family members and friends who are members of the gay and lesbian community. These folks include my daughter Lisa and her partner, as well as members of my personal staff.

"I want for them the same thing that we all want for our loved ones -- for each of them to find a mate whom they love deeply and who loves them back; someone with whom they can grow old together and share life's wondrous adventures.

"And I want their relationships to be protected equally under the law. In the end, I could not look any of them in the face and tell them that their relationships -- their very lives -- were any less meaningful than the marriage that I share with my wife Rana. Thank you."

Touching, well thought out, reflective, compassionate, and sincere.

A hand for Jerry Sanders.

 Thursday, September 13, 2007

Double Dispatch To The Rescue

9/13/2007 9:55:42 AM (Eastern Daylight Time, UTC-04:00)

In working out a tricky design issue surrounding the usage of the Visitor pattern, I stumbled upon the related Double Dispatch pattern/mechanism.

In short, double dispatch, when implemented, allows an object - a "dispatcher" - to delegate method calls based on the runtime type or types involved in the interaction.

The two core problems with visitor are that:

  1. You must have access to the visitable object to implement an IVisitable interface.  Often times, when dealing with binary code references, this is not an option.
  2. Each visitor must implement IVisitor, regardless of whether all of the Visit() interactions make any sense.  This means that if there are 10 concrete IVisitable classes, then each IVisitor must implement 10 Visit() methods that support each of the concrete classes, even if the particular IVisitor has no valid operations on a given IVisitable.

I suppose point number 1 is not really a constraint, it's just that it's a criterion for a by-the-book visitor pattern implementation.  But point number 2 is a really sticky situation since in many cases, not all of the IVisitor concrete classes should support all of the IVisitable concrete classes.  Of course we could just add a blank method stub, even for operations that don't make sense, but that just seems like bloat and a maintenance nightmare.

The key in understanding the use of double dispatch is to understand the core issue with the Visitor pattern.  We want the visitor to perform different operations based on the runtime type passed into a call to an abstract Visitor base class.  Unlike method overloading, which relies on compile time types to determine the method to invoke, we want the code to decide which method to invoke based on the runtime type of the object being passed in.

Ideally, we could have a scenario like this:

public class Program {
    private static void Main(string[] args) {
        Collection<AbstractVisitor> visitors 
			= new Collection<AbstractVisitor>();
        Collection<Pet> pets = new Collection<Pet>();

        pets.Add(new Fish());
        pets.Add(new Dog());

        visitors.Add(new Feeder());
        visitors.Add(new Walker());

        // Visit each of the pets.
        foreach (Pet pet in pets) {
            foreach (AbstractVisitor visitor in visitors) {
                visitor.Visit(pet);
            }
        }
    }
}

/// <summary>
/// Abstract base class for visitors.
/// </summary>
public abstract class AbstractVisitor {
    public abstract void Visit(Pet pet);
}

/// <summary>
/// Concrete visitor, a pet feeder.
/// </summary>
public class Feeder : AbstractVisitor {
    public void Visit(Dog dog) {
        // Feed the dog
        dog.Visitors.Add("Fed the dog");
    }

    public void Visit(Fish fish) {
        // Feed the fish
        fish.Visitors.Add("Fed the fish");
    }
}

/// <summary>
/// Concrete visitor, a pet walker.
/// </summary>
public class Walker : AbstractVisitor {
    public void Visit(Dog dog) {
        dog.Visitors.Add("Walked the dog");
    }

    // Fish can't be walked!
}

But this code doesn't work!  Both Walker an Feeder must now implement Visit(Pet pet) like so:

/// <summary>
/// Abstract base class for visitors.
/// </summary>
public abstract class AbstractVisitor {
    public abstract void Visit(Pet pet);
}

/// <summary>
/// Concrete visitor, a pet feeder.
/// </summary>
public class Feeder : AbstractVisitor {
    // Yucky if block...
    public override void Visit(Pet pet) {
        if(pet is Dog) {
            Visit(pet as Dog);
        }
        if(pet is Fish) {
            Visit(pet as Fish);
        }
    }
    
    public void Visit(Dog dog) {
        // Feed the dog
        dog.Visitors.Add("Fed the dog");
    }

    public void Visit(Fish fish) {
        // Feed the fish
        fish.Visitors.Add("Fed the fish");
    }
}

This is a less than desirable situation since for every new pet type we introduce, we need to introduce another entry in the if-else block. Yuck. 

While there were many articles on how to implement double dispatch in C# using various techniques, by far, the simplest implementation that I found was one by Anthony Cowley.

So let's see how our code would look using this technique (I'll omit the implmentation of the abstract visitor class for now):

public class Program {
    private static void Main(string[] args) {
        Collection<AbstractVisitor> visitors 
			= new Collection<AbstractVisitor>();
        Collection<Pet> pets = new Collection<Pet>();

        pets.Add(new Fish());
        pets.Add(new Dog());

        visitors.Add(new Feeder());
        visitors.Add(new Walker());

        // Visit each of the pets.
        foreach (Pet pet in pets) {
            foreach (AbstractVisitor visitor in visitors) {
                visitor.Visit(pet);
            }
        }

        // Check the results.
        foreach(Pet pet in pets) {
            Console.Out.WriteLine(pet.GetType().Name);
            foreach(String note in pet.Visitors) {
                Console.Out.WriteLine("\t{0}", note);
            }
        }
    }
}

/// <summary>
/// Concrete visitor, a pet feeder.
/// </summary>
public class Feeder : AbstractVisitor {
    public void Visit(Dog dog) {
        // Feed the dog
        dog.Visitors.Add("Fed the dog");
    }

    public void Visit(Fish fish) {
        // Feed the fish
        fish.Visitors.Add("Fed the fish");
    }
}

/// <summary>
/// Concrete visitor, a pet walker.
/// </summary>
public class Walker : AbstractVisitor {
    public void Visit(Dog dog) {
        dog.Visitors.Add("Walked the dog");
    }

    // Fish can't be walked!
}

/// <summary>
/// Base class for pets.
/// </summary>
public abstract class Pet {
    private readonly Collection<string> visitors;

    public Collection<string> Visitors {
        get { return visitors; }
    }

    protected Pet() {
        visitors = new Collection<string>();
    }
}

/// <summary>
/// A pet fish.
/// </summary>
public class Fish : Pet {}

/// <summary>
/// A pet dog.
/// </summary>
public class Dog : Pet {}

When I run this program, I get the following output:

As expected, the dog was walked and fed, but the fish was only fed. Now we can go about adding pets to our heart's content and we won't be forced to add another Visit() method declaration. If there is no Visit() method implemented for a particular pet type, then nothing happens and the default implementation of Visit() on the abstract class handles it. The magic all happens in Cowley's implementation of AbstractVisitor:

/// <summary>
/// Abstract base class for visitors.
/// </summary>
public abstract class AbstractVisitor {
    private static readonly Dictionary<long, MethodInfo> dispatch;

    static AbstractVisitor() {
        dispatch = new Dictionary<long, MethodInfo>();

        foreach (Type t in Assembly.GetCallingAssembly().GetTypes()) {
            if (t.IsSubclassOf(typeof(AbstractVisitor))) {
                foreach (MethodInfo mi in t.GetMethods()) {
                    if (mi.Name == "Visit") {
                        ParameterInfo[] pars = mi.GetParameters();
                        if (pars.Length == 1) {
                            Int64 code = ((Int64)t.GetHashCode() << 32) +
                                pars[0].ParameterType.GetHashCode();
                            dispatch.Add(code, mi);
                        }
                    }
                }
            }
        }
    }

    public virtual void Visit(object pet) {
        Int64 hash = ((Int64)GetType().GetHashCode() << 32) + 
            pet.GetType().GetHashCode();
        if (dispatch.ContainsKey(hash)) {
            dispatch[hash].Invoke(this, new object[] { pet });
        }
        else {
            // This is our fallback functionality
            Console.WriteLine("Visiting object " + pet.ToString());
        }
    }
}

You may have spotted an issue here: since the Visit() method is virtual, the subclasses of AbstractVisitor aren't strictly forced to define a Visit() method of any sort nor is there a constraint that forces any implementation to have only one argument.  But this is just fine, since all of the classes must inherit from AbstractVisitor to participate in this pattern, it will also inherit the default implementation of Visit() which, conveniently, contains a fallback do-nothing behavior.

You can download the full source here: SimpleDoubleDispatchSample.zip (4.08 KB)

I also have a second sample that I modified from Cowley's code that uses singleton instances of the visitors and improved encapsulation of the dispatch lookup table.  I also modified the catch all virtual Visit() method to a call to another virtual method to allow subclasses to change the default implementation of the case that no specific Visit() is found: SimpleDoubleDispatchSample.2.zip (4.12 KB)

Once again, credit goes to Anthony Cowley for an excellent and simple implementation of double dispatch in C#. There were two others that I examined, namely one by Max Hajek (which actually generated IL) and one by Steve Love using Generics.  In both cases, I thought the solutions were far more complex than the actual problem that they tried to solve, though Max's solution seems far more powerful and may be more useful in some scenarios.

 Friday, September 07, 2007

Code Complete: Chapter 31

9/7/2007 1:50:37 PM (Eastern Daylight Time, UTC-04:00)

I've recently picked up my copy of Code Complete - 2nd Edition again after a long hiatus from it.  It's such a massive book that I think if you plan on reading it from front to back, it'll bore you to death and put you to sleep.  Of course, this is not to say that the book is bad - quite the opposite, the book is filled to the brim with knowledge that will benefit any level of developer - but that you have to approach it in a more "leisurely" manner.

The book itself is one of those that you can really just kind of jump in and out of the chapters (except for some of the early ones that should be digested together).

Some bits from Chapter 31 that I think really capture the essence of the book. 

McConnell opens with an excellent statement that succintly summarizes my infatuation with proper code structure, naming, and other seemingly "non-development" coding activities: it is a matter of personal pride in my work and the effort that I put forth to make the code legible:

“The visual and intellectual enjoyment of well-formatted code is a pleasure that few nonprogrammers can appreciate.  But programmers who take pride in their work derive great artistic satisfaction from polishing the visual structure of their code.” (P.729)

The chapter covers the importance of good formatting and layout, the psychological effects of good layout and formatting (such as easier to memorize code structure), and techniques to achieve good layout.

McConnell introduces the idea of “The Fundamental Theorem of Formatting” which says “good visual layout shows the logical structure of a program” (P.732)

He quotes Elliot Soloway and Kate Ehrlich in their studies:

“…there is a psychological basis for writing programs in a conventional manner: programmers have strong expectations that other programmers will follow these discourse rules.  If the rules are violated, then the utility afforded by the expectations that programmers have built up over time is effectively nullified."  (P.733)

This is in alignment with the ideals of best practices.  The core concept is to have a codebase that exudes familiarity even to first time readers.  McConnell emphasizes the importance of the human aspect of coding:

“The smaller part of the job of programming is writing a program so that the computer can read it; the larger part is writing it so that other humans can read it.” (P.733)

Indeed, writing code so that the machine can read it is easy: the compiler, IDE, and development tools like ReSharper will tell you when the machine can’t read it.  Writing code so that other humans can read it is a true challenge since there is no one to confirm your view of the code or structure (without a well defined code review practice or pair programming). 

In that sense, writing code is not so different than writing in general.  Using shorthand is always the fastest ways to write little notes for oneself, but when composing a written work that others must consume, there are certain conventions that people come to expect: proper spacing, proper usage of punctuation, proper grammar, and the usage of paragraphs to delineate discrete bodies of text – these details all help to make the text more readable from a mechanical perspective.

While code is certainly not literature (well, not to most normal people anyways ;-)), there are similar traits in elegant code structure and elegant prose: it is simple, clear, concise, and expressive.  It might follow a pattern (rhyming, iambic pentameter, etc.) that gives it a flow.

Soloway and Ehrlich’s studies concluded that:

“The results point out the fragility of programming expertise: advanced programmers have strong expectations about what programs should look like, and when those expectations are violated—in seemingly innocuous ways—their performance drops drastically.” (P.735)

They cite examples where advanced chess players showed a marked increase in ability to memorize chess pieces arranged in “standard” or common scenarios over novice players, but demonstrated no increased ability when the pieces were arranged in a random fashion.  The conclusion is that familiarity increases the ability to internalize and process an otherwise abstract structure (or in this case, arrangement of chess pieces).

Of course, it’s not all just fluff and “nice to haves”, right?  McConnell raises an interesting observation that:

“The information contained in a program is denser than the information contained in most books.  Whereas you might read and understand a page of a book in a minute or two, most programmers can’t read and understand a naked program listing at anything close to that rate.  A program should give more organizational clues than a book, not fewer."

This makes the argument clear for commenting, proper and consistent application of white space, and using descriptive rather than short names (see Framework Design Guidelines for more coverage on that).  For example (and I’ve never understood this one), the use of “itm” instead of typing “item” or “tsk” instead of “task” or the use of “d” to declare a local variable instead of “document”.  One letter makes the code much more readable and much easier to process for another human reader of the code.

McConnell also makes a very good case for how code should be structured to reduce the complexity of the visual layout.  He gives a good abstract comparison on page 747.  These are small items which increase the readability of the code in very subversive ways; you probably never think about such details actively, but when processing a page of code, little details like indentation probably have a strong effect on your ability to understand the purpose and nature of the code.  More importantly, when other humans have to process your code, these little details, taken in cumulative, could mean the difference between a day of ramp up and a week of ramp up time.

Of course, McConnell does acknowledge that in many cases, such matters of style are borderline “religious”.  But from an objective perspective:

“…it’s clear that some forms of layout are better than others.  Good programmers should be open-minded about their layout practices and accept practices proven to be better than the ones they’re used to, even if adjusting to a new method results in some initial discomfort.” (P.735)

Definitely a book that deserves some shelf space on any developer's desk (edit: or nightstand ;-)).

 Tuesday, August 21, 2007

Working With SQL Server Compact Edition 2005

8/21/2007 6:05:02 PM (Eastern Daylight Time, UTC-04:00)

One interesting issue that I just solved involved how to specify the location of the database file for a SQL Server Compact Edition 2005 connection string in a .Net add-in for Microsoft Office.

You see, when the add-in starts, it sets the context directory as the user's documents directory, which of course, makes it impossible to enter a configuration string for the data source of the connection string.

It works fine if the directory is hard coded - which is what I did for testing purposes initially, but of course, when I switched over to XP64, this broke as on XP64, the program is installed to "Program Files (x86)".

The solution lies buried in Microsoft's SQL CE documentation: there's a note that you should use a special token with the connection string like so:

<connectionStrings>
	<add name="ClientDatabase" 
		connectionString="Data Source=|DataDirectory|\data-file.sdf"
		providerName="Microsoft.SqlServerCe.Client" />
</connectionStrings>

The token needs to be included exactly as entered "|DataDirectory|". So how is this token replaced? In the static constructor of my Connect class that was autogenerated by Visual Studio, I added the following code:

/// <summary>
/// Initializes the logging subsystem for the <see cref="Connect"/> class.
/// </summary>
static Connect() {
	string path = Assembly.GetExecutingAssembly().Location;
	path = path.Substring(0, path.LastIndexOf('\\'));

	// Set the DataDirectory for the SQL Server CE connection string.
	AppDomain domain = AppDomain.CurrentDomain;
	domain.SetData("DataDirectory", path);
}
 Monday, August 20, 2007

Nerd Glee

8/20/2007 9:24:31 AM (Eastern Daylight Time, UTC-04:00)

So this morning, a FedEx Express (redundant?) truck showed up at my front door promptly at 9:00 to deliver a little bundle of joy: a new workstation.

For as long as I've worked, I don't think I've ever received a new development machine from any of the companies I've worked for.  To cope with the invariably crappy, last gen machines that I've been assigned, I've always ended up buying my own.  I bought my own laptop after a few months suffering on an NT4 workstation with something like an 4 GB harddrive and only 100 MB were left for me to work with (this was in 2003, mind you).  I bought my own desktop (a screamer of a machine in its own right) after my laptop became too outdated to handle the resource hungry 2005 suite of software and servers from Microsoft.

The importance of good hardware can't be emphasized enough.  Fast hardware helps shorten compile times, helps shorten debugging cycles by offering better runtime performance, helps shorten development times by allowing for more installed tools (think ReSharper), and I think, in the big picture, help reduce developer stress and frustration.

As trivial a gesture as this may seem, for the first time, I feel appreciated and I feel like my employer takes my job and tasks seriously.  It's a truly special moment :-D It's as if he understands my pain (well, not so much mine since my machine is less than a year old (dual core @ 3.2GHz, 4GB RAM, 3x10K RPM HDs), but my pain in working with the rest of the team who are still on first gen. Centrino laptops with 4200RPM HDs).

I'll have to add some pictures later and some screenshots.  For now, I am beyond ecstatic that, finally, our entire team will be able to really be much, much more productive.  I can't say enough about our once CEO and now VP who really went the distance to make sure that we got some quality hardware.

 Friday, August 17, 2007

Interesting Find

8/17/2007 9:32:30 AM (Eastern Daylight Time, UTC-04:00)

So this morning, I was contemplating signing up for Amazon Prime since the holiday shopping season is a mere three months away and because I just moved to a new house that's kind of out in the middle of nowhere.

In doing some research about the general satisfaction about the service, I came across an amazing find on the BusinessWeek website, of all places.

The article/post itself isn't so interesting or amazing in any sense, rather, it's the comments left by the readers that are amazing and utterly baffling.

Who would have thought that the readers of BusinessWeek are such giant retards who have no concept of how the Interwebs work?  Nay, who would have thought that they were so dense as to not have any concept of how customer service works?

As evidence, I present some of the comments to the article:

I had no idea that it would cost me 79 dollars to join the shipping club and would not have joined if I did. I don't order that much and don't care if it took longer.

I would like to cancel my membership and get a refund for that amount. The one purchase I made took longer then two day's anyway. It was not even paid for or shipped till 8 o2. I have not even receive any imformation about the club yet.

Than You
Donald TenEyck

Hey Donald, this is BusinessWeek, not the Amazon customer service page...get a clue!  I'm pretty sure that Jeff Bezos is not going to call you and apologize.

I have just received a charge on my Visa bill
for $79.00. I did not authorize this and will not
pay it. Please cancel "MY MEMBERSHIP" and I will expect confirmation from you immediately. I notice that I am not the only one that has unknowingly been charged. What a rip off. Please credit my account now. And then lose my email
address
Bonnie Smuffer

Is it really possible for people to be this dense and stupid and yet have access to the Internet?

And it goes on and on...the stupidity really reaches critical mass in this posting.  Of course, it's fully possible that it's just comment spam, but check out these two postings by "Jaques Laporte":

Hi AMAZON.COM

I have just received a charge on my Amex bill for $79.00.

>PRIME SHIPPING CLUB.
>Free Standard Shipping for eligible items shipped to P.O. boxes in the continental United States (excluding Alaska, Hawaii, and U.S. >territories, possessions and protectorates) and APO/FPO addresses with U.S. zip codes.

Note that I do not live in the continental USA.

I did not authorize this and will not pay it. AMEX will be notified.

Please cancel my so-called membership and refund me.
I don't want to spoil my relation with Amazon, but until total refund, YOU ARE NOT AUTHORIZED to bill directly my credit cards.
Take notice please that I currently have no payment methods in your system.

Best regards.
Jacques Laporte.

Posted by: Jacques Laporte at January 3, 2007 06:56 AM

And then:

I must confess that the refund was fast (2 days).
All's well that ends well.

Posted by: J. Laporte at January 5, 2007 12:38 PM

Amazing to think that there are such a large quantity of people with this level of stupidity...

 Thursday, August 16, 2007

Book Review: Framework Design Guidelines

8/16/2007 4:30:48 PM (Eastern Daylight Time, UTC-04:00)

I originally came across a title Framework Design Guidelines: Conventions, Idioms, and Patterns for Reusable .NET Libraries after perusing the documentation on the Subtext site.

For the most part, I had been following the guidelines outlined by Scott Bellware in his handy dandy style guide, but this text - FDG - takes it to another level and formalizes it in a way that it must be accepted by development teams since it was born from the source itself: the .NET Framework development teams.

I've reviewed it on Amazon, but here is the transcripted text:

I don't personally think that all developers will find this book useful. In fact, I have a feeling that some may find it highly useless and disruptive as it is abstract in a sense (one must apply the lessons to each library and scenario independently, taking into consideration many different aspects of usability and readability) and it does require some "retraining" of bad practices which have been long since ingrained due to years of usage.

But whether this book deserves a five star rating or a one star rating - whether this book is for you - can be answered by asking yourself the following question: are you obsessed with quality? Quality in the sense of creating a library that is:

- Easily reused by others, even first timers encountering the library or even first timers to .Net
- Well thought out with well designed classes
- Consistent within itself and consistent with the base libraries from Microsoft

The importance of the little things like naming classes, properties, methods, using one type of construct over another, using one type of accessor over another, etc. cannot be stressed enough in the overall picture of creating a library to a higher standard of quality, usability, and extensibility.

As Confucius is to have said:

"If names be not correct, language is not in accordance with the truth of things. If language be not in accordance with the truth of things, affairs cannot be carried on to success.

"When affairs cannot be carried on to success, proprieties and music do not flourish. When proprieties and music do not flourish, punishments will not be properly awarded. When punishments are not properly awarded, the people do not know how to move hand or foot.

"Therefore a superior man considers it necessary that the names he uses may be spoken appropriately, and also that what he speaks may be carried out appropriately. What the superior man requires is just that in his words there may be nothing incorrect."

As I wrote in an e-mail to my team, I think that digesting this book will lead to: higher quality public facing APIs for our customer development teams seeking to extend the functionality, increased readability and more consistency internally in our teams, increased usability and decreased maintenance costs for the support teams as well as new developers on our team, and of course, increased skill, knowledge, and competency as developers of each of the team members.

The title of this book is perhaps a bit misleading.  In reality, this book is applicable for anyone doing .Net development since it will lead to better quality code construction irregardless of whether you happen to be working on a "framework".  What I also like about the book is that the authors, architects, and various developers who worked on the .NET Framework admit error and inconsistency in some design and shows that this book is truly a work of the men in the trenches and intended for those of us who work on the front line of software development.

While the book does not delve into architecture or design, I think it still has value in enhancing the skill and mastery of any developer that takes the time to read it.  Definitely pick up this book if you are serious about becoming a better developer in the sense of being a more refined craftsman.

 Wednesday, August 15, 2007

Running Trac, Subversion, And Apache On Ports 80 And 443

8/15/2007 8:41:15 PM (Eastern Daylight Time, UTC-04:00)

If you are proxying Subversion through Apache, chances are you are probably using a non-default port since Apache won't start if you configure it use port 80 and 443 for SSL if you have IIS installed.  IIS uses socket pooling which binds port 80 and 443 on all IPs -- even ones not use by IIS -- to IIS.

To disable this behavior, you need the httpcfg.exe utility.  For Windows Server 2003, this can be found in the SP1 32-bit Support Tools download.  For Windows XP, the utility is available as part of the SP2 Support Tools download.

You can find a good overview of how to use this tool at neowin.net.

Some tips:

  • I didn't have luck running net stop http /y alone; I had to stop IIS first by running net stop iisadmin.
  • Assuming you have two or more IPs, the key is that you are actually telling IIS which IPs are okay to bind to.  If you are proxying Apache over IIS, you are likely (or should) use SSL.  This means that you have to make sure that you explicitly force IIS to bind to 80 and 443 for a specific IP and leave the other IP available for Apache.
 Tuesday, August 14, 2007

Random DevTools Entry: #014

8/14/2007 12:07:35 PM (Eastern Daylight Time, UTC-04:00)

Okay, so this isn't strictly a development tool, but Gantt Project has a pretty nifty, free, project management application.

With GanttProject you can break down your project into a tree of tasks and assign human resources that have to work on each task. You can also establish dependencies between tasks, like "this task can't start until this one is finished". GanttProject renders your project using two charts: Gantt chart for tasks and resource load chart for resources. You may print your charts, generate PDF and HTML reports, exchange data with Microsoft(R) Project(TM) and spreadsheet applications.

The site also mentions a good point with regards to Project:

  • Good (and growing!) set of basic features. This set is enough for most people (remember that 80% of MSProject customers use 20% of it's numerous features)
  • Easy learning. You don't need thick manuals to start working with GanttProject. If you are familiar with the notion of tasks, assignments and dependencies, you'll become an expert in GanttProject in a couple of hours.

Check it out if you're in the market for a free, simple, task based project management.

RSS 2.0 Atom 1.0 CDF