Friday, February 27, 2009

Source Code Doesn't Lie #3 - The Visual Studio Class Browser

The heart of any object oriented application development should be the class browser. While there are numerous benefits to following object oriented design patterns, the two benefits I want to discuss are inheritance and programming code reuseability. Given there are few things in life that suck less then the Class Browser found in Visual Studio (well .BLOAT does come to mind to think of it), it defies logic why the Visual Studio Class Browser has not been corrected.

Before moving to looking at the class browser lets review a simple example of how inheritance works.

Lets say we have a base class called "vehicle", and this base class has certain functionality (methods) such as "Turn on Engine", "Turn Off Engine", "Make Vehicle Go", "Make Vehicle Stop", "Motor" along with some properties that tell us what is happening to the vehicle: "Are headlights On", "Is Motor Oil Full", "Are Seat Belts Fastened" etc....

Next we are going to build a benz and a septic tank truck (class). Instead of building these classes from scratch we can start with the vehicle class and subclass it. By doing so we gain access to all the functionality found in the original vehicle class and we simple build upon it.

By writing code in this manner we know the foundation is stable and tested i.e. the vehicle class. Besides that let's say we come up with a new property like "Is Transmission Fluid Low" instead of adding this to both the benz and septic tank truck we only need to write the code into the vehicle class because the benz and septic tank are inherited from the vehicle class, this new property is there and ready for us to use. Neither the benz or septic tank truck have to worry about everything going on behind the scenes to make "Is Transmission Fluid Low" work.

So it should be clear why this is a great programming model and a huge time saver.

The purpose of the class browser is to allow us to work with these classes in a "productive" manner. Now let's compare the legacy Foxpro's class browser to that of Microsoft newest technology advancement, Visual Studio's Class Browser, to see if perhaps we can Develop at Light Speed using Visual Studio and maybe Microsoft's slogan for Visual Studio is correct.

Below is the legacy FoxPro class browser. It is the standard explorer interface. For the purpose of this sample I added a UI control and subclassed it to prove it could be done and to point out this is something that CAN NOT be done in Microsoft newest tool Visual Studio, yes this is a WTF moment! The reasons why this is important is for developing a UI layer in N-TIER applications. The other thing that is noteworthy in FoxPro's class browser, class inheritance is performed in the class browser NOT in code like in the great Visual Studio 2008.
















Double clicking on a class allows you to drill into the class browser code environment where you can create proprieties, methods and add programming code. With the legacy Visual FoxPro Class Browser you have a "productive" environment to get your work done. You have a property sheet that displays all the proprieties, events and methods for the class. Double click on the method in the property sheet you want to work with and a code window opens that only displays code for that method furthermore there is a "view parent code" button that brings up a window that contains the code in the base class for that method. Of course you have the option to export the class from the class browser to a file and work with the code outside the legacy class browser .




















Now lets examine the Great Visual Studio's Class Browser. It looks flashier then the VFP class browser but that is where the benefit, if that even is one, ends. It is entirely symbolism over substance. More importantly there is not a way to subclass the .BLOAT UI controls using the class browser, remember this is something the legacy FoxPro Class Browser could do.























After the class diagram has been constructed you switch to, what I refer to as, Visual Studio's DOS MODE and you are basically digging through code to do everything that needs to be done with the classes. Unlike the legacy Visual FoxPro's class browser, Visual Studio doesn't provide you with a productive code environment instead we are given a text editor with intellisense to maintain the code.

Below is the code the simple vehicle class structure generated that we have to maintain using Visual Studio 2008 glorified text editor.

using System;
using System.Collections.Generic;
using System.Text;

