CodeBetter.Com
CodeBetter.Com
RSS 2.0 via Feedburner
           Do you Twitter? Follow us @CodeBetter

Jeffrey Palermo (.com)

Blog moved to www.jeffreypalermo.com

March 2005 - Posts

  • Highlights from my previous 199 ramblings - level 100 - 400

    I started out reading blogs in early 2004 while in Iraq.  In March, I started a blog at blogspot (and with a little 'customization' of the stylesheet, I got it to redirect to my blog at .Net junkies).  On April 16th, I transfered my initial posts to .Net junkies. 

    One of the drawbacks of blogs is that old posts get buried even though the information may continue to be relavent.  Here, I'll review some topics:

    I'm not sure how many regular readers I have (that isn't my goal), but I figured that on average, my blog website gets 430 hits per day.  Google is responsible for most of them by matching up searches with content on my blog.  Then another 500 RSS hits for most blog posts.

     

    Looking back on my blog, it really is a journal of my coding experiences, and I can see how far I've progressed. 

  • Local Agile lunch today - level 100

    Today we had our second Agile lunch at the Mongolian BBQ.  We have a Yahoo group at: http://groups.yahoo.com/group/BellwareNET to coordinate locals interested in Agile methodologies.  We've decided to have our meetings be over lunch since the attendance will be small; much smaller than the Austin .Net User Group attendance.  At today's meeting we discussed such topics as:

    - San Antonio user group web site
    - FitNesse
    - Continuous integration, CruiseControl
    - Testing user interfaces
    - NUnitForms
    - Model-View-Presenter pattern
    - DI, IOC, Structure Map, Spring .NET

  • Cool family website hosted by Community Server - level 000

    Community Server has been out for a while now, but I haven't seen many new sites using it yet.  Here is a family website hosted by community server.  There are BUNCHES of pictures, blogs and forums. 
  • General application architecture diagram - level 300

    Many applications I've encountered and most of my first applications had loose or no defined architecture.   From a high level, everything just was.  And it worked.  And it became hard to maintain.  I've been researching better ways to organize the application and how to take advantage of high-level design patterns.  With this knowledge, I've developed a general architecture for any application with a UI (apps without a UI will just lack that layer, and, of course, I haven't included a service layer (which might even be the interface layer).

    My goal was to describe how the layers might interact and what bindings would exist.  The most important things follow:  The UI layer holds references to the process and business layers and no others.  The process layer holds references to the repository, business, and UI layers.  The repository layer references business and DAL.  The business layer references nothing (and this is key for object portability).  The DAL references only the database (most likely through the connection string) but holds no assembly references except ADO.NET, of course.

    With this architecture, we can implement Model-View-Presenter,  Repositories, and Observer.   For example, the Process layer would hold presenter objects that invoke business objects and set the View (UI).  The View observes business objects but does not control them.  The Presenter objects control the process layer and invoke the repository classes to get or persist the business objects.  The repository layer does this by calling the correct classes of the DAL.  And then, if the database changes (either in vender or schema), only the DAL needs to be changed.  The DAL should expose classes that return data by calling the right query in the database.  The DAL might wrap ADO.NET or perhaps the Data Access Application Block for the direct database access.  The DAL would know the names of stored procedures.  The repository objects would not know this.  Rather the repository objects would just know what class and method to invoke to get information with which to populate a business object.  The DAL should return generic objects such as an IDataReader. 

    I've read a lot about application design patterns and best practices, but I wish there was some more architecture guidance out and about.  I think the industry would benefit from standard approaches to application development from a high level.  We hear a lot about n-tier and business layers, but a business layer that knows how to persist its own objects is not the way to go, so I see this guidance lacking.

    Feedback is welcome on the above diagram.

  • Trying out the Model-View-Presenter pattern - level 300

    After reading Martin Fowler's Model View Presenter article, I did some deep thinking about how to implement that pattern.  The purpose of the pattern is to decouple UI process logic from the UI container.  If  you think about the code-behind classes in your UI, all the examples we see have button-click handlers performing process logic.  Below is my first attempt at creating a behavior layer for UI testability and portability:

    I'll present this example using a simple ASP.NET page:

    <%@ Page language="c#" Codebehind="default.aspx.cs" AutoEventWireup="false" Inherits="ModelViewPresenter.WebForm1" %>
    <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" >
    <HTML>
     <body>
      <form id="Form1" method="post" runat="server">
       <asp:textbox id="txtName" runat="server">
       </asp:textbox><asp:button id="btnAdd" runat="server" Text="Add Name"></asp:button>&nbsp;
       Number of items:
       <asp:label id="lblCount" Runat="server"></asp:label><br>
       <asp:datagrid id="dgdNames" runat="server">
        <Columns>
         <asp:ButtonColumn CommandName="delete" ButtonType="PushButton" Text="Remove" />
        </Columns>
       </asp:datagrid></form>
     </body>
    </HTML>

     

    This page is used to maintain a list of names.  Type in a name and click the add button; remove a name from the list.  The current names are shown in a datagrid, and the count is shown next to the button.  Here is the code-behind:

       14 public class WebForm1 : System.Web.UI.Page, Presenter.INamesView
       15 {
       16     protected System.Web.UI.WebControls.TextBox txtName;
       17     protected System.Web.UI.WebControls.Button btnAdd;
       18     protected System.Web.UI.WebControls.DataGrid dgdNames;
       19     protected System.Web.UI.WebControls.Label lblCount;
       20 
       21     private Presenter.NamesPresenter _presenter;
       22 
       23     private Model.Names _names {
       24         get { return (Model.Names)ViewState["names"]; }
       25         set { ViewState["names"] = value; }
       26     }
       27 
       28     private void Page_Load(object sender, System.EventArgs e)
       29     {
       30         _presenter = new Presenter.NamesPresenter(this);
       31         if(!IsPostBack) {
       32             _presenter.Load();
       33         }
       34     }
       35 
       36     public Model.Names Names {
       37         get { return _names; }
       38         set { _names = value; }
       39     }
       40 
       41     public void Update() {
       42         dgdNames.DataSource = _names;
       43         dgdNames.DataBind();
       44 
       45         lblCount.Text = _names.Count.ToString();
       46     }
       47 
       48     private void btnAdd_Click(object sender, System.EventArgs e) {
       49         _presenter.AddName(txtName.Text);
       50         txtName.Text = string.Empty;
       51     }
       52 
       53     private void dgdNames_DeleteCommand(object source, DataGridCommandEventArgs e) {
       54         _presenter.RemoveName(e.Item.ItemIndex);
       55     }

     

    I have omitted the using statements and the IDE-generated code, so this is not complete, but it shows how I am delegating behavior to the presenter layer.  Here is my presenter:

        5 public class NamesPresenter
        6 {
        7     private INamesView _view;
        8 
        9     public NamesPresenter(INamesView view) {
       10         _view = view;
       11     }
       12 
       13     public void AddName(string nameToAdd) {
       14         _view.Names.Add(nameToAdd);
       15         _view.Update();
       16     }
       17 
       18     public void RemoveName(int indexOfNameToRemove) {
       19         _view.Names.RemoveAt(indexOfNameToRemove);
       20         _view.Update();
       21     }
       22 
       23     public void Load() {
       24         _view.Names = new Model.Names();
       25         _view.Update();
       26     }
       27 }

     

    This presenter controls the model (my business object) and tells the UI what to do and when through the interface that the UI must implement (below):

        5 public interface INamesView
        6 {
        7     Model.Names Names{get;set;}
        8     void Update();
        9 }

     

    As long as my UI implements this interface, my presenter can control it, and I can make changes to the UI (including total replacement) without impacting the core behavior. 

    Next, all this exists to manage my model or business object:

        6 [Serializable]
        7 public class Names : IEnumerable
        8 {
        9     private ArrayList _entries = new ArrayList();
       10 
       11     public string this[int index] {
       12         get { return _entries[index].ToString(); }
       13         set { _entries[index] = value; }
       14     }
       15 
       16     public int Count {
       17         get { return _entries.Count; }
       18     }
       19 
       20     public void Add(string name) {
       21         _entries.Add(name);
       22     }
       23 
       24     public void RemoveAt(int index) {
       25         _entries.RemoveAt(index);
       26     }
       27 
       28     public IEnumerator GetEnumerator() {
       29         return _entries.GetEnumerator();
       30     }
       31 }

     

    Events from the UI are delegated to the presenter, which decides what to do and calls interface methods on the UI.  The presenter controls interaction between the UI and the model just as a repository layer would control presistence between the model and a data store.

     

    I don't pretend that this example is perfect, and I'm open for criticism, but the model view presenter pattern for the UI is very tempting for testability and UI portability.

  • Speaking schedule for the next quarter - level 000

    On April 1st, I'll be giving a talk on web services to a groups of students in a .Net web development class at Texas A&M University.  Then on May 2nd, I'll be presenting to the Texas A&M .Net User Group an overview of the Dell IDD, a smart client shell to host multiple applications.  Then I'll move on to show how to implement a plugin design in web applications.
  • Implementing a data repository class with a _true_ business object all with TDD - level 300

    I've revised my previous sample that contained a Category class.  This Category has an id, a name and description.  There is a Category table to persist the object. I pulled everything data out of my business object and created a CategoryData object that will know the DAL and know how to persist and hydrate the Category object.  This approach greatly simplifies the business object and decouples persisting the object to the database.  In the future, if I changed the persistence method, I don't have to change the business object, just the data object.  Here are my sample classes:

    Category:  note how simple my business object is now:

        7 public class Category {
        8 
        9     private int _id = 0;
       10     private string _name = string.Empty;
       11     private string _description = string.Empty;
       12 
       13     public int ID {
       14         get { return this._id; }
       15         set { this._id = value; }
       16     }
       17 
       18     public string Name {
       19         get { return this._name; }
       20         set { this._name = value; }
       21     }
       22 
       23     public string Description {
       24         get { return this._description; }
       25         set { this._description = value; }
       26     }
       27 }

    And my unit test class for this:

       12 [TestFixture]
       13 public class CategoryTest
       14 {
       15     private Category _category = null;
       16 
       17     public CategoryTest() {
       18         Trace.Listeners.Add(new TextWriterTraceListener(Console.Out));
       19     }
       20 
       21     [SetUp]
       22     public void GetACategory(){
       23         this._category = new Category();
       24     }
       25 
       26     [Test]
       27     public void CreateCategory() {
       28         Assert.IsNotNull(this._category);
       29     }
       30 
       31     [Test]
       32     public void CategoryID() {
       33         this._category.ID = 2;
       34         Assert.AreEqual(2, this._category.ID);
       35     }
       36 
       37     [Test]
       38     public void CategoryName() {
       39         this._category.Name = "Beverages";
       40         Assert.AreEqual("Beverages", _category.Name);
       41     }
       42 
       43     [Test]
       44     public void CategoryDescription() {
       45         this._category.Description = "MyDescription";
       46         Assert.AreEqual("MyDescription", _category.Description);
       47     }
       48 }

    Then I have my CategoryData object that knows how to persist using the DAAB:

        7 public class CategoryData
        8 {
        9     private Database _database = null;
       10 
       11     public Database Database {
       12         get {
       13             if(this._database == null)
       14                 this._database = DatabaseFactory.CreateDatabase("DEV");
       15             return this._database; }
       16         set { this._database = value; }
       17     }
       18 
       19     public Category GetCategory(int categoryID) {
       20         Category cat = null;
       21         using(IDataReader reader = this._database.ExecuteReader("GetCategoryByID", categoryID)) {           
       22 
       23             if(reader.Read()){
       24                 cat = new Category();
       25                 cat.ID = reader.GetInt32(reader.GetOrdinal("CategoryID"));
       26                 cat.Name = reader.GetString(reader.GetOrdinal("CategoryName"));
       27                 cat.Description = reader.GetString(reader.GetOrdinal("Description"));
       28                 return cat;
       29             }else {
       30                 return null;   
       31             }
       32         }
       33     }
       34 
       35     public void Insert(Category newCategory) {
       36         newCategory.ID = (int)this._database.ExecuteScalar("InsertCategory", newCategory.Name, newCategory.Description);
       37     }
       38 }

    And the unit tests with stubs for the CategoryData class:

       12 [TestFixture]
       13 public class CategoryDataTest
       14 {
       15     private CategoryData _categoryData = null;
       16 
       17     [SetUp]
       18     public void GetACategory(){
       19         this._categoryData = new CategoryData();
       20         this._categoryData.Database = new DatabaseStub();
       21     }
       22 
       23     [Test]
       24     public void GetCategory() {
       25         Category cat = this._categoryData.GetCategory(1);
       26         Assert.IsNotNull(cat);
       27         Assert.AreEqual(1, cat.ID);
       28         Assert.AreEqual("Beverages", cat.Name);
       29         Assert.AreEqual("MyDescription", cat.Description);
       30     }
       31 
       32     [Test]
       33     public void GetCategoryThatDoesntExist() {
       34         Category cat = this._categoryData.GetCategory(500);
       35         Assert.IsNull(cat);
       36     }
       37 
       38     [Test]
       39     public void InsertCategory() {
       40         Category cat = new Category();
       41         cat.Name = "Jeffrey";
       42         cat.Description = "Hello category";
       43         this._categoryData.Insert(cat);
       44         Assert.IsTrue(cat.ID == 400);
       45     }
       46 
       47     internal class DatabaseStub : SqlDatabase {
       48         public override object ExecuteScalar(string storedProcedureName, params object[] parameterValues) {
       49             switch(storedProcedureName) {
       50                 case "InsertCategory":
       51                     return 400;
       52                     break;
       53             }
       54 
       55             return null;
       56         }
       57 
       58 
       59         public override IDataReader ExecuteReader(string storedProcedureName, params object[] parameterValues) {
       60 
       61             switch(storedProcedureName) {
       62                 case "GetCategoryByID":
       63                     if(parameterValues.Length == 1 && (int)parameterValues[0] == 1) {
       64                         return new DataReaderForCategory1Stub();
       65                     }
       66                     break;
       67             }
       68 
       69             return new EmptyDataReaderStub();
       70         }
       71     }
       72 
       73     internal class DataReaderForCategory1Stub : IDataReader  {
       74 
       75         public bool Read() {
       76             Trace.WriteLine("Returning true from Read()", this.GetType().Name);
       77             return true;
       78         }
       79 
       80         public string GetString(int index) {
       81             string retValue = string.Empty;
       82             switch(index) {
       83                 case 1:
       84                     retValue = "Beverages";
       85                     break;
       86                 case 56:
       87                     retValue = "MyDescription";
       88                     break;
       89             }
       90 
       91             return retValue;
       92         }
       93 
       94         public int GetInt32(int index) {
       95             int retValue = int.MinValue;
       96             switch(index) {
       97                 case 0:
       98                     retValue = 1;
       99                     break;
      100             }
      101 
      102             return retValue;
      103         }
      104 
      105         public int GetOrdinal(string name) {
      106             int retValue = 0;
      107             switch(name) {
      108                 case "CategoryName":
      109                     retValue = 1;
      110                     break;
      111                 case "CategoryID":
      112                     retValue = 0;
      113                     break;
      114                 case "Description":
      115                     retValue = 56;
      116                     break;
      117             }
      118 
      119             return retValue;
      120         }
      121 
      122         #region IDataReader Members
      123 
      124         // extra members omitted
      279         #endregion
      280     }
      281 
      282     internal class EmptyDataReaderStub : IDataReader {
      283         #region IDataReader Members
      284 
      285         // implementation omitted 
      468         #endregion
      469 
      470     }
      471 }

    This makes my model so much easier because now my business rules don't have to have anything to do with the database, and if we change databases later, my business object doesn't have to change.  I've been talking with Scott Bellware a lot lately about Domain-driven design, and it's some pretty deep stuff.  One thing we agree on:  RAD sucks!

  • My first Test-Driven Development presentation - and concerns raised - level 100

    Sorry folks, no code in this post. 

    I just finished giving a one-hour presentation on how to do TDD with VS 2003 and NUnit.  I gave a brief overview of TDD but didn't try to persuade them to change right off the bat.  Heck, I'm just getting started!  I started with the approach of referring them to the explanation given on AgileData.  Then I went into a demonstration.  I emphasized the need to see the test fail to ensure that your test is correct.  One time, I forgot to add an Assert to the test, and, of course, it would never fail.  That hit home the point that seeing it fail verifies that the test is good.

    One of the concerns raised about using this methodology is:  “That's a lot more code to write”.  We talked as a group about the benefits of having unit tests for all the code in a project.  The project could be shipped to another building totally cut off from all networks, and another team could add functionality and be sure they didn't break anything else as long as all the existing unit tests all continue to work.

    Another question was if this approach would lead to better code. . .or “what about the novice programmer”.  We talked about how this can lead to a clean design but that it would not artificially make a bad programmer's code better. 

    I only started doing TDD last week, so if almost feels like I'm leading the group while stumbling through the dark myself.  It's becoming familiar quickly, though.  I'm learning how to decouple external dependencies and test in isolation, using SetUp and TearDown methods, etc.  Performance counters were a bit tricky, though because I couldn't decide if they should be considered an external dependency that should be stubbed or not.  After all, I'm just calling classes in the .Net Framework.  The code isn't calling over the network.  With a database, it's clear:  stub it! 

    Another topic that came up concerned some of our existing codebase.  We have some class libraries that were designed to be consumed in a flexible manner, but not test-first, and we don't have unit tests for them.  Each of the classes has about 5 overloaded constructors.  We discussed that if we developed it with TDD, we'd only have the constructors that were required or that we tested.  We may still decide that we want 5 constructors, but each one would have to have a consuming test written first, and I would think all other tests on that class would need to be performed with an object constructed with each of the constructors.

    The more I learn about TDD, the more I find I need to learn.  What a vicious cycle!  I'm loving it, though.

  • TDD with the new Enterprise Library DAAB redux - level 300

    Yesterday's attempt at TDD with the DAAB prompted me to use NMock to imitate the external dependency so my test would be a true _unit_ test.  Since then, I've given it more thought - about the best way to proceed for future tests.  I've revised my test and included two concrete stub classes:  one that derives from the DAAB SqlDatabase class, and one that implements IDataReader.  These classes have turned out to be easier to work with, and I like being able to see the code directly in my test.  I would run against  a roadblock if I needed to stub a class that didn't implement an interface _and_ was sealed (I'm hoping none of the .Net Framework is like this).

    My Category class is the same:

        7 public class Category {
        8 
        9     private string _name = string.Empty;
       10     private static Database _database = null;
       11     private static string _databaseInstance = "DEV";
       12 
       13     public string Name {
       14         get { return this._name; }
       15         set { this._name = value; }
       16     }
       17 
       18     public static Database Database {
       19         get {
       20             if(_database == null)
       21                 _database = DatabaseFactory.CreateDatabase(_databaseInstance);
       22 
       23             return _database;
       24         }
       25         set { _database = value; }
       26     }
       27 
       28     public Category(int categoryID)
       29     {
       30         IDataReader reader = Category.Database.ExecuteReader("GetCategoryByID", categoryID);
       31 
       32         if(reader.Read()){
       33             this._name = reader.GetString(reader.GetOrdinal("CategoryName"));
       34         }
       35     }
       36 }

     

    But my unit test class has changed.  The [Test] method has been simplified with the use of concrete stubs instead of dynamic Mocks.  My stubs are nested classes so that they are truly dedicated to this test class:

       12 [TestFixture]
       13 public class CategoryTest
       14 {
       15     public CategoryTest() {
       16         Trace.Listeners.Add(new TextWriterTraceListener(Console.Out));
       17     }
       18 
       19     [Test]
       20     public void GetACategory(){
       21         Category.Database = new DatabaseToReturnCategory1();
       22 
       23         Category existing = new Category(1);
       24         Assert.AreEqual("Beverages", existing.Name);
       25     }
       26 
       27     public class DatabaseToReturnCategory1 : SqlDatabase {
       28         public override IDataReader ExecuteReader(string storedProcedureName, params object[] parameterValues) {
       29             return new DataReaderToReturnBeveragesAsCategoryName();
       30         }
       31     }
       32 
       33     public class DataReaderToReturnBeveragesAsCategoryName : IDataReader  {
       34         public bool Read() {
       35             Trace.WriteLine("Returning true from Read()", this.GetType().Name);
       36             return true;
       37         }
       38 
       39         public string GetString(int index) {
       40             string retValue = string.Empty;
       41             switch(index) {
       42                 case 1:
       43                     Trace.WriteLine("Returning Beverages from GetString(int)", this.GetType().Name);
       44                     retValue = "Beverages";
       45                     break;
       46             }
       47 
       48             return retValue;
       49         }
       50 
       51         public int GetOrdinal(string name) {
       52             int retValue = 0;
       53             switch(name) {
       54                 case "CategoryName":
       55                     Trace.WriteLine("Returning 1 from GetOrdinal(string)", this.GetType().Name);
       56                     retValue = 1;
       57                     break;
       58             }
       59 
       60             return retValue;
       61         }
       62 
       63         #region IDataReader Members
       64 
    -- unneeded stub methods not posted
      224 
      225         #endregion
      226     }
      227 }

     

    I have started a switch statement in the stubs so that I can easily add some more cases to test the other fields that I expect back.

    Note also my use of a trace listener.  I've grown to prefer Trace.Writeline instead of Console.Writeline because with Trace I can hook up more listeners and also get this output to other callers.  Using Console.Out with the listeners also allows me to get these statements to the console (and the NUnit gui).

    This approach is more straight-forward to me than dynamic mocks, so I'm going to stick with this approach as much as I can.

    This afternoon I'll be giving a presentation to my team about TDD and doing this demo to help get them started.  I hoping my team can quickly start using iterative development to drive quality and flexibility in our software.

  • TDD with the new Enterprise Library DAAB - level 300

    First, I give props to they guys at Microsoft who put out the Enterprise Library.  I especially like the data access application block.  I do, however, have one beef with it.  Everyone preaches “code to an interface”, and ADO.NET exhibits this (IDataReader, IDbCommand, etc), but the DAAB doesn't do this.  Consequently, I can't stub out a mock object to decouple the DAAB from the code I'm trying to unit test with NUnit.  I then tried NMock to create a dynamic mock, but the ExecuteReader(string, params object) method wasn't marked as virtual.  After changing it to virtual and recompiling the source, NMock would work (it appears most methods were marked virtual, but that some were overlooked).  Not having the interface to stub out _really_ makes TDD difficult.  It forces me to use dynamic mocks (which are more brittle).

    Here's a quick test I whipped up to create a Category class that is a record in the Categories table of Northwind.  Note the use of NMock to get my unit test to work without the dependency on the DAAB:

        7 public class Category {
        8 
        9     private string _name = string.Empty;
       10     private static Database _database = null;
       11     private static string _databaseInstance = "DEV";
       12 
       13     public string Name {
       14         get { return this._name; }
       15         set { this._name = value; }
       16     }
       17 
       18     public static Database Database {
       19         get {
       20             if(_database == null)
       21                 _database = DatabaseFactory.CreateDatabase(_databaseInstance);
       22 
       23             return _database;
       24         }
       25         set { _database = value; }
       26     }
       27 
       28     public Category(int categoryID)
       29     {
       30         IDataReader reader = Category.Database.ExecuteReader("GetCategoryByID", categoryID);
       31 
       32         if(reader.Read()){
       33             this._name = reader.GetString(reader.GetOrdinal("CategoryName"));
       34         }
       35     }
       36 }

    Now my test:

       10 [TestFixture]
       11 public class CategoryTest
       12 {
       13     [Test]
       14     public void GetACategory(){
       15 
       16         Mock mockDatabase = new NMock.DynamicMock(typeof(Database));
       17         Mock mockReader = new NMock.DynamicMock(typeof(IDataReader));
       18 
       19         mockReader.ExpectAndReturn("GetString", "Beverages", 56);
       20         mockReader.ExpectAndReturn("GetOrdinal", 56, "CategoryName");
       21         mockReader.ExpectAndReturn("Read", true);
       22         mockDatabase.ExpectAndReturn("ExecuteReader", mockReader.MockInstance, "GetCategoryByID", new object[]{1});
       23 
       24         Category.Database = (Database)mockDatabase.MockInstance;
       25 
       26         Category existing = new Category(1);
       27         Assert.AreEqual("Beverages", existing.Name);
       28 
       29         mockReader.Verify();
       30         mockDatabase.Verify();
       31     }
       32 }

    I had to use NMock for the Database class, so I just used it for the IDataReader interface as well (as I further this class, I will modify that to use a mock stub that implements IDataReader).

    This code work and allows me to test the instantiation of my Category object with the ID of a category.

    The data access block is awesome, but I WISH I had an interface to code against instead of just the abstract class.  I guess I'm going to have to insert the interface myself.

    By the way, I attended the webcast about this block this afternoon, and I have to say that it was the most fun webcast I've every attended.  The presenters were in shorts and cutting up and laughing the whole time.  :)

  • Thanks to those in the community from whom I've learned - level 000

    I have to take some time and formally thank those in the .Net community who have helped me achieve MCSD either by direct learning or by their webcasts, articles, or blog posts.

    • Noah Coad (MS) - The release manager for VSTS Dev & Test tools.  Noah and I went to college together at Texas A&M University and have been good friend since.  He has done some amazing stuff in his life with software, and I've learned a great deal from him.  He is excited about software, and it's contagious.
    • Mike Hnatt - Mike is a good friend, and an old professor of mine from Texas A&M.  He makes a living by selling custom software to manage fairs and consulting.  He's an inspiration as well.
    • Mark Dunn, Carl Franklin, Rory Blyth (.Net Rocks) - My education in .Net really began in January of 2003.  I had poked around with it when it first came out, but in January, I really got serious with it.  The trouble came when in Feb 2003, I was deployed with my Army Reserve unit to Iraq.  I purchased a Dell laptop over there, and I began reading blogs, articles, and anything .Net I could get my hands on.  This included .Net Rocks, which debuted while I was over there.  I synchronized as much content as possible while connected to the Net, and I digested it all offline.  I have learned a ton from .Net Rocks.  I even had an opportunity to call in to the show from Kuwait.  Thanks guys.
    • Steve Hickman - Hired me for my first programming job.  I programmed web apps for him using IDC/HTX.  This is where it all got started.
    • Scott Mitchell - So many articles.  I've learned a great deal from them.  I especially enjoyed the series on Data Structures that came out while I was overseas.
    • Scott Bellware (C# MVP) - Scott is a part of the local Austin, TX .Net User Group and is big into TDD.  I'm just getting started in TDD, and he's been a great help here.
    • Rockford Lhotka - Rocky doesn't know me too well, but his articles on SOA and OO are awesome.  He spoke at our user group once, and it blew my mind.  If you ever get to hear Rocky speak, take advantage of it.  Also, it's not very often that I run across another developer bigger than me (I'm 6'3", 275lbs) (Rocky is a rock!)
    • Jeffrey Richter - The first .Net book I ever read was Mr. Richter's Applied Microsoft .Net Framework Programming book.  It was like drinking from a fire hose.  I'm better off for it, though.  The detail about garbage collection has enabled me to debug memory problems in my code.  I had the pleasure of meeting Mr. Richter and the whole Wintellect crew when they came to Austin last month.
    • Paul Wilson - Specifically, his master pages controls taught me a lot about the ASP.NET control hierarchies and the page life cycle.  I dove in and extended his controls and have published my own set here.
    • Brad Abrams (MS) - I'm sure we've all learned from him in some form, but I thoroughly enjoyed his MSDN TV and .Net Show appearances.  Brad recently visited our User Group, and I had the opportunity to converse with him over BBQ!

    Thank you all for sharing your knowledge.

  • I became an MCSD.Net today! And 70-300 turned out to be not so bad - level 000

    I passed 70-300 today.  I had left that test till last because I had gotten the impression that it was the hardest one.  It turned out not to be.  70-229 (SQL Server) was the hardest for me.  Indexes, etc!  I'm an MCSD.Net now.  I went the track of doing MCAD.Net and now MCSD.  I'm excited.  Today I join the 12,829 people world-wide to hold this certification.  I guess now the number is 12,830.
  • Tech Ed 2005 - I'll be there - level 000

    It's confirmed.  I'll be in Orlando for Tech Ed 2005.  My registration is paid, hotel booked and plane ticket purchased!  I'm all set.  This will be my first Tech Ed.  I kept up with last year's Tech Ed from Iraq by reading other TechEdBloggers.  What a great idea!  I'm signed up.

    Check out my TechEdBloggers.Net profile.

  • XP SP2 makes it a snap to disable the Shockwave add-in - level 000

    If you are like me, you are annoyed when a flash advertisement on a website steals the entire screen and won't give it back until I click a small “close” button, but I have to make sure my mouse is on the exact right spot or I'll be forwarded to a site asking me to buy something.

    I have found no value in flash as it is currently used on the Net.  I know it can create some great UI stuff, but all it does for me is annoy me.  With SP2 for XP, a button is added in IE to Internet Options called “Manage Add-ins” under the Programs tab.  Here I was able to easily disable the shockwave add-in, and now I can't be happier.  Those annoying adds don't show up anymore, and if I need to use a site that depends on Flash, it's just a few clicks away.  In fact, if a site tries to load Flash while it's disabled, a quick click in the IE status bar will enable it for me.

     

  • My newly renovated desk at work - 3 displays - level 000

    Honestly, my CRT was starting to give me eye strain.  I'm a hardcore developer, and I decline meetings whenever possible.  I routinely type code at my computer 7-8 hours per day.  I have two LCD monitors now, and my screens are SO much clearer.  No refresh rate, just crystal clear pixels.

    Here's my desk.  I run off of a Lattitude D600 laptop (P-m 1.8/1GB RAM) with Windows Server 2003.  I have VS.Net 2003 and 2005 Beta 1 (they work great together).  And once you can run your app on one screen, debug it on another, and keep NUnit/Outlook on the other, you'll never go back.  I'm already thinking of how I can work in a 4th display.  For laptops, it's difficult because you actually need another video adapter.  I ordered the VTBook.

     

More Posts Next page »

Our Sponsors