11.01.2010

OMG Dependencies–new direction time

After looking at the BaseDALObject and tracing its usage, I’ve come to the conclusion that at the moment, it is too intertwined to refactor. I will leave it as is with its simple code cleanup and try a different angle.

So I decided to run the application. And kaboom! No go. So I think I will just start from the top down.

Wow, I completely forgot that back in the day we didn’t have the awesomeness of partial classes. So my main form has a bunch of generated controls etc from the designer. So I am going to create a new MainForm and let VS do its magic joo joo. And actually since I have to create a new form anyway, I am going to create a WPF application.

Step 1 – Create a new WPF project called RMS

Step 2 – Move all the WinForm controls over

When I tried to compile after fixing some minor issues. I got this error message

image

The issue is my MainForm still has a ‘main’ method. The new WPF application project has the main method in the App.xaml.cs

Remove this and we should be good to go.

  1.         /// <summary>
  2.         /// The main entry point for the application.
  3.         /// </summary>
  4.         [STAThread]
  5.         static void Main()
  6.         {
  7.             Application.Run(new MainForm());
  8.         }

The project already has a MainWindow and it is opened up by the application on startup. How do I know? I can just look at the App.xaml and the StartupUri.

image

So now time to start moving over the actual code and controls for the MainForm.

Menu

File > Quit

Manage Data > Manage Datasets, Manage Other Data

Analysis > Analyze Rate Schedules

To recreate this in WPF we simply do:

  1.         <Menu>
  2.             <MenuItem Header="File">
  3.                 <MenuItem Header="Quit" />
  4.             </MenuItem>
  5.             <MenuItem Header="Manage Data">
  6.                 <MenuItem Header="Manage Datasets" />
  7.                 <MenuItem Header="Manage Other Data" />
  8.             </MenuItem>
  9.             <MenuItem Header="Analysis">
  10.                 <MenuItem Header="Analyze Rate Schedules" />
  11.             </MenuItem>
  12.         </Menu>

Change layout controls

  1.             Panel leftPanel = new Panel();
  2.             leftPanel.AutoScroll = true;
  3.             leftPanel.Width = 350;
  4.             leftPanel.Dock = DockStyle.Left;
  5.  
  6.             Splitter splitterCtrl = new Splitter();
  7.             splitterCtrl.Dock = DockStyle.Left;
  8.             splitterCtrl.MinExtra = 200;
  9.             splitterCtrl.MinSize = 200;
  10.  
  11.             Panel mainPanel = new Panel();
  12.             mainPanel.AutoScroll = true;
  13.             mainPanel.Dock = DockStyle.Fill;
  14.  
  15.             Controls.AddRange(new Control[] {mainPanel, splitterCtrl, leftPanel});

Based on the naming of the controls and my recollection. I had a left side and a main panel. And looks like a splitter between the two panels. In WPF we can do this all within a grid control.

  1.     <Grid>
  2.         <Grid.RowDefinitions>
  3.             <RowDefinition Height="Auto" />
  4.             <RowDefinition />
  5.         </Grid.RowDefinitions>
  6.         <Grid.ColumnDefinitions>
  7.             <ColumnDefinition />
  8.             <ColumnDefinition />
  9.             <ColumnDefinition />
  10.         </Grid.ColumnDefinitions>
  1.         <StackPanel x:Name="leftPanel"
  2.                     Grid.Row="1"
  3.                     Grid.Column="0"
  4.                     Width="350"
  5.                     MinWidth="200"
  6.                     />
  7.         <GridSplitter Grid.Row="1"
  8.                       Grid.Column="1" />
  9.         <StackPanel x:Name="mainPanel"
  10.                     Grid.Row="1"
  11.                     Grid.Column="2" />

