Posted on July 14, 2009 17:02 by swilliams

I like frameworks. I spent far too much time in my programming infancy reinventing the wheel, and I don’t want to ever have to write more code than I have to again. Thus, I like relying on frameworks to take the tedium out of certain parts of the craft.

However, a problem arises when you don’t know what that framework is doing. Recently I spent many hours tracking down one specific bug that needed a single line changed to fix. In this specific case it was in an ASP.NET WebForms app. A <button> tag was used to make some fancy ajaxy calls via jQuery and PageMethods and the onclick event. The problem was that the form that was supposed to be displayed only appeared for a few seconds, then vanished again.

I poured through the code, set many breakpoints, broke out both Firebug and the Safari debugger (both proved useless due to the actual problem). Despite all of this, I still couldn’t figure out what the heck was going on. Finally, after I was ready to jump off the parking garage, the light bulb clicked on.

The <button> tag behaves like <input type=”submit” />; it sends a postback. And since the form was wrapped in an UpdatePanel, it was executing both the jQuery ajax, as well as the ASP.NET ajax, which were clobbering each other. In Firefox, the jQuery code finished first, and was then overwritten by the Page_Load from the UpdatePanel, causing our freshly rendered form to go away.

Changing the <button> to <input type=”button” /> fixed things. There are plenty of other fixes for this issue, but that’s what we used.

ASP.NET WebForms and ASP.NET Ajax like to abstract many of the “complicated” web development concepts away from the developer. I’m not going to comment on whether this is a good or bad thing, but it can present issues if you are using some mechanism and are not aware of what is going on under the hood. These problems usually don’t even manifest until late in a project- when the bosses are breathing down your neck and wondering why the app isn’t finished yet.

Does this mean we should abandon frameworks entirely and code everything in C (or assembler)? Certainly not, but if you are going to use that extra super duper happy UpdatePanel, you had better know what it is going to do to everything inside of it.

I like frameworks. I spent far too much time in my programming infancy reinventing the wheel, and I don’t want to ever have to write more code than I have to again. Thus, I like relying on frameworks to take the tedium out of certain parts of the craft.

However, a problem arises when you don’t know what that framework is doing. Recently I spent many hours tracking down one specific bug that needed a single line changed to fix. In this specific case it was in an ASP.NET WebForms app. A <button> tag was used to make some fancy ajaxy calls via jQuery and PageMethods and the onclick event. The problem was that the form that was supposed to be displayed only appeared for a few seconds, then vanished again.

I poured through the code, set many breakpoints, broke out both Firebug and the Safari debugger (both proved useless due to the actual problem). Despite all of this, I still couldn’t figure out what the heck was going on. Finally, after I was ready to jump off the parking garage, the light bulb clicked on.

The <button> tag behaves like <input type=”submit” />; it sends a postback. And since the form was wrapped in an UpdatePanel, it was executing both the jQuery ajax, as well as the ASP.NET ajax, which were clobbering each other. In Firefox, the jQuery code finished first, and was then overwritten by the Page_Load from the UpdatePanel, causing our freshly rendered form to go away.

Changing the <button> to <input type=”button” /> fixed things. There are plenty of other fixes for this issue, but that’s what we used.

ASP.NET WebForms and ASP.NET Ajax like to abstract many of the “complicated” web development concepts away from the developer. I’m not going to comment on whether this is a good or bad thing, but it can present issues if you are using some mechanism and are not aware of what is going on under the hood. These problems usually don’t even manifest until late in a project- when the bosses are breathing down your neck and wondering why the app isn’t finished yet.

Does this mean we should abandon frameworks entirely and code everything in C (or assembler)? Certainly not, but if you are going to use that extra super duper happy UpdatePanel, you had better know what it is going to do to everything inside of it.



Digg It!DZone It!StumbleUponTechnoratiRedditDel.icio.usNewsVineFurlBlinkList

Be the first to rate this post

  • Currently 0/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

Posted on June 15, 2009 09:43 by swilliams

I gave two talks at Desert Code Camp this last weekend on ASP.NET MVC. The talks went well enough, though the time was far too short to cover everything I wanted to. I did get requests to share the code created during the sessions. So, here it is, for the most part.

http://krazyyak.com/sogeti/DemoBlog.zip