namespace sample
{

class Vehicle
{

public int IsOilFull
{
get
{
throw new System.NotImplementedException();
}
set
{
}
}

public int AreHeadLightsOn
{
get
{
throw new System.NotImplementedException();
}
set
{
}
}

public int AreSeatBeltsFastened
{
get
{
throw new System.NotImplementedException();
}
set
{
}
}

public void Motor()
{
throw new System.NotImplementedException();
}

public void TurnEngineOn()
{
throw new System.NotImplementedException();
}

public void TurnEngineOff()
{
throw new System.NotImplementedException();
}
}

public class Benz : Vehicle
{
}

public class SepticTruck : Vehicle
{
}

It should be clear the Class Browser in Microsoft's Great Visual Studio 2008 is about as useful to developers as an Indian Saris is to Jenna Jameson.

Now you are thinking Mark that only is your opinion of the Visual Studio Class Browser. But oh not so Markus Egger MVP, VS cheerleader and editor of code magazine wrote the following in his blog.

..."The class browser was the VFP workhorse tool, true. Especially in the early days of .NET I have often wished I had it, especially since OO is and always has been so important to me. I even considered writing one"...

To add insult to injury, with WPF Microsoft is moving away from this productive object oriented subclass programming paradigm for UI controls to the miserable XAML composition implementation. In a future post, I will explain in great and gory detail why Microsoft's decision to implement the WPF/XAML paradigm is misguided and flawed at best. Their decision can only be compared to deciding to spend Christmas in Iraq! As hard as it is believe the WPF tools suck even worse then what we currently have available to us in Visual Studio, I really didn't even think that was possible, but yes friends it is true leave it Microsoft to develop the impossible. Unforunately for developers in this case it is not a good thing!

I'm still trying to find out what Microsoft meant by "Development at Light Speed" in the context of the Great Visual Studio perhaps they are comparing Visual Studio to assembler? Maybe we will have more luck with my next post trying to figure this out...

The score sheet thus far:

Sample Application: Legacy FoxPro beats Visual Studio 2008 and .NET
Class Browser: Legacy FoxPro beats Visual Studio 2008 and .NET

Legacy Visual FoxPro: 2 points
Visual Studio 2008 and .BLOAT: 0 points

Maybe I should have used DOS Foxbase to compare against Visual Studio 2008 to give Visual Studio a chance.

Until next time let's all "develop at bloat speed" with Visual Studio 2008 and the 70k+ classes of the .BLOAT API wrappers.

.Mark

Friday, February 20, 2009

SOURCE CODE DOESN'T LIE PART 2: The sample application code in C#

If you recall in my prior post I wrote a small application using the outdated legacy development tool known as Visual FoxPro and I had to write about 26 lines of code to finish the application and it took about 8 minutes. The legacy Visual FoxPro code and application specifications are in the previous blog entry.

When I was assembling the C# code contained in this post, since neither Sam or anyone else wanted to even quote the application let alone write it, I was thinking of all these witty criticisms to preface the code. However I don't even need to say anything else as I truely believe the volume of code this application required, that Sam referred to as a "toy", speaks for itself.

Update 2/23/2009
I was reading through mini microsofts blog which is one of favorites and I found this quote I wanted to share with you as he defined visual studio, wpf, mvc perfectly!

"Going big and broad and trying to enter and dominate every possible software market is exactly what resulted in Microsoft having reactive and broad, shallow features that are rushed out lacking polish and usually lead to user frustration as the shallow experience putters out. "


Enjoy the show!
.Mark


Dot Bloat proudly present "Developing at Light Speed! "

Act 1: The Screen Shots To Prove The Code Runs!


















Act 2: The Source Code

Application Start Up Code
Code auto generated by Visual Studio to launch the application.

using System;
using System.Collections.Generic;
using System.Windows.Forms;
namespace sample
{
static class Program
{
///
/// The main entry point for the application.
///

[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new Form1());
}
}
}

UI Form Code
The form designer code auto generated by Visual Studio

namespace sample
{
partial class Form1
{
///
/// Required designer variable.
///

private System.ComponentModel.IContainer components = null;
///
/// Clean up any resources being used.
///

/// true if managed resources should be disposed; otherwise, false.
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Windows Form Designer generated code
///
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
///

private void InitializeComponent()
{
this.button1 = new System.Windows.Forms.Button();
this.button2 = new System.Windows.Forms.Button();
this.button3 = new System.Windows.Forms.Button();
this.dataGridView1 = new System.Windows.Forms.DataGridView();
this.textBox1 = new System.Windows.Forms.TextBox();
this.label1 = new System.Windows.Forms.Label();
((System.ComponentModel.ISupportInitialize)(this.dataGridView1)).BeginInit();
this.SuspendLayout();
//
// button1
//
this.button1.Location = new System.Drawing.Point(403, 371);
this.button1.Name = "button1";
this.button1.Size = new System.Drawing.Size(75, 23);
this.button1.TabIndex = 0;
this.button1.Text = "button1";
this.button1.UseVisualStyleBackColor = true;
this.button1.Click += new System.EventHandler(this.button1_Click);
//
// button2
//
this.button2.Location = new System.Drawing.Point(479, 371);
this.button2.Name = "button2";
this.button2.Size = new System.Drawing.Size(75, 23);
this.button2.TabIndex = 1;
this.button2.Text = "button2";
this.button2.UseVisualStyleBackColor = true;
//
// button3
//
this.button3.Location = new System.Drawing.Point(556, 371);
this.button3.Name = "button3";
this.button3.Size = new System.Drawing.Size(75, 23);
this.button3.TabIndex = 2;
this.button3.Text = "button3";
this.button3.UseVisualStyleBackColor = true;
this.button3.Click += new System.EventHandler(this.button3_Click);
//
// dataGridView1
//
this.dataGridView1.ColumnHeadersHeightSizeMode = System.Windows.Forms.DataGridViewColumnHeadersHeightSizeMode.AutoSize;
this.dataGridView1.Location = new System.Drawing.Point(1, 27);
this.dataGridView1.Name = "dataGridView1";
this.dataGridView1.Size = new System.Drawing.Size(630, 341);
this.dataGridView1.TabIndex = 3;
//
// textBox1
//
this.textBox1.Location = new System.Drawing.Point(128, 3);
this.textBox1.Name = "textBox1";
this.textBox1.Size = new System.Drawing.Size(344, 20);
this.textBox1.TabIndex = 4;
//
// label1
//
this.label1.AutoSize = true;
this.label1.Location = new System.Drawing.Point(12, 6);
this.label1.Name = "label1";
this.label1.Size = new System.Drawing.Size(35, 13);
this.label1.TabIndex = 5;
this.label1.Text = "label1";
this.label1.TextAlign = System.Drawing.ContentAlignment.MiddleRight;
//
// Form1
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(633, 399);
this.Controls.Add(this.label1);
this.Controls.Add(this.textBox1);
this.Controls.Add(this.dataGridView1);
this.Controls.Add(this.button3);
this.Controls.Add(this.button2);
this.Controls.Add(this.button1);
this.Name = "Form1";
this.Text = "Form1";
this.Load += new System.EventHandler(this.Form1_Load);
((System.ComponentModel.ISupportInitialize)(this.dataGridView1)).EndInit();
this.ResumeLayout(false);
this.PerformLayout();
}
#endregion
private System.Windows.Forms.Button button1;
private System.Windows.Forms.Button button2;
private System.Windows.Forms.Button button3;
private System.Windows.Forms.DataGridView dataGridView1;
private System.Windows.Forms.TextBox textBox1;
private System.Windows.Forms.Label label1;
}
}