Now time to swap out change the code where some other controls are added to the panels.

  1.             Contract_Control contractsCtrl = new Contract_Control(rmsController);
  2.             contractsCtrl.Dock = DockStyle.Fill;
  3.             leftPanel.Controls.Add(contractsCtrl);
  4.  
  5.             RateSchedule_Control rateScheduleCtrl = new RateSchedule_Control(rmsController);
  6.             rateScheduleCtrl.Dock = DockStyle.Fill;
  7.             mainPanel.Controls.Add(rateScheduleCtrl);

We just need to wrap up the form controls in WindowsFormsHost controls and add them to the stackpanels.

  1.             var contractsCtrl = new Contract_Control(rmsController);
  2.             contractsCtrl.Dock = DockStyle.Fill;
  3.             var host = new WindowsFormsHost();
  4.             host.Child = contractsCtrl;
  5.             leftPanel.Children.Add(host);
  6.  
  7.             var rateScheduleCtrl = new RateSchedule_Control(rmsController);
  8.             rateScheduleCtrl.Dock = DockStyle.Fill;
  9.             var host2 = new WindowsFormsHost();
  10.             host2.Child = rateScheduleCtrl;
  11.             leftPanel.Children.Add(host2);

Now I can compile. But when I run, I blow up. Looks like I need to take a look at the RMS Controller. But that can wait for another day.

10.31.2010

baseDALObject–Refactor

DAL in this case stands for Data Access Layer. Since this the application was built in a very data centric manner, I figure I will start my refactoring here.

In the DAL project, I found an object named baseDALObject. I am assuming this is a base class used by the other DAL objects. The fact that the objects and project is called DAL objects makes me cringe.

The original class file looks like:

  1. using System;
  2. using System.Data;
  3. using System.Data.SqlClient;
  4. //using Microsoft.ApplicationBlocks.Data;
  5.  
  6. namespace RMS_DALObjects
  7. {
  8.     /// <summary>
  9.     /// Summary description for Class1.
  10.     /// </summary>
  11.     public class baseDALObject
  12.     {
  13.         #region "Variables"
  14.  
  15.         private string strConn = "connection_string";
  16.         private SqlConnection sqlConn;
  17.  
  18.         #endregion
  19.  
  20.         #region "Constructors"
  21.  
  22.         public baseDALObject(){}
  23.  
  24.         #endregion
  25.  
  26.         #region "Methods"
  27.  
  28.         public DataSet getDataSet(string strSQL)
  29.         {
  30.             try
  31.             {
  32.                 return null;
  33.                 //return SqlHelper.ExecuteDataset(strConn, CommandType.Text, strSQL);
  34.             }
  35.             catch (SqlException e)
  36.             {
  37.                 string msg = e.Message;
  38.                 return null;    
  39.             }
  40.         }
  41.  
  42.         public SqlDataReader getDataReader(string strSQL)
  43.         {
  44.             try
  45.             {
  46.                 sqlConn = new SqlConnection(strConn);
  47.                 sqlConn.Open();
  48.  
  49.                 SqlCommand sqlCmd = new SqlCommand(strSQL, sqlConn);
  50.  
  51.                 return sqlCmd.ExecuteReader();
  52.             }
  53.             catch (SqlException e)
  54.             {
  55.                 string msg = e.Message;
  56.                 return null;    
  57.             }
  58.         }
  59.  
  60.         public void closeConnection()
  61.         {
  62.             try
  63.             {
  64.                 sqlConn.Close();
  65.             }
  66.             catch (SqlException e)
  67.             {
  68.                 string msg = e.Message;
  69.             }
  70.         }
  71.  
  72.  
  73.  
  74.  
  75.         public SqlParameter[] getParameters(string storedProcedureName)
  76.         {
  77.             return null; //SqlHelperParameterCache.GetSpParameterSet(strConn, storedProcedureName);    
  78.            }
  79.  
  80.         public void executeUpdate(string storedProcedureName, SqlParameter[] sqlParams)
  81.         {
  82.             try
  83.             {
  84.                 sqlParams[sqlParams.Length-3].Value = "RMS";
  85.                 //SqlHelper.ExecuteNonQuery(strConn, CommandType.StoredProcedure, storedProcedureName, sqlParams);
  86.             }
  87.             catch (SqlException e)
  88.             {    string msg = e.Message;    }
  89.         }
  90.  
  91.         public void executeDelete(string storedProcedureName, SqlParameter[] sqlParams)
  92.         {
  93.             try
  94.             {
  95.                 //SqlHelper.ExecuteNonQuery(strConn, CommandType.StoredProcedure, storedProcedureName, sqlParams);
  96.             }
  97.             catch(SqlException e)
  98.             {    string msg = e.Message;    }
  99.         }
  100.  
  101.         #endregion
  102.  
  103.     }
  104. }

