The Core of Obviel

The Core of Obviel

Start with jQuery

Obviel's core principle is pretty simple if you know jQuery.

With jQuery, you can select one or more elements like with a selector:

var el = $('#foo')

You get a list of wrapped DOM elements. You can do things with these:

el.text(); // get the text content

el.attr('foo'); // get an attribute

el.html('<p>Hello</p>'); // set the HTML content

Add the Obviel

Obviel expands jQuery with a render function:

el.render(obj); // render an object on el

Once you know this, you know the most important thing about Obviel.

Views

Now how does Obviel know how to render obj on el?

You need to tell Obviel first (typically when the JavaScript file is being loaded) by defining a view:

obviel.view({
  iface: 'animal',
  html: '<p>This is an animal</p>'
});

This view works for the iface animal. An iface is a simple marker on objects you want to render. So if you have this object:

var obj = {
  iface: 'animal'
};

We render obj on el:

el.render(obj);

Obviel knows that to render obj, it needs to use the view registered for animal above.

Once the view is found, Obviel renders the view on the element. In the case of the view above, it will insert <p>This is an animal</p> into el.

Obviel Template

Above we insert a snippet of HTML. Typically you want to insert something more specific to the object at hand. Let's expand the animal object a bit so it has some more information:

var obj = {
  iface: 'animal'
  name: 'lion',
  sound: 'growls'
};

Here's a view that will display a bit of information about such an animal with a name and sound property:

obviel.view({
  iface: 'animal',
  obvt: '<p>The {name} {sound}</p>'
});

When this view is rendered:

el.render(obj);

the <p>The lion growls</p> will be inserted into el.

The obvt bit above is an Obviel Template. Obviel Template lets you do variable substitution, repeat elements, bind events and has extensive i18n support.

Custom JavaScript

Finally, you may want to execute some custom JavaScript code when a view is rendered. You can do this by defining a render function on the view:

obviel.view({
   iface: 'animal',
   obvt: '<p class="animal">The {name} {sound}</p>',
   render: function() {
      $('.animal', this.el).click(function() {
        alert("You clicked on the animal: " + this.obj.name);
      });
   }
});

As you can see you can combine obvt (or html) with a custom render function. You can access the element on which the view is rendered with this.el and the object being rendered with this.obj.

In fact you can use Obviel Template's event handler support to clean up this code:

obviel.view({
   iface: 'animal',
   obvt: '<p class="animal" data-handler="click|animalClicked">The {name} {sound}</p>',
   animalClicked: function() {
     alert("You clicked on the animal: " + this.obj.name);
   }
});

More

This should get you started! But Obviel is extensively documented at http://obviel.org should you need more information.

Good luck!

The Story of None: Part 3 - Handling It

The Story of None: Part 3 - Handling It

part 1 part 2 part 3 part 4 part 5 part 6

Last time...

In part 1 of the Story of None we've seen this validation function:

def validate_end_date_later_than_start(start_date, end_date):
    if end_date <= start_date:
        raise ValidationError(
            "The end date should be later than the start date.")

We've determined start_date and end_date may be None. In part 2 we've seen that we can recognize this case by using is None or is not None.

So:

  • we should consider whether None is possibility.

  • we should use value is None or value is not None to check.

Once we know that we're not out of the woods yet though: we still need to decide what to do when either of the arguments is None. This will need to be thought about and depends on the circumstances.

Requirements

So what would make sense in this case? If either start_date or end_date are None, does it make sense to validate this at all? What does an omitted date mean in this case? This depends on the application's requirements.

For the sake of the example I will make up a few simple requirements here:

  • Let's say that in this application the start and end dates define a period when a product is on the market.

  • If a start_date is None, we don't have a start date, and we'll interpret this as as far as we know now, the product has been in the market from the indefinite past, until the end date.

  • If an end date is None, we interpret this as as as we know now, the product will be on the market from the start date until the indefinite future.

  • If both are None, we assume the product has been on the market from the indefinite past to the indefinite future.

Something like that. The specification doesn't have to be perfect and it often won't be. If it isn't clear it'll be your job to find out what it should be, generally by asking someone (and perhaps giving them a few suggestions).

start_date is None

