Making images in .resx files available to other projects (they default to internal) – level 200

I find it very frustrating that there is no obvious way to have the .resx
generator mark members as public instead of internal.  In my team's solution, we
have a need for these to be public.  Here's how I solved it:

Add a nant target that can do a
find/replace in a file (I don't know of a shell command that will do that)

<?xml version="1.0" encoding="utf-8"?>

<!–EXTERNAL_PROPERTIES:
filename;stringToReplace;newString
–>

<project name="BuildTasks" xmlns="http://nant.sf.net/release/0.85-rc4/nant.xsd">

  <target name="FindReplace">

    <move file="${filename}" tofile="${filename}.bak">

      <filterchain>

        <replacestring from="${stringToReplace}" to="${newString}" />

      </filterchain>

    </move>

 

    <move file="${filename}.bak" tofile="${filename}"/>

  </target>

</project>

Add a pre-build step to the project
to run this target and feed in the correct file:

pushd .
cd "$(ProjectDir)...."
binnantnant.exe -buildfile:buildtasks.build FindReplace -D:filename="$(ProjectDir)PropertiesIcons.Designer.cs" -D:stringToReplace=internal -D:newString=public
binnantnant.exe -buildfile:buildtasks.build FindReplace -D:filename="$(ProjectDir)PropertiesToolbarIcons.Designer.cs" -D:stringToReplace=internal -D:newString=public
popd

Compile as you normally would and
note the output:

------ Build started: Project: MyProject, Configuration: Debug Any CPU ------
pushd .
cd "C:svnMyProject-trunksrcMyProject...."
binnantnant.exe -buildfile:buildtasks.build FindReplace -D:filename="C:svnMyProject-trunksrcMyProject\PropertiesIcons.Designer.cs" -D:stringToReplace=internal -D:newString=public
binnantnant.exe -buildfile:buildtasks.build FindReplace -D:filename="C:svnMyProject-trunksrcMyProject\PropertiesToolbarIcons.Designer.cs" -D:stringToReplace=internal -D:newString=public
popd
NAnt 0.85 (Build 0.85.2344.0; rc4; 6/2/2006)
Copyright (C) 2001-2006 Gerry Shaw
http://nant.sourceforge.net

Buildfile: file:///C:/svn/MyProject-trunk/buildtasks.build
Target framework: Microsoft .NET Framework 2.0
Target(s) specified: FindReplace


FindReplace:

[move] 1 files moved.
[move] 1 files moved.

BUILD SUCCEEDED

Total time: 0 seconds.

NAnt 0.85 (Build 0.85.2344.0; rc4; 6/2/2006)
Copyright (C) 2001-2006 Gerry Shaw
http://nant.sourceforge.net

Buildfile: file:///C:/svn/MyProject-trunk/buildtasks.build
Target framework: Microsoft .NET Framework 2.0
Target(s) specified: FindReplace


FindReplace:

[move] 1 files moved.
[move] 1 files moved.

BUILD SUCCEEDED

Total time: 0 seconds.

Compile complete -- 0 errors, 0 warnings
MyProject -> C:svnMyProject-trunksrcMyProjectbinDebugMyProject.dll
========== Build: 1 succeeded or up-to-date, 0 failed, 0 skipped ==========

Iteration discipline: another Agile mind-shift – level 200

In an effective organization, discipline is key.  You can't run a loose ship and expect to be effective.  One of the disciplines that his hard to master is speculation.

Speculation

When working on a story, the developer team might have questions or even ideas for improvement.  A common temptation is to speculate about a solution that seems right to the developer(s).  Sometimes this speculation is correct, and sometimes it isn't.  Either way, developers should not speculate about business value.  Note that I am assuming we have a healthy organization where a product manager (or customer) is actually planning the software and thinking about business value.  In this environment, the customer is responsible (and qualified) for determining priority based on business value.  A customer is charged with knowing the problem domain and making decisions about what software to write to fulfill the business need.  Developers take this business landscape and deliver a technical solution to the business problem.  Developer speculation can hurt productivity when developers start making assumptions about the business problem. 

I talk about discipline because it takes effort sometimes to force the customer to make business decisions.  Developers are the technical experts, and customers are the business experts.  Just as a customer is not qualified to make assumptions about technical feasibility or technical estimates, a developer is not qualified to make assumptions about business value or priority.  When I say "qualified", I mean it is not their role in the organization. 

How to beat developer speculation (or guessing)

  • Keep the customer onsite so that the communication overhead is very low.  That way whenever questions come up, the source of information is right there.
  • Plan the iteration effectively.  An iteration planning meeting should model and task out the work planned for the iteration.  Whether if be one, two, or three weeks, do a good job planning so that all big questions are answered up front (or spikes are declared for specific items).  Lean on the customer during the iteration for smaller, detailed questions.  If you have a hard time planning for your three-week iteration, shorten the iteration to one or two weeks.
  • Focus on delivering software.  Focus on the iteration.  For the individual developer, that means trusting your customer and manager.  Developers are creative and have good ideas.  These ideas should be communicated to the customer, but the customer is responsible for integrating those ideas into the roadmap.  An idea that pops up mid-week should not halt the iteration unless it was something critical that was missed.  Planning (in detail) only a short period of time allows for changing course rapidly since each iteration's plan is defined in real-time.  Remember, the customer (or customer representative) is always planning the future roadmap.
  • Don't tolerate it.  This is more of a management item.  It's a slippery slope.  If a little speculation (or developer-driven business plan) is allowed, then more will follow.  Be clear about the roles of the development organization, and have the developers enforce this discipline within the team.  All technical discussions should focus on iteration deliverables.

What about planning ahead to prevent major technical problems?
Someone on the team should be a strong enough developer to understand these issues.  This is not a role, but more a capability.  If the team is filled will strong developers, then any developer is capable of seeing a roadblock coming.  If the team is more junior with only one senior dev leading the way, then it will fall on that person's shoulders, but this is more of a team-makeup issue.  In practice, with strong people, you have high-quality, loosely coupled, well-tested code that is delivered every iteration.  In this healthy environment, the code is easy to change to react to business decisions down the road.  If you have good people, they won't be coding into a roadblock.

 

What's the secret?
No secret.  Get good people, and they will deliver good software.  There is no cookie-cutter process that magically turns a dysfunctional developer culture into an effective one.  Good people, driven by Agile principles formulate a good process and deliver good software.

XmlSerializer will use the Equals() method to find circular references

This post saved me quite a bit of time:

http://sqljunkies.com/WebLog/kmarple/archive/2005/01/11/6180.aspx

 We were having a problem with serializing a domain object.  It was reporting a circular reference problem.  We found out that because we had overriden the Equals method to compare our ids, the XmlSerializer thought all the objects were the same if the id had not been assigned yet.  Assigning an id up front solved this serialization issue.
 

Firefox 2 installed – love the spellchecking! – level 100

There's a lot of talk about IE7 vs. FF2.  It's all pretty boring for me. 
Browsers are boring.  They are glorified terminals.  Dave Thomas (of Pragmatic
Programmers fame) puts it in an interesting way: (paraphrasing) -We have the same
client-server terminal we had years ago, but now the terminal can show porn.- 
That drew quite a few laughs at the NoFluffJustStuff conference in Austin this
past summer.

In short, displaying web pages isn't all
that exciting.  What all the browsers have turned to for added value is
add-ins.  Add-ins for ad-blocking, popup blocking, anti-phishing, etc.  While
some browsers develop all add-ins in-house, I believe the main factor behind
Firefox's success is the large number of add-ins available for free that have
been contributed by the developer community.  The other browsers don't have
this.  If it weren't for all the FF add-ins, FF wouldn't have much of a leg to
stand on.

Back to my main reason for this post:  I
have installed Firefox 2, and I love the spell checking.  Anywhere I write text
in a web-page, I get in-line spell checking.  Write emails with Gmail, Forum
posts, anything – instant spell-checking.  Brilliant!

Sorting in .Net (don’t sort manually, let .Net do it for you) – level 100

I've labeled this as a level 100 topic because I feel that every .Net developer
should know the basics of sorting.  With the base class library that we have to
work with, we don't have to worry about sorting algorithms or speeding up our
sorts.  Folks smarter than I have implemented the fast sorting that we have in
.Net.

Here, I'll cover the basics of how
to sort your own domain object as well as how to sort any other object (even
ones you didn't create).

Let's consider
the following domain object, Person:

   11 public class Person

   12 {

   13     private string _firstName;

   14     private string
_lastName;

   15 

   16     public Person(string firstName,
string
lastName)

   17    
{

   18        
_firstName = firstName;

   19         _lastName =
lastName;

   20    
}

   21 

   22     public string
FirstName

   23    
{

   24        
get { return _firstName;
}

   25    
}

   26 

   27     public string
LastName

   28    
{

   29        
get { return _lastName;
}

   30    
}

   31 }

In our application, we may want to display
FirstName LastName or LastName, FirstName.  Also, we may want ascending or
descending sorts.  If you are using a database, you may be tempted to let the
database order the records for you, and that's fine if you never need to change
the sort inside the application.  In object-oriented systems, however, a lot of
code never talks to the database, so we need to be able to sort.  Now, suppose I
wanted the following code to work:

 

[Test]

public void ShouldSortPersonsAscending()

{

    Person[] persons =
new Person[]{new Person("Homer", "Simpson"), new Person("Bart", "Simpson"), new Person("Jerry", "Seinfeld")};

    Array.Sort(persons);

    foreach(Person person in persons)

    {

        Console.WriteLine(person.FullName);

    }

}


This code won't work right now because
Array.Sort( ) counts on the elements in the array implementing the IComparable
interface.  This is a key interface in .net for sorting.  By adding an
implementation of that method to my Person class, I get sorting for free.  What
I am going for here is a sort by last name and then first name:

public class Person : IComparable

{

    private string _firstName;

    private string
_lastName;

 

    public Person(string firstName,
string
lastName)

   
{

        _firstName
= firstName;

       
_lastName = lastName;

    }

 

    public string FirstName

    {

        get { return _firstName;
}

    }

 

    public string
LastName

    {

        get { return _lastName;
}

    }

 

    public string
FullName

    {

        get { return string.Format("{0} {1}",
FirstName, LastName); }

    }

 

    public int CompareTo(object obj)

    {

        Person person = (Person)obj;

        int compareResult =
LastName.CompareTo(person.LastName);

        if(compareResult == 0)

        {

            compareResult
= FirstName.CompareTo(person.FirstName);

        }

 

        return compareResult;

    }


Notice how
I just had to implement a single method comparing first on last name and then on
first name.  Here is my output:

------ Test started: Assembly: BlogScratchPad.dll ------

Jerry Seinfeld
Bart Simpson
Homer Simpson

1 passed, 0 failed, 0 skipped, took 0.41 seconds.

That's the bread and butter sorting case,
and that gives my Person object a default sort order.  Anyone working with
Person(s) can now sort by last name, first name in ascending order.  But what if
I wanted to sort in descending order?  There is another key interface in .Net
called IComparer.  This interface enables you to create a class that defines the
sort order for any class.  Consider the following tests.  I would like my
Person(s) to be listed in descending alphabetical order (reverse of above). 
Here, I choose to implement the generic form to avoid some casting:
IComparer<T>.

[Test]

public void
ShouldSortPersonsDescending()

{

    Person[] persons = new Person[] { new Person("Homer", "Simpson"), new Person("Bart", "Simpson"), new Person("Jerry", "Seinfeld")
};

    Array.Sort(persons,
new ByLastNameFirstNameDescendingComparer());

    foreach (Person person in persons)

    {

        Console.WriteLine(person.FullName);

    }

}


Notice how this test looks very similar to
the previous one; however, I've added my new comparer class to instruct
Array.Sort( ) how to sort the array.

public class ByLastNameFirstNameDescendingComparer :
IComparer<Person>

{

    public int Compare(Person x, Person y)

    {

        int compareResult =
y.LastName.CompareTo(x.LastName);

        if (compareResult == 0)

        {

            compareResult
= y.FirstName.CompareTo(x.FirstName);

        }

 

        return compareResult;

    }

}


Notice how I just compared y to x instead of
x to y.  This gets me the descending order that I want.  Here is the result of
running the test:

------ Test started: Assembly: BlogScratchPad.dll ------

Homer Simpson
Bart Simpson
Jerry Seinfeld

1 passed, 0 failed, 0 skipped, took 0.41 seconds.

Notice how it is exactly the
reverse of the previous result – just what I wanted. 

Array.Sort(Array, IComparer) works to sort an array of any object under the
sun.  My team's Visual Studio solution has accumulated  a healthy number of
IComparer classes.  This allows our application to sort objects however needed,
whenever needed. 

We’ll see Microsoft’s OR Mapper soon – level 100

Many long-time Microsoft developer hold fast to the "all data access must be stored procedures" thought, and that was, at one time, the guidance from Microsoft.  Soon we'll see the Object-relational mapper from Microsoft in the form of Linq for Entities.  I drove up to the North Dallas .Net User Group yesterday and visited with Scott Guthrie on the topic.  Microsoft has tried a few times before at creating an OR mapper, but they've learned from past attempts and are releasing v1.0 of Linq as their entry into the ORM space.

I'm very much entrenched in the ORM space with NHibernate, but I'm interested in how Linq for Entities pans out.  From a cursory look, the mapping information is specified with attributes that are placed on the entity class.  I'm not sure if that's the only method for this, but I'm very much looking forward to the release.

An interesting tidbit demonstrated was the server-side paging of a Linq query.  For instance, the C# query: from customers select customer, you can specify to skip 10 and then return 10 (or any number) if you need to page through the resultset 10 at a time.  Linq will formulate the SQL query to get you exactly what you want.  Very nice.  Ayende, in the comments below gives an example of that with NHibernate.

IronPython for ASP.NET CTP downloaded – level 100

I searched MSDN this morning for “ironpython”, and found a CTP had been posted yesterday.  It installs into Visual Studio and makes it possible to write ASP.NET websites using all the dynamic language Python.  This is very interesting as it’s the first dynamic language will full tool support in Visual Studio.

I personally am going to investigate it for use in testing.  If some of my code depends on the system clock, it would be so nice to just fake out the system clock in real-time with the power of a dynamic language instead of having to fake it out with more intrusive techniques such as putting it behind an interface.