I commented out the application block since I don’t have it installed and well I plan on removing it. I will give my past self a gold star that it only affected a single class.

But then I noticed I am catching exceptions and not throwing them… no idea what the hell I was thinking there.

So here are some steps I am taking to just reformat the code and basic refactoring.

1. Removing the regions

2. Getting rid of unused namespaces

3. Removing the try catch blocks (We can figure out exception handling later)

And I removed unused comments. These steps alone reduced the size of the file by half.

I am going to rename files as well to reflect a more common coding standard.

The resulting file is now:

  1. using System.Data;
  2. using System.Data.SqlClient;
  3.  
  4. namespace RMS_DALObjects
  5. {
  6.     public class BaseDALObject
  7.     {
  8.         SqlConnection sqlConn;
  9.         string strConn = "connection_string";
  10.  
  11.         public DataSet GetDataSet(string strSQL)
  12.         {
  13.             return null;
  14.             //return SqlHelper.ExecuteDataset(strConn, CommandType.Text, strSQL);
  15.         }
  16.  
  17.         public SqlDataReader GetDataReader(string strSQL)
  18.         {
  19.             sqlConn = new SqlConnection(strConn);
  20.             sqlConn.Open();
  21.  
  22.             SqlCommand sqlCmd = new SqlCommand(strSQL, sqlConn);
  23.  
  24.             return sqlCmd.ExecuteReader();
  25.         }
  26.  
  27.         public void CloseConnection()
  28.         {
  29.             sqlConn.Close();
  30.         }
  31.  
  32.         public SqlParameter[] GetParameters(string storedProcedureName)
  33.         {
  34.             return null; //SqlHelperParameterCache.GetSpParameterSet(strConn, storedProcedureName);    
  35.         }
  36.  
  37.         public void ExecuteUpdate(string storedProcedureName, SqlParameter[] sqlParams)
  38.         {
  39.             sqlParams[sqlParams.Length - 3].Value = "RMS";
  40.             //SqlHelper.ExecuteNonQuery(strConn, CommandType.StoredProcedure, storedProcedureName, sqlParams);
  41.         }
  42.  
  43.         public void ExecuteDelete(string storedProcedureName, SqlParameter[] sqlParams)
  44.         {
  45.             //SqlHelper.ExecuteNonQuery(strConn, CommandType.StoredProcedure, storedProcedureName, sqlParams);
  46.         }
  47.     }
  48. }

I am pretty sure we will eventually change this from using inheritance to using composition but for now, I will just leave it alone. I will change the code to use regular good ole ADO .net

You can’t change everything at once. But we can start to change one thing at a time. So although I am slightly confused as to why I need to keep the connection around and why some other object is using that connection and calling close, I will leave it as is.

But I will change the name of the sqlConn to _connection. I will also create a createConnection method the other methods can use.

It has also been awhile since I used plain ole vanilla ADO so forgive me if I do something wrong. Smile

After a bit of tweaking the GetDataSet method now looks like

  1.         public DataSet GetDataSet(string sql)
  2.         {
  3.             createConnection();
  4.             var dataSet = new DataSet();
  5.             new SqlDataAdapter(sql, _connection).Fill(dataSet);
  6.             
  7.             return dataSet;
  8.         }

Refactoring the GetDataReader method results in

  1.         public SqlDataReader GetDataReader(string sql)
  2.         {
  3.             createConnection();
  4.             _connection.Open();
  5.  
  6.             return new SqlCommand(sql, _connection).ExecuteReader();
  7.         }