The C# Code which was manually written for the form

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
//Sample data layer and generic file utilities class
using SampleDataLayer;
using SampleFileUtilities;
namespace sample
{

public partial class Form1 : Form
{
//Create a property to hold the dataset
DataSet oDataSet;

public Form1()
{
InitializeComponent();
}

private void Form1_Load(object sender, EventArgs e)
{

//Note: I put the code to populate the grid in the form load event
//when developing this app and I forgot to move it to the populate
// button on the form. Therefore there is no click event code in the
// populate button and I'm too lazy to worry about it now - I do apologize.....
//
//This section of code could have been done using the property sheet
//Set the label captions
this.label1.Text = "Selected Filename:";

// Put the captions on the command buttons
this.button1.Text = "Get File";
this.button2.Text = "Populate Grid";
this.button3.Text = "Export Grid";
//Put a caption on the form
this.Text = "Visual Studio Sample";
//End playing with simple properties

//Create the data layer
DataLayer oDataLayer = new DataLayer();
//Create a binding source object for the grid
BindingSource oBindingSource = new BindingSource();
//We need to get a dataset so the grid has something to play with
//I stored it in a property just to make passing it around easier for clarity in the sample.
this.oDataSet = oDataLayer.PopulateDataSet("Select * from person.contact", "dsPersons");
//Now we need to bind the dataset to the BindingSource
oBindingSource.DataSource = this.oDataSet;

//Finally we hand the bindingsource datasource off to the datagrid
this.dataGridView1.DataSource = oBindingSource.DataSource;
this.dataGridView1.DataMember = "dsPersons";
}

private void button1_Click(object sender, EventArgs e)
{

// Create the save file dialog object
SaveFileDialog dlg = new SaveFileDialog();

//Populate the pull down list in the save file dialogue
dlg.Filter = "Excel Files (*.xls)*.xls";

// Show the box and ensure the ok button has been pressed
if (dlg.ShowDialog() == DialogResult.OK)
{

// Update the form with the name of file the user entered
this.textBox1.Text = dlg.FileName;

}
}

private void button3_Click(object sender, EventArgs e)
{

//Get a reference to the fileutilites namespace
FileUtilities oFile = new FileUtilities();

// Send the data to excel
oFile.ExportToExcel(this.oDataSet, this.textBox1.Text.ToString().Trim());

}
}
}

Yes keep scrolling down there is more code yet to come!

Data Access Class Code

using System;
using System.Collections.Generic;
using System.Text;
using System.Data;
using System.Data.SqlClient;
namespace SampleDataLayer
{

public class DataLayer
{

public DataLayer()
{
}

// For fairness in the comparision I used basically a simple read only data set.
// To send up to the form to bind to the grid.

public DataSet PopulateDataSet(String cSelectCommand, string cDataSetName)
{
//Create a data set that we can populate
DataSet ds = new DataSet();

//Establish the connection to SQL Server
//For the sake of this sample the connection string is hard coded
//in production applications the SQLConnectionStringBuilder would be used.
//The connection string was removed for security reasons
SqlConnection oSqlConnection = new SqlConnection("MyConnectionString");

//Create the sql command object
SqlCommand oSqlCommand = new SqlCommand();

//Tell the sql object what type of statement we are going to work with
oSqlCommand.CommandType = CommandType.Text;

//Pass the sql statement to the sql command object
//In a production application should set other properities such as the timeout etc.
oSqlCommand.CommandText = cSelectCommand;

//Bind the connection object to the sql command
oSqlCommand.Connection = oSqlConnection;

//Create a data adapter
SqlDataAdapter da = new SqlDataAdapter(oSqlCommand);

//Try Catch Throw structure should be used to handle errors
//But I didn't want to be accused of code bloating - Lighten up it was a joke

//Open the sql connection
oSqlConnection.Open();

//Fill the dataset
da.Fill(ds, cDataSetName);

//Close the sql connection
oSqlConnection.Close();

//Return the data set
return ds;
}
}
}

You are in the home stretch 150+ lines of code left! And remember it took VFP 26 lines of code....


Utility File Class Code

Note: The less than and greater than signs and slashes in this section of code was messing up the formatting of the blog. Those characters have been replaced with the word slash, lt and gt.
This code, with the exception of the patching I had to put in to extend the datatype support, was originally published on codeplex.

using System;
using System.Collections.Generic;
using System.Text;
using System.Data;

