Scott Hanselman

NotNorthwind - Update #1 - All Your Northwind Are Belong To Us

June 27, 2008 Comment on this post [21] Posted in Musings | NotNorthwind | Source Code
Sponsored By

imageI posted a little rant against the Northwind Database a few weeks back, and suggested that we, the community, create a better demo database than Northwind.  I proposed the name NotNorthwind.

There were some varied and interesting responses.

From Scott Mitchell:

Yes, it is far from perfect and could use some updating with regards to the date/time values and the category pictures, but those warts aside, it does a good job at what it was designed to do.

From Brian Sullivan:

I feel the same way. I have to stifle a groan whenever I hear the word "Northwind" come out of presenter's mouth. I've even jokingly said that Microsoft ought to have an internal metric for new technologies called "TTN", "Time to Northwind." In mathematical terms:
Product Coolness = 1 / TTN

From Duncan Smart:

We don't a need a new one! Pubs FTW! :-)

Steven Smith says Whither Northwind?

Enter NorthWind, the HTTP standard of databases, understood by virtually all Microsoft developers without need for preamble.  It just works.  With the words, "I'm using Northwind for my database." I now have the complete understanding of 95% of the people in the room - we're all on the same page - and I can continue with the actual point of the presentation or demo, which is not, has not, and probably will never be, "why this database isn't Northwind."

And Jeff Atwood from Twitter ;)

@shanselman rejects the standard MSFT Northwind database. What next? "Hello World" isn't good enough for you? Snob!

There were also a lot of great comments and ongoing discussion the CodePlex site's Discussions tab and project comments. We brainstormed alternative domains like Medical, Insurance, Media, and many others. Others suggested that AdventureWorks was a fine replacement.

ASIDE: Some folks suggested just updating the dates in Northwind to the present, but as attractive as the idea of adding ELEVEN YEARS to these columns is, I just didn't feel like doing this (Thanks to the folks on Twitter for their ideas, though!).

use Northwind
update Employees set BirthDate = dateadd(yy, 11, BirthDate)
update Employees set HireDate = dateadd(yy, 11, HireDate)
update Orders set OrderDate = dateadd(yy, 11, OrderDate)
update Orders set ShippedDate = dateadd(yy, 11, ShippedDate)
update Orders set RequiredDate = dateadd(yy, 11, RequiredDate)

We had a SkypeCast call today at noon and it was agreed that Northwind does have some redeeming qualities. It's simple, it works, it's understood and there's a pile of demos written against it. We rethought the requirements.

As a small group, we've decided to extend Northwind. We'll still call it NotNorthwind (although Super Northwind 2000 and "Microsoft Visual Northwind Enabler SP2 RC0 Beta1 July Refresh Plus Pack" were also possibilities), though, but we want to add a bunch of features that should make it a more interesting database for demos/prototyping/experimenting.

It's worth pointing out that I (and we) are not interested in showcasing the shiniest, latest new thing in SQL2008 with this small effort. We're just trying to have a little fun, while updating a very old database with some interesting and fun features in the hopes that our demos/prototypes/experiments/whatever that use Northwind could possibly become more interesting.

  • Product Reviews and Ratings
    • This new area should introduce a number of interesting, but easily understood concepts that can be used to showcase everything from whatever cool AJAX toolkit you're demoing to how flexible your CodeGenerator or ORM is.
    • Perhaps extending reviews to "x people found this review helpful" as well. Also, wish-lists, etc.
  • Tagging
    • In parallel to, and juxtaposed against the existing Product/Category relationship, tagging, and social tagging, introduces some interesting DB issues as we'll want to tag anything not just products, resulting in a many-to-many heterogeneous situation.  It also makes for some potentially interesting User Interfaces.
  • Compatibility
    • We're going to pretend that the existing database can't be changed, but only extended.  This way folks with existing Northwind Demos will "just work" against NotNorthwind. This plug-ability should also encourage people with demos to extend their existing those of things like web frameworks but are just using the database as a place to find scenarios.
    • We'd like it to support (either via creative SQL or multiple versions) multiple databases like mysql, SQLite, Oracle, etc.
    • We'd like it to be an existing "legacy" database that ORM tools could each build on top of so we could compare apples to apples.
  • Sample Data
    • At some point it'd be cool to make the database REALLY HUGE to test the scale of both it, and the things folks build on top of it.
    • We'd like pluggable Sample Data, so we'll make the structure file separate from the sample data. Basically Database "Themes" as not everyone wants the standard Microsoft "scrubbed" names.
  • Alternate Domains
    • We also think that the Northwind world could be explored with more "Vertical" things like these. These could also be done without changing the core database.
      • Expense Tracking and Approval
      • Accounts Receivable and Payable and Payroll
      • Business Intelligence - Warehousing, Sales, Trends

