Test-Driven Learning

You may not have realized it, but learning Ruby is like being attacked by a bunchof ADD Buddhist Monks. They’ll jump into your living room, raving and excited, anddo back flips while telling you how Zen and relaxing development should be. It’s weird.

Once we’ve medicated the frenetic relaxation, though, it’s really evident that therea lot of good ideas to be found in this community. The latest that I’ve discoveredis Test-Driven Learning.

What this means to me is that I can FINALLY stop writing ‘Hello World’ programs. Languageshave print or printf or puts commands—we can stop being thrilled by that now. Ok?Let’s just write Tests! If we can make test Assertions, we can kick the tires of eachnew piece of language syntax we learn as we learn it without creating silly, baroqueprograms to host them.

Lets start out by discovering the shortest syntax to use the language’s testing framework.The one built into Ruby is Test::Unit. This is easy in Ruby. You need a ‘require’line and to subclass the test fixture class.

require "test/unit"
class TestTest< Test::Unit::TestCase
def test_tests
assert true
end
end

That’s easy. And now you can assert things. Like ‘true’. Save that in a file, like‘test.rb’ then execute it with the ruby command line.

C:UsersjoshDesktop> ruby test.rb
Loaded suite test_test
Started
.
Finished in 0.001seconds.
??
1 tests, 1 assertions, 0 failures, 0 errors

From here on out, just start adding ‘assert’ lines as you discover things about Ruby.Since we started with ‘true’, maybe some asserts on Truth would be a good start. Iwonder which of these will pass and which will fail? If you know Perl, Javascript,or C# your preconceptions will be different.

assert true
assert false
assert 'True'
assert ""
assert 0
assert 1

So little code, and now you can curl up with your favorite Ruby howto book and spenda warm afternoon pondering the nature of Truth. Exciting eh? Well calm down! You don’tneed to be a crazy Zen guy. Just do some learning.

Resources:

Learn a Language Each Year

There’s a piece of advice that floats around,apparently from the PragmaticProgrammer, which goes like this:

Learn One New Language Each Year

I made a good start at Ruby last year, but got derailed by new exciting things overin the .NET world. This year is definitely the one.

I’ve got two reasons:

First, I’m really excited about programming phone systems with Adhearsion.

Second, I’ve realized that all the cool kids over at Microsoft spent the last 3 yearsgetting excited about Ruby. Not only are they developing their own Ruby runtime, butthe dynamicfeatures of C# 4.0 coming in VS2010 are obviously being designed to keep developersfrom jumping ship. We need to learn to think like Ruby coders toadapt to the new problems coming down the line.

One more thing…

Ruby is becoming a first-class citizen for Macintosh GUI application development.If you can write cross-platform libraries that work on the first-class frameworkson Windows, Linux, and the Mac…soon life will be nothing but champagne and swimsuitmodels!

Vista Continual Reboot After Removing Red Gate ANTS

Apparently this is a rareissue. However, it did cost me four days of mucking with my laptop to fix.

The Red Gate ANTS uninstaller doesn’t always remove it’s services, even though thefiles are gone. For some reason, this causes Vista to reboot almost immediately aftergetting to the login screen. The fix is simple:

SCDELETE ANTSPerformance Profiler 4 Service SCDELETE ANTSMemory Profiler 4 Service

>

A couple of commands from the command prompt will clear the services. Try using ‘lastknown configuration’ to get you to that command prompt. Safe Mode didn’t work forme.

NameValue, now with Distinct() support

One of the more useful little classes in my utility box is NameValue. It’s so veryeasy to fill with useful data from a Linq query, and once filled so easy to move betweenlayers, in a way that a projection simply can’t be used. The simple little NameValueclass bind just fine to a drop down menu, and will bring you tea after you finishwith that stupid girl that didn’t like your pony/monkey chimera.

I recently had to add equality checks and an override for == and != in order to makemerging two lists of name value pairs together possible. Now .Distinct() works ona List<NameValue>! There’s some goodmaterial out there for how to make a quality equality implementation.