namespace SampleFileUtilities
{
public class FileUtilities
{
public FileUtilities()
{
}

// Allows the dataset to be exported to excel
//
// Codeplex introduction
// This function takes in a DataSet and file name and writes the DataSet to an Excel worksheet.
//The code is pretty straightforward. Great thing about this function is that, it's technically an
//XML file that is saved as an XLS file. So it can be used as either file format. No more leading zero
//truncation on numbers that look like strings. Example, if you made a tab delimited file and put a field
//such as "00036" (a field that looks like a number but should be regarded as a string), MS Excel would truncate the leading zeros...
//This problem is solved with this method.
//
//I really enjoy the problem solved with this method - In VFP a single line of code SOLVES this problem

public void ExportToExcel(DataSet source, string fileName)
{
System.IO.StreamWriter excelDoc;

excelDoc = new System.IO.StreamWriter(fileName);
const string startExcelXML = "LTxml versionGT SLASH r SLASH nLTWorkbook " +
"xmlns= SLASH "urn:schemas-microsoft-com:office:spreadsheet SLASH " SLASH r SLASH n" +
" xmlns:o= SLASH "urn:schemas-microsoft-com:office:office SLASH " SLASH r SLASH n " +
"xmlns:x= SLASH "urn:schemas- microsoft-com:office:" +
"excel SLASH " SLASH r SLASH n xmlns:ss= SLASH "urn:schemas-microsoft-com:" +
"office:spreadsheet SLASH "GT SLASH r SLASH n LTStylesGT SLASH r SLASH n " +
"LTStyle ss:ID= SLASH "Default SLASH " ss:Name= SLASH "Normal SLASH "GT SLASH r SLASH n " +
"LTAlignment ss:Vertical= SLASH "Bottom SLASH "/GT SLASH r SLASH n LTBorders/GT" +
" SLASH r SLASH n LTFont/GT SLASH r SLASH n LTInterior/GT SLASH r SLASH n LTNumberFormat/GT" +
" SLASH r SLASH n LTProtection/GT SLASH r SLASH n LT/StyleGT SLASH r SLASH n " +
"LTStyle ss:ID= SLASH "BoldColumn SLASH "GT SLASH r SLASH n LTFont " +
"x:Family= SLASH "Swiss SLASH " ss:Bold= SLASH "1 SLASH "/GT SLASH r SLASH n LT/StyleGT SLASH r SLASH n " +
"LTStyle ss:ID= SLASH "StringLiteral SLASH "GT SLASH r SLASH n LTNumberFormat" +
" ss:Format= SLASH "@ SLASH "/GT SLASH r SLASH n LT/StyleGT SLASH r SLASH n LTStyle " +
"ss:ID= SLASH "Decimal SLASH "GT SLASH r SLASH n LTNumberFormat " +
"ss:Format= SLASH "0.0000 SLASH "/GT SLASH r SLASH n LT/StyleGT SLASH r SLASH n " +
"LTStyle ss:ID= SLASH "Integer SLASH "GT SLASH r SLASH n LTNumberFormat " +
"ss:Format= SLASH "0 SLASH "/GT SLASH r SLASH n LT/StyleGT SLASH r SLASH n LTStyle " +
"ss:ID= SLASH "DateLiteral SLASH "GT SLASH r SLASH n LTNumberFormat " +
"ss:Format= SLASH "mm/dd/yyyy;@ SLASH "/GT SLASH r SLASH n LT/StyleGT SLASH r SLASH n " +
"LT/StylesGT SLASH r SLASH n ";
const string endExcelXML = "LT/WorkbookGT";

int rowCount = 0;
int sheetCount = 1;
excelDoc.Write(startExcelXML);
excelDoc.Write("LTWorksheet ss:Name= SLASH "Sheet" + sheetCount + " SLASH "GT");
excelDoc.Write("LTTableGT");
excelDoc.Write("LTRowGT");
for (int x = 0; x LT source.Tables[0].Columns.Count; x++)
{
excelDoc.Write("LTCell ss:StyleID= SLASH "BoldColumn SLASH "GTLTData ss:Type= SLASH "String SLASH "GT");
excelDoc.Write(source.Tables[0].Columns[x].ColumnName);
excelDoc.Write("LT/DataGTLT/CellGT");
}
excelDoc.Write("LT/RowGT");
foreach (DataRow x in source.Tables[0].Rows)
{
rowCount++;
//if the number of rows is GT 64000 create a new page to continue output
if (rowCount == 64000)
{
rowCount = 0;
sheetCount++;
excelDoc.Write("LT/TableGT");
excelDoc.Write(" LT/WorksheetGT");
excelDoc.Write("LTWorksheet ss:Name= SLASH "Sheet" + sheetCount + " SLASH "GT");
excelDoc.Write("LTTableGT");
}
excelDoc.Write("LTRowGT"); //ID=" + rowCount + "
for (int y = 0; y LT source.Tables[0].Columns.Count; y++)
{
System.Type rowType;
rowType = x[y].GetType();
switch (rowType.ToString())
{
case "System.String":
string XMLstring = x[y].ToString();
XMLstring = XMLstring.Trim();
XMLstring = XMLstring.Replace("&", "&");
XMLstring = XMLstring.Replace("GT", "GT");
XMLstring = XMLstring.Replace("LT", "LT");
excelDoc.Write("LTCell ss:StyleID= SLASH "StringLiteral SLASH "GT" +
"LTData ss:Type= SLASH "String SLASH "GT");
excelDoc.Write(XMLstring);
excelDoc.Write("LT/DataGTLT/CellGT");
break;
case "System.DateTime":
//Excel has a specific Date Format of YYYY-MM-DD followed by
//the letter 'T' then hh:mm:sss.lll Example 2005-01-31T24:01:21.000
//The Following Code puts the date stored in XMLDate
//to the format above
DateTime XMLDate = (DateTime)x[y];
string XMLDatetoString = ""; //Excel Converted Date
XMLDatetoString = XMLDate.Year.ToString() +
"-" +
(XMLDate.Month LT 10 ? "0" +
XMLDate.Month.ToString() : XMLDate.Month.ToString()) +
"-" +
(XMLDate.Day LT 10 ? "0" +
XMLDate.Day.ToString() : XMLDate.Day.ToString()) +
"T" +
(XMLDate.Hour LT 10 ? "0" +
XMLDate.Hour.ToString() : XMLDate.Hour.ToString()) +
":" +
(XMLDate.Minute LT 10 ? "0" +
XMLDate.Minute.ToString() : XMLDate.Minute.ToString()) +
":" +
(XMLDate.Second LT 10 ? "0" +
XMLDate.Second.ToString() : XMLDate.Second.ToString()) +
".000";
excelDoc.Write("LTCell ss:StyleID= SLASH "DateLiteral SLASH "GT" +
"LTData ss:Type= SLASH "DateTime SLASH "GT");
excelDoc.Write(XMLDatetoString);
excelDoc.Write("LT/DataGTLT/CellGT");
break;
case "System.Boolean":
excelDoc.Write("LTCell ss:StyleID= SLASH "StringLiteral SLASH "GT" +
"LTData ss:Type= SLASH "String SLASH "GT");
excelDoc.Write(x[y].ToString());
excelDoc.Write("LT/DataGTLT/CellGT");
break;
case "System.Int16":
case "System.Int32":
case "System.Guid":
case "System.Int64":
case "System.Byte":
excelDoc.Write("LTCell ss:StyleID= SLASH "Integer SLASH "GT" +
"LTData ss:Type= SLASH "Number SLASH "GT");
excelDoc.Write(x[y].ToString());
excelDoc.Write("LT/DataGTLT/CellGT");
break;
case "System.Decimal":
case "System.Double":
excelDoc.Write("LTCell ss:StyleID= SLASH "Decimal SLASH "GT" +
"LTData ss:Type= SLASH "Number SLASH "GT");
excelDoc.Write(x[y].ToString());
excelDoc.Write("LT/DataGTLT/CellGT");
break;
case "System.DBNull":
excelDoc.Write("LTCell ss:StyleID= SLASH "StringLiteral SLASH "GT" +
"LTData ss:Type= SLASH "String SLASH "GT");
excelDoc.Write("");
excelDoc.Write("LT/DataGTLT/CellGT");
break;
default:
throw (new Exception(rowType.ToString() + " not handled."));
}
}
excelDoc.Write("LT/RowGT");
}
excelDoc.Write("LT/TableGT");
excelDoc.Write(" LT/WorksheetGT");
excelDoc.Write(endExcelXML);
excelDoc.Close();
}
}
}

