


Remember how I wrote a while back that I wanted to write a script to let me do some quick and easy pre-commit continuous integration with the MarkUs project?
Well, I think I just wrote one.
TestDrive will fetch a review request, grab the latest diff (yes, found an easy way past the lack of API there), check out a fresh copy of MarkUs, throw down the diff, set it up with some Sqlite3 databases, run your tests, and voila – go to localhost:3000, and you’re running the review request diff.
I’ve been using it myself for about a week or so, and so far, it’s helped me catch a number of bugs that I wouldn’t have caught just by looking at the code in ReviewBoard. Nice.
My daughter has a floor-mat jigsaw puzzle of the Solar System. It only has eight planets—no Pluto. I feel… dated.
Zuzel , a Master Student at the University of Toronto under the supervision of Greg Wilson (and the occasional collaboration of myself, Robert Clarisó and Mike Conley) is working on a method/tool to back-annotate data models at run-time .
According to your votes (number of votes = number of clicks on the post), the five most popular blog entries in January 2010 are (in this order):

In my opinion, at least for The MarkUs Project, post-commit code review would probably be analogous to putting on your shoes before your pants. And though I mentioned earlier that there is plenty of preference for post-commit, I forgot to include this juicy little tidbit.
Click here to read one of the developers of ReviewBoard state his case for pre-commit code review.
To each their own. But I dig his points.
I’ve been trying to record myself performing code reviews for The MarkUs Project.
It’s a lot harder than I thought it’d be. The screencasts are really only useful if I’m saying what I’m thinking, and I’m finding it difficult to maintain stream of consciousness and perform an effective/thorough review. The last few times I’ve tried it, I find myself blurting an expletive, stopping the recording in frustration, and then starting the review over so that I can do a good, proper job.
I think this is going to take more practice.
The reason I pointed you to Conservapedia is because they do allow primary sources and original work to be included in their articles.This is surprising to me, but I'm happy going with it--the more primary sources the better.
;This seems to be one of a set of files amongst 4 labeled "briffa_sep98_a.pro" through "briffa_sep98_d.pro". The other files, (a-c), don't seem to have this comment.
; Apply a VERY ARTIFICAL correction for decline!!
;
Climate researchers know their prescriptions don't carry the certainty laymen assume from that which is labeled "science," yet most shy from a straightforward account of this uncertainty.Wilson goes on to say that he doesn't think people would want to know. I disagree, but I also don't know how to communicate the nuances effectively. Much of science takes tens of years for very smart people to really learn, and the conclusions are often of the form, "we think this, but we're not totally sure". To add to that, often times scientists are not the best communicators in the world. It takes a rare and special person to figure out how to distill these complex ideas, nuances, and uncertainties into explanations that people can understand. I think it's absolutely something that scientists should continually be thinking about, and I do think scientists should be open to audit by the public, so long as that doesn't require them to spend all their time responding to unfounded criticisms.
"Methods certainly need to be continually refined and improved. I doubt that anyone in the paleoclimate community would disagree with that," says Rob Wilson of the University of St. Andrews's School of Geography and Geosciences. "However, can the nuances of methodological developments be communicated to the laymen—and would they want to know?"
by Danny Tarlow (noreply@blogger.com) at February 08, 2010 06:04 PM
Dear Lazyweb,
Is there a tool somewhere that will automatically generate and validate all possible output variations for a Django HTML template page? We’re using Django in Basie, and have been running into problems when one branch of a conditional closes a tag, but the other doesn’t:
<li>opening text
{% if something %}
blah blah
</li>
{% else %}
Whoops, forgot to close the list element.
{% endif %}
I know that code review should catch these, but when the examples are longer, it’s hard to keep track of as-yet unclosed tags. Testing should catch them too, but sometimes people forget to write as many test as they should *cough* *cough*. So, is there something that will parse the HTML templates, generate all possible variations, and check that they’re valid? It wouldn’t have to generate all possible cross-products (at least, I don’t think it would), so runtime would be manageable.
Thanks in advance.
Continue reading Tragedy of the Commons: Part II — The Professorial Take
I have seen plays that have very clear stories, and very clear plots. I leave the theatre knowing what has happened, and I can be pretty confident that the people who sat around me in the theatre all got the same message as I did.
I have also seen plays that are completely the opposite. There doesn’t appear to be a story. There doesn’t appear to be plot. There are no real characters. For these plays, all of a sudden, I have to do the work in order to make sense of it all. And you can be pretty sure that every single audience member got something different out of it.
I want to talk about this second kind of play. For now, I’m going to call this kind of play a discussion play, because for me, the best part about these kinds of plays is the discussion I have with my friends afterwards. We’ll all sit down in a restaurant or a cafe, order some food, and try to figure out what the hell we just saw. Theories are tossed around. Everybody brings their own unique impressions and observations to the table. A very rich ecosystem of ideas develops.
(trust me, this all ties together in the end)
When Jason Cohen did his Peer Review at Cisco Study, he noticed that code that had been prepared by the author for review seemed to have a lower defect density than code that had not been prepared.
What do I mean by prepared? I’ll let Jason Cohen explain:
The idea of “author preparation” is that authors should annotate their source code before the review begins. Annotations guide the reviewer through the changes, showing which files to look at first and defending the reason and methods behind each code modification. The theory is that because the author has to re-think all the changes during the annotation process, the author will himself uncover most of the defects before the review even begins, thus making the review itself more efficient. Reviewers will uncover problems the author truly would not have thought of otherwise.
(Best Kept Secrets of Peer Code Review, p80-81)
Looking at the data, author preparation does seem to have a palpable effect. As Cohen notes, “for all reviews with at least one author preparation comment, defects density is never over 30; in fact the most common case is for there to be no defects at all!”.
The study has two explanations for this:
Cohen buys into the first explanation. He writes:
A survey of the reviews in question show the author is being conscientious, careful, and helpful, and not misleading the reviewer. Often the reviewer will respond to or ask a question or open a conversation on another line of code, demonstrating that he was not dulled by the author’s annotations.
I have huge respect for this study. But I don’t entirely buy this explanation. As Cohen later mentioned in an email to me, this conclusion is not derived from a controlled experiment, and also suffers from selection bias.
One of the worst things that can happen to me before going into a discussion play is for someone who has already seen it to tell me their impressions of what they thought was going on. As soon as I hear their opinion, my own objectivity is compromised. Whether I want to or not, I’ll have their impressions in the back of my mind, and I’ll be using it as a measuring stick or reference point for my own opinions and critiques. They’ve carved a cognitive path through the work, and I’m doomed to notice that path, and react to it.
This is horrible. This limits me. This more or less hobbles my ability to contribute something unique to the pool of ideas and criticisms in the after-play discussion. Every impression I have is tainted by someone else’s first impression.
Don’t get me wrong – I love hearing about everyone’s impressions. But after I have formed my own. This way, I believe we cover more ground. A group of us watching a discussion play will carve unique cognitive paths through the work without influencing one another. When we finally open up and present these paths and ideas to one another over food and drink, I believe we cover more ground.
I have no data to back this up. Only years of theatre-going experience.
I recently received an email from a colleague of mine. She wanted me to go over some of her Javascript to make sure it was up to snuff, since she was relatively new to the language. I noticed that she had also sent a copy of the email to another developer who has pretty sharp Javascript chops.
When I finally had some free time, I went back to her email to write up the review. I felt bad – it was late, and the other reviewer hadn’t made a peep on the email thread, and she was hoping to use the code relatively soon. So I dove in, wrote my review, and sent it off.
A little while later, the other developer sent me his review, saying:
And here was my answer, which I didn’t send to you so as not to influence your reply. ;)
So the author of the code received two unique reviews, and neither of them had influenced the other. When I read his review, I noticed that we covered some similar ground, but a lot of unique ground as well. I suspect this wouldn’t have been the case had he sent his review to me first.
I hypothesize that author preparation in code review sabotages reviewers abilities to objectively carve their own unique cognitive paths through the code. They see things from the author’s point of view, and this dulls their critical eye. Because of this, I believe fewer defects are detected.
I will take this hypothesis one step further.
I suspect any review, by the author or otherwise, will taint future reviews. If someone has already reviewed some code, I suspect this review will impact and possibly limit the ability of other reviewers to look at the code objectively. Like author preparation, I suspect this prevents reviewers from getting their own unique, valuable first impressions of the code. And I suspect that this causes some defects to go undetected.
It’s a simple idea really. Take a chunk of code, and get some number of developers to review it. Take this same code, add some author preparation comments, and get more developers to review it. Do all of the normal balancing, etc.
The question: do the number of detected defects drop? If so, this looks like evidence that author preparation sabotages review ability.
Take the experiment one step further. Take some code, have someone else review it, and then have participants review this code, having seen the first review. What happens to the number and type of defects that they find? What happens if they don’t see that initial review? What yields high defect detection?
Sounds doable. Sounds interesting. Sounds like something that would answer a few questions.
So what if one or both of my hypotheses are true? What does this mean for peer code review?
Well, if author preparation alone sabotages review ability, then the answer is simple: don’t let the authors prepare the review. The code goes up, and they stay silent.
But what if both are true?
An idea: how about I tweak MarkUs’s ReviewBoard so that reviewers cannot see what other reviewers have said until they’ve given one review? What would happen to the defect detection numbers? Would reviewers react negatively to this? Would there be lots of repetition in the comments? Sounds like something worth looking into.
I’d love to hear some thoughts on this. Anyone?
Rafael Chaves has just posted a new entry in his blog talking about the "Myths that give model-driven development a bad name".
IT news online reports about the collaboration between the OMG (Object Management Group) and HL7 (Health Level Seven International) in order to develop new standards for the healthcare industry.
As Richard Soley (chairman of the OMG) summarizes:
template <class IndexedType,
class RandomAccessContainer = std::vector<IndexedType>,
class Comp = std::less<typename RandomAccessContainer::value_type>,
class ID = identity_property_map >
class mutable_queue { ...
Conveniently, though, when we are working with basic types, we can just give it one template argument, and the defaults will work for the other template parts.
This worked great for me when I tried it out with a simple mutable_queue<double>, and it was pretty easy to get it running and working correctly.
typedef Node * entry_t;
typedef vector<entry_t> storage_t;
typedef CompareNodeStar comp_t;
typedef identity_property_map prop_map_t;
typedef mutable_exposed_queue<entry_t, storage_t,
comp_t, prop_map_t> queue_t;
queue_t *q = new queue_t(N, comp_t(), prop_map_t());
Which says give me a queue of Node *'s, use a vector of Node *'s as the underlying storage, compare elements using the CompareNodeStar comparison function that I defined, and use the default property_map*.
The property map interface consists of a set of concepts (see definition of "concept" in [1] and [2]) that define a syntax for mapping key objects to corresponding value objects. Since the property map operations are global functions (actually they don't have to be global, but they are always called unqualified and may be found via argument dependent lookup), it is possible to overload the map functions such that nearly arbitrary property map types and key types can be used. The interface for property maps consists of three functions: get(), put(), and operator[].At this point, I'd already sunk a couple hours into the boost library, and I was getting a bit frustrated -- why should I have to learn about the internal details of property_maps when all I want to do is apply the data structure in a fairly natural way? Yes, maybe I'm being lazy, and granted I don't use C++ as much as I used to, but it seems to me that this should be easier than it is. (Maybe somebody can come along and point out the correct way of doing this -- I put in a reasonable effort to figure it out, but by no means am I confident that I'm even on the right track).
// test.cpp
// Used to test heapplus.h
// lihw
// 2006.12.18
// ChangeLog:
// 2009.08.10 - Added tests for Node and Node * heaps, and added Comparator
// argument to print_heap, so that pop_heap works as expected.
// (Danny Tarlow: dtarlow@cs.toronto.edu)
// 2006.12.18 - Initially created (lihw)
#include <iostream>
#include <ostream>
#include <functional>
#include <algorithm>
#include <vector>
#include "heapplus.h"
#include <ctime>
#include <cstdlib>
using namespace std;
template<typename Container>
inline
void PRINT_ELEMENTS(const Container& container, const char* title= 0)
{
if (title)
std::cout << title << std::endl;
typename Container::const_iterator iter, beg = container.begin(),
end = container.end();
for (iter = beg; iter != end; ++iter)
std::cout << *iter << " ";
std::cout << std::endl;
}
template<typename Container, typename Compare>
void print_heap(const Container& container, Compare comp, const char* title = 0)
{
if (title)
std::cout << title << std::endl;
std::vector<typename Container::value_type> temp(container.begin(),
container.end());
while (temp.size()) {
std::cout << temp[0] << " ";
std::pop_heap(temp.begin(), temp.end(), comp);
temp.pop_back();
}
std::cout << std::endl;
}
/**
* A very simple node class just to test the update_heap_pos functions
* and to show an example usage. Each node lies on an x-y grid, and it
* has a priority associated with it, which we assume will be computed and
* and modified by some procedure outside the scope of these functions.
*
* This example shows how to maintain a queue of grid points, ordered by
* priority, where updates take at worst O(lg N) time.
**/
class Node {
friend ostream &operator<<(ostream &os, Node &n);
friend bool operator<(Node a, Node b);
friend bool operator==(Node &a, Node &b);
friend ostream &operator<<(ostream &os, Node *n);
public:
Node() : x_(0), y_(0), priority_(0.0) { }
Node(int x, int y) : x_(x), y_(y), priority_(0.0) { }
double Priority() { return priority_; }
void SetPriority(double priority) {
priority_ = priority;
}
protected:
double priority_;
int x_;
int y_;
};
ostream &operator<<(ostream &os, Node &n) {
os << "(" << n.x_ << "," << n.y_ << "):" << n.Priority();
return os;
}
bool operator<(Node a, Node b) {
return (a.Priority() < b.Priority());
}
bool operator==(Node &a, Node &b) {
return (a.x_ == b.x_ && a.y_ == b.y_);
}
ostream &operator<<(ostream &os, Node *n) {
os << "(" << n->x_ << "," << n->y_ << "):" << n->Priority();
return os;
}
struct CompareNodeStar {
bool operator()(Node *a, Node *b) {
return (a->Priority() < b->Priority());
}
};
int main(void) {
int side = 4;
int N = side * side;
vector<double> doubleheap(0);
vector<Node> nodeheap(0);
vector<Node *> nodestarheap(0);
for (int x = 0; x < side; x++) {
for (int y = 0; y < side; y++) {
Node node = Node(x, y);
Node *nodestar = new Node(x, y);
double priority = (x - side / 2.0) * (y - side / 4.0);
node.SetPriority(priority);
nodestar->SetPriority(priority);
doubleheap.push_back(priority);
nodeheap.push_back(node);
nodestarheap.push_back(nodestar);
}
}
cout << "heap<double>" << endl;
//PRINT_ELEMENTS(doubleheap, "Initial heap");
print_heap(doubleheap, less<double>());
make_heap(doubleheap.begin(), doubleheap.end());
//PRINT_ELEMENTS(doubleheap, "Made heap");
print_heap(doubleheap, less<double>());
doubleheap[4] = 100;
//PRINT_ELEMENTS(doubleheap, "edited");
print_heap(doubleheap, less<double>());
vector<double>::iterator itdouble = doubleheap.begin() + 4;
update_heap_pos(doubleheap.begin(), doubleheap.end(), itdouble);
//PRINT_ELEMENTS(doubleheap, "Updated and sorted");
print_heap(doubleheap, less<double>());
cout << endl;
cout << "heap<Node>" << endl;
print_heap(nodeheap, less<Node>());
make_heap(nodeheap.begin(), nodeheap.end());
print_heap(nodeheap, less<Node>());
nodeheap[4].SetPriority(100);
print_heap(nodeheap, less<Node>());
vector<Node>::iterator it = nodeheap.begin() + 4;
update_heap_pos(nodeheap.begin(), nodeheap.end(), it);
print_heap(nodeheap, less<Node>());
cout << endl;
cout << "heap<Node *>" << endl;
//PRINT_ELEMENTS(nodestarheap, "Initial heap");
print_heap(nodestarheap, CompareNodeStar());
make_heap(nodestarheap.begin(), nodestarheap.end(), CompareNodeStar());
//PRINT_ELEMENTS(nodestarheap, "Made heap");
print_heap(nodestarheap, CompareNodeStar());
nodestarheap[4]->SetPriority(100);
//PRINT_ELEMENTS(nodestarheap, "edited");
print_heap(nodestarheap, CompareNodeStar());
vector<Node *>::iterator itstar = nodestarheap.begin() + 4;
update_heap_pos(nodestarheap.begin(), nodestarheap.end(), itstar, CompareNodeStar());
//PRINT_ELEMENTS(nodestarheap, "Updated and sorted");
print_heap(nodestarheap, CompareNodeStar());
return 0;
}
And here is the modified heapplus.h file:
// Heap Plus implementation 1.01alpha
// lihw
// 2006.12.18
// ChangeLog:
// 2009.08.10 - Added update_heap_pos functions so that we can adjust
// heap values outside of update_heap functions -- e.g., if
// we have external pointers into the heap entries -- then
// call update_heap on the position only, regardless of the value.
// (Danny Tarlow: dtarlow@cs.toronto.edu)
// 2006.12.18 - Initially created (lihw)
#ifndef HEAPPLUS_H_
#define HEAPPLUS_H_
#include <iterator>
namespace std {
template<typename _RandomAccessIterator, typename _Distance, typename _Tp, typename _Compare>
inline void
__up_heap(_RandomAccessIterator __first, _RandomAccessIterator __end, _RandomAccessIterator __pos,
_Distance, _Tp __value, _Compare __comp)
{
_Distance __parent = (__pos - __first - 1) / 2;
_Distance __index = __pos - __first;
while (__index > 0 && __comp(*(__first + __parent), __value)) {
*(__first + __index) = *(__first + __parent);
__index = __parent;
__parent = (__parent - 1) / 2;
}
if (__pos != (__first + __index))
*(__first + __index) = __value;
}
template<typename _RandomAccessIterator, typename _Distance, typename _Tp, typename _Compare>
inline void
__down_heap(_RandomAccessIterator __first, _RandomAccessIterator __last, _RandomAccessIterator __pos,
_Distance, _Tp __value, _Compare __comp)
{
_Distance __len = __last - __first;
_Distance __index = __pos - __first;
_Distance __left = __index * 2 + 1;
_Distance __right = __index * 2 + 2;
_Distance __largest;
while (__index < __len) {
if (__left < __len && __comp(*(__first + __right), *(__first + __left))) {
__largest = __left;
} else {
__largest = __right;
}
if (__largest < __len && __comp(__value, *(__first + __largest))) {
*(__first + __index) = *(__first + __largest);
__index = __largest;
__left = __index * 2 + 1;
__right = __index * 2 + 2;
} else
break;
}
if (__pos != (__first + __index))
*(__first + __index) = __value;
}
template<typename _RandomAccessIterator, typename _Distance, typename _Tp,
typename _Compare>
inline void
__update_heap(_RandomAccessIterator __first, _RandomAccessIterator __last,
_RandomAccessIterator __pos, _Distance, _Tp __value, _Compare __comp)
{
*(__pos) = __value;
_Distance __index = (__pos - __first);
_Distance __parent = (__index - 1) / 2;
if (__index > 0 && __comp(*(__first + __parent), __value))
__up_heap(__first, __last, __pos, _Distance(), __value, __comp);
else
__down_heap(__first, __last, __pos, _Distance(), __value, __comp);
}
template<typename _RandomAccessIterator, typename _Distance, typename _Compare>
inline void
__update_heap(_RandomAccessIterator __first, _RandomAccessIterator __last,
_RandomAccessIterator __pos, _Distance, _Compare __comp)
{
_Distance __index = (__pos - __first);
_Distance __parent = (__index - 1) / 2;
if (__index > 0 && __comp(*(__first + __parent), *(__pos)))
__up_heap(__first, __last, __pos, _Distance(), *(__pos), __comp);
else
__down_heap(__first, __last, __pos, _Distance(), *(__pos), __comp);
}
template<typename _RandomAccessIterator, typename _Tp>
inline void
update_heap(_RandomAccessIterator __first, _RandomAccessIterator __last,
_RandomAccessIterator __pos, _Tp __value)
{
typedef typename iterator_traits<_RandomAccessIterator>::value_type _ValueType;
typedef typename iterator_traits<_RandomAccessIterator>::difference_type _DistanceType;
__update_heap(__first, __last, __pos, _DistanceType(), __value, less<_ValueType>());
}
template<typename _RandomAccessIterator, typename _Tp, typename _Compare>
inline void
update_heap(_RandomAccessIterator __first, _RandomAccessIterator __last,
_RandomAccessIterator __pos, _Tp __value, _Compare __comp)
{
__update_heap(__first, __last, __pos, __value, __comp);
}
template<typename _RandomAccessIterator>
inline void
update_heap_pos(_RandomAccessIterator __first, _RandomAccessIterator __last,
_RandomAccessIterator __pos) {
typedef typename iterator_traits<_RandomAccessIterator>::value_type _ValueType;
typedef typename iterator_traits<_RandomAccessIterator>::difference_type _DistanceType;
__update_heap(__first, __last, __pos, _DistanceType(), less<_ValueType>());
}
template<typename _RandomAccessIterator, typename _Compare>
inline void
update_heap_pos(_RandomAccessIterator __first, _RandomAccessIterator __last,
_RandomAccessIterator __pos, _Compare __comp) {
typedef typename iterator_traits<_RandomAccessIterator>::value_type _ValueType;
typedef typename iterator_traits<_RandomAccessIterator>::difference_type _DistanceType;
__update_heap(__first, __last, __pos, _DistanceType(), __comp);
}
}; // namespace std
#endif // !HEAPPLUS_H_
And finally, here is the output from compiling and running the test case:
heap<double> 2 2 -0 1 1 0 0 0 0 -0 -1 -0 -1 -2 -2 -4 2 2 1 1 0 0 -0 0 0 -0 -0 -1 -1 -2 -2 -4 2 2 100 1 0 0 -0 0 0 -0 -0 -1 -1 -2 -2 -4 100 2 2 1 0 0 -0 0 0 -0 -0 -1 -1 -2 -2 -4 heap<Node> (0,0):2 (3,3):2 (0,1):-0 (1,0):1 (3,2):1 (2,2):0 (3,1):0 (2,1):0 (2,3):0 (2,0):-0 (3,0):-1 (1,1):-0 (1,2):-1 (0,2):-2 (1,3):-2 (0,3):-4 (3,3):2 (0,0):2 (3,2):1 (1,0):1 (3,1):0 (2,3):0 (1,1):-0 (2,2):0 (2,1):0 (2,0):-0 (0,1):-0 (1,2):-1 (3,0):-1 (0,2):-2 (1,3):-2 (0,3):-4 (3,3):2 (0,0):2 (1,0):100 (3,2):1 (3,1):0 (2,3):0 (1,1):-0 (2,2):0 (2,1):0 (2,0):-0 (0,1):-0 (3,0):-1 (1,2):-1 (1,3):-2 (0,2):-2 (0,3):-4 (1,0):100 (3,3):2 (0,0):2 (3,2):1 (3,1):0 (2,3):0 (1,1):-0 (2,2):0 (2,1):0 (2,0):-0 (0,1):-0 (3,0):-1 (1,2):-1 (1,3):-2 (0,2):-2 (0,3):-4 heap<Node *> (0,0):2 (3,3):2 (0,1):-0 (1,0):1 (3,2):1 (2,2):0 (3,1):0 (2,1):0 (2,3):0 (2,0):-0 (3,0):-1 (1,1):-0 (1,2):-1 (0,2):-2 (1,3):-2 (0,3):-4 (3,3):2 (0,0):2 (3,2):1 (1,0):1 (3,1):0 (2,3):0 (1,1):-0 (2,2):0 (2,1):0 (2,0):-0 (0,1):-0 (1,2):-1 (3,0):-1 (0,2):-2 (1,3):-2 (0,3):-4 (3,3):2 (0,0):2 (1,0):100 (3,2):1 (3,1):0 (2,3):0 (1,1):-0 (2,2):0 (2,1):0 (2,0):-0 (0,1):-0 (3,0):-1 (1,2):-1 (1,3):-2 (0,2):-2 (0,3):-4 (1,0):100 (3,3):2 (0,0):2 (3,2):1 (3,1):0 (2,3):0 (1,1):-0 (2,2):0 (2,1):0 (2,0):-0 (0,1):-0 (3,0):-1 (1,2):-1 (1,3):-2 (0,2):-2 (0,3):-4
by Danny Tarlow (noreply@blogger.com) at February 06, 2010 12:50 PM
Continue reading Tragedy of the Commons: Part I — The Setup
I just took one more step towards wrapping up my studies –I presented my thesis proposal to my committee. They gave me lots of good, constructive feedback (thanks!), and agreed I could and should be defending my thesis this Summer.
I postponed doing my checkpoints for a long time, and I’m not sure this was the right approach. On one hand, I was able to focus on doing my research and publishing, and to let my ideas grow and mature before I had to defend them. On the other hand, my committee’s feedback steers me in what I think is usually the right direction; it helps me stay on track, and I could probably have gotten much more from this feedback if I had gone for earlier committee meetings.
In any case, there are just two checkpoints remaining: the internal and the external defenses. But first I need to finish writing my dissertation…

If I’m supposed to meet you today, but don’t show up, I apologize: Google Calendar is “temporarily unavailable”. There was no warning that I saw; disturbing that someone a continent away can disrupt my life in the same way that losing my day timer did twenty years ago. When I upgrade this WordPress installation in May, I’m going to look seriously at moving my life planning there—at least then there’s a tech support team I can contact.
Martin Thiede announces "Concrete" a web-base model editor which can be configured for different DSLs by providing a metamodel and optional concrete syntax definition in HTML/CSS.
Models are created mainly by typing text in the browser, using autocompletion, constraint checks, etc. They are exchanged in JSON format with any backend, e.g. via AJAX.
Continue reading More on Paper vs. Screen: The Creative Process
I just found this on Slashdot – a guy named Fabien Sanglard reviews the code for the iPhone DOOM port. This is cool – I wish I had time to read it thoroughly. It’ll have to wait until after my assignments are done.
Looks like this guy has a thing for FPS’s – he’s also done a code review for “Wolfiphone” (Wolfenstein for iPhone) and the original Quake.
I like this idea. Why aren’t there more of these on the web? Or am I not looking hard enough?
I do almost all of my work now in a command-line shell, including reading email and composing text of all kinds. And I mean it when I say “a” shell—I almost never have two open at once. The reason? It encourages me to use only one tool at a time, which I find makes me more productive by reducing context switching overheads. I don’t yet have the willpower to (re-)open Firefox each time I need something on the web, then close it when I’m done, but that’s the next step. Who’d have thunk that going back to 1984 would be the right answer in 2010?
My side of the conversation this morning went like this. (I would have recorded it “for quality assurance purposes”, but where would I send the recording?)
Google Summer of Code 2010 is on for 2010! They will begin accepting applications from would-be mentoring organizations on March 8th, with applications closing on March 12th. Students can apply between March 29th and April 9th.
State machines are without any doubt a very good choice for designing and implementing the behavior of reactive systems. Whether you've used statecharts to model a device, a subsystem, or a module, you might ask yourself why you don't just generate code from that model.
Antonio Vallecillo sends me a link to a "Survey of Model-Based Systems Engineering (MBSE) Methodologies"
The purpose of this report is to provide a cursory description of some of the leading Model-Based Systems Engineering (MBSE) methodologies used in industry today. A MBSE methodology can be characterized as the collection of related processes, methods, and tools used to support the discipline of systems engineering in a “modelbased”