[Serializable] public class NameValue{ public object Name{ get { return _Name;} set {_Name = value;} } protected virtual object _Name{ get; set;} public object Value{ get { return _Value;} set {_Value = value;} } protected virtual object _Value{ get; set;} public override bool Equals(object obj){ if (obj == null) return false; if (this.GetType() != obj.GetType()) return false; // safebecause of the GetType check NameValuenv = (NameValue)obj; // usethis pattern to compare reference members if (!Object.Equals(this.Value,nv.Value)) return false; if (!Object.Equals(this.Name,nv.Name)) return false; return true;} public override int GetHashCode(){ return Name.GetHashCode() ^ Value.GetHashCode();} public static bool operator ==(NameValuen1, NameValue n2) { return n1.Equals(n2);} public static bool operator !=(NameValuen1, NameValue n2) { return !n1.Equals(n2);} }

The Mystery of the Missing Permission

While writing Unit Tests for my membership provider code, I tried adding a permissionI had defined on one test user to a different test user. I was completely freakedout, since user1 suddenly no longer had that permission.

What kind of witchery is this? Does Collection<T>.Add() remove items from thesource collection?

No. It doesn’t. I tried it all with simple collections. List<string>.Add() doesn’thave this effect. So what’s going on?

The problem has to be in my persistence layer. My User and Permissions objects areprovided by LLBLGen. So it’s gotta be something in there. (A light dawns). I lookback at my table definitions. Sure enough, a permission as a m:1 relationship withit’s user. A permission entity can’t belong to more than one user. And LLBLGen issmart enough that when I take the object in the graph and add it to a different user,it not only updates the relationship(FK), but removes it from the original object.

But how do I get the result I wanted? A simple duplication of an existing permission?I adapted the deepcopy method I found over on Stack Overflow into a general extension method andused it to dupe the permission as I added it. Clean copy in the object graph=>nochanges to the relationship(FK)=>success.

public static class DeepCloneExtension{ public static TDeepClone<T>(this Tobj) { using (varms = new MemoryStream()){ var formatter = new BinaryFormatter();formatter.Serialize(ms, obj); ms.Position = 0; return (T)formatter.Deserialize(ms);} } }

IIS FTP 7 Provides Easy Virtual Host FTP

While it didn’t ship with Server 2008, Microsoft added a new FTPServer for the new version off IIS. Unfortunately it is not an SFTPserver, at best supporting FTP/S. However the new authentication options stillmake it a winner. You can provide a virtual FTP host for each web site you host withIIS 7. Just remember to login with [siteFQDN]|[username]…like 

erudition.radianttiger.com|josh

>

The pipey notation tells the server which vhost you belong to. Not elegant. Just waybetter than it was previously.

Next I’m excited to play with provider-basedauthentication. Having a pluggable architecture for logging in makes this FTPserver really powerful.

Simple ASP.NET Custom Forms Authentication

So, I’ve been a really happy CSLA.NET user for a while, but I’ve been finding thatgenerating the code has becoming tedious and my development velocity has been slowingdown on my CSLA libraries. And so, rather than getting back involved with blood sacrifice,I figured I’d experiment with another layer in there. I’m currently working up somecode with LLBLGen Pro (becausellblgen lite is for suckers!), and it’s working great….but Rocky made it so easyto do forms authentication with CSLA. It was just a couple’a pages in the book andit worked just fine and ….well…. I don’t understand how it works. Now that I’mnot including his framework, I need to figure it out.

So, follow along with me as we figure it out. Here’s how it’s done.

Step 1: Some configuration

First thing I tried was putting a Label on a form and assigning HttpContext.Current.User.ToString()to it. The result? “System.Security.Principal.WindowsPrincipal”

Right. My application is still out-of-the-box set to Windows authentication (Kerberos.ActiveDirectory. NSA Backdoor.) Let’s change that.


<?xmlversion=”1.0″?> <configuration> <system.web> <authentication mode=”Forms” /> </system.web> </configuration>

>

Good. What’s in that label now? “System.Security.Principal.GenericPrincipal” Muchbetter.

Step 2: The Password is ‘Joshua’!

This step is a big one. There are 27 members defined in the MembershipProvider contract,so go get some coffee, lithium, and a rotisserie chicken, and we’ll get started.

Make a new class, call it MyMembershipProvider.cs. Make it extend MembershipProvider:


using System; using System.Web.Security; using System.Web; namespace Website1{ public class MyMembershipProvider: MembershipProvider

>

Go ahead and let Visual Studio define all of the inherited members. We’re only goingto change one:


public override bool ValidateUser(string username, string password){ return true;}

>

Now we’ve got another little configuration change to make.


<configuration> <system.web> <authentication mode=”Forms” /> <membership defaultProvider=”HscMembershipProvider”> <providers> <add name=”MyMembershipProvider” type=”Website1.MyMembershipProvider” enablePasswordRetrieval=”false” enablePasswordReset=”false” requiresQuestionAndAnswer=”false” applicationName=”/” requiresUniqueEmail=”false” passwordFormat=”Clear” /> </providers> </membership> </system.web> </configuration>

>

Go head and drop a Login control and a LoginStatus on the form and try it out. Itlogs you in! No matter what you enter! Sure, you could put in some code that checksagainst your database to see if people are allowed in or not, but that’s just elitist,isn’t it? Creating an ‘In-group’ and an ‘Out-group’ and segregating them? Next thing,you’ll be wanting to beat up blue eyed people because they prefer Lord of the Ringsto Star Wars. Well, if you’re going to put in some authentication code, go for it.I won’t stop you.

Step 3: The Principal’s Orifice

Ok. So there’s a little gotcha at this point. If all you’re looking for is a loginand password check…then it’s time to feed your brain to the zombies, ’cause youwon’t need it anymore. But if you want more than just a username logged in, we’vego some stuff to do. Forms auth never gives you anything but the GenericPrincipal.It will be marked ‘IsAuthenticated’ if it is…and you can use the Roles providerto fill in the roles if you want. It also looks like it’s possible to fill in theroles manually using an event handler in Global.asax.

But here’s the thing. While I really dig on the login functionality of ASP.NET Membership,I’m not so convinced that Roles or Profiles provide a meaningful, robust implementationthat’s useful for more than a toy web forum. Can you give the branch manager for theSalem office full privileges to the customers there without letting him check on PresidentObama’s secret pornography transactions at the Hillsboro branch? With just IsInRole(string)?It sure doesn’t seem like it. The major advantage of Profiles seems to be that youcan use web.config to define the fields….which is great until the point where youwant to find all users within 50 miles of Denver….and then you’re stuck in an abandonedwarehouse with the vampires. Serialized XML doesn’t query too very well. There’s probablysolutions to these problems, but not out-of-the-box and why work really hard to havea decoupled design with a provider model that is so customized and complicated toimplement that you won’t ever be swapping it out?

This is a job for a Custom Principal. That’s what it is. Implement just enough tomake the ASP.NET controls happy and then add the real meat to your own object. Theprincipal also encapsulates an IIdentity object. You could go ahead and implementboth of these, but since I’m lazy and want to go play Rock Band, I’m going to do bothin onefell swoop. (Note that this is untested, and may put cracks in your DilithiumCrystals requiring embarrassing compromises with pimps.


using System; using System.Security.Principal; namespace Website1{ [Serializable()] public class MyPrincipal: IPrincipal, IIdentity { public static MyPrincipalLogin(string username, string password){ MyPrincipal loginUser = new MyPrincipal(); if (!string.IsNullOrEmpty(password)){ loginUser.Name = username;loginUser.IsAuthenticated = true; return loginUser;} return loginUser;} public bool RussianRoulettePermission(){ Random random = new Random(); if (random.Next(1, 6) == 3) return false; return true;} #region IPrincipalMembers public IIdentityIdentity { get { return this;} } public bool IsInRole(string role){ return false;} #endregion #region IIdentityMembers public string AuthenticationType{ get { return Custom;} } public bool IsAuthenticated{ get; private set;} public string Name{ get; private set;} #endregion }}

>

I accept that you and your fascist friends will probably want to do more passwordchecking than making sure that the user typed a letter. Goodfences make good neighbors, right? The real point is that you can put your ownCrazy User Code in here and have it available when your pages want to use it.

Now we can fix the Membership Provider to use our new shiny principal object!


public override bool ValidateUser(string username, string password){ HttpContext.Current.User = MyPrincipal.Login(username,password); return HttpContext.Current.User.Identity.IsAuthenticated;}

>

Give it a try!

Step 4: Dammit!

I set Current.User to my Principal. I did. I did. I did. Why doesn’t my damn labelchange from GenericPrincipal when I log in? It’s cheesin’ me off here!

The problem here is the Forms Authentication uses it’s own principal and sets thecontext to it on each page load. This is what it’s supposed to do, but we want better!We’re going to add a few methods and fix the problem. One caveat here (and why dopeople want to eat caves? And which Cave are you At when that happens? Where’s mylithium?): I’m going to trust the forms authentication cookie. I think that’s enoughof a ticket to bypass password authentication. If you don’t, you might want to jumpthrough some extra hoops. I’m also trusting that my developers won’t use the bypassmethods to create secret login backdoors and the like. I figure if you can’t trustthe coders then…well, you work at my office. But anyways….

To the principal!


public static MyPrincipalGetLoggedInUser(string username){ MyPrincipal loginUser = new MyPrincipal();loginUser.Name = username;loginUser.IsAuthenticated = true; return loginUser;} public static MyPrincipalGetLoggedOutUser(){ return new MyPrincipal();}

>

And in Global.asax!


protected void Application_AcquireRequestState(object sender,EventArgs e) { if (User.Identity.IsAuthenticated){ HttpContext.Current.User = MyPrincipal.GetLoggedInUser(User.Identity.Name);} else {HttpContext.Current.User = MyPrincipal.GetLoggedOutUser();} }

>

Step 5: And now for a magic trick.

Happy Day! Kill Ugly One-Horned Mule!

My cheap and dirty Membership implementation works. Now I can put this in my Form_Loadmethod:

Label1.Text = You’reLogged in: +HttpContext.Current.User.Identity.IsAuthenticated + Andyou’re dead!: + ((MyPrincipal)HttpContext.Current.User).RussianRoulettePermission();

>

Sweet! You can find out if you’re logged in. And if you’re dead. All at the same time.

Next Steps: Drunk on Cookie Magic

Obviously we’re going to need some code to check passwords. Probably fetching againstthe database. No problem. I’m planning on encapsulating my DTOs from LLBLGen intomy principal. That way I can expose read access to user objects for the logged-inusers. I can also put in complex permissions right there. I’m going it my way.Sweet!

It’s worth noting that this implementation goes off to the DB for each page load.That can sure suck up the performance points under a real load. However, a littlebit of effort can store the principal in the session object and then you get it back,deserialized, instead of requiring a round-trip. Just remember to code for the casewhere the session expires, but the forms cookie does not.

 

until next time, remember: the skin is the best part.

Software Entreprenuerism

Rob James writes Eightthings I wish I had been told before doing my start-up. There’s some good thoughtsthere for anyone who’s looking at making a company big enough for investment. #1 Investin People is the one that rings true for me, since I’ve spent years pursuing a modelthat requires more people…on a budget that can’t afford more people.

Rob Secretlastname has a post on the Buildor Buy Decision when starting a small ISV. I found this one personally interesting,since I’ve bought the software from him! It’s also worth noting that the initial effortof getting a product online is probably more costly than it’s really worth. If youcan capitalize it…and if there’s a market, it’s probably better to pay someone else.

I’vegot an IDEA!” Who hasn’t said that. Who hasn’t heard that. Of course the ideais the easy part. Mitch Denny shares some thoughts on getting started with SAAS asa business (SAASAAB?)