That's all folks....
The End

Monday, February 16, 2009

Source Code Doesn't Lie

MSFT'S NEW CATCH PHRASE - VISUAL STUDIO: DEVELOPING AT LIGHT SPEED

Perhaps they confused the source code with FoxPro when they came up with this slogan as the code comparision is complete. To develop the same application between Visual FoxPro -vs- Visual Studio the results are:

VISUAL FOXPRO 26 LINES OF CODE - 8 MINUTES *from scratch

VISUAL STUDIO 2008 POWERED BY 70K+ CLASSES OF .NET BLOAT 300+ LINES OF CODE - 35 MINUTES! *using some of my prewrriten framework components!

------------------------------------------------------------------------------------

Background

If anyone has been following my friend Soma’s blog, Someone named Sam and I have been debating the pros and cons of using Microsoft's Latest and Greatest Rapid Application Development Toolkit otherwise known as Visual Studio/.NET compared to the outdated legacy Visual Basic and Visual FoxPro development tools. In the event you haven't been following this I will give you the short version of what has transpired so far:

Sam appears to be your typical VS cheerleader or Microsoft employee not sure which as he refuses to answer the question even thou I asked him multiple times. He is very pro Visual Studio to say the least and needless to say I have a difference of opinion. After several rounds of back and forth debating various points, I asked him to write a small N-TIER application using The Great Visual Studio 2008 and I will do the same using the outdated legacy application FoxPro 9.0..

