Thursday, June 23, 2011

Keyboard vs. Mouse

When it comes to speed nothing beats keyboard shortcuts. First time users of Gigantt often start out by using the mouse quite a lot: clicking on buttons, zooming in and out with the mouse wheel. But once they learn the keyboard shortcut alternatives they usually adopt them and don't look back. Ten fingers are faster than two fingers.


Keyboard shortcuts also have the advantage of not cluttering up the screen with endless buttons and menus. But there's a UX price to pay - a steeper learning curve. For everything but the most obvious and intuitive keyboard shortcuts, like ESC (cancel), Ctrl+C (copy), there's no getting around the fact that users probably won't be able to guess which key-combo corresponds to which feature.


We still try our best to make sure keyboard shortcuts are as intuitive as possible. For example:


D - Mark a task as done
I - Implode a few tasks into one complex task
E - Explode a complex task into several tasks (the opposite of implode)
L - Create a link between tasks
DEL - deletes anything selected
INSERT - inserts a new task.


See? It all makes sense...


Until now nearly all mouse operations had keyboard alternatives. I say nearly because there's one thing you still couldn't do: select and manipulate arrows between tasks. Now you can. 




The Up & Down keys still navigate between tasks according to their vertical order. If you want to select the arrow into the current task, just hit Left. You can then delete the arrow with DEL, insert an intermediate task with INSERT, and so on. If there are more than one arrow you can move between arrows with Up/Down as well.


These new shortcut solve a painful UX problem: switching input modes. No matter which you prefer, mouse or keyboard, having to constantly switch between them is a real speed bump. So rejoice, fellow typists! From this day on no feature is beyond your keyboard's reach.



Saturday, June 18, 2011

Collaboration in Gigantt

Today we're happy to release the first collaborative version of Gigantt.

What's changed?


Collaboration

Multiple users can now edit the same plan at the same time. It's also cool for the same user to edit the plan in multiple browser windows. However, Gigantt still doesn't support managing multiple resources (i.e. a team). That's our next major feature.
So what happens if two people make conflicting changes at the exact same time? Gigantt helps you avoid this problem by featuring a "freeze period". Basically, any task you modify and its immediate vicinity get frozen for 60 seconds. During this period only you can edit these tasks. Others have to wait for them to "thaw". Frozen items have a snowflake icon. If you hover over one you'll see who has been editing it and how long until it thaws out.


We think this approach to collaboration is better than simply letting people step on each other's toes and then asking them to resolve their conflicting changes.

Visual Clipboard

We got quite a lot of feedback about the way copy, cut & paste wasn't so intuitive. Now it's just like in Windows explorer, but you also get a visual clipboard window that shows you the contents of the clipboard.


The clipboard is also used for creating connections between remote items. To create a new link you select the source task and hit "L" (or the new link button). The task will be added to the clipboard in _linking_ mode. You then
select the target task and paste. That's it.

Performance

We won't bore you with all the details, but Gigantt is now wicked fast. Navigation is much quicker, even for very complex tasks, because sub-tasks are now rendered in the background (they sort of fade in). Auto-save is also much faster and so is every editing operation.

There are tons more improvements and fixes. But I'll leave it to you to find.

Keep sending us your feedback. It's really valuable to us and we do act on it.

Sunday, June 5, 2011

T-Shirt Sized Estimates



How long would it take you to write a Hello World program in a language you've never used? Minutes, probably. But how many minutes? three? nine? Asking for such precise estimates just doesn't feel right, does it? But if you pose the question like this "Would it take you less than 15 minutes?" it suddenly seems like an entirely reasonable question.


This, in a nutshell, is why T-shirt sized estimates work. There are other reasons, as well, but before we dive into them let's review what T-shirt sized estimates (TSE) are.


Agile development methodology has made the concept of TSE rather popular in recent years. The idea is to give rough estimates to tasks in the form of T-shirt sizes. Small, medium, large, extra-large and so on; you get the point. But what does "small" mean, really? This is pretty open to interpretation and each team may define these sizes in its own terms. Some associate a duration range with each size. e.g. S is less than one hour. M is between one and three hours. Some associate T-shirt sizes with points that are later added to an aggregate estimate. But in essence the idea is simple: instead of arguing over how many minutes or hours a task is going to take, let's just agree that it's small and move on. 