I say “for the most part” because it’s not the exact same stuff written during the presentation. I went through, cleaned up, and commented many of the methods and functions in everything.

The stuff with StructureMap is still pretty rough; I’m not a StructureMap expert, but I want to learn more about it. I’ll hopefully be able to blog about it in July.

As far as a disclaimer, this code is public domain and should be only used for demonstration/educational purposes. I offer no warranties on it, etc. Actually using it for a blog engine is probably a bad idea.

Feel free to discuss it here and ask questions.



Digg It!DZone It!StumbleUponTechnoratiRedditDel.icio.usNewsVineFurlBlinkList

Be the first to rate this post

  • Currently 0/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

Posted on June 2, 2009 17:41 by swilliams

In the project I am currently working on, we are using JavaScript and jQuery in just about everything. One of the frustrations that I have been seeing is that I’ll render a view representing an object, but also want a JSON version of that object to manipulate. I am also quite anal when it comes to keeping my code clean and separating the concerns; I did not want to have JavaScript strewn throughout my HTML or vice versa.

I considered a couple of options. The first just involved making an AJAX call to the server and having it return a JsonResult. This is clean, but I did not want to effectively double my calls to the server.

I also considered extending the MVC framework and writing my own ActionResult class that returned both HTML and JSON. However, that also “felt” wrong; like I was short-circuiting the framework. I would have had to rely on JavaScript on the client side to parse the resulting object and place the HTML, not something I want to be doing with all of my views.

I let it sit on the backburner for a while, and then today came up with a pretty good solution. It’s not ideal, but it works well enough for me. I created a simple HtmlHelper extension that just dumps the JSON out into a variable:

    
using System.Web.Script.Serialization;

    public static class JsonExtensions {
        public static string Json(this HtmlHelper html, string variableName) {
            return Json(html, variableName, html.ViewData.Model);
        }

        public static string Json(this HtmlHelper html, string variableName, object model) {
            TagBuilder tag = new TagBuilder("script");
            tag.Attributes.Add("type", "text/javascript");
            JavaScriptSerializer jsonSerializer = new JavaScriptSerializer();
            tag.InnerHtml = "var " + variableName + " = " + jsonSerializer.Serialize(model) + ";";
            return tag.ToString();
        }
    }

You call it from a page like so:

<%= Html.Json("foo") %>
<%= Html.Json("bar", Model.Something) %>

This is not an ideal solution, you are still technically putting JavaScript in the HTML. But, it does not make an extra call to the server, and the markup in the IDE is still very clean.

Another approach I considered was to have an Action that returned a JavaScriptResult that consisted of the same thing. You could then add a script tag like:

<script type="text/javascript" src="/javascript/MyObject/1000">

The catch though is that it would cause more overhead, especially if the app was designed in such a way that the retrievals are expensive (ours is).

I’m still ruminating on that perfect scenario, but for now I’ll be doing it this way.



Digg It!DZone It!StumbleUponTechnoratiRedditDel.icio.usNewsVineFurlBlinkList

Be the first to rate this post

  • Currently 0/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

Posted on May 14, 2009 13:04 by swilliams

Just prior to their 1.0 release, the ASP.NET MVC dev team added a nice feature to prevent CSRF attacks, the AntiForgeryToken. In brief, a CSRF attack is when a 3rd party gets one of your users to accidentally run a malicious script that accesses normally restricted URLs. The AntiForgeryToken pattern allows the web server to reject requests that come from places it was not expecting. More details can be found here. If you are a web developer and aren’t familiar with CSRF attacks, you need to fix that.

Anyways, the AntiForgeryToken bit is all well and good, but what if you are using jQuery (or another library) to handle your AJAX calls? Say you have an Action method like this:

[AcceptVerbs(HttpVerbs.Post), ValidateAntiForgeryToken]
public ActionResult DeleteAccount(int accountId) {
    // delete stuff
}

And you call it via:

$.post('/home/DeleteAccount', { accountId: 1000 }, function() {
    alert('Account Deleted.');
});

Since the POST does not include the AntiForgeryToken, it will fail.

Fortunately, it doesn’t take much brainpower to fix this. All the client side component of AntiForgeryToken does is put the token in a basic hidden field. So, you just need to pull that data out and include it in your AJAX call.

var token = $('input[name=__RequestVerificationToken]').val();