Now here is the really cool part Sam would like nothing better then for me to quit posting on Soma's blog and furthermore he would be delighted if I quit telling the truth about Visual Studio, I'm sure Soma would like that as well. Therefore I stated if Sam could write this application in fewer lines of code using Visual Studio 2008 then I can in Visual FoxPro I will stop posting on Soma's blog. Seems fair enough. I will extend this offer to Soma and Scott Gu as well. Just post the code in the comments of my blog and use Visual Studio 2008 - I really don't care if they use VB.NET or C# just make it a simple N-TIER application hopefully using LINQ so I can mock the poorly implemented data context and helper objects that are required to use Linq in the middle tier.

Now common sense would lead us to believe a new great technology such as Visual Studio powered by all bloat in .NET should be the easy victor after all would Microsoft's marketing department and the cheerleaders try to misinform us? Especially since FoxPro is no longer worthy of even being produced anymore by Microsoft.

Specifications

The specs are simple, create a very small N-TIER application (user interface, data layer, database) that simply displays a form, connects to SQL Server that pulls some customer data from adventureworks or northwest sample database. Display the data in a grid formatted correctly (phone numbers etc) contained on the form and include a command button to save the data to excel. .

Actions speaks louder then words

Given I made this wager I wanted to keep up my end of the bargain. I wrote this little application. The application required 26 lines of FoxPro code and took 8 minutes to generate. There is some code that the form designer auto generated that I did not count. At the end of the blog I included all the code.

The WinForms C# version which I wrote tonight also, using my C# framework required 35 minutes. I do not have an exact line count as I had to allow for my framework code. Making a rough estimate excluding framework code, the application is around 3o0 lines of code.

Since I already had much of the functionality written into my "framework" it is hard to tell exactly how long this would take by hand to code out, I'm guessing a minimum of 2 hours assuming codeplex was used to steal some sample excel export logic since VS doesn't natively export to excel, as a sidebar can you freaking believe 70k classes of bloat in .NET and can't freaking export a dataset to excel WTF! - anyway- However, if you wrote everything from scratch including the excel export (which would be the fairest comparision given that is how I wrote the VFP application) I would bill this out at a minimum 6 hours using Visual Studio 2008 and .BLOAT.

Development Cost

Visual FoxPro: If I used VFP dbf files instead of SQL Server this application would cost about 50 bucks as that is the minimum I charge. Of course VFP has a royalty free distribution so no licensing is involved and yes it would support more then 20 users.

Visual Studio: The Rapid Application Development Tool Visual Studio Microsoft Latest and Greatest Development Environment required more then 10 times more code then Visual Foxpro to write the same application. YES THAT IS RIGHT MORE THEN 10 TIMES MORE CODE THEN FOXPRO. Being generous I will use the 2 hour estimate for the sake of argument. If we assume 125 a hour is the going rate for a Visual Studio Programmer the cost is 250 dollars. Then we still have to be concerned with data storage and hardware requirements to even get the application to run.

Even if you really want to remain in your fantasy Visual Studio World and think I don't know what I'm talking about, as misguided and flawed as that thought pattern is, below is a comment from a Microsoft MVP regarding the cost of a Visual Studio application.

...Les Pinter has a nice strategy for selling VFP apps.He first shows to his audience, most likely managers and budget-responsible people, the whole myriad of classes and possibilities of VB.Net of C# or whatever they can come up with.He is driving them crazy with all the things you can do in .NET to a point where they ask him for a price to develop that must-have application XYZ.He gives them the price and the time to deploy the app and tells them there is an alternative.... and then says, "nahhh, you probably won't be interested, it will cost you only 25% of the price I just mentioned but it won't be interesting of you". Well, those budget-responsible people ARE interested then, and then he shows them his "special framework, developed in C++, AKA VFP".He drives their minds to a boiling point with another show-off from VFP and compares that with the things he just showed to his audience. And shows that it is indeed, remarkably quicker, and, what's more, cheaper!!

Waiting for the cheerleaders to prove me wrong

I will give Sam or any other cheerleader for the matter that disagrees with my assessment sometime to respond perhaps a couple of weeks and we can see what the self proclaimed expert VS programmers can do. If I don't hear anything, which wouldn't surprise me, I will post my VS code.

I even took this one step further I offered to pay Sam to code the application in WPF and Winforms. The only catch is I get to post the code on my blog. So we will see if Sam takes me up on my offer.

Cheerleaders - No excuses for Visual Studio Please - Source Code Doesn't Lie

I know the arguments the cheerleaders will make:

1) This application is simple - Have you happen to see the examples GU uses to showcase new technology none of it is real world, cheerleaders get off and praise him for it! The size of the project shouldn't matter! The bottom line is new technology should be better then legacy technology even for simple tasks that is called progress. If new technology is not better then legacy technology it is called going backwards. If we have to pay more for new technology so we can move in a backward direction that is called getting screwed!

2) Visual Studio can do all this cool stuff Visual FoxPro and Visual Basic Can't - Some of this argument might be valid but guess what C++ can! And yes C++ DLL libraries can be consumed by FoxPro more over many small and medium size businesses only require a LAN based crud database application they don't need enterprise based features.

3) What about internet - I'm referring to lan based desktop application database development for small and medium size businesses. The market Microsoft can careless about!

4) What about data level security - Guess what FoxPro can access SQL Server so how is FoxPro to SQL Server different than Visual Studio to SQL Server. If it is written correctly!

I'm sure they will come up with other excuses and I will deal with those as they arise.

