Blog of Jeff A blog about programming and random other things.

9Feb/10link

Django’s Flaws

This is a response to Brandon Taylor. It was a bit lengthy, so I thought a post would be better off.

Like you, I felt this "poor" design pain from Rails. The less then spectacular docs (although that's changing too) made me prefer Django over it.
With that being said, the settings.py of Django is a crutch. There's quite a bit of needless configuration: You need to set template directories, installed apps, etc. While that's less than Java, why can't there be some reasonable defaults? Make template point to a local 'templates' subdirectory; default directory for media files; default to sqlite3 database config; time-zone defaulting to your computer's time settings; etc.
No migrations. Sure there are third party, but an official version would be nice. Most projects would be greatly aided by such a feature.
Django's reverse URL lookup system (for templates) is a pain. Besides the fact that the {%url%} is usually long with all the parameters (imagine a date-based a blog post URL). get_absolute_url in models seem dirty and hackish, but it's a lot shorter. Rails' routes provides this style of url referencing (by model instance).
Why no JavaScript integration with Django? Sure you can say it provides free choice, but that's why Rails has an advantage: it's not using the best javascript framework, in my opinion, but something is better than nothing. It's far easier to write simple javascript code through Rails then it is in Django.
Tying along the JS issue, is the templating problem. How would one go around supporting themes? What about different templates based on the incoming client? This has to be manually handled by custom-view code. Rails supports this pretty simply.
Django's admin is particularly amazing; however, it's more towards data entry and site admin (hence the name) but not regular usage -- it's not designed for web apps which have users "managing" their own content: for that you want to create a polished experience for the end user. Validations for both frameworks are done through the model.
Recently, the admin interface has gotten a lot more extensible, but it's still designed for the site admin in mind. While Rails' scaffolding isn't great, it's closer toward user-generated content, you're improving the design on behalf of the end user going to see it. Writing basic HTML for this stuff is pretty repetitive if you ask me.
If you like the argument from more of a Djangoist, I'll refer you to one of the creator's of Django.
http://simonwillison.net/2009/May/19/djng/
I've shared many of his pain points.
But Django's documentation is second to none in comparison to any open source project. Django's querying system through models is also great in comparison to Rails -- something that Rails 3 is also going to deliver.

Like you, I felt this "poor" design pain from Rails. The less then spectacular docs (although that's changing too) made me prefer Django over it.

With that being said, the settings.py of Django is a crutch. There's quite a bit of needless configuration: You need to set template directories, installed apps, etc. While that's less than Java, why can't there be some reasonable defaults? Make template point to a local 'templates' subdirectory; default directory for media files; default to sqlite3 database config; time-zone defaulting to your computer's time settings; etc.

No migrations. Sure there are third party apps, but an official version would be nice. Most projects would be greatly aided by such a feature.

Django's reverse URL lookup system is a pain. Besides the fact that the {%url%} is usually long with all the parameters (imagine a date-based a blog post URL). get_absolute_url in models seem dirty and hackish, but it's a lot shorter. Rails' routes provides this style of url referencing (by model instance).

Why isn't there JavaScript integration with Django? Sure you can say it provides free choice, but that's why Rails has an advantage: it's not using the best javascript framework, in my opinion, but something is better than nothing. It's far easier to write simple javascript code through Rails then it is in Django.

Related to the JavaScript issue is the templating problem. A view function usually only directs to one template. How would one support themes? What about different templates based on the incoming client? This has to be manually handled by custom-view code. Rails' render_to dispatcher in the controller makes this a lot easier.

No doubt Django's admin is awesome; however, it's more towards data entry and site admin (hence the name) but not regular usage -- it's not designed for web apps which have users "managing" their own content: for that you want to create a polished experience for the end user. Validations for both frameworks are done through the model.

Recently, the admin interface has gotten a lot more extensible, but it's still designed for the site admin in mind. While Rails' scaffolding isn't great, it's closer toward user-generated content, you're improving the design on behalf of the end user going to see it. Writing HTML isn't fun -- for me at least.

If you like the argument from more of a Djangoist, I'll refer you to one of the creator's of Django.

http://simonwillison.net/2009/May/19/djng/

I've shared many of his pain points.

But Django's documentation is second to none in comparison to any open source project. Django's querying system through models is also great in comparison to Rails. Rails 3 intends to copy Django on that respect.

The merb probably slowed the progress of Rails in the recent years.

  • Share/Bookmark
Tagged as: , , 16 Comments
5Jan/10link

Clojure

I've recently picked up on Clojure, a LISP-dialect that runs on the JVM and I absolutely love it; but like other programming languages, it's difficult to convince others to try a programming language other than c/c++ or PHP.

Many friends are in the blub paradox camp: people view programming languages only in the mental model of his/her favorite programming language. Languages more powerful are deemed "unnecessarily complex", where languages less powerful are viewed as inferior.

In the Programming Languages course, we covered functional programming. The person next to me said:

"c++ can do functional programming, it has function pointers."

For someone that ever passed functions without any messy declarations knows that it's just not quite the same. Ruby is particularly nice with blocks, which is syntactic sugar for passing a function to another function:

with_file('myfile.txt') { |line|
   puts line
}

While with_file doesn't really exist in ruby, it can be easily implemented by someone to open a file, iterate it line by line, and close it. On the other hand, c doesn't provide as nice syntax for something like this.

In clojure, syntax is similar, with the (in)famous parenthesizes.

(with-file "myfile.txt" (fn [line] (println line)))

Some people may say that's a lot of parenthesizes, like any other LISP, but they're mostly in different places. Idiomatically, this with-file would be a macro - a function that generates code to compile. A good use of a macro abstracts boilerplate code away: such as the declaration of the function in the example above.

(with-file "myfile.txt" line (println line))

As you can see, lisp deals away with most of the character syntax that other languages have. Macros can do other handy language-abstractions. For example instantiating an object make take several statements:

MyClass obj = new MyClass();
obj.setProperty("value");
obj.doMagic();
obj.checkForErrors();

There's some repetition here. Clojure has interop support with java, and supports java objects without any wrappers. The above code in clojure looks like:

(doto (MyClass.)
  (.setProperty "value")
  (.doMagic)
  (.checkForErrors))

For one more pair of  parenthesizes, you get to avoid typing the type of class twice, and the variable you're operating on. All while maintaining the readability of the code. That's a pretty sweet deal if you ask me.

There are more issues Clojure touches upon. No doubt multi-threading is a growing concern as CPU manufacturers add more cores, but multi-threaded applications are difficult to make. Dealing with deadlocks is a perplexing experience many first-time threading programmers. Clojure's immutable data structures and concurrency semantics ensures no deadlocks. It's quite a different experience than worrying about if your code functions properly.

I'll leave it to you to check out clojure. Clojure's creator, Rich Hickey, is probably the better person to look for the design philosophies of clojure via his screencasts.

  • Share/Bookmark
22Nov/09link

“Brief” Guide to JavaScript – Part 11

You should check out the previous parts before continuing with this final part:

Ajax

It's part of the "Web 2.0" trend. Ajax, or Asynchronous JavaScript and XML provides a background-styled http request to a URL. This is different from the traditional, "load a new page to perform an action" style. With the ability to essentially load a page in the background, you can let the user interact with the rest of your site while performing an operation by the user.


Pros & Cons

"With great power, comes great responsibility."

Ajax provides some very nice benefits, but there are some issues you should consider before determining to use ajax. A lighter-weight response from the server (instead of a full page reload) which can improve the user experience with ajax. But keep in mind:

  • The user's back button won't "undo" the last action. This has to be implemented manually.
  • Browsers without JavaScript or Ajax can't perform these actions.
  • Search engines & bots usually don't run JavaScript, so content provided via ajax is inaccessible to them.
  • Ajax doesn't provide an accessible way for blind people to figure out changes on a page (if any).

Providing a graceful alternative, the traditional page-reload mechanisms, is a good way to combat most of the issues above. Although, it's a good practice to avoid using Ajax for simply displaying content.

XMLHttpRequest

The core behind Ajax is the XMLHttpRequest object in JavaScript. XMLHttpRequest is a functional object that needs to be instantiated, so we do this:

 


var request;
try{
    if(XMLHttpRequest) // for all modern browsers
        request = new XMLHttpRequest();
    else // for IE prior to 8
        request = new ActiveXObject("Microsoft.XMLHTTP");
}
catch(error){
    request = false;
}
if(request){
    // do ajax stuff here...
} else {
    // browser doesn't support ajax
}

It's worth noting the both the ActiveXObject & XMLHttpRequest object have the possibility of throwing an exception, so use a try/catch block and handle if the feature is not supported.

Next, we need to configure the request object, the basics:


request.open('get', 'http://google.com', true);

open interface is as follows:


open(method, url, async?, username, password)
  • method: usually a string of get or post which describes how additional data should be sent. Identical to the method attribute of form tags.
  • url: the url to fetch. Identical to the action attribute of form tags.
  • async?: You should usually set this to true. This tells the browser to perform the request asynchronously and not freeze up the browser. The advantage of synchronous is after you perform the request, you can immediately use the results in your next line of code. This cannot be guaranteed with an asynchronous request. (optional - defaults true)
  • username & password: is the simple http-supported username & password. This does not work for sites that have a username & password login form, but rather for urls that prompt a login dialog before displaying the page. (optional - defaults to no login credentials)

Of course, doing an async request is useless if we can't handle it when the request is completed, so we add an event handler.


request.onreadystatechanged = function(){
    // our code goes here.
};

There's a handful of different cases when this handler will be called. In order to differentiate between the requests, the XMLHttpRequest object has a readyState property which we can use to check the current state the request is in. The values are:

  • 0: The xmlhttp object hasn't been initialized
  • 1: Xmlhttp object has been initialized
  • 2: Xmlhttp object has sent request
  • 3: Xmlhttp object is being processed (performing request)
  • 4: Xmlhttp object is completed (the request is completed)

Most of the time, you'll be checking to see the readyState property is 4.

Also worth mentioning the status property, for the XMLHttpRequest object, which returns the server response code from the request: 200 for successful request, 404 for missing file, etc.

Finally, there's the responseText property which contains the content of the server request.

Now let's build our onreadystate function body:

 


request.onreadystatechanged = function(){
    // ajax request finished & server returned 200
    // (url resource found and returned)
    // it's probably a better idea to accept any
    // status in the 200's, but for simplicity, we'll
    // do this
    if(request.readyState == 4 && request.status == 200){
        var c = document.getElementById('ajax_content');
        c.innerHTML = request.responseText;
    }
};

Here we set the interior html of the element with id attribute of ajax_content to whatever the server gave us. After we configured our object, we need to perform the request:


// string contains POST data to send to the server. null indicates no POST data.
request.send(null);

It's worth noting the POST data string should be in a query-string format:


request.send('var1=value1&var2=value2');

That's it, JavaScript ajax in a nutshell. No fancy voodoo magic.

XML / HTML / Text data

Just pinging a URL is definitely not useful, we want to handle the data from the user. There are several typical server responses, but usually you have control over this since ajax is used to improve the user experience of your web app.

For text we simply utilize the responseText property:


request.onreadystatechanged = function(){
    if(request.readyState == 4 && request.status == 200){
        // request.responseText
    }
};

This behavior is similar for XML, except when you need to parse them for specific information, then responseXML will be your friend then.

 


request.onreadystatechanged = function(){
    if(request.readyState == 4 && request.status == 200){
        // request.responseXML is like a DOM object, supporting DOM
        // traversal techniques.
        alert(request.responseXML.getElementsByTagName(‘h1’).length);
    }
}

Alternatively, you can manually create the XML parser object:


request.onreadystatechanged = function(){
    if(request.readyState == 4 && request.status == 200){
        var contents = request.responseText;
        var xml = null;
        if(window.DOMParser){ // all browsers but IE
            var parser = new DOMParser();
            xml = parser.parseFromString(contents, ‘text/xml’);
        } else { // internet explorer
            xml = new ActiveXObject(‘Microsoft.XMLDOM’);
            xml.async=’false’;
            xml.loadXML(contents);
        }
        // use xml identically to request.responseXML
    }
}

JSON

Another common data-transfer format is JSON (JavaScript Object Notation), which is a subset of JavaScript syntax – specifically the data structures part. The only accepted types of JSON are:

  • Numbers – 1, 2.5, –4, –5.2, etc.
  • Booleans – true, false
  • Null value
  • Strings - ‘abc’, “defghi”
  • Arrays – [‘a’, 1, 2]
  • Objects – {‘key’ : ‘value’} where keys must be strings!

The main advantage is the simple ways to use JSON as true JavaScript values. Given that json_string contains json data – whether from ajax or somewhere else – we can simply do:


var json = eval(‘(‘ + json_string + ‘)’);

To convert it to it’s equivalent data structure in JavaScript. Using eval is not safe parsing unsafe JSON code (eg – from a third party), use the JSON parser at json.org. This is simply because eval interprets a given string as JavaScript: including function calls and prototype definitions.

The json.org parser is also bundled with a stringify function to convert JavaScript data structures into JSON.

The End

(no really)

I’m wrapping up my exhausting JavaScript coverage here. But there’s plenty more things to learn if you’re up to it:

  • Debugging your JavaScript in IE, Safari, Firefox (with Firebug), etc.
  • Gracefully degrading when the user doesn’t have JavaScript or certain JavaScript features
  • JavaScript optimization techniques
  • XPath for DOM traversal
  • AJAX
  • Supporting the back button with AJAX actions
  • Modifying/Reading HTTP Headers
  • JavaScript Frameworks (Prototype/Scriptaculous, Mootools, YUI, jQuery, dojo, ext, etc.)
  • With that, I’ll tilt my hat, and walk off. If only I had a cool hat.

    - Jeff

    • Share/Bookmark

    Recent Posts

    Topics

    Archives

    Following

    Links