That's about it. I'll update the Issue Trackers and we'll try another SkypeCast same time next Thursday around noon. I'll announce the SkypeCast URL on Twitter. (AYNABTU)

About Scott

Scott Hanselman is a former professor, former Chief Architect in finance, now speaker, consultant, father, diabetic, and Microsoft employee. He is a failed stand-up comic, a cornrower, and a book author.

facebook bluesky subscribe
About   Newsletter
Hosting By
Hosted on Linux using .NET in an Azure App Service

Back to Basics: var != Dim

June 25, 2008 Comment on this post [36] Posted in Back to Basics | Programming | VB
Sponsored By

Someone said today after seeing the C# var operator for implicitly typed variables, "Oh, now C# has Dim." Well, not exactly. Not even close.

I like what this C# tutorial says about var.

...[var is] a new keyword that means, "I want to declare a variable, but I’m too lazy to write out its type."

One way to look at the power of VB's Dim operator is to say,

Dim kind of means, "I want to declare a variable but I can't tell you much about how it behaves until much later."

Dim lets you do actual late-binding while in C# (today) you do late-binding with reflection. I wanted to find a way to clearly express this in a very visceral sample.

A friend wanted to change a value in the CustomDocumentProperties in Word and see that change reflected in an updated field. In the document properties dialog below, you can see there's a "CustomProperty1" that has the value of "Scott" in it. Then in the document, there's a Field that is bound to that property. It's not meant to be a mail merge, but more of a MadLibs kind of a thing for writing applications that update forms and templates within Word or Excel documents.

image

His language of choice is C#, so he started off in C#. He added a reference to the Microsoft.Office.Interop.Word PIA (Primary Interop Assembly) and fought with the  system for some hours. After a while, I got enlisted, and after I figured out that the specific COM interface he needed was a late-bound IDispatch interface, we were able to crack with the Reflection.

I'm starting to think of Reflection much the way I think about Regular Expressions. If you have to solve your Problem with Reflection, you may just end up with Problems, plural!

Notice a few things. First, the need for some of those obvious strings and booleans to be of type Object. Notice all the System.Reflection.Missing.Values passed by reference. Most of all, notice the custom GetCustomPropertyValue and SetCustomPropertyValue that had to use Reflection.

  ApplicationClass WordApp = new ApplicationClass();
WordApp.Visible = true;
object missing = System.Reflection.Missing.Value;
object readOnly = false;
object isVisible = true;
object fileName = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, @"..\..\..\NewTest.doc");
Microsoft.Office.Interop.Word.Document aDoc = WordApp.Documents.Open(
ref fileName,ref missing,ref readOnly,ref missing,
ref missing,ref missing,ref missing,ref missing,
ref missing,ref missing,ref missing,ref isVisible,
ref missing,ref missing,ref missing,ref missing);

aDoc.Activate();

string propertyValue = GetCustomPropertyValue(aDoc, "CustomProperty1");
SetCustomPropertyValue(aDoc, "CustomProperty1", "Hanselman");

foreach (Range r in aDoc.StoryRanges)
{
r.Fields.Update();
}
}

public string GetCustomPropertyValue(Document doc, string propertyName)
{
object oDocCustomProps = doc.CustomDocumentProperties;
Type typeDocCustomProps = oDocCustomProps.GetType();
object oCustomProp = typeDocCustomProps.InvokeMember("Item",
BindingFlags.Default |
BindingFlags.GetProperty,
null, oDocCustomProps,
new object[] { propertyName });

Type typePropertyValue = oCustomProp.GetType();
string propertyValue = typePropertyValue.InvokeMember("Value",
BindingFlags.Default |
BindingFlags.GetProperty,
null, oCustomProp,
new object[] { }).ToString();

return propertyValue;
}

public void SetCustomPropertyValue(Document doc, string propertyName, string propertyValue)
{
object oDocCustomProps = doc.CustomDocumentProperties;
Type typeDocCustomProps = oDocCustomProps.GetType();
typeDocCustomProps.InvokeMember("Item",
BindingFlags.Default |
BindingFlags.SetProperty,
null, oDocCustomProps,
new object[] { propertyName, propertyValue });
}