Why do this to the Great Visual Studio and expose the truth?

No I'm not pro-mac or unix over Microsoft. I develop for the Windows platform, I really wish they gave us the "right" tools for the job - that is what I want. What I am is totally pissed about is the amount of extra work VS requires to code out an application compared to other development tools that Microsoft has stopped producing (VB/VFP), the high cost of ownership related to Visual Studio for small and medium size businesses, all the cheerleadering/bullshit going on how great VS/.BLOAT are - this amounts to spin and wishful thinking.

Furthermore, VS lacks a complete implementation/integration between technologies such as WPF/ Winforms (Can you say blend) and MVC and ASP on the web side of things, everything floats out there in a half finished state of suck! Then there is all the bs plumbing/glue code to get everything working right which we should not have to worry about especially on the web side of development - want examples just view GU'S blog it is full of it.

Microsoft is also trying to redefine OOP and N-TIER standards by totally taking the focus off reuse and creating a cluster-f&*k in the UI layer - yes this includes WPF / XAML! Moreover Microsoft is spinning OS api wrappers as a framework and VS as being object oriented - then they goes as far as treating data like objects which has huge draw backs besides the bloat in the dataset object. In my opinion data should be treated as data but yet a UI control, which should be subclassed can not be in the class browser and requires jumping through hoops to code these classes out from scratch in c#!

Finally VFP has a great data centric language engine that should be part of Visual Studio which Microsoft owns the source to but they are too freaking arrogant to implement it, so instead we have 5 different miserable data access strategies in Visual Studio and we simply pick which one sucks less to implement in the application based on the requirements. Despite what you hear and read all of them have limitations in the middle tier that requires various ass backward workarounds and helper objects.

Look VS has a clear niche it is enterprise application development I will not aruge that, as a matter of fact that is exactly the technology I would use for enterprised based applications even with it's high suck factor! VS/.BLOAT are more productive to use then C++ to obtain certain functionality which exceed the capabilities of VB/VFP. However this is more the exception then the rule. For Microsoft to kill off VB/VFP and expect us to shoehorn VS and .Bloat in the small medium size business market is bullshit it doesn't fit!

This is why this blog exists and I waste my time with my friend, Soma!

Some other random thoughts

1) I want to give Soma credit, as least he posts my ramblings on his blog that is more then I will say for Scott Gu!

2) I also made the point on Soma's blog why wasn't WPF used in windows 7? Needless to say I'm not the only one raising this issue, despite what Sam would like for you to believe. Here is the link ... http://blogs.zdnet.com/carroll/?p=1890

FINALLY: The results and Foxpro code in detail

VFP Lines Of Code:
Form Init: 10 (Most of this code just sets properities which could have been done using the property sheet)
Button Click Code: 5
Middle Tier Code To Populate A Cursor: 4
Middle Tier Code To Generate an Excel File from a FoxPro Cursor: 7

Note: If you set the properites using the designer instead of coding it out, the amount of code required for this application is more then cut in half.

Total lines of code I had to write: 26
Time to build the application: 8 minutes


Below are the screen shots and code to evidence I actually did write it.

Using the class brower in Visual FoxPro, which works by the way, I exported the form and class code. The VFP class browser can also sub-class UI controls try that in Visual Studio!



















**************************************************
*-- Form: form1 (d:\sam\sample.scx)
*-- ParentClass: form
*-- BaseClass: form
*-- Time Stamp: 02/16/09 10:46:00 PM
*

* NOTE: THIS SECTION OF CODE VFP AUTO GENERATED FROM THE FORM DESIGNER

DEFINE CLASS form1 AS form

Top = 76
Left = 252
Height = 393
Width = 691
DoCreate = .T.
Caption = "Form1"
odatalayer = ""
cfilename = ""
Name = "Form1"

ADD OBJECT grid1 AS grid WITH ;
Height = 336, ;
Left = 0, ;
Top = 29, ;
Width = 696, ;
Name = "Grid1"

ADD OBJECT command1 AS commandbutton WITH ;
Top = 365, ;
Left = 312, ;
Height = 27, ;
Width = 127, ;
Caption = "Command1", ;
Name = "Command1"

ADD OBJECT command2 AS commandbutton WITH ;
Top = 365, ;
Left = 438, ;
Height = 27, ;
Width = 127, ;
Caption = "Command2", ;
Name = "Command2"

ADD OBJECT command3 AS commandbutton WITH ;
Top = 365, ;
Left = 564, ;
Height = 27, ;
Width = 127, ;
Caption = "Command3", ;
Name = "Command3"

ADD OBJECT label1 AS label WITH ;
Alignment = 1, ;
Caption = "Label1", ;
Height = 17, ;
Left = 8, ;
Top = 7, ;
Width = 121, ;
Name = "Label1"

ADD OBJECT text1 AS textbox WITH ;
Height = 23, ;
Left = 137, ;
Top = 3, ;
Width = 551, ;
Name = "Text1"

* END AUTO GENERATED VFP CODE

