Cost Effective C# IDE

What is the most cost effective way to develop C#?I use VS 2005 with R# when working with clients, but unfortunately that copy of VS 2005 is owned by my employer. The same setup at home would cost $1400+. I know there are free C# IDEs, but they all have flaws that are hard to overlook.What are you using to develop C# outside of your workplace?Looking for ideas.p.s.I wish the ALT.NET guys would start building the Ideal IDE 😉

Advertisements

RoR based MVC Web Frameworks – Friend or Foe?

Ruby on Rails has inspired a whole generation of MVC Web Frameworks. The RoR inspired frameworks follow the same basic design; Controllers whose public methods are web endpoints. So…Do RoR based MVC Web Frameworks encourage good design?

MonoRail and MS MVC are a part of the RoR generation.  

They must. Right? I show, in the code below, that RoR inspired frameworks can actually encourage bad design. I show, in the end, what I think is a better way.

The code presented here is written for MonoRail, but the same problems exist in MS MVC and RoR.  

Let’s start with a simple ProductsController. The index method of this controller is the implementation of http://whocares.com/products/<code&gt;. The code on the end of the URL is the code for a specific product (i.e. nj1287).

public class ProductsController : SmartDispatcherController{   public void Index(string code)   {      Product product = Product.FindByCode(code);      if(product == null)      {         PropertyBag["UnknownSearchTerm"] = code;         RenderView("common/unknown_quick_search");      }      PropertyBag["Product"] = product;      RenderView("display_product");   }}

CategoriesController is our next controller. The index method of this controller is the implementation of http://whocares.com/categories/<name&gt;. The name on the end of the URL is the name for a specific category (i.e. montiors).

public class CategoriesController : SmartDispatcherController{   public void Index(string name)   {      Category cat = Category.FindByName(name);      if(cat == null)      {         PropertyBag["UnknownSearchTerm"] = name;         RenderView("common/unknown_quick_search");      }      PropertyBag["Category"] = cat;      RenderView("display_category");   }}

The index method in both classes are basically the same. We can remove the duplication. Let’s extract an abstract class.

public abstract class SearchableController : SmartDispatcherController{   public void Index(string name)   {      ISearchable item = FindByName(name);      if(item == null)      {         PropertyBag["UnknownSearchTerm"] = name;         RenderView("common/unknown_quick_search");      }      PropertyBag["Item"] = item;      RenderView(IndexView);   }   protected abstract ISearchable FindByName(string name);   protected abstract string IndexView { get; }}public class ProductsController : SearchableController{   protected ISearchable FindByName(string name)   {      return Product.FindByCode(name);   }   protected string IndexView { get { return "display_product"; } }}public class CategoriesController : SearchableController{   protected ISearchable FindByName(string name)   {      return Category.FindByName(name);   }   protected string IndexView { get { return "display_category"; } }}

What do you think about our new DRY code?I don’t like it. Why?

  1. ProductsController and CategoriesController no longer “speak” to me.
  2. Inheritance. I really don’t like the template method pattern because of #1.

Can we fix this?We can use a DynamicAction in MonoRail. Let’s see that code.

Does RoR or MS MVC have a concept of a “DynamicAction”?  

public class IndexAction : IDynamicAction{   private ISearchableRepository repos;   private string indexView;   public IndexAction(      ISearchableRepository repos,      string indexView)   {      this.repos = repos;      this.indexView = indexView;   }   public void Execute(Controller controller)   {      string name = controller.Params["name"];      ISearchable item = repos.FindByName(name);      if(item == null)      {         controller.PropertyBag["UnknownSearchTerm"] = name;         controller.RenderView("common/unknown_quick_search");      }      controller.PropertyBag["Item"] = item;      controller.RenderView(indexView);   }}public class ProductsController : SmartDispatcherController{   public ProductsController()   {      DynamicActions["Index"] = new IndexAction(             new ProductsRepository(), "display_product");   }} public class CategoriesController : SmartDispatcherController{   public CategoriesController()   {      DynamicActions["Index"] = new IndexAction(             new CategoryRepository(), "display_category");   }}

I like this code better. We are no longer using inheritance to reuse code and the code “speaks” better to me. This code has two things that bug me.

  1. The controllers are really not doing much.
  2. DynamicActions are second class citizens in MonoRail.

How do we fix these issues? I don’t know how in the RoR inspired frameworks. I think we need another abstraction. Chris Ortman and I discussed the below code at HDC 07 (so he deserves at least part of the credit). I am not sure he agreed, but maybe this post will change his mind.

The code below is not apart of any framework. It is only an idea.  

public class IndexAction : SmartDispatcherAction{   private ISearchableRepository repos;   private string indexView;   public IndexAction(      ISearchableRepository repos,      string indexView)   {      this.repos = repos;      this.indexView = indexView;   }   public void Execute(string name)   {      ISearchable item = repos.FindByName(name);      if(item == null)      {         PropertyBag["UnknownSearchTerm"] = name;         RenderView("common/unknown_quick_search");      }      PropertyBag["Item"] = item;      RenderView(indexView);   }}