$.post('/home/DeleteAccount', { accountId: 1000, '__RequestVerificationToken': token }, function() {
    alert('Account Deleted.');
});

Do note that if you have multiple forms on the page with multiple AntiForgeryTokens, you will have to specify which one you want in your jQuery selector. Another gotcha is if you are using jQuery’s serializeArray() function, you’ll have to add it a bit differently:

var formData = $('#myForm').serializeArray();
var token = $('input[name=__RequestVerificationToken]').val();
formData.push({ name: '__RequestVerificationToken', value: token });

$.post('/home/DeleteAccount', formData, function() {
    alert('Account Deleted.');
});

Again, if you are making a web site that has any sort of interactivity at all, you need to be aware of these kinds of attacks. The tools to prevent them are readily available for you to use.



Digg It!DZone It!StumbleUponTechnoratiRedditDel.icio.usNewsVineFurlBlinkList

Be the first to rate this post

  • Currently 0/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

Posted on May 11, 2009 21:36 by swilliams

I'm a big fan of the ASP.NET MVC framework. I love the fine grained control it gives you over everything. But what I love most is that you can unleash the fully armed and operational firepower of jQuery.

Recently, I've been working on a site that is using both MVC and jQuery to make AJAX calls. Typically the method being called returned HTML (via a PartialView). But, if an error was thrown, I wanted to return a JSON object encapsulating it.

Unfortunately, jQuery could not decide how to handle a response that could be either HTML, or a JSON object. You can tell jQuery what to expect, or let it try to figure out what the response dataType is. Here's the behavior of my Action method:

[AcceptVerbs(HttpVerbs.Post)]
public ActionResult HandleAjax(int id) {
    try {
        var myObj = RetrieveData(id);
        return PartialView("myview", myObj);
    } catch (Exception ex) {
        return Json(new { success = false, message = ex.Message });
    }
}

The problem is that regardless of what gets returned, jQuery only recognizes it as a string, and treats it as HTML.

I did think of one solution, but it used pretty poor design: it attempted to parse the responseText as JSON. If that was successful, it meant the error object was returned. But, if an exception was thrown, it was the HTML. The problem is that it was using error handling mechanisms to capture an expected result. Bad news; I'm not even going to post the code.

Fortunately, someone pointed out that if I set the http status code to 500, jQuery will send the result to the error() callback function, as opposed to success(). Thus, if you added:

this.Response.StatusCode = 500;

In the catch block, you can then use jQuery's error() callback to do exactly as you'd expect:

$.ajax({
    data: { id: 100 },
    dataType: 'html',
    error: function(XMLHttpRequest, textStatus, errorThrown) {
        var errorObj = JSON.parse(XMLHttpRequest.responseText);
        handleError(errorObj);
    },
    success: function(data) {
        $('#resultContainer').html(data);
    },
    url: '/home/HandleAjax'
});

This also makes use of Crockford's JSON library to parse the responseText string to a JSON object.

It is this transparency that makes me sing the praises of the MVC framework. Such a mechanism is certainly possible with classic WebForms, but it is hidden under layers of abstraction, and likely would have required mixing of markup, script, and server side code.



Digg It!DZone It!StumbleUponTechnoratiRedditDel.icio.usNewsVineFurlBlinkList

Be the first to rate this post

  • Currently 0/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

Posted on December 12, 2008 13:57 by swilliams

I kind of left my last post on this subject dangling, but now I'm ready to come clean.  I was proceeding merrily along, removing the tightly coupled LINQ to SQL generated code into something nice and loose, but ran into some serious snags when trying to update the database objects that had joins associated with it.

The code became more and more unwieldy; I was creating extra loader classes for longer inheritance chains, and more and more abstractions to get everything to work properly. At some point, a little voice in the back of my head started saying, this is supposed to be EASIER? Finally it reached a point where it simply did not appear that I would be able to meet my goal of defining my class models separately from LINQ to SQL's generated ones.

So, I gave up and let the idea die while I focused on other things. Occasionally I did revisit it, but only met with the same conclusion.

About a month ago I became interested in the new ASP.NET MVC framework. Rob Conery has been publishing a series of videos that detail his process of creating an online store. While watching those, I realized that he was implementing the very idea that I had wanted to do here. And amazingly, the code to do it was surprisingly simple and small.