0103mf1 There's a great article from 7 (yes SE7EN) years ago on Dr. Dobb's about Invoking COM Components from C# that provided me this diagram. The RCW (Runtime Callable Wrapper) sits in front of the COM Object and makes my reflection calls work.

Sure, I could have created some IDL and laid out an IDispatch implementation for these CustomDocumentProperties, but that's getting REALLY involved. Actually, there's supposed to be an implementation for CustomDocumentProperties but the MSDN Sample fails with this:

"Unable to cast COM object of type 'System.__ComObject' to interface type 'Microsoft.Office.Core.DocumentProperties'. This operation failed because the QueryInterface call on the COM component for the interface with IID '{2DF8D04D-5BFA-101B-BDE5-00AA0044DE52}' failed due to the following error: No such interface supported (Exception from HRESULT: 0x80004002 (E_NOINTERFACE))."

Competing with that non-working MSDN sample is this KB article from 2007 that provided the bulk of the yucky, but straightforward reflection code.

Why is this a Back to Basics post? Well, two fold. First, COM is Old and it's Basic. Seriously, though, the secondly (and only) reason is that, in my opinion, C# 3.0 is lousy for this kind of late-bound, COM-interop, Office Automation work.

Don't believe me? Here's the same code in VB. See the named parameters on the Open()? Notice the late-bound COM stuff just works without Reflection? (I've got Option Strict to Off for this code)

Dim WordApp = New Microsoft.Office.Interop.Word.ApplicationClass
WordApp.Visible = True

Dim fileName = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "..\..\..\NewTest.doc")
Dim aDoc As Document = WordApp.Documents.Open(FileName:=fileName, ReadOnly:=True, Visible:=True)
aDoc.Activate()

Dim PROP = "CustomProperty1"
Dim propertyValue = aDoc.CustomDocumentProperties(PROP).Value
aDoc.CustomDocumentProperties(PROP).Value = "Hanselman"
For Each r As Range In aDoc.StoryRanges
r.Fields.Update()
Next

VB.NET is really well suited for this kind of thing, and my buddy will likely use it in this scenario.

I hear this big difference in dynamism will change for the next version of C#. I'll talk to the team and try to get some details or rewrite my C# sample in C#.Next. I've also asked John Lam to help me write this sample in IronRuby. I suppose it'd look nice in PowerShell also.

The Point is, and until some future date, var != Dim.

The Back to Basics thing to remember is that the language you know might not always be suited for the problem you have. Just because you CAN solve a problem in a certain language doesn't mean that you should. If something REALLY doesn't feel right in a certain language, ask around, perhaps there's another that makes more sense for what you're trying to do.

About Scott

Scott Hanselman is a former professor, former Chief Architect in finance, now speaker, consultant, father, diabetic, and Microsoft employee. He is a failed stand-up comic, a cornrower, and a book author.

facebook bluesky subscribe
About   Newsletter
Hosting By
Hosted on Linux using .NET in an Azure App Service

The Weekly Source Code 29 - Ruby and Shoes and the First Ruby Virus

June 24, 2008 Comment on this post [11] Posted in Ruby | Source Code
Sponsored By

I was in Norway last week at the Norwegian Developers Conference, so I'm afraid the Weekly Source Code is the bi-weekly source code this month. It's amazing how international travel can really slow a body down. This trip just obliterated me. I'm slowly coming back to the world of the living, though.

I've been getting more and more interested in how folks extend their applications using plugins and things. In my new ongoing quest to read source code to be a better developer, Dear Reader, I present to you twenty-ninth in a infinite number of posts of "The Weekly Source Code."

This week's source is a clever "ClickOnce"-style hack for Ruby. It's cool because it brings together a number of technologies into a very clean end-user experience. The intent is to make the running of a Ruby GUI Application effortless, and it works and it's brilliant on several levels. Thanks to Sam Saffron for pointing me to it!

To start out, it's a hack says the author why the lucky stiff (or "_why" for short), so it's very early and there's bugs. You can check out the code on GitHub: http://github.com/why/shoes/tree/master or clone the whole tree using git via "git clone git://github.com/why/shoes.git"

Shoes

Ruby is a very aesthetically (to me) pleasing and flexible language. Shoes is a GUI Toolkit for making Windowing Applications using Ruby. I mentioned it back in TWSC12. Shoes is legendary for a number of reasons, but above all, it has the greatest API documentation in the history of all software documentation. The main book on Shoes Development called "nobody knows shoes" is fantastic. Even Chris Sells likes it!