Now the parameters methods I am going to have to think about. It’s rather late and that is a pretty good start.

Again check out the code at http://github.com/RookieOne/RMS_Refactor

In the future I should branch the code, but … I forgot.

10.30.2010

My Dream Refactoring

I’ve always wanted to go back and refactor my first program I wrote right out of school. But although I could find my hastily scrounged together notes on the application, alas I could not find the source.

But recently while cleaning off some external hard drives, I found it. And maybe I did a jig with delight. … maybe.

Why do I care? Not because the application would be of use, but because I wrote it. I wrote it straight from school, with no senior or experienced developer around for guidance. I’ve never heard of source control, testing, design patterns.. or anything. I had no .Net experience and had to figure out everything on my own.

I was a reimbursement analyst and I programmed on the side. This application was meant to replace self created unwieldy access databases and queries. Turn an adhoc process to an automated one. And the crazy thing was… it worked. I turned my job into a button pushing operation where I could spend most of my days reading a book or surfing the internet as the application would churn through data.

I turned a day or two process into a 30 minute turn around. When the negotiations for rates were going on, I could give the team almost instant turn around on proposed rate changes. It was a major win.

Anyway, now… 5 years later, I have a unique chance to refactor my own code. Take a WinForms application written by a junior developer in .Net 1.0 and update everything to better coding standards and .Net 4.0.

I don’t have a plan, nor do I want one. I am just going to open the application up and start fiddling. I want to go piece by piece. Slowly add tests and update the code. I want the work to be a demonstration on how to take a legacy application and not just rewrite, but refactor it to better standards and updated frameworks.

Word to the wise, there is some VB and C# projects (I had to install VB for my Visual Studio because normally I leave it out). Also the application won’t run at first because I don’t have a database and I noticed some projects failed to build. And the project structure is whack. But that will be fixed in time.

Check out the original code at : http://github.com/RookieOne/RMS_Refactor

10.29.2010

Learning Bash Aliases and Functions

During our fantastical Lunch and Learn at ChaiOne, we went over customizing bash using aliases and functions. These little tools make normal command line mortals into command line gods… or at least demi-gods.

If you are new to Macs and other Unix based systems, like I am, then what I am about to share will be new to you. It was new to me until today. And for those Unix gurus, if I describe something incorrectly please let me know.

First of all there is a file called .bashrc in your home directory ( ~ ). This file is loaded anytime you run a command script or open a terminal window. In this file we can add aliases, functions, and other customizations for our command line.

With an alias I can create a shortcut ‘g’ for ‘git status’.

alias g=’git status’

Now I can just type ‘g’ to run ‘git status’.

I can use a function to create a more robust shortcut. For example, I can create a shortcut for ‘git push’. In this function by default I push to ‘origin master’ but if I provide an argument it will push to ‘$argument master’.

function gpush {
if [[ -z $1 ]]
then
git push origin master
else
git push $1 master
fi
}

gpush => git push origin master

gpush heroku => git push heroku master

Once you add the alias or function to your .bashrc, you can reload the file using

source ~/.bashrc

And there is a shortcut for source ( . ) So you can use

. ~/.bashrc

Now you know how to create aliases and functions. I must admit, I think its pretty damn cool. This coming from the guy that a year ago was hesitant to use git on the command line.

10.26.2010

Houston Techfest – Design Patterns

An email from Claudio reminded me that I completely forgot to link the slides and code from the Houston Techfest presentation!

And just a reminder that everything is offered as is. But that doesn’t mean you can’t email me or Claudio for more information. :)

You can find the slides on slideshare at :

http://www.slideshare.net/RookieOne/techfest-design-patterns

And the code you can find (as is) at bitbucket :

http://bitbucket.org/rookieone/design-patterns

And you can find the code on GitHub at :

http://github.com/RookieOne/Houston-Techfest-Design-Patterns