Showing posts with label design. Show all posts
Showing posts with label design. Show all posts

Monday, August 16, 2010

Good Practices for Rich Web Applications

Use jQuery

jQuery is the best thing that has happened to Javascript since it got first class functions in version 1.2. The library is elegant, powerful and has exactly the right level of abstraction for working with the DOM. There is nothing more to say. Learn it and use it. Good resources are: the jQuery API, my view of the jQuery API

Learn Javascript

Javascript is the programming language of the web. Learn it! Javascript is different from most other programming languages. It is dynamic, it has prototypical inheritance, and works more like Scheme than any of the languages that you are probably used to. If you want to learn Javascript you should get the following books, The Little Schemer, The Seasoned Schemer, Javascript, the Good Parts, and possibly High Performance Javascript

Learn CSS

Many programmers think that CSS is the language of designers and not programmers. This is not the case at all. If you are lucky enough to have a designer on your team (most people don't), CSS is the language with which you communicate. It is the interface between designers and programmers and as a programmer you should know it better than the designers. By knowing CSS well you will reduce the misunderstandings between you and your designer.

Unfortunately, many designers don't care about how code looks, as long as the design looks good on the surface. It will be up to you to make sure that the CSS doesn't get out out of hand. It will also be up to you to keep the HTML clean, and a good way to do this is to use semantic HTML, combined with CSS. You have no idea what the designers can come up with.

<!-- 
  Old School rounded corners, invented by a GOOD designer. 
  All this code was actually needed to achieve the purpose.
  -->
<style>
.t {background: url(dot.gif) 0 0 repeat-x; width: 20em}
.b {background: url(dot.gif) 0 100% repeat-x}
.l {background: url(dot.gif) 0 0 repeat-y}
.r {background: url(dot.gif) 100% 0 repeat-y}
.bl {background: url(bl.gif) 0 100% no-repeat}
.br {background: url(br.gif) 100% 100% no-repeat}
.tl {background: url(tl.gif) 0 0 no-repeat}
.tr {background: url(tr.gif) 100% 0 no-repeat; padding:10px}
</style>
<div class="t">
  <div class="b">
    <div class="l">
      <div class="r">
        <div class="bl">
          <div class="br">
            <div class="tl">
              <div class="tr">
                Lorem ipsum dolor sit amet consectetur adipisicing elit
              </div>
            </div>
          </div>
        </div>
      </div>
    </div>
  </div>
</div>

As an additional benefit you will become better at jQuery. Not only is CSS the query language of the browsers it is the query language of jQuery. Jariba!

Bulletproof Web Design is a good book web design, including CSS.

Decide how "Rich" your application should be

How rich should your application be? The scale varies from no Javascript to only Javascript, but you will probably want to land somewhere in between. Here are a few suggestions.

  • No Javascript, everything is server generated.
  • Slightly enhanced pages, simple validations, but no Ajax.
  • Ajax enhanced pages, but every page still reloads frequently.
  • Single page per area, entire area is handled by Javascript.
  • Only Javascript, Ajax interaction with the server
  • Only Javascript, no interaction with the server.

The important thing is to make a decision. If you don't make the decision, everyone will do different things on different parts of the application and you will loose consistency. In GUI, consistency is king. Make a decision and move on, you can always change your decision later.

Organize your code

Javascript

Make sure that all your Javascript code is namespaced properly. It is impolite to pollute the global namespace and it will bite you in the end. A simple variable declaration will do.

// Common namespace for your entire application
// This declaration lets you split your code of multiple files.
// If MyNamespace is defined use it, otherwise declare it.
MyNamespace = MyNamespace || {};

But, of course, it is also possible to get fancy and encapsulate the functions that you don't want to expose, if that is your cup of tea.

MyNamespace = MyNamespace || {};

MyNamespace.Tournament = function() {
 // Private stuff
 var tournamentCount = 0;
 function addTournament(tournament) {
  tournamentCount++;
 }
 
 return {
  //public stuff
  numberOfTournaments: function() {
   return tournamentCount;
  }
 }
}();

You should also separate your Javascript code into different files. The namespace idiom above helps to have the same namespace across multiple files. The same principles as with other type of code is valid with Javascript, organize the code by area, when it changes, where it is used, etc. Don't be afraid of the additional load time, splitting the files will give you. The files can easily be concatenated with tools like Rake, SCons, Ant or even a simple:

$ cat file1.js file2.js file3.js > all.js

They can also be compressed with JSMin or YUI Compressor.

Optimize your environment for development, not for production!

HTML

HTML is code! Divide your pages into partials by responsibilities. It allows you to keep your pages DRY and readable. The Single Responsibility Principle applies to HTML too.

Make sure you keep the Javascript with the code that it manipulates. If you, for example, have a calendar partial that uses jQuery DatePicker, you have to make sure that the partial includes all the necessary Javascript to configure the calendar. Don't keep Javascript code in the page away from the partial. Things that change together should be together.

CSS

Stylesheets are code too. They should also be split into areas that allow you to easily find and navigate them. Use Sass or SCCS to keep your CSS files DRY. Sass is good for designers to. It gives them the ability to use variable names, mixins, etc. and simplifies their usage of semantic names such as notice, and sidebar instead of yellow and left.

Optimize your environment for development, not for production!

Separate your Javascript from your HTML

All too often I see generated HTML pages with Javascript code in them. Don't do it. Keep the HTML free from Javascript.

<!-- DON'T DO THIS!  -->
<button id='update-button' onclick="MyNamespace.updateList();">Update List</button>

// In the Javascript file for the page.
MyNamespace.updateList = function() {...}


<!-- DO THIS! -->
<button id='update-button'>Update List</button>

// In the Javascript file for the page.
MyNamespace.updateList = function() {...}

$(function() {
  $("#update-button").click(function() {
    MyNamespace.updateList();
  });
});

It may seem like there is a lot more code in the good example, but notice the symmetry. The code that attaches the listener is in the same file as the code that uses the listener. This is good. Symmetry is good.

Use clone()

Separating the HTML and the Javascript goes both ways. Don't generate HTML code in Javascript. It doesn't matter that it is super simple to do it using jQuery.html(). Keep them separate, use jQuery.clone() instead.

// DON'T DO THIS
$("<li data-id='123'>My new item</li>").appendTo("ul");
// OR THIS
$("ul").append("<li data-id='123'>My new item</li>");


<!-- DO THIS -->
<ul>
<li id="list-template" class="template">All .template are hidden (display: none) in the CSS</li>
</ul>

// AND THIS
var $clone = $("#list-template").clone();
$clone.attr("data-id", "123").text("My new item").removeClass("template");
$("ul").append($clone);

The point of this is, again, to keep the HTML separate from the Javascript.

Decide how content flows between, the page, Javascript and the Server.

Once you have decided how rich your application should be, you have to decide on a method for moving the data between the HTML Page, Javascript and the Server. My preferred choice is to have every page that is served from the server include a context object with all the static data for the page and to have additional data that belongs to parts of the page be sent as data-attributes on the elements concerned.

The context object will contain all the data that is commonly needed in the page.

// Sample context object that is generated with the page.
MyNamespace = MyNamespace || {};
MyNamespace.Context = {
  user: {
    id: "28",
    name: "Anders Janmyr"
  },
  tournament: {
    id: "78344",
    name: "Fifa World Cup"
  }
};

I use the context object(s) to keep state on the client to. If it is important that the page looks exactly the same, even if the user reloads the page, I make sure that the state I stick into my context object is synched back to the server. This can easily be done, asynchronously, with Ajax and does not affect performance noticeable.

Elements specific data is sent along with the element it defines.

<!-- Element specific data attached to the elements with data-attributes -->
<ul id="tournament-menu">
  <li data-id="78344" data-participant-count="64">Fifa World Cup</li>
  <li data-id="666"  data-participant-count="44">Americas Cup</li>
  <li data-id="1464" data-participant-count="32">Rugby World Cup</li>
</ul>

The same argument as with the context object applies, as soon as I change an element in the GUI i need to feed that information back to the server. With elements I usually send the information to the server before updating the GUI, since element specific data is usually permanent data and not just session data.

An alternative solution to the context object above is to use the body element as the data-container, like this:

<body data-user-id="28" data-user-name="Anders Janmyr" data-tournament-id="78344" data-tournament-name="Fifa World Cup">

I tend to use the context object because I find it easier to add functionality to it than to the DOM element.

Only send the data that is needed to the client with the page. The rest of the data should be loaded on demand, with Ajax. Both JSON data and HTML templates can be loaded on demand. There is no need to deliver the entire page at once. Experiment and do what gives the best user experience.

Use file watchers to speed up feedback

If you compare the feedback cycle of Javascript and HTML development to Java and C# development, you are probably very happy with the short, tight feedback loop. This doesn't mean that you should be content. A feedback cycle cannot be too short.

xrefresh for Firefox and IE, and LiveReload for Safari and Chrome, are a couple of tools that will tighten your feedback loop even more.

Both tools are file watchers that listen to changes for files and refresh the browser when they change. If you combine this with two screens, you will have one screen for the browser, that updates continuously, while you edit your code on the other screen. Fabulous!

Conclusion

Rich web applications are very close to the traditional client-server model. We have to keep state on the client side to give the user a good experience. At the same time the application state, and indeed the entire application, can be swept away by a click of a button or a page reload.

This puts new demands on us as developers. We have to realize that we are responsible for the entire application, not just the business logic, but the HTML and CSS too. More that anything, we have to realize that Javascript is a first class programming language with its own programming techniques, which we need to master to be able to develop good web applications.

Friday, August 21, 2009

Fat is Better

I have recently had discussions with some colleagues about what architecture they prefer and, while they seem to favor thinly sliced services, I have come to the conclusion that the overhead that comes with slicing services thin is not worth the extra time that it takes to setup, verify and test the complex, internal communication that comes with this kind of architecture. Fat is better!

If I am designing a system that should work in a coherent way, I want it all in my big, fat, juice object model. This enables me to put the functionality where it is most cohesive and, therefore, gives me the best design possible. Every object should carry its own weight.

If there are external services they must, by necessity, be outside the model, but the internal representation of the external service should be inside my model.

An example of an architecture that relies on thinly sliced services is REST. REST is very elegant and it definitely has a place when publishing resources. But REST models are anemic. They rely on you to GET the information from the resource, do things to it and then replace the information of the resource with a PUT. It is CRUD for the web. It is not intended to take advantage of what is good in object-oriented and functional programming, like sending behaviors into an object and have it perform the calculations for you.

The elegance of map and reduce (fold) is the essence of functional programming. How do you model map and reduce with REST? You can't! Polymorphism and encapsulation is the essence of object-oriented programming. Where does it go when everything is a resource? It disappears!

I have worked on projects where the goal has been to design every little part of the system as a free standing module with its own life and versioning, that can be switched in and out, but the artifacts have mostly been deployed together and have rarely given any extra value standing on their own. But they have given us a lot of grief when we tried to build a DRY system.

So, a fat model is the way to go. How fat? As fat as possible, but no fatter. How fat is that? As always this is a judgment call but, err on the side of fatter.

If, by luck or skill, my fat system reaches a workload where it will have to be split over multiple processors or machines, it will not be very difficult to split the system, since the system will be well factored, cohesive and DRY!

Note: "Fat is better" is somewhat related to worse is better by Dick Gabriel

Wednesday, August 12, 2009

What Eric Evans Would Have Changed in the DDD Book.

Here are my notes of Eric Evans talk What I've learned about DDD since the book

Essentials

Emphasize that the collaboration with the domain experts is essential. It is up to you to show the domain experts how valuable their collaboration is. If they cannot see the value of participating in the project, they will not to a good job, and they will try to avoid it.

Always produce at least three bad models. These models help to emphasize what is important.

The chapters "Distillation of the Core Domain" and "Context Mapping and Boundaries" should have been moved to the start of the big since these are the most essential areas.

Changes to Building Blocks

Domain Events

There is one new Building Block and it is the Event Object. The Event Object is an object the represents an Event that is significant to a domain expert. A benefit of domain events is that they give clearer, more expressive, models.

The events can be used for: - Representing the state (history) of entities. - Decouple systems with event streams (publish-subscribe) - Enable high-performance system.

Aggregates

Evans want to emphasize som things of aggregates. The boundaries of an aggregate need to contain transactions, distribution and concurrency.

When modelling the aggregates it is important to not over-specify on what part of the aggregate the properties and invariants are placed. Even though they are commonly placed on the aggregate root, this is not essential and it gives you a freedom if you not specify it too hard and too early.

Strategic Design

Large-Scale Structure does not come up very often and would probably have been left out of the book.

It is important to not spread modelling to thin, and to focus on the core domain and to create a clean bounded context.

Collaboration Patterns

There is two new collaboration pattern called Partners. This pattern differs from the other collaboration patterns in that it is cooperative and mutually dependent.

Another pattern is the Big Ball of Mud"_. This pattern is known as an anti-pattern since it implies that the code is just fixed as things go. This pattern is utterly pragmatic but the point Evans is making is that if there is a Big Ball of Mud in the system, it is important to define the boundaries of it, so that it doesn't spread to other systems that are more rigorously architected.

Context Mapping

  • What models do we know of?
  • Where does each apply? Define boundaries in words?
  • Where is the information exchanged?
  • The service interface may define a context boundary.

DDD and SOA

  • The service interface must be defined in some context.
  • Internals also, but often not the same one.
  • The service interface may define a context boundary.

Precisions Designs are Fragile

Sophisticated design techniques are wasted in a ball of mud. It must be isolated with an Anti-Corruption Layer.

Not all of a large system will be well designed. Figure out what part of the system is most critical and benefits most from a really nice design.

Monday, December 15, 2008

Thoughts on Simplicity

A scientific theory should be as simple as possible, but no simpler. —Albert Einstein

Do the simplest thing that could possibly work. Keep it simple by refactoring. —Kent Beck

If you think something is clever and sophisticated, beware: it is probably self-indulgence. —Donald Norman

Simplicity does not precede complexity, but follows it. —Alan Perlis

To make something generic is to make the simple things complex. —Adam Keys

Simple things should be simple. Complex things should be possible. —Alan Kay

Don’t EVER make the mistake that you can design something better than what you get from ruthless massively parallel trial-and-error with a feedback cycle. That’s giving your intelligence much too much credit. —Linus Torvalds

Consistency is Simplicity: A consistent approach to style and solutions can make code easier to maintain. —Ken Pugh

If you think you’re designing something for idiots, the odds are that you’re not designing something good, even for idiots. —Paul Graham

It is better to be wrong than to be vague. —Fred Brooks

Simplicity is the ultimate sophistication. —Leonardo da Vinci

If you want to make something 10 times cheaper, remove 90 percent of the material—Amy Smith

Saturday, November 08, 2008

What should be in an application 2008?

Listed here are features that I want in any application. The features are separate from the domain specific service that the application is designed to provide.

Search

The feature that I want more than anything is search. Everything should be indexed: menus, toolbars, dialogs, windows, selection boxes, shortcuts, help files, configuration files, application components, objects, scripts, the works! It should be possible to make generic full-text searches for anything matching my criteria, but it should also be possible to make specific searches by category or tag. It should also be possible to save the searches for later.

Search should also be available in all places possible. It does not have to be a search field, it can be a selection box or a textfield. It should preferably be integrated into the components to help me out whenever it is possible.

External tools should also be able to search. Tools like Google Desktop and Spotlight, and Launchers like Quicksilver and Launchy must be kept in mind when designing for search.

Tags

Anything searchable should also be taggable. It is possible that my terminology is different from the one that the application developers have. I may also want to group things together that does not appear related to anyone else. It should of course be possible to assign multiple tags to the same thing.

Scripting

Everything should be scriptable. Whatever is possible to do in the GUI should be possible to script. This lets me create my own automated tasks that I can re-use later or share with other users. It should be possible to run and create the scripts both inside and outside the application. The scripts should not be limited to use application functionality, they should be allowed to call operating system commands or other applications. The scripts will thus also serve as plugins for the application.

As with search it is important to have external tools like Quicksilver and Launchy in mind, but when it comes to scripting the scope is wider and you need to think about command line interfaces and other external applications too. Provide many entries to your application.

Shortcuts

It should be possible to assign shortcuts to any action available in the system. This includes saved searches, tags and scripts. Shortcuts should allow Emacs-style multi-key-shortcuts, such as Ctrl-C, Esc-V, M.

Persistence

It should be possible to save the state of the application at any time!. It does not matter to me that a form or that whatever I’m doing is an invalid state. Perhaps I like invalid.

It should be possible to save it anyway. It should also be possible to take snapshots at any time and to reset the application to a previous snapshot at any time. Preferably it should also be possible to compare different snapshots with each other in a useful way.

All in all I want persistence to work like a versioning system giving me the possibility to move through history at my leisure.

Export – Import

Exporting is just a different flavor of persistence. It should be possible to export (persist) the application data into some format that is useful to another similar application. This format should naturally also be importable.

Since exporting is just a flavor of persistence I naturally want versioning of my exports to. Perhaps it’s a good idea to just use git as a persistence engine?

Validation

I mentioned validation above on persistence. Validation is a valuable tool in an application but more often than not it gets in the way. The validation should not force me to enter data in a specified order unless it is absolutely necessary. It is good and even helpful to provide hints and markers along the way. But let me work the way I want to work and stay out of my way.

The important thing with validation is that it should indicate an error as soon as it appears but it should not force me to do anything about it until whenever I try to do something fatal such as, to quote Simon Peyton Jones, launch missiles.

Wiki

I find it really helpful to be able to link things together in Wiki style. The need for this is very dependent on the type of application but I find it very useful to be able to relate one item to another when I commonly need them together.

Conclusion

This list is by no means meant to cover everything, but I think it is a good starting point for anyone who want to make a useful application that can evolve with time.

Saturday, August 16, 2008

Notes On Design

A summary of The Non-Designers Design Book by Robin Williams. The four basic principles of design are: Proximity, Alignment, Repetition and Contrast – PARC.


Proximity

The purpose of proximity is to organize. Elements that are intellectually connected should be visually connected. Unrelated elements should not be in close proximity. The closeness or lack of closeness indicates the relationship. Equal amounts of whitespace between elements indicate that they are part of a subset.

Alignment

The purpose of alignment is to unify and organize. Every element on a page should have visual alignment with another item on the page. Nothing should be placed on the page arbitrarily. Find a strong line, such as a graphic, and use it.

Repetition

The purpose of repetition is to unify and to add visual interest. Repetition is being consistent. Examples are headlines, list items, page numbering, etc. Repetition can be accomplished with a mere suggestion of a repeated element. It is not necessary to use the whole thing.

Contrast

The purpose of contrast is to create interest. If two items are not exactly the same then make them very different. Contrasted elements can often be used with repetition in the page.

Using Color

Get to know the color wheel. Good color combinations are:

  • Complementary colors – two color on opposite sides of the color wheel.
  • Triads – three colors equidistant from each other.
  • Split complement triads – two colors on each side of the complement instead of the complement.
  • Analogous colors – three colors next to each other on the wheel.

Use shades (black added) and tints (white added) to vary the combinations above. Be aware that cool colors recede into the background and warm colors come to the front.

Using Fonts

Fonts can be categorized into roughly six categories:

  • Oldstyle with slated serifs.
  • Modern with horizontal serifs.
  • Slab Serif with fat horizontal serifs.
  • Sans Serif without serifs.
  • Script looks like handwriting.
  • Decorative are crazy fonts like Zapf Dingbats

Never use two different fonts from the same category on the same page.

Friday, March 07, 2008

Summary of "Tog on Maximizing Human Performance"

Summary of Tog on Maximizing Human Performance with additional conclusions.

Prefer the human model to the machine model:

  • Eliminate as much as possible through calculations or guesses.
  • Prefer the human model to the machine model, compare two faucets, a good one lets the user control flow with one control and temperature with another.

Decrease Data Entry

  • Limit decision making.
    • Limit required information.
  • Provide the user with the needed information.
    • Pop up help information.
    • Find the information automatically if possible.
  • Communicate high probability answers.
    • Present choices so the odds become clear.
  • Hide obscure information under an advanced tab.

Limit percieved wait

  • Do calculations in the background.
    • Get the needed information first.
    • Start the background task while the user enters other information.
  • Pop up something relevant for the user to read if the wait is inevitable.
  • Mark lengthy operations early in the design process.