Now there's a hidden aspect to this method. The sizes are limited and have an upper bound. No T-shirt is XXXXXXXXL. This is significant. People are terrible estimators of large efforts. We're less terrible with reasonably sized efforts. So using TSE doesn't mean we don't invest any real effort into estimating and just spit-ball "2 years!". It only means we're not fooling ourselves into thinking that giving a very specific estimate would improve our project's total estimate in any way.


In fact, overly specific estimates are detrimental to delivery on time. Estimation is a well researched area in psychology. People aren't just bad at estimating, they're also terrible at knowing how bad their estimate really are. That's why the vast majority of people consider their own intelligence or attractiveness to be above average (which is plainly impossible). Ask people to give a 90% certainty estimate and they'll consistently give a too precise answer. A well known experiment has been widely replicated in many classrooms. Students are asked when queen Victoria was born, and they need to give their answer in the form of a range of years (e.g. 1800-1900) that they consider to be 90% certain to be true. The goal of this experiment is to see how well people estimate their own ignorance/knowledge. Statistically, you would expect students to specify a range so wide that only 10% of the students would actually miss the correct year. But instead a much larger portion of the audience gives a wrong answer by selecting a too-narrow range. We're overconfident in our knowledge and underestimate our ignorance. 


When you think about it, efforts estimates are really a form of self-estimation (uh-oh!). People are asked how long it would take them to finish a task. That's why most estimates are overly optimistic. It's tied to a host of psychological factors: over-estimating our own capabilities and skills, wanting to please our superiors (and ourselves) with a smaller estimate, ignoring potential unexpected surprises along the way, etc. 


Here's how TSE solve these problems. 


First, if you force people to round their answers they're more likely to factor some uncertainty into it. If you internally estimate a task at 40 minutes, but are then asked to choose between a 30 or 60 minute estimate, you'll suddenly remind yourself that 40 minutes doesn't really take into account various overheads or possible interruptions. And it's much easier to justify an over-estimation to yourself when it's someone else who's forcing you to round it up. Rounding up on a small scale is a good thing.


Second, by limiting yourself to small estimates you avoid those big vague predictions which are the root of all evil. If there's no T-shirt size for 3 months, then you have no choice but to actually break your estimate down to smaller chunks. This, in turns, forces you to invest just a bit more time into planning ahead than you might have otherwise. Suddenly you're reminded of holidays and hiring efforts, and integration, and setup time... This, of course, is tied to the first rule of project underestimation: it's not the estimates that are wrong, it's the plan that's incomplete. 
If you allow yourself overly specific large estimates you also introduce a mental block: you've checked the box. It's "done". You wrote down "4 months" as your estimate for that distant milestone and now you don't have to look at it again until you reach that task. How convenient. If, on the other hand, you only allow yourself to provide smaller estimates, that milestone is now sitting there taunting you, begging to be further elaborated. You may be comfortable with a large estimate that's not based on reality, but if the aggregate estimate is small because you haven't yet taken the time to drill down even a bit to day-scale, well... that's just unacceptable. 


Third, it's harder to argue with TSE. Which is another way of saying it's easier to accept a TSE. When your manager sees you've created a well thought out plan in advance that tries to capture all those details that normal intuition misses, he's not going to haggle with you over that one-week estimate for integration time ("one week? no no... it's 4 days at most!"). That's just not going to matter. Everybody knows we're not that good at estimating in that scale, anyway, so as long as an estimate isn't egregiously wrong people just move on. The discussion is suddenly focused on the content of your work plan, instead of the price tag attached to each task. Now the challenge  is "who can think of more shit that can go wrong, that you forgot to include" instead of "who thinks this feature can be developed in less time". 