After studying it and poking around, here I am today with the answer! It lies in what Rob calls the Repository pattern. It boils down to this: you have your model classes defined somewhere (in the sample app, I'm using LinqExample.Core), an IRepository interface that states the methods that will interact with the database, and the implementation (LinqRepository here). Rob goes on to create a Service class that sits between the UI and Repository, but for this example, I'm leaving that out.

public interface IPersonRepository {
    IQueryable<Person> GetAll();
    Person GetSingle(int personId);
    IQueryable<TpsReport> GetReports(int personId);
    
    int SavePerson(Person person);
    int SaveReport(TpsReport report, Person forThisPerson);
}

This also makes testing easy. I can cook up a TestPersonRepository that returns dummy data, allowing any UI testing to avoid touching the database.

Next, we create the implementation of this interface using LINQ to SQL. Add the .dbml CropperCapture[13] file and drag the two tables onto the workspace as you would normally. The key part here is to change the Context Namespace and Entity Namespace to something other than the default (an empty string). I used LinqExample.Data.Repository. This has the effect of namespacing each generated class. Thus, they will not conflict with the model classes we have already defined.

Our example actually looks similar to what I laid out in Part 3, however I do not use the Entity types for the joining objects, but rather IQueryable<T>. This allows a lazy evaluation of the objects, and let's LINQ to SQL's binding work better. Additionally, I reverted all of the properties in the classes to the basic auto-properties that C# 3.0 brings us.

public class Person {
    public int Id { get; set; }
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public IQueryable<TpsReport> Reports { get; set; }
}

The key piece from Rob's code is how he pulls the data using LINQ to SQL. Rather than just returning the auto-generated classes, he selects the actual Person or TpsReport class and the initializers to populate them:

public IQueryable<LinqExample.Core.Person> GetAll() {
    var people = from pe in this.db.Persons
                 select new Person {
                     Id = pe.id,
                     FirstName = pe.fname,
                     LastName = pe.lname,
                     Reports = this.GetReports(pe.id)
                 };
    return people;
}

At this point you may be thinking "All you did is create a class and just do a bunch of right/left property setting." While that is true (and the right/left bit does get tedious), it does more than that by return IQueryable<T>.

Returning as an IQueryable<T> has an extra advantage of letting you do further queries without having to throw away parts of the initial return set. Thus, if you chose to implement the Service layer, you could keep GetAll() in the Repository implementation, and have GetSingle(), GetWithLastName(), and others in the Service assembly.

If you returned an IList<T> instead, you would need to call ToList(), which would run the whole query right then, and forsake all the lazy evaluation benefits from IQueryable<T>. Of course, you may want to do that, but that is what the Service Layer is for.

Updating the database is not quite as simple, but doesn't involve black magic either. The gist of it is to check to see if this is an update or an insert call, and to perform accordingly. Here is SavePerson(), but SaveReport() is very similar

public int SavePerson(Person person) {
    using (Repository.LinqExampleDbDataContext saver = new Repository.LinqExampleDbDataContext()) {
        Repository.Person pe = saver.Persons.SingleOrDefault(p => p.id == person.Id);
        bool isNew = false;
        if (pe == null) {
            isNew = true;
            pe = new Repository.Person();
        } 
        pe.fname = person.FirstName;
        pe.lname = person.LastName;
        if (isNew) {
            saver.Persons.InsertOnSubmit(pe);
        }
        saver.SubmitChanges();
        return pe.id;
    }
}

And, you're done! This is a little easier to swallow than what I had going in Part 3, no XML to muck around with, and is far simpler than the code soup I was cooking up before abandoning that approach.

Should you decide to go with another technology, be it the Entity Framework, NHibernate, or even a non SQL Server database, you would only need to create an IRepository implementation for that particular framework/database. It can be tedious for large quantities of tables, but that is the price you might have to pay for loose coupling and a friendlier design. Of course, you could refactor that to automatically set properties through Reflection or something, but that is another article altogether.


Source code for this post is located here.

Digg It!DZone It!StumbleUponTechnoratiRedditDel.icio.usNewsVineFurlBlinkList

Be the first to rate this post

  • Currently 0/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

Posted on November 18, 2008 08:32 by swilliams

Everybody does things differently. When it comes to designing web applications, there is no single Right way to do things (though there are many Wrong ways). This is the first in a series of how I design an application.

John Gruber coined a great phrase, "Ronco Spray-on Usability" when referring to the practice of treating the UI work as something that can be applied at any point, typically the end. This is how crummy designs happens. If you've ever found yourself thinking did they put ANY effort into this at all? this is probably how it went down.

If you do not put forth a significant amount of thinking about your design, and not just at the beginning, it will be being sub-standard at best, and abysmal at worst. That doesn't mean you need to spend all of your project time thinking about the design, work in baby steps.

The 37Signals guys state that you should do the UI first, before coding, and I tend to agree. Perhaps the biggest benefit of this approach is that it keeps you from avoidable work. Say you thought you needed to sort an array of objects on different properties. But, while making the UI, you realized this was unnecessary. You just saved yourself the time that would have spent writing, debugging, and testing that feature.

The opposite can happen as well. In the process of designing the UI, it may become apparent that two previously separated components need to be more tightly integrated. This may create more work, but pays off by improving the user's experience. And ultimately, it saves you the time of implementing the incorrect model, then going back and changing it. Additionally, it is far cheaper to make corrections earlier in a design than later.

In order to marshal my thoughts about a design, I'll make simple lists detailing what will be on the page before drawing anything or opening an editor. If the page contains a basic CRUD form, I'll quickly jot down the needed fields, if only to keep from forgetting one when it comes time to write the code.

I prefer using a pen and paper, though a basic text-editor is fine too. I like paper here because mucking around is easier; I can scribble tiny notes next to my points, or cross things off. The key though is to keep it as simple as possible, so that it is easy to throw away. If you immediately dive into Photoshop or Visual Studio, you can become too attached to a bad design. A piece of paper or a .txt file is of no consequence and can be thrown out with only 15 minutes of lost time.

Once you have some basic ideas ready to go, it is time to proceed to the next step, The Sketch.



Digg It!DZone It!StumbleUponTechnoratiRedditDel.icio.usNewsVineFurlBlinkList

Be the first to rate this post

  • Currently 0/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

Posted on November 10, 2008 13:48 by swilliams

One thing that every developer can agree on is that code readability and maintainability is a Good Thing. Nobody wants to come back to a project several months later only to find the critical piece of it is poorly formatted, uses three separate programming paradigms, and Oh My Goodness why is it using Exceptions as GOTO statements?

Wars have been fought over whether the opening curly brace goes on the same line as the expression, or a new one*. However, I am always surprised to see that the markup created by many developers is a tangled mess of HTML, CSS, and JavaScript. In a sufficiently large project, doing something as simple as moving a <div> from one corner to another is tantamount to sending a rocket to the moon.

[* The answer is the same line, as God intended.]

The common justification is the old "Well, I'm not a designer" routine. And again, yes, that is probably true, but do you actually like wasting hours figuring out why things aren't lining up the way they should?

Something that I've found helps enormously is to just treat your markup, style, and script as first class citizens. Here's how I do it:

Keep Your Stuff Separate

Keep your HTML, CSS, and JavaScript in separate files. Just like it's a bad practice to embed database logic in your UI, it's a bad practice to use the style="" attribute on an HTML tag*.

Why is this bad? It all comes back to readability, in both a human and machine sense. Fixing markup is easier when you don't have to account for styling and JavaScript embedded throughout. Programmatically parsing HTML is same way.

[* I'm using absolutes here for emphasis, there are always exceptions.]

To accomplish this, I use a file structure I call "The Cradle." It consists of my main HTML page (index.html, or a Master Page, or whatever), and all of the .js and .css files I will be needing. Its contents are:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
    <title>Title</title>
    <link type="text/css" rel="stylesheet" href="css/master.css" />
</head>
<body>

<!-- Content goes here -->

<script type="text/javascript" src="js/framework.js"></script>

</body>
</html>

The reference to the master.css file is the only time CSS is ever mentioned in the page. The CradleFramework.js is replaced by whichever JavaScript framework I am using, usually Prototype or jQuery. I'll also add another JavaScript line to reference custom JavaScript for the page. Again, this is the only time JavaScript is ever mentioned on the page. I do not use any of the onclick, onmouseover, onwhatever event attributes here. This keeps the HTML light and easy to scan.

Additionally, all CSS file references are at the top of the page, since the styles won't be applied otherwise, and JavaScript at the bottom to avoid as much of a delay as possible when the page is rendered.

Split up your CSS

Why only one css file referenced? Because with the @import directive, you can call separate CSS files from the master.

This means my master.css file looks like:

@import url('type.css');
@import url('layout.css');
@import url('color.css');

If I feel that a CSS reset is needed, I'll include a reset.css above all of that. As you can probably guess, type.css contains styling for text, and text only. Layout determines the positioning and sizing of things, and color.css makes them pretty. I try to avoid spillover as much as possible; type does not define font color. Borders are kind of a wildcard since they deal with both layout and have a color component, so I keep them in color.css.

Additionally, these can split up further for the various media types out there. @importing a print_layout.css in the layout file can help if you need to maintain a print version of the page. Same with a mobile version. They are not kept in the Cradle since I rarely use them.

An added benefit of splitting CSS is that file sizes become shorter. A smaller line count makes it easier to scan and find selectors.

One Off Styles

All of these tips have applied to a global style. But what happens if you have a separate page that needs various elements specific to just it to be styled? If the page only has a minimum set of elements, I'll throw them in with the global style. If not, I'll use a separate file and include it on just that page.

Use JavaScript To Wire Up Events

I mentioned earlier that you should avoid using the onevent attributes that HTML provides. When I first heard this, I thought it was silly, since it meant I wouldn't be able to have all the fancypants Web 2.0 things that all the hip kids were doing.

It turns out that you can have your cake and eat it too. One convention I use with my JavaScript is to have an init() method like so:

var MYAPP = function() {
  return {
    init: function() {
      // put stuff here
    }
}();

$(document).ready(MYAPP.init);

If this syntax looks a little screwy to you, that's ok, read up on some of JavaScript's awesome functional roots.

This bit of code runs the init() function when the page loads. Inside init() is where other functions are called, including createEvents():

var createEvents = function() {
  $('#new').click(function() {
    alert('You clicked the new link!');
  });
};

This attaches a function to an element with the id "new." When it is clicked a friendly dialog pops up providing some useful text.

Both of these examples use the jQuery library, though you can do the same thing with Prototype, YUI, MooTools, or plain old JavaScript.

Once you have The Cradle set up to your specifications, it is easier to keep designs up to date. If someone tells you, "The font in the header needs to be bigger" you automatically know that it is in type.css, and won't be difficult to find from there. No more poking through various HTML and CSS files to find it.

I keep my version of The Cradle in my documents folder and copy it to each new project at the beginning. You can download your very own copy and use it however you would like. I included a recent copy of jQuery and Prototype, but you can use whichever library suits you.



Digg It!DZone It!StumbleUponTechnoratiRedditDel.icio.usNewsVineFurlBlinkList

Be the first to rate this post

  • Currently 0/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

Posted on October 29, 2008 14:13 by swilliams

I've been playing around with a few Python based web frameworks for the last few months in order to improve my non .NET based skills. What I like about all of them is that in terms of functionality and programmer friendliness they hold their own, if not surpass, more traditional "enterprise" frameworks.

The three I've spent the most time with are web.py, Pylons, and Django. I wouldn't hesitate to recommend them to anyone, but each has their own strengths and weaknesses.

web.py -- The Good

The calling card for web.py is:

"Think about the ideal way to write a web app. Write the code to make it happen."

and that's a succinct way to describe it. The syntax is very minimal, but expressive. The footprint is the smallest of the three I've used; I wrote the least amount of code out of the three of these frameworks with web.py, and that is a very good thing.

I love the way it handles routing and URL definition. A class represents a view, and GET and POST methods handle those particular http calls. This makes the most sense to me.

The built in template system was a little quirky, but easy enough once I got the hang of it. Installing and running in a development environment was also easy. All things considered, I would have been content using it exclusively, but for a few important issues:

web.py -- The Bad

First and foremost, the documentation is "sparse." Aaron Swartz (the creator and maintainer) is very smart and knowledgeable in Python, but I am not, and often could not figure out a solution to a problem without extensive research.

Installation on a production environment was much more difficult. I have only a basic knowledge of Linux administration, and was only able to get a web.py app running under the slower old CGI based way. Again, the documentation didn't really provide a lot of guidance beyond the basics.

web.py -- The Followup

It looks like some extra documentation has been created for web.py since I last took a look at it, sepcifically with regard to getting it up and running on a server. It does apply to version 0.3, but looks like it warrants another look.

Pylons -- The Good

My next stop on my Python Framework World Tour was Pylons. I found it because at some point reddit switched from web.py to this. I found Pylons to be much more newbie friendly. The documentation ranges from decent to good, and the "getting started" videos were incredibly valuable. Development was just as easy as web.py, though the dev server did not work on my Vista x64 workstation (this may be a Python issue though).

Pylons 0.9.6 uses the Mako template system, which probably was my favorite by a nose. There was a bit of a learning curve to it, but with ample documentation, I didn't have too much trouble.

Debugging Pylons is simple as well. If a page crashes, it presents the stack trace, but goes a step further and lets you execute code at each step in the stack. Just be sure to disable this in production.

The URL routing is great, though a little confusing.

Pylons -- The Bad

While not as sparse as web.py, Pylons' documentation could be better. Too often I found tutorials written for older versions that did not work any more. This next point may be a product of the prior one, but I also found the wiring of the models and controllers to be rather unintuitive and required too much code.

The biggest issue I had again came with deployment. I was unfamiliar with .egg packages and had to stumble around a bit before things were working. I ended up using FastCGI to serve pages, which also required to frustrating moments, but ultimately worked.

Despite these issues, I still maintain a simple photo blog built on top of Pylons.

Django -- The Good

Django is one of the biggest rising stars out there right now. It recently released version 1.0.

What I liked most about Django was the documentation. This is how you are supposed to do it. Thorough, but not overwhelmingly wordy, very quick, and well laid out.

The built in "admin" functionality is also incredibly useful. I wrote my own [crummy] version for the photo blog I mentioned above, but Django's would have been perfect had I known about it. This is an example of one of the many useful features thrown in.

I like the way Models are connected to the Persistance layer as well. You define a class, and the database structures are generated automatically, which makes the most sense to me.

Django does not allow in page debugging like Pylons, but does have a specialized Python shell that let's you perform all of the operations your page would.

Django -- The Bad

Of course, nothing is without fault. The biggest issue I have with Django is the URL routing. Both web.py and Pylons allow you to define a generic view to point to like this:

map.connect(':controller/:action/:id')

While Django basically forces you to be explicit while defining your routes. To me this seems to be too much, though others disagree that the generic way is more "Pythonic."

The template system takes a little time to get used to. It has a very small subset of functionality built in to it, and does not allow for inline python code. Rather, you use what are called filters to do things. You can develop your own filters as well pretty easily.

Memory seems to be an issue as well. My web server does not have a ton of RAM, which didn't seem to be a problem with web.py or Pylons, but when some of my django apps get busy, it quickly runs out of room. This may be developer error on my part though.

In Conclusion

I don't think I can give a recommendation to any one platform, all three in my opinion are strong enough for using in a modern app. web.py is for those who feel adventerous, and know python better than me. Pylons is a good middle ground and has a slightly better template system. Django is the easiest to set up and manage, and has the best documentation when you're stuck.



Digg It!DZone It!StumbleUponTechnoratiRedditDel.icio.usNewsVineFurlBlinkList

Be the first to rate this post

  • Currently 0/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

Posted on October 20, 2008 10:19 by swilliams

I've recently taken to learning about Microsoft's Team Foundation Server. It has a good API and I wanted to see if I could do something similar to what I did with SubVersion and Python. So, I spent the weekend getting everything up and running.

For comparison's sake, here is how you install and create SubVersion repositories in a commonly used development environment:

  • Download SubVersion.
  • Install it.
  • Don't like the command line? Download TortoiseSVN and install it.
  • Right click somewhere and select "Create repository here..."

Four steps (with two being optional). The biggest problem I had with the TFS install was that it took far too many hoops to jump through that I almost considered giving up. Fortunately, I'm stubborn and pushed through.

Firstly, TFS can install on a domain-less network (like what I run at home), but I figured that the most common implementation is on a domain, so I created a new VM and installed Windows Server 2008 for the Domain Controller.

[It should be noted that this isn't necessarily a good differentiation from the SubVersion install, since the best practice would be to install SubVersion on a separate server, preferably Linux based.]

Once the Domain Controller was set up, I installed SQL Server 2008 since that is what TFS uses as the data store. This too went without a hitch.

However, upon starting the installer for TFS I was greeted with a message stating that it cannot be installed on a Domain Controller, or a server running "Enterprise" applications (Exchange, BizTalk, etc).

I'm assuming this is for security reasons, which brings me to a grumbling point I have with TFS: there is no "Developer Version." It must be installed as if for a production environment. I understand that Microsoft wants to ensure that their customers aren't doing something stupid and opening themselves up to attacks, but this is solely on a virtual environment that will be inaccessible from the outside. SQL Server has a developer version that can be installed on a client OS, why doesn't TFS? And further, you can install SQL Server and IIS on a Domain Controller, which is already a bad practice, why not TFS?

Anyways, after some mild cursing I spun up another Virtual Machine for another Server 2008 installation. Fortunately I have 4 Gigabytes of RAM in my workstation, though at this point I was wondering if I should convince my wife that upgrading to a quad core processor would be worth it.

Eventually, the second server was up and connected to the domain. Installed SQL Server 2008 again and went to install TFS. This time I got an incredibly worthless error message that annoyed me enough that I Twittered about it. It effectively said that there  was an error, but it was so dire that it couldn't be displayed in a dialog, so you should check the logs, but there wasn't even a link to where those were. I briefly looked in the filesystem, but didn't see anything obvious. Hindsight says that I should have checked the Event Viewer, but I hate digging through that and I found my solution regardless.

I suspected I had missed a pre-req and consulted the documentation again. Herein my second grumbling point. The documentation for TFS is a .chm file. I hate these things. They're essentially hypertext viewers, but without any benefits from modern browsers, like tabs. I would have loved to have opened a bunch of different tabs for each page I was looking at, but was stuck with a Single Document Interface.

The missing pre-requisite was IIS. Whoops, my bad. Installed that lickety split and fired up the installer. Again, I understand that the target market for TFS is larger development groups with 10,000+ users, and a powerful web server is required for that, but for tiny groups, why not just include Cassini or something similar?

This time I did not get the stupid error, but failed when it scanned for the required pre-requisites (somehow IIS was needed to get to this part). There were a few errors regarding my SQL Server install, it needed Analysis Services, Reporting Services, and a couple of other things. Whoops again. It also said that my version of SQL Server was incompatible, though at the time I figured that this was the catch-all error to display when there were other problems too.

Went back to the SQL Server 2008 installer and added everything except the Management Studio and on-line books. See my similar bone of contention with needing IIS for enterprisey development, when something tiny and embedded would be awesome for me.

Again, my version of SQL Server was incompatible. More cursing, though a little stronger this time, because I knew that SQL Server 2008 would work with TFS 2008. After sifting through the documentation some more, I found that SQL Server 2008 will work with TFS 2008 Service Pack 1. Of course, there wasn't a download available for an installer with both, so I had to merge the service pack into the base installer (I would love to link to a webpage detailing this, but again, .chm file).

Finally, I was able to install TFS 2008. TFS also requires SharePoint (why?), but one good thing about the 2008 version is that it will install SharePoint Services 3.0 automatically for you. This is good because if you think this post is just a rant in disguise, it's cupcakes compared to SharePoint. My memory may be faulty but I believe that TFS 2005 did not do this for you, so 2008 gets high marks here.

This is starting to seem like a Shaggy Dog story, but that was basically it. My install wasn't exactly a standard one; I should probably keep SQL Server and TFS on separate machines, but I only have so much memory for these resource intensive virtual environments.

The moral here is that this install experience borders on unacceptable. Yes there were some user errors, but those could all have been taken care of in a Developer Version. SubVersion only features Source Code Management, but in my experience most developers only use TFS for that as well (which is sad since it offers much more). Installation is the very first thing that people see when they actually use your app, and it will color their opinion throughout the rest of the experience.

Installing TFS requires the developer to dig through mediocre documentation. Developers hate reading documentation, when things should "just work." And installers need to be simpler, especially when they don't always have to be Enterprise level.



Digg It!DZone It!StumbleUponTechnoratiRedditDel.icio.usNewsVineFurlBlinkList

Be the first to rate this post

  • Currently 0/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5