IndexAction is now a first class citizen of the framework. Actions have all the benefits that controllers have in MonoRail (parameter binding, …).How do we hook this action to a URL?

new Route("/products/<name>",    new IndexAction(new ProductRepository(), "display_product"));new Route("/categories/<name>",    new IndexAction(new CategoryRepository(), "display_category"));

Routing engines allow us to remove the “controller” completely. We don’t need a “controller” (at least not in the RoR framework form). What were our controllers doing? They were really just organizing our actions. Routing engines allow us to organize our actions without the “controller”.What do you think? I would really like some feedback on this topic. Does anyone else feel this pain with these frameworks?

Rumbster has Graduated to RubyForge

Thanks to Pat Courtney, Rumbster – The Fake Email Server has graduated to RubyForge!Rumbster is a fake email server, written in Ruby. Rumbster was designed to test web based email functionality with Watir. Rumbster facilitates email testing by publishing received emails to registered observers. Rumbster currently ships with two observers; FileMessageObserver and MailMessageObserver.FileMessageObserver dumps received email messages to a file in a defined message directory. The files are named "#{@system_time.current_time_in_seconds}_#{mail.to}.txt".MailMessageObserver appends all received email messages to a message list.

message_observer = MailMessageObserver.newserver = Rumbster.newserver.add_observer(message_observer)server.add_observer(FileMessageObserver.new('message_dir'))server.start# assert message_observer.messages has your email messagesserver.stop

How do I get Rumbster?gem install rumbstersvn co http://rumbster.rubyforge.org/svn/trunkHow do I learn more about Rumbster?Read the tests. Rumbster was written test first, so the tests should tell a good story. If you would like to contribute documentation, we would be happy to have it 😉

MonoRail – Beginner FAQ

I am giving a MonoRail talk, at HDC 07, on Thursday morning.What questions do you think I should be prepared to answer?Here is a list of questions, and answers, that I typically get, and give, about MonoRail.Why would I use (care about) MonoRail?

  • Separation of concerns makes your application easier to test.
  • Microsoft will soon be releasing MS MVC. It is very similar to MonoRail.
  • It works well on teams where the designers and developers are not the same people.
  • Your team does not come from the MS world. MonoRail is closer to the framework designs from other languages (Java, Ruby).

Why would I not use MonoRail?

  • Your project depends too much on 3rd party controls.
  • Your teams skill set is totally centered around WebForms.
  • If your only experience with developing web sites is with WebForms, then you will have to learn HTTP.

What kinds of projects work best with MonoRail?

  • I would choose MonoRail for all projects, except for simple reporting web applications.

Do you have any other questions that you think I should be prepared to answer? Do you have anything to add to the current set of answers?

MS MVC – A MonoRail Perspective

Scott Guthrie gave us our first look at the the new Microsoft MVC framework at ALT.NET. I took special care, while watching the video, to answer one question.What, if anything, can MonoRail learn from MS MVC?

  1. Routing – RoR and MS MVC treat Routing as a first class citizen. Routing in MonoRail is an after thought and it shows.Why is first class Routing a big deal?
    • DRY – Tight integration between the routing engine and URL generation allows URLs to refactored easily and safely.
    • Testing – Testing routes, in MonoRail, requires an end-to-end test. If routes were first class objects, then routes could be tested in isolation.
  2. Typed PropertyBag – Typed PropertyBag is not the default behavior in MS MVC, but it is supported.Why is a Typed PropertyBag important?Contract – A Typed PropertyBag communicates the contract between the controller and view. Without this contract, refactoring anything in the view or the controller is difficult and error prone. We enforced a contract by implementing Advocates, but it would be nice if it were supported by MonoRail.

What are your thoughts?

Updated: Rumbster; Ruby Fake Email Server

Update: Rumbster has been moved to RubyForge.What is Rumbster?Rumbster is a simple SMTP server that receives email sent from a SMTP client. Received emails are published to observers that have registered with Rumbster.Updated

  • Applied patch from Pat Courtney that allowed Rumbster to handle multiple emails per session.

Downloadhttp://rumbster.rubyforge.org/svn/trunk/

C# Puzzlers: The Joy of Lists

My quest to take a “deep dive” into C# has led me to this variation on the ShortSet Java Puzzler. I translated the ShortSet class, described in Java Puzzlers, to C#. C# does not have a Set class, so I used List.

public class ShortList{    public static void Main(string[] args)    {        IList<short> l = new List<short>();        for(short i=0; i<100; i++)        {            l.Add(i);            l.Remove(i - 1);        }        Console.WriteLine(l.Count);        Console.Write("Press any key to continue . . . ");        Console.ReadKey(true);    }}

What gets printed to the console?Well… this code does not even compile. List defines the Remove method as Remove(T value). The compiler correctly tells us that i - 1 is an int. We cannot remove an int from a List<short>.The Java compiler correctly allows this to compile, because Set’s remove method is defined with Object as a parameter. Remove is defined this way for backward compatibility.Does C# always behave as expected?My second attempt at a “deep dive” results in another boring/pointless example. Does C# not have puzzler material? Is it really that well designed?Where are the C# edge cases?