I believe TSE needs to be the default method for estimating projects, as long as they're restricted to small sizes. Gigantt uses a variation of TSE. Our estimates aren't actually S/M/L/XL. They are currently: 1h/3h/5h/1d/3d/1w. Estimating a task is a one-click operation. This really reduces the friction of estimating (something people just don't like doing). It's always going to be the preferred, easiest way of estimating in Gigantt. In future versions we'll also add 0-duration estimates, for checklist type tasks (e.g. milestones). We may even add custom estimates (e.g. "4 months"), because we realize not everybody shares our above views on how to properly estimate projects and alternative project management solutions do offer this feature ubiquitously. But even if we do it's certainly going to be the 2nd choice, and we hope most users won't take advantage of this feature at all.

Friday, May 13, 2011

Ants, Popcorn & Sex – An Introduction To Resource Leveling Algorithms

What would you do if you were asked to plan the construction of a building? Construction projects are typically big, involving many people and resources. They're also time-sensitive - you have exactly one week to build each floor, and the material for the next one needs to arrive just in time. Cement won't wait.


Since the 50's various methodologies have been developed to tackle the issue of creating a work-plan that result in a smooth-running project, with as few costly delays as possible and without wasting precious resources. Most notable in the construction industry is the Critical Path method. But while CPM may help you create a logically coherent plan that finishes on time, it doesn't really guarantee you that your plan is optimal in any way. What if the whole thing could be finished two months earlier? What if it could cost a lot less money simply by better utilizing the same resources? These are big projects with big money that needs to be spent correctly.

This brings us to the concept of resource leveling. It's easiest to describe what resource leveling is by giving examples of projects running without it. For example:
  • Workers are standing around idly because it's not their turn to use some machine.
  • Lots of people are hired at the beginning of the project and then need to be fired when they're not needed.
It's all about making the best use of limited resources. Ideally, you'd want to hire a fixed number of people and employ them fully for the entire duration of the project. When that's the case your project is optimally planned for the amount of resources it may expend.

To better illustrate what resource leveling “looks like” resource histograms are often used. It's just a graph with two axes: time and resources. The horizontal axis is usually work days and the vertical axis is the amount of resources used (e.g. man hours).

Here's a terrible one where it's easy to see that resources aren't used evenly throughout the project.




Resource leveling is all about getting that histogram to have a rectangular shape. If all of your workers are constantly employed then there's not much to improve - you have a perfectly leveled plan.



It is thus the process of moving tasks around, while still maintaining their logical order of dependence, in a way that maximizes the use of your available resources. Resource leveling algorithms differ mainly in the way in which you choose which task to move where.

Turns out it's a hard problem. NP-hard, to be exact. In other words, you can't simply try all feasible task arrangements until you find the optimal one. Unless of course your project is tiny, trying to exhaust every possible solution to the problem generally requires an exponential running time, and your deadline is probably before the next ice-age, so no luck there.

The problem is known as the resource constrained scheduling problem (RCSP). In a way it is a generalization of the traveling salesman problem (TSP). There are tons of very clever algorithms that try to solve these problems by approximating the optimal solution. They differ in their running time and how close they get to an optimal solution. Some of them are pretty neat. Let's review them.

Heuristic Algorithms

This family of algorithms tries to use rules of thumb to make decisions. Remember, the decision a RCSP algorithm has to make is which job to shift in time in order to evenly distribute resources. Not every job can be moved. Some have to happen at a very specific time and have many successive jobs depending on their completion. But there's always some degree of freedom (or float) in the plan, and that's the space in which these algorithm mostly operate.

An example of a heuristic is the following rule: choose the job with the most float from all the jobs in the last sequence step of the plan (i.e. it's final stages), and move it to a location where it has the biggest positive impact on the plan's “levelness”. Do this repeatedly, constantly measuring how leveled the resource histogram is at every step, until you can improve no more.

It's a relatively simple heuristic - too simple, really. Think about it; why should it find the optimal solution? It scans the work plan from end to beginning, greedily shifting jobs as much as it can. Why start at the end? Why not shift the smallest job instead of the one with the most float? It might very well make some unfortunate early decisions that would prevent it from reaching the optimal solution.

Most heuristic algorithms are considerably cleverer than the one above, but they've long been considered insufficient since it's not hard to find negative examples where they produce really poor results.

Metaheuristic Algorithms

Instead of following a rule of thumb when searching the solution space, metaheuristics often try to take cues from various natural processes in trying to figure out their search strategy. How do ants “know” the shortest path from their colony to food? How do organisms “know” how to adapt to their environment? Let's see how the answers to these questions can reveal interesting solutions to RCSP.

Genetic Algorithms

Which job shall we shift next and where do we shift it to? Deciding on this question over and over forms a path through the solution space. Our goal is to find the global optima – the place in which the histogram is rectangular (i.e. has a minimal moment, or in other words the least amount of fluctuations in resources). If we measure how leveled a plan is by some function F (for Fluctuations), we can describe our effort as trying to find the lowest point in the solution space, where F reaches a global minimum. The solution space usually has many dimensions, but for the sake of illustration let's think of it as a 3D terrain. Your goal is to reach the deepest valley, but you can't look ahead more than one step. How do you decide which way to go? Where do you even start?




Instead of trying to solve the problem directly (as the heuristic algorithm above) metaheuristic algorithms are good at taking an existing solution and improving it iteratively. Genetic algorithms belong to this family. They start out by creating a few solutions somewhat at random. Each solution is encoded as a “DNA” sequence. For example, if the path a solution takes is “left, right, straight, straight” then its DNA can be encoded as “LRSS”. Each solution's fitness (how well it levels the histogram) is measured and the best ones are mated with each other to produce offsprings that share half of each parent's DNA at random. Then the process is repeated with the next generation. By adding randomness in the form of mutations we can prevent the algorithm from fixating on a sub-optimal path for too long. Mutations drive the algorithm to explore new paths, and getting rid of the unfit drives the algorithm to improve the promising paths.

A major challenge of such metaheuristics is, indeed, not getting stuck in local optima. A cool way to overcome this challenge is called simulated annealing.

Simulated Annealing

Imagine we're trying to find the deepest valley in the terrain pictured above by scattering a few popcorn kernels from above and letting them fall into the valleys. You want at least one of these kernels to reach the deepest valley, but how do you prevent them from getting stuck in a local valley? You turn on the “temperature” of the terrain until they start to pop and jump around slightly, possibly jumping right out of the local valley they might be in. You then turn the temperature back down and let them continue falling. This is similar to how simulated annealing works. Just like a metallurgist heats up a metal and cools it over and over to make it stronger, the simulated annealing approach to RCSP allows the algorithm to explore the solution space by converging on promising paths (cold) but also jumping around to explore nearby paths every once in a while (hot).

Ant Colony Optimization

Ants are smarter than popcorn. Collectively, that is. Individually, not so much. Let's see how ants would find the deepest valley. Ants seek food pretty much at random, at first. They don't have a fantastic sense of smell like dogs, or amazing vision. But once they find food they somehow converge pretty quickly onto the shortest path from their colony to it. It doesn't take them long to form an orderly single file that shoots directly to the food and back. They do this by secreting pheromones.

Each ant secrets a pheromone that causes other ants to want follow it. The more pheromone an ant picks up, the more likely it is to go in its direction. If an ant finds food and travels back and forth on the same path, it secrets more and more pheromone along this path, making it more and more appealing to other ants. And the more ants follow the path it becomes even stronger. It's a feedback loop that makes the ants converge on a path to food. But that's only part of the story. The pheromone also evaporates over time. So what happens if two ants find two separate paths to the same food, but one is longer than the other? The longer path takes more time to travel and as a result the pheromone has more time to evaporate, making it ultimately less attractive to the ants. So ants don't just find food and “tell” each other about it, they also iteratively find the best route to the food by choosing the one with the most pheromone on it.



We can do the same for the RCSP. Start out with a few feasible work plan arrangements and let simulated ants search for improvements. When an ant chooses a modification to the plan that results in a more rectangular histogram (an improvement) we deposit pheromones along the path to that solution. The bigger the improvement, the more pheromone we deposit. Pheromones here are just the probability of an ant following the same path. Ants will still wander off a bit, trying to explore nearby paths, but as the scent becomes stronger they will converge on a good solution. Pheromone evaporation will make sure they choose the shortest path.

There are many more approaches to solving such global optimization problems: artificial neural-networks, packing algorithms, monkey searches, tabu search, bee colony optimization (like ants, but with dancing instead of secreting).
What's neat about all these algorithms, aside from their awesome names, is that they don't require a real understanding of the particular problem at hand. They don't rely on intuition in deciding how to reschedule jobs. They just know how to improve an existing solution.

Tuesday, May 10, 2011

Collaboration in Gigantt

We're in the final testing stages of the first version of Gigantt that supports real-time collaboration. You can see what it's going to be like in our new preview video.


turn on your speakers for full enjoyment. :)


Gigantt takes a novel approach to collaboration. We want to allow multiple users editing the same plan at the same time - seeing each other's changes as they are made (like Google Docs, Wave) - but we don't want people stepping on each other's toes. Our solution is called a freeze period. Basically anything you touch while editing a plan in Gigantt gets frozen for everybody else for 60 seconds. So each user can safely edit his own area of the organization's big work plan.




This approach has the advantage of making it visibly clear when someone else is editing the plan with you, so you can avoid conflicts instead of having to resolve them. We think this is a better form of collaboration than what most other collaborative systems offer, where if two people are editing the same document one of them will be notified of a conflict once he tries to save his changes (e.g. Wikipedia). We believe true collaboration is not racing to save your changes before someone else does, but rather being aware of who's editing alongside you right now and being able to give each other just enough time to edit in peace.


Our apologies, again, for taking so long working on this release. We want to get it right. Many people have signed up for an invite to the private beta program - more than we can handle at this point. But once this collaboration release is finished we're immediately going to start working on the registration/invitation system (now it's all manual) so we can let more people in. Thanks for being patient.