Given these requirements, how would we handle None for start_date? If the start_date is in the indefinite past, we don't have to check whether end_date is earlier than it, because we'll say the indefinite past is always earlier. (If you're not sure about this, ask someone, but in this case we are sure as we make it up ourselves.)

Let's express that in code:

def validate_end_date_later_than_start(start_date, end_date):
    if start_date is None:
        return
    if end_date <= start_date:
        raise ValidationError(
            "The end date should be later than the start date.")

end_date is None

If end_date is None, it's in the indefinite future. start_date can not be later than a date in the indefinite future, so we don't need to check then either. Let's express this in code too:

def validate_end_date_later_than_start(start_date, end_date):
    if start_date is None:
        return
    if end_date is None:
        return
    if end_date <= start_date:
        raise ValidationError(
            "The end date should be later than the start date.")

start_date is None and end_date is None

Now what if both end_date and start_date are None? A date in the indefinite past is always earlier than the indefinite future, so we're safe too and don't need to compare dates either. We can express this in code too:

def validate_end_date_later_than_start(start_date, end_date):
    if start_date is None and end_date is None:
        return
    if start_date is None:
        return
    if end_date is None:
        return
    if end_date <= start_date:
        raise ValidationError(
            "The end date should be later than the start date.")

It turns out the last bit was superfluous as turn out to handle this case correctly already anyway. That's fine and will often be the case, but not always so we do need to briefly think about this case before we stop worrying about it.

Next time we'll talk about what this pattern really is.

part 1 part 2 part 3 part 4 part 5 part 6

Modern Client-Side Times

Introduction

Reinout wrote a blog post about the client side and what it means for server-side web development. Lots of it is very interesting to me, so I'm going to give some feedback here.

One of the central questions Reinout covers is whether the server-side web framework will become merely a system that serves up an API (presumably RESTful, or at least not so RESTful HTTP, or perhaps web sockets). A rich client-side application written in JavaScript then does the actual UI presentation. Does this mean current web frameworks such as Django, or the people using the server-side paradigm, such as Reinout, are becoming obsolete?

(By the way, I prefer the term "web service" to API, but the difference is at best subtle. A web service promises some discoverability (using, say, hyperlinks) that an API perhaps does not. A RESTful web service leads to resource-oriented modeling, which is subtly different from traditional OOP API design.)

Since I've been doing a lot of work on client-side single-page user interfaces that talk to RESTful (or web socket) backends in recent years, I figure I'd comment. I've been working on and with Obviel, and I've mostly worked with Grok-based RESTful + JSON backends.

The new way obsoletes the old?

So, back to Reinout's question: is the new paradigm going to obsolete the old? Does the rich client-side user interface approach obsolete server-side web frameworks?

Reinout disagrees, and I do too. There is a huge area where server-side rendered HTML is the way to go. Not all web sites are single-page web applications, nor should they be. Not all rich web applications are single-page either.

I do find rich client side web applications a very interesting part of web development. I think much innovation takes place here. I am attracted to areas of innovation as I like being creative. I think the client-side paradigm can, when used well, lead to improved application design, with better separation between UI and backend code.

I'll also note that the old way informs the new: I've found it extremely useful to think about Obviel as a web framework and think about what server-side web frameworks do and what this might look like in the client. Your knowledge of server side web development is not obsoleted even if you develop in the client-side paradigm.

What goes and what stays?

With a single-page rich client application, the server-side web framework has to do less. What tends to go away from the server side?

  • server-side templates (templates are now client-side).

  • form generation (at least with Obviel; though form-definition generation is still there)

  • sessions (a single-page web app doesn't need a session; it can store whatever it likes between requests to the backend service)

What remains is still significant, however:

  • serving up JSON on URLs with hyperlinks to other URLs

  • processing POSTs of JSON content (this may include parts of form validation)

  • traversal or routing to content

  • integrating with a database (SQLAlchemy in this case)

  • authentication - who are you?

  • authorization - who can access this URL?

  • serve up an initial web page pulling in a whole bunch of static resources (JS, CSS)

The client web framework (such as Obviel) gains some features that are traditionally done on the server-side:

  • templating

  • form generation and part of validation

  • routing (though this is in addition to any routing done by the server - it's to allow URLs for different aspects of a single page application)

  • i18n (if your client side web framework can do it)

Saying that the server side becomes "just an API" is an overstatement, I think. Much of what was useful to a server side web framework is still useful. The main thing that changes is that what goes over the wire from server to client isn't rendered HTML anymore. This is a major change that affects everything, but much does stay the same nonetheless.

Random extra points

Reinout makes a few assorted extra points, and I'll respond to some:

  • "I do want to use APIs and javascript a lot, I just don’t want the user interface to be king."

    I try to design web services where the web service in itself makes sense, independent of user interface. I haven't gotten this 100% right yet, but I do notice that I can develop the back-end and the client-side rather independently from each other. I don't find myself switching from client-side to server-side and back again the whole time when developing a new feature or fixing a bug; usually the problem is isolated in one place or another.

    Ideally, the web service isn't the servant of one UI; doing so will create a service that is purely ad-hoc and doesn't expose clean resources. The web service should be designed in a clean way independent of particular UIs. In the real world of course there are compromises, but if you just go into this direction a little the UI will be brought down from its kingship and become a proper citizen.

  • "i18n is easier to manage in Python/Django than in Javascript."

    For most JavaScript web frameworks this appears to be true. But not if you use use Obviel! Obviel's i18n system is on-par with best of breed server-side i18n, and in some points stronger (pluralization). Obviel builds on babel (in Python) and you can extract translatable strings from JavaScript, Obviel Templates (client-side) and Python code.

    (Obviel still needs a kick-ass localization system for things like dates and such - want to help?)

  • "We haven’t tested a single line of javascript in the three years [of development]..."

    Reinout here implies that if you move functionality to JavaScript you won't test it. It's certain possible to do extensive test coverage for JavaScript code, and there are high-quality tools: I've used Buster.JS and Sinon.JS for Obviel, for instance. Tools like Selenium let you write automated tests for complex user interfaces too.

    While it may be true that you have experience with writing Python tests now and not with writing tests for client-side JavaScript code, it is possible to do this for client-side code just fine.

  • "The core of the new html+javascript+api approach sounds to me like 'I want to build a modern web interface with html+javascript+api'. There isn’t much 'data source' or 'customizations' or 'quick modification in a subclass' in the core of that approach. It sounds like it is aimed at building one single individual great website."

    I'm not entirely sure what this is about. Server-side web development doesn't go away, and you can do whatever you want with data sources and customization there. The main difference I see is that when you need to display the results in a UI, you don't use a server-side template but serve up JSON and use client-side templates instead. I'd also say the concept of a data source can become more explicit if it's also served up under a URL.

    Perhaps this is therefore also about user interface customization. The way this is done would have to move, at least in part, from the server to the client, but that is certainly possible (Obviel offers one way to do that, and you can drive UI construction from the server).

  • "Repeatability, rebuildability, customizability."

    Reinout has a great deal of experience with creating repeated builds of complex Python applications. He wonders what the state of the art is for JavaScript applications.

    It's not as good as the Python world, I think.

    While there are a whole bunch of tools available for JavaScript, it's scattered all over the place. You can package a JavaScript library and manage its dependencies, but the problem is that often you have to do such a thing instead of simply using packaging by the original authors. Common approaches are in the works, but they're not very mature yet, at least on the client-side.

    For Python projects we created a static resource packaging solution called Fanstatic, by the way. But it's one way of many.

Conclusions

Server-side web applications aren't going to go away. Server-side concepts often apply to the client side. These things will exist in parallel. So: you are not obsolete.

Client-side web development is trendy, and trends tend to bring in hype, and hype is overstated. Let's not throw away our server-side wisdom just because new ways of doing things have emerged.

Solid, client-side development can be done, but it's not as mature as with Python. A corollary to that: there is a lot of creativity on the client side, and that is fun!

And a plug for Obviel: Obviel is a client-side web framework that you can adopt incrementally, and it's informed by server-side concepts.

The Story of None: Part 2 - Recognizing It

The Story of None: Part 2 - Recognizing It

part 1 part 2 part 3 part 4 part 5 part 6

Last time...

In part 1 of the Story of None we've seen this validation function:

def validate_end_date_later_than_start(start_date, end_date):
    if end_date <= start_date:
        raise ValidationError(
            "The end date should be later than the start date.")

We've decided that start_date or end_date may be omitted (and be None), and that this function is therefore buggy: we'll get a TypeError if it's called with None as one of the arguments and a date with the other.

A type check?

One reaction to a TypeError is to do a type check to see whether the values are really of the right types, in this case, date, and to only proceed if they are. Something like:

if type(start_date) == date:
   ...

or:

if isinstance(start_date, date):
    ...

This works, but I think this signals the wrong thing to the reader of the code.

The reader may start wondering whether there are code paths that generate a start_date that is not a date but something else; we seem to be guarding against a set of other possibilities. But in reality we're only guarding against one possibility: None.

It is a bit of cognitive load for the developer to consider None is what we're really checking for, and that type(None) is NoneType and that this isn't equal to the date type. It's not right to make a developer think about stuff they don't have to think about.

Let's instead be specific, and just handle None, and avoid type checking.

if value?

So we want to make sure that start_date and end_date are present. That something is there. It's now very tempting to check for their presence with a clause like this:

if start_date:
   ...

This again will work, at least in this particular case, where the arguments are dates.

But it won't work for other things, like a function where the arguments are numbers.

Why won't it work for numbers? Because 0 in Python evaluates to False. And the number 0 doesn't mean that the number is omitted. So if we were, for example, comparing start_age and end_age, where the ages are integer numbers, we'd be in trouble if we did something like this:

if end_age and start_age and end_age >= start_age:
   raise ValidationError("End age should come before start age")

end_age could be 0, and 0 would definitely come before a start_age of say, 10, and we still don't raise ValidationError. A bug!

We want to reduce the burden on the developer who has to reason about this code, if we can, we should use a pattern that works for any case where None can be a value. Doing so will make our code be more regular and easier to understand.

So when we can, we should explicitly compare with None.

value == None?

Don't use == None either. It will work but it'll be a tiny bit slower and it's not the Pythonic convention. Plus if the __eq__ operator is overloaded it may dive into that, which is what you don't really want.

Follow the convention so that other programmers will be able to read your code more easily. In Python you compare for equality with == but for identity with is. I won't go into the details of identity versus equality here. Instead I'll say that you can always safely do an identity comparison with None.

value is None

So how do you compare with None in Python? You use:

value is None

and if you want to check whether something is not None the idiom is:

value is not None

In JavaScript by the way the idiom is value === null and value !== null, as triple comparison is identity comparison in JavaScript.

Next time we'll apply this approach to our validation function.

part 1 part 2 part 3 part 4 part 5 part 6

Obviel Compared

I'm asked sometimes how Obviel compares to other client side web frameworks. This evaluation of JavaScript MVC frameworks provides a few useful points to consider and gives a good opportunity for me to highlight some features of Obviel.

I think Obviel comes out pretty nicely in this particular set of criteria, but of course many other criteria exist.

UI Bindings ✓

A declarative approach where the UI is updated when the underlying model changes.

Obviel provides this because views can listen to events on models. When a model is updated, an event can be sent to the model. If a view is currently representing the model in the UI, that view will be notified. A typical response by the view can be to rerender itself, but more detailed updates exist as well.

Obviel Forms uses a more direct form of data binding -- when you modify a field in a web form, an underlying JavaScript object is updated automatically with the JavaScript representation of that field. If you change the underlying JavaScript object, the form is automatically updated as well. I am hoping we can eventually expand Obviel Template with some features to do in-line updates directly, though re-rendering a view (these are typically small already) can take you a long way in the mean time.

Then there's Obviel Sync. Obviel Sync is a library that lets you declaratively bind models to some backend, typically a server. Using Obviel Sync you can automate the sending of events to models. Unfortunately Obviel Sync is as yet undocumented (the only part of Obviel not to have docs) and needs a bit more polishing. If you're interested in helping out, let me know!

While there is still a lot of potential in further expanding this approach, I think Obviel already has a pass mark on this feature.

Composed Views ✓

Compose views (preferably at the template layer). This should entail the potential for a rich view component hierarchy.

Obviel is built around the concept of composing views, and the template layer supports this. A central trick in Obviel is that the view to use for a model is determined by looking at that model - if you swap in a different model, a different view will be rendered. The code that renders the view doesn't need to know or care what specific view is used.

This can be driven from the template layer, by using the data-view directive.

You can create rich view components with Obviel; more about this in the next section.

A definite pass for Obviel on this feature.

Web Presentation Layer ✓

No native-style widgets, but instead let people use HTML and CSS.

What the right approach here is a debatable topic. Some client-side web frameworks provide a whole widget abstraction and you build the user interfact by composing those widgets together. Others are explicitly centered around HTML and templating. Both approaches have their advantages and disadvantages.

The author of the article leans heavily towards the approach where people use their own HTML and CSS. Luckily to gain the pass on this feature, Obviel fits in with this approach: Obviel is centered around HTML templates and JavaScript and lets you do everything on that level. It does not provide its own widget set but lets you use the UI elements you want to use, directly in HTML.

That said, it is possible to create widgets on top of Obviel, using Obviel Views. The Obviel Forms library is an example of such an approach. Another very interesting up and coming library created by Rob Gietema, Obviel Bootstrap, creates a set of Obviel views for Bootstrap UI elements. Note that you don't have to use Obviel Bootstrap to use Bootstrap with Obviel; instead you can directly use the bootstrap css classes in the HTML of the templates.

So, a pass for Obviel; Obviel's designed this way.

Plays Nicely With Others ✓

jQuery is pretty amazing. I want a framework which recommends using jQuery itself instead of providing its own sub-par jQuery clone.

Obviel is built on jQuery, so that's an easy pass for Obviel. jQuery extends jQuery in a small but powerful way by letting you do $(el).render(obj) to render a view on an element for an object.

Obviel passes on this one by design again.

The Story of None: Part 1 - The Beginning

The Story of None: Part 1 - The Beginning

part 1 part 2 part 3 part 4 part 5 part 6

Introduction

I'm going to be talking about None in a series of short articles. It is intended for less experienced developers. We're going to talk about some basic patterns that can clean up your code. Welcome!

If you're an experienced developer what I'm going to say is probably obvious to you. Nothing I'm going to say is particularly new or innovative, so this series of articles is probably not for you. But feel free to follow along and comment anyway!

While I'll focus on Python as an example language, most of this stuff is also applicable to many other programming languages as well. So if you use, say, JavaScript, don't go away, this may be useful to you too! Python is pretty easy to read so you should be able to follow along.

None

What is None? Python has a special value called None. None in Python is the standard sentinel, though of course other objects could also be used (and sometimes are). Other languages use NULL or null or nil; JavaScript confusingly has two values along these lines, null and undefined.

So what do we use None for? It turns out that when we have some value (attribute, return value, function argument), in many cases we want to be able to signal that the value is not there at all. In other words, the value is maybe there, and maybe not. To signal this we typically use None in Python.

If None is a possible value, it becomes important to make sure you handle the None case. Handling None is what this is all about.

Examples

Let's get a bit more concrete and give some simple examples of where None may come in.

A form in a user interface (for instance a web form) could have some fields that are not required to be filled in by the user. These empty fields can be represented as None by the application.

None is also often the default fallback value when no value can be found: the get method on the Python dictionary has such behavior.

Some functions have optional arguments. If they are not given, the value is some default. Often None is used for this default. The function's implementation can then detect this and deal with it accordingly.

A detailed example

Let's look at an example in more detail. This is a validation function:

def validate_end_date_later_than_start(start_date, end_date):
    if end_date <= start_date:
        raise ValidationError(
            "The end date should be later than the start date.")

The idea is that the function passes silently if the arguments (start_date and end_date) are valid, but will fail with a ValidationError if not.

If start_date and end_date may be omitted (for instance in a user interface), this omission can be represented as None. In this case, the function may be called with either two dates as arguments, or None in either one or both of them.

But if the arguments can be None, the implementation of this validation function is buggy, because we've neglected to consider the None case for the arguments. If one of the arguments is None we'll see this:

TypeError: can't compare datetime.date to NoneType

That's not what we want!

So next we will talk about how to recognize None properly in the first place.

part 1 part 2 part 3 part 4 part 5 part 6

New Blog Engine

My blog used to use the venerable newsbruiser system. It worked, and has a nice web UI, but looked ugly. Now I could've fixed that, but since I wanted to change my blog workflow anyway to something filesytem and version control based, I've switched to a static blog generator instead: Nikola. Thank you newsbruiser, you did well for me!

This was a fun little project: it involved taking the restructured text content from newsbruiser and generating restructured text content that Nikola could deal with, configuring Nikola, digging out the comments from newsbruiser and putting them into disqus (I hope I got out most of them), and all the little conversion issues surrounding it.

I've retitled my blog from "Python Secret Weblog" to just "Secret Weblog" to reflect my increasing focus on JavaScript code too. I still love Python, though, so I will be writing more Python-related content as well.

The blog's URL changed too: it's now at http://blog.startifact.com instead. I've put redirects in place on the old http://faassen.n--tree.net/blog location to preserve links to the old articles.

I also hope that with this refresh I'll start blogging a bit more often!

Welcome to my new blog!

Dear Django, please ask others about packaging!

Dear Django, please ask others about packaging!

Introduction

Dear Django, and any human beings interested in what I have to say too... This blog post is ostensibly about Python packaging. It's responding to Tarek's post.

But I'm actually currently not that concerned about Python packaging - it's good to see it is improving! This blog post is really a plea for people to learn from others if possible, in this case about packaging. So if you take message to heart already, you can just stop reading now and I won't mind.

Of course my whole core spiel about learning from others could be seen as hypocritical as I haven't bothered to learn much about distutils2 yet and admit this below. This is because I'm not anticipating an imminent switch to it myself, nor am I actively working on Python packaging solutions. I do hope to learn more about NodeJS's npm at some point, which currently confuses me but also vaguely intrigues me...

I understand why distutils2 is there. It was high time to take a fresh look at Python packaging. And when you do this it is useful to ignore details for a while - you can't change everything in one big step.

I also understand why Tarek sees Django, one of Python's most popular frameworks, as a great opportunity to help distutils2 adoption. This is because core Django has rejected automated packaging tools until now. That's a great opportunity for distutils2. I'm one of those people who has talked about Django and packaging before. I'm all for Django look into adopting distutils2. Sounds like a good way forward for Django!

I think Tarek or others could also help distutils2 adoption a lot by offering interoperability features between old & smelly stuff with distutils2. More of that please! I hope we'll get to a world soon where I can adopt distutils2-based packages in my existing buildout-based Python 2 stacks.

Now we're done with the preamble, and we'll get to the core of my point.

Greybeard leans over cane and tells his tale...

Setuptools is messy and has misfeatures. But people have been doing all kinds of advanced packaging projects on top of it for over 5 years nonetheless, with all kinds of great incremental advances along the way, and lots of experience gained.

So the existing, smelly, messy stack got strengths too. I really like being able to be able (with buildout) to automatically install even very complex development environments that some other developers have worked on, or give mine to others. That happens quite a lot to me, and the alternative of telling people to follow complex manual instructions would have been quite painful.

So I get a bit frustrated when Tarek says:

Some people will tell you that the new things we've built are not production-ready or that they don't match the features Setuptools provides. But ask yourself if those Setuptools features are really something you want or are subcultures additions from some specific communities.

This is because he is not countering any specific argument about bits not being production ready, nor is it about particular missing features, meaning this counterargument is, frankly, just as worthless as saying "it's not production ready" without elaboration. It may even be somewhat dangerous.

To ignore hard-won experience merely on the basis handwaving it away as "subculture additions from some specific communities" is to throw out the experience of those communities, and then you risk being condemned to repeat some bad history, as, face it, quite a few of us subculture folks over here (and I'm including Tarek) have way more experience with Python packaging than the subculture of the Django core developers.

Subculture grumbles

I don't know what distutils2 infrastructure can or cannot do. If I, native of some undoubtedly backward setuptools-stack subculture, were to evaluate it, I'd certainly look for various things.

I'd want to know whether it can pin down versions of library dependencies somehow for my projects. My subculture finds this very important. Are these just useless backward traditions?

I'd also definitely want some of the features of mr.developer available to me, so I can easily check out various dependencies of a project in a hackable form. Another one of those subcultural quirks, or worthwhile even in modern civilization?

I'd like there a way for me to automate the installation of scripts and applications that I can then invoke from the command-line, because I find my subculture projects doing quite a bit of that. Perhaps this is just ancient subculture stuff or do modern folks need that too?

If I were to build large projects, I'd probably want some features along the lines of buildout for including non-Python code. Can we do without such quaint notions in modern times?

Hohum, so, if you are thinking about adopting distutils2, please do ask yourself what particular neat features are offered by setuptools, buildout, pip, mr.developer, instead of saying "it's just some subculture thing we don't care about".

Instead, I hope people will try to establish the use cases handled by these in a distutils2 world in some shape or form. Hopefully it'll work better with better documentation. Or at least people can reject the call for particular features with considered opinions and solid counterarguments.

Now I know that's probably what Tarek means himself when he says that subculture stuff that just rubs me the wrong way:

But ask yourself if those Setuptools features are really something you want or are subcultures additions from some specific communities.

Do consider feature requests carefully. Try to understand the underlying use cases. But don't use the "subculture additions from some specific communities" argument to handwave arguments or people away.

Obviel 1.0b2 released!

Obviel 1.0b2 released!

Since the last release of Obviel 1.0b2, I've been plugging away at creating a new version. This version has a massive list of changes. Some highlights:

  • a much nicer demo app, the inevitable todo list. This is a demo along the lines of the TodoMVC project. I haven't quite got it to the state where I think it's ready to submit to that project, but I'm getting there. One thing you'll notice is that the UI is in Dutch. By a one-line change in the JS code you can switch that UI to English. I still need change the UI so you can change the locale in the UI itself; next release!

  • extensive improvements in the i18n infrastructure.

  • pluralization support in templates. This brings Obviel Template's i18n support to a level slightly beyond what I'm familiar with as best-of-breed i18n in server-side templates (ZPT/Chameleon). In brief, you can have a UI that says "{count} cows", and when count is 1, it'll say "1 cow", and when count is 2, it'll say "2 cows", without the need for a conditional in the template. You'll note that in English there are two forms (one and many). Other languages have other rules and may have only one form for all numbers, or more than 2 forms. Obviel builds on gettext to support all these different pluralization rules.

  • data-handler lets you bind a DOM event to a view method directly in a template.

  • data-func can now also use methods of the view, which turns out very useful to support more complex attribute rendering logic which is better written in JavaScript instead of in clunky templates.

  • some backwards incompatible changes: the great renaming (under_score to camelCase in the API, as that's more the JS way), and eliminated callbacks in favor of jQuery deferred. A bit late, but the installed base is still small, and I figured now is better than never!

  • the docs got a freshening up, both in presentation as well in contents.

  • many bugfixes and minor improvements.

Please give it a spin and give feedback!

Obviel 1.0b

Obviel 1.0b

It's been quiet around Obviel, the client-side web framework that I've been working on. That isn't because there wasn't any activity. The opposite is the case: I've just released Obviel 1.0b with a ton of new goodies. And when I mean a ton I do mean a ton:

  • a whole new template language called Obviel Template that supports sub-views & i18n

  • gettext-style i18n in JavaScript

  • and the most out there new thing: an actual client-side routing library called Traject

For more details, here's the changelog.

Why would you want a client-side web framework like Obviel? More and more web development is happening on the client side, in JavaScript. End users get a more dynamic user interface. Developers get to enjoy a cleaner separation between UI and backend, and various scalability benefits as the burden of rendering the UI has moved to the client. A rich client-side UI isn't something to use for all web sites, but it certainly is a nice thing for the web applications where you can!

jQuery is a very nice library to help build dynamic web UIs, but for larger projects your JavaScript easily grows out of control and becomes a tangled mess. With Obviel you can add structure to your jQuery application, and make each bit more easy to understand and more reusable.

You can get started with Obviel without learning a ton of new things beyond jQuery: learn about the new function .render() that Obviel adds to jQuery, and you're quite far along already. You'll find your client-side code becomes more clean and RESTful.

Obviel is there for you then you need more: templating, internationalization, forms, client-site routing, and more.

Obviel isn't the only client-side framework out there. I do think it offers some unique perspectives on how to do templating, i18n, model/view separation and form generation. Unique for the client-side that is: I've been porting over patterns from advanced server web frameworks that I'm familiar with to JavaScript and the browser to see what happens. And what happens feels good to me. I hope you'll check it out and let me know what you think!