Here's part of an example phone book application written in Ruby and Shoes):

Shoes.app :width => 320, :height => 350 do

stack :margin => 40 do
stack :margin => 10 do
para "Name"
@name = list_box :items => ["Yes, please!", "NO. No thankyou."]
end
stack :margin => 10 do
para "Address"
@address = edit_line
end
stack :margin => 10 do
para "Phone"
@phone = edit_line
end
stack :margin => 10 do
button "Save" do
Shoes.p [@name.text, @address.text, @phone.text]
end
end
end
end

It feels a lot like Tcl/Tk or Rebol. It'll be interesting to see if someone writes a mainstream application that is non-trivial. Shoes works on XP, Vista, MacOSX and Linux. Do note that you'll need to right click and run it as Administrator on Vista as _why hasn't put in an elevation prompt yet. You'll need Admin to do the initial bootstrap install.

However, in order to get Shoes to work, before today, you had to install Ruby, then get the Shoes libraries installed, usually via a gem. Then you'd need to run your app via ruby.exe yourapp.rb or a shortcut you'd setup.  The second comment on _why's blog post announcement says it all:

"Wow, this is super. We can actually give our apps to other people now :)"

Here's an explanation from _why on how the Shoes "bootstrapper" (my word) works:

If you poke around with a hex editor inside Windows’ PE binary format, you’ll find an .rsrc section at the end of the file which contains the icons and dialog boxes. I insert the Ruby script into this mess.
binj = Binject::EXE.new("blank.exe")
binj.inject("SHOES_FILENAME", "simple-accordion.rb")
File.open("simple-accordion.rb") do |f|
  binj.inject("SHOES_PAYLOAD", f)
end
binj.save("accordion.exe")

Fantastic hack. He shoves the Ruby script into a Windows Resource! He does the same thing for DMG (Disk Images) on Mac OSX, so you can create Ruby scripts that are portable to these two platforms.

When it runs, it checks for the existence of Shoes on your system. It's in C:\Program Files (x86)\Common Files\Shoes\. If Shoes (which includes a private copy of Ruby) is not there, it's downloaded and installed, and then your app runs. Bam, one-click cross-platform GUIs.

I'm not clear what the security ramifications are. Well, I am. I suspect there is no security that isn't already provided by the host operating system. Once you're running, the Ruby script has full control to do whatever it likes, so I suppose someone could write a malicious program just as they could write a malicious .NET app if they liked.

You can package your apps just by running shoes --package and you'll get this dialog. You can chose to include Shoes and Ruby inside the resulting EXE if you like.

 Shoes

Shoes also supports custom "Widgets." For example, here's a custom Speedometer control.

Shoes (2)

The code for the entire app, including the custom control is this:

class Speedometer < Widget
attr_accessor :range, :tick, :position
def initialize opts = {}
@range = opts[:range] || 200
@tick = opts[:tick] || 10
@position = opts[:position] || 0
@cx, @cy = self.left + 110, self.top + 100

nostroke
rect :top => self.top, :left => self.left,
:width => 220, :height => 200
nofill
stroke white
oval :left => @cx - 50, :top => @cy - 50, :radius => 100
(ticks + 1).times do |i|
radial_line 225 + ((270.0 / ticks) * i), 70..80
radial_line 225 + ((270.0 / ticks) * i), 45..49
end
strokewidth 2
oval :left => @cx - 70, :top => @cy - 70, :radius => 140
stroke lightgreen
oval :left => @cx - 5, :top => @cy - 5, :radius => 10
@needle = radial_line 225 + ((270.0 / @range) * @position), 0..90
end
def ticks; @range / @tick end
def radial_line deg, r
pos = ((deg / 360.0) * (2.0 * Math::PI)) - (Math::PI / 2.0)
line (Math.cos(pos) * r.begin) + @cx, (Math.sin(pos) * r.begin) + @cy,
(Math.cos(pos) * r.end) + @cx, (Math.sin(pos) * r.end) + @cy
end
def position= pos
@position = pos
@needle.remove
append do
@needle = radial_line 225 + ((270.0 / @range) * @position), 0..90
end
end
end

Shoes.app do
stack do
para "Enter a number between 0 and 100"
flow do
@p = edit_line
button "OK" do
@s.position = @p.text.to_i
end
end

@s = speedometer :range => 100, :ticks => 10
end
end

It's about 24 megs of libraries on disk when you're done, but you've got multimedia support and a lot of great library support in that space, not to mention a copy of Ruby itself. The download is only 2.5M bare or 6.8M with Video support.