PROCEDURE Init
* Note I added two properties to the form cFileName and oDataLayer using the property manager
* Reference to tell VFP where the class library can be found
SET CLASSLIB TO datalayer.vcx
* Get rid of the word NULL in the grid
SET NULLDISPLAY TO ""
* Set a caption on the form
THISFORM.Caption = "VFP Example"
* Set the label caption for the filename to save and bind the textbox to the property
* Note this could have been set using the property sheet
THISFORM.Label1.Caption = "Selected Filename:"
THISFORM.Text1.ControlSource = "THISFORM.cFileName"
THISFORM.Text1.Alignment = 0 && Right Align

* Set the captions on the command buttons
* Note: This could have been done in the property sheet
* I split these into seperate buttons for the purpose of code examples
THISFORM.Command1.Caption = "Get Filename"
THISFORM.Command2.Caption = "Populate Grid"
THISFORM.Command3.Caption = "Export Grid"
* Get a reference to the middle tier SQL data layer
* Note: The class could have been dropped on the form
THISFORM.oDataLayer = CREATEOBJECT("cusSqlData")
ENDPROC

PROCEDURE command1.Click
* Use the built in VFP GetFile dialogue box
THISFORM.cFileName = GETFILE("XLS")
* Refresh the textbox
THISFORM.Text1.Refresh()
ENDPROC

PROCEDURE command2.Click
* Get a cursor from the adventurework person.contacts table for security I did not display the connection string
THISFORM.oDataLayer.PopulateCursor("Contacts", "MyConnectionString", "Select * from person.contact")
* Bind the dataset to the grid
THISFORM.Grid1.RecordSource = "Contacts"
ENDPROC

PROCEDURE command3.Click
* Export the sql contacts table to excel
THISFORM.oDataLayer.ExportCursor("Contacts", THISFORM.cFileName)
ENDPROC

ENDDEFINE
*
*-- EndDefine: form1
*************************************************


**************************************************
*-- Class Library: d:\sam\datalayer.vcx
**************************************************

**************************************************
*-- Class: cussqldata (d:\sam\datalayer.vcx)
*-- ParentClass: custom
*-- BaseClass: custom
*-- Time Stamp: 02/16/09 10:32:12 PM
*
DEFINE CLASS cussqldata AS custom

Name = "cussqldata"

PROCEDURE populatecursor
* tcCursorName name of the dataset to return
* tcConnString name of the connection string to use
* tcSelectStatement to execute against the sql database
LPARAMETERS tcCursorName, tcConnString, tcSelectStatement
* lnHandle holds a connection to sql server
LOCAL lnHandle
* Connect to sql
STORE SQLSTRINGCONNECT(tcConnString) TO lnHandle
* Create a dataset
SQLEXEC(lnHandle, tcSelectStatement, tcCursorname)
ENDPROC

PROCEDURE exportcursor
* tcData name of the cursor to export
* tcFileName name of the excel file to create
LPARAMETERS tcDataSet, tcFileName
* This code is not needed for this example but
* it is a good practice when changing workareas to save off the current one
LOCAL lnSelect
lnSelect = SELECT()
* Create the excel file
SELECT (tcDataSet)
COPY TO (tcFileName) TYPE XLS
* Return to the original workarea
SELECT (lnSelect)
RETURN .T.
ENDPROC

ENDDEFINE
*
*-- EndDefine: cussqldata
**************************************************

Until next time - Develop at bloat speed!

.Mark

Saturday, February 14, 2009

Windows 7: Vista Renamed!

Sorry I haven’t been around much as I’m sure my friends Scott Gu and Soma missed my blog entries but I spent the last month on site with a client from Louisville Ky, fixing yet another Visual Studio application abortion written by some over zealous Microsoft technology cheerleader.

While onsite one of the things the client asked was if the VS application would run on Windows 7. Given I prefer to wait until service pack 2 is released before using a Microsoft product, vista proved 2 service packs may not even be enough. I honestly told the client it should but then again it is a Microsoft product so who knows.

So one of their helpdesk people and I found a XP machine and decided to try it out. It didn’t take long at all to have my first WTF moment, apparently Windows 7 does not have an XP upgrade path. Therefore we ended up reformatting the machine which is probably a good idea anyway but still this is the lack of thought shows just how pathetic Microsoft is. What were they thinking everyone uses Vista?

The Windows 7 operating system is not sexy and looks for the most part like Vista with poorly implemented stolen inspiration from KDE and Mac. Not surprising they took the worse part of office 2007 (the suck ribbon bar) and implemented it all over the place in the OS. At least Microsoft’s lack of innovation reputation is still intact.

While the Windows 7 OS seemed a bit snappier then Vista, then again what OS isn’t, it was still not as quick as XP. Of course there was a crash right after installation due to a video device driver problem (what a fing joke) and without hacking the registry, as least that I could find, you could not install unsigned device drivers.

One thing I did find very interesting is the lack of WPF used in Windows 7. Given WPF has been out for more then 2 years you would think Microsoft’s own internal development would have used this great framework (yeah I even laughed at that one). It seems the only package Microsoft is releasing with a WPF UI is VS 2010 and even that will be some hybrid UI, according to my friend, Soma’s blog,

At the end of the day we were able to get the application running on Windows 7 but my first impression is Windows 7 amounts to nothing more then Vista Service pack 7000 and far from anything to get overly excited about unfortunately. Windows 7 is simply just another attempt to fix the magnitude of issues in Vista.

.Mark