Tuesday, April 26, 2011

Introduction to Mind-Maps

Gigantt draws lots of inspiration from Mind-Maps. They're terribly useful things, not just for brainstorming but also for managing projects. Just though I'd share a great introduction to mind-maps I've read today on InstantShift. Go read it - it's well written.


I've written about mind-maps way back when I started this blog. 

Nothing beats their ability to capture ideas quickly and to manipulate a tree of ideas visually with drag-and-drop. I do like to think of Gigantt is a work-plan oriented collaborative mind-map with support for more complex plan topologies. I think any project management tool that's slower to operate than a mind-map is a waste of time.

Monday, April 11, 2011

Smooth Rendering in Flex


What do you do if the amount of interactive items you give Flex to render makes it choke and drop the frame rate to 0.3? This is something we encountered recently at Gigantt, and I thought I'd share our solution to the problem.

The Problem

So let's say you have a few hundred complex interactive items that you want to add to the stage. In our case we sometimes need to fit a very large number of "task" objects into the screen by scaling them down, because that's part of Gigantt's infinite-zoom approach.
Giving Flex too many items to render at once just chokes it. Flex tries to render them all at the next frame and just doesn't make it. It tries to do something called phased instantiation, but most of the time this seems to do more harm than good. You can end up with a Flex application that, instead of rendering at a smooth - let's say, 25 FPS - pauses every once in a while to render a bunch of items, which results in a really choppy UI experience. This becomes especially clear if you use lots of animation.
To be sure, if you constantly need to render more than Flex can do in 1/25th of a second then you're out of luck. But in many cases rendering happens in bursts. This is because one of the more costlier operations you can do with interactive objects in Flex is to add them to the stage. Once they're staged moving them around and even transforming and scaling them is much quicker.
To top that all off, you never know just how much free CPU your customer's machine is going to have. Maybe they're running a bunch of stuff already and there just isn't enough juice left for Flex. So you can't really decide in advance how many items per second you feel comfortable rendering, because this number will vary between machines.