I think it'd be great to build a Twitter Client using Shoes. The race is on! Hopefully we'll be able to get a Twitter Client done before some schmuck writes a Ruby Shoes virus. I for one, will be keeping the Ruby Shoes virus I wrote to myself. Well, not really a virus as it's a self propagating annoyance. But still. :)

It'll be fun to watch how this evolves. I hope there will be a clean upgrade process. If you want to try running your first Ruby/Shoes app, then run this EXE if you've got Windows or this DMG if you're on a Mac to see a basic demo application, but more importantly, to experience in the installer/bootstrapping process.

Technorati Tags: ,,

About Scott

Scott Hanselman is a former professor, former Chief Architect in finance, now speaker, consultant, father, diabetic, and Microsoft employee. He is a failed stand-up comic, a cornrower, and a book author.

facebook bluesky subscribe
About   Newsletter
Hosting By
Hosted on Linux using .NET in an Azure App Service

Hanselminutes Podcast 118 - Lean Software Development with Tom and Mary Poppendieck

June 23, 2008 Comment on this post [6] Posted in Podcast
Sponsored By

image image My one-hundred-and-eighteenth podcast is up. In this episode, I sit down with Lean Software legends Tom and Mary Poppendieck and chat about their thoughts on the state of Software Development. Is Agile a fad? We'll also learn how my (and likely your!) definition of "success" is wrong.

Subscribe: Subscribe to Hanselminutes Subscribe to my Podcast in iTunes

If you have trouble downloading, or your download is slow, do try the torrent with µtorrent or another BitTorrent Downloader.

Do also remember the complete archives are always up and they have PDF Transcripts, a little known feature that show up a few weeks after each show.

Telerik is our sponsor for this show.

Telerik's new stuff is pretty sweet, check out the ONLINE DEMO of their new ASP.NET AJAX suite. RadGrid handles sorting, filtering, and paging of hundreds of thousands of records in milliseconds, and the RadEditor loads up to 4 times faster and the navigation controls now support binding to web services on the client.

As I've said before this show comes to you with the audio expertise and stewardship of Carl Franklin. The name comes from Travis Illig, but the goal of the show is simple. Avoid wasting the listener's time. (and make the commute less boring)

Enjoy. Who knows what'll happen in the next show?

About Scott

Scott Hanselman is a former professor, former Chief Architect in finance, now speaker, consultant, father, diabetic, and Microsoft employee. He is a failed stand-up comic, a cornrower, and a book author.

facebook bluesky subscribe
About   Newsletter
Hosting By
Hosted on Linux using .NET in an Azure App Service

Hanselminutes Podcast 117 - Sorting out Internationalization with Michael Kaplan

June 18, 2008 Comment on this post [10] Posted in Internationalization | Podcast
Sponsored By

Unicode_sample My one-hundred-and-seventeenth podcast is up. Michael Kaplan is a Developer in the Windows International group and the author of the popular 'Sorting It Out' blog that is dedicated it all things '-ization.' That means Globalization, Internationalization, and Localization. Do check out Michael's blog as well as the Internationalization category of this blog.

Subscribe: Subscribe to Hanselminutes Subscribe to my Podcast in iTunes

If you have trouble downloading, or your download is slow, do try the torrent with µtorrent or another BitTorrent Downloader.

Do also remember the complete archives are always up and they have PDF Transcripts, a little known feature that show up a few weeks after each show.

Telerik is our sponsor for this show.

Telerik's new stuff is pretty sweet, check out the ONLINE DEMO of their new ASP.NET AJAX suite. RadGrid handles sorting, filtering, and paging of hundreds of thousands of records in milliseconds, and the RadEditor loads up to 4 times faster and the navigation controls now support binding to web services on the client.

As I've said before this show comes to you with the audio expertise and stewardship of Carl Franklin. The name comes from Travis Illig, but the goal of the show is simple. Avoid wasting the listener's time. (and make the commute less boring)

Enjoy. Who knows what'll happen in the next show?

About Scott

Scott Hanselman is a former professor, former Chief Architect in finance, now speaker, consultant, father, diabetic, and Microsoft employee. He is a failed stand-up comic, a cornrower, and a book author.

facebook bluesky subscribe
About   Newsletter
Hosting By
Hosted on Linux using .NET in an Azure App Service

Disclaimer: The opinions expressed herein are my own personal opinions and do not represent my employer's view in any way.