The Solution

What we need is a way to make sure our application never drops below 25 FPS so that everything feels snappy. In the current development version of Gigantt we ended up implementing something we call an idle rendering queue. In essence what we do is divide all our rendering operations into reasonably sized chunks that are rather small. We then measure the application's actual frame rate. As soon as we detect a high enough frame rate we know that Flex is done rendering whatever it worked hard to render and that the engine is free to handle more work. We then take another chunk out from the queue and feed it to Flex. Our application's declared frame rate is 60 FPS, but it never really reaches that number unless your have a strong CPU or you're not rendering a lot of new items. By throttling our rendering jobs according to what the user's machine is able to handle at each point in time we make sure our application is never too heavy for whatever machine is running it. The frame rate remains the same - a minimum of 25 FPS - it might just take it more time to actually show every interactive object. If you implement a ZUI like Google Maps (or Gigantt) you can naturally allow "farther away" elements to render in the background, so to speak. 

This isn't ideal. An ideal solution would be something that's able to render as many items as can be discerned on screen, so that if you zoom in you get a continuous impression of the items already "being there". But that's an extraordinarily large number of polygons to render (in the trillions, really). Our approach does the best with what we have by providing a seamless zoom-in effect that takes advantage of the fact that it takes the eye a few hundred milliseconds to actually see what's being rendered on screen before the user can make a conscious decision where next to zoom-in to. This optimization is neat trick that we thought we'd share with the world. You can expect to enjoy it in the next release of Gigantt in a few weeks.