tag:blogger.com,1999:blog-78786315571409715942024-03-08T09:49:07.784-05:00The Softer Side of Software DevelopmentSoftware development is often seen as a "man vs machine" endeavour. In reality, it's still people who do the work, a work that often has a clear artistic component. It is work we do with others, for others. And here are some of my thoughts on thatNancyhttp://www.blogger.com/profile/17327927253598730674noreply@blogger.comBlogger16125tag:blogger.com,1999:blog-7878631557140971594.post-73623856787553659602012-12-13T12:18:00.002-05:002012-12-13T16:29:56.455-05:00Conway's Game of Life in SQL, Part 2I showed <a href="http://blog.nancydeschenes.com/2012/12/conways-game-of-life-in-sql.html" target="_blank">my implementation</a> of <a href="http://en.wikipedia.org/wiki/Conway's_Game_of_Life" target="_blank">Conway's Game of Life</a> in SQL to a few people, a co-worker pondered if it could be done without the stored procedure. I gave it some thought, and came up with an implementation that relies on views. I used views for the simple reason that it made things easier to see and understand. If a query can be written using views, the it can be written as straight SQL, but the results are generally uglier, messier, and can often be unreadable. Since I'm using MySQL, I realize how bad views can be when it comes to performance, but since this is a proof of concept, and a toy anyway, I'm not too worried. I honestly doubt any real-life application would ever require me to implement the Game of Life in SQL!<br />
<div>
<br /></div>
<div>
I started as I had earlier, by defining the table as holding all the live cells for each generation.</div>
<pre class="brush:sql">create table cell (
generation int,
x int,
y int,
primary key (generation, x, y));
</pre>
<div>
Then, I created a view to represent all the candidate position on the grids where we might find live cells on the next generation. We can only find cells where there are cells for the current generation, and in all 8 neighbour positions of those cells:</div>
<pre class="brush:sql">create view candidate (generation, x, y) as
select generation, x-1, y-1 from cell union
select generation, x, y-1 from cell union
select generation, x+1, y-1 from cell union
select generation, x-1, y from cell union
select generation, x, y from cell union
select generation, x+1, y from cell union
select generation, x-1, y+1 from cell union
select generation, x, y+1 from cell union
select generation, x+1, y+1 from cell;
</pre>
<div>
Next, I counted the number of live cells in the 3x3 square around each candidate. This isn't quite the same as counting the neighbours, since it includes the current cell in the count. We will need to take that into account in a bit.</div>
<pre class="brush: sql">create view neighbour_count (generation, x, y, count) as
select generation, x, y,
(select count(*)
from cell
where cell.x in (candidate.x-1, candidate.x, candidate.x+1)
and cell.y in (candidate.y-1, candidate.y, candidate.y+1)
and not (cell.x = candidate.x and cell.y = candidate.y)
and cell.generation = candidate.generation)
from candidate;</pre>
<div>
From the previous post, the rules of the game can be reduced to: a cell is alive in the next generation if<br />
<br />
<ol>
<li>it has 3 neighbours</li>
<li>it has 2 neighbours and was alive in the current generation</li>
</ol>
<div>
Let's write this as a truth table:</div>
<blockquote class="tr_bq">
<table style="border-collapse: collapse; border-spacing: 5px;">
<thead style="border-bottom: 1px black solid;">
<tr>
<th style="border-right: 1px black solid; padding: 0px 14px;">Live?</th>
<th style="border-right: 1px black solid; padding: 0px 14px;">Neighbours</th>
<th style="padding: 0px 14px;">Alive in the next generation</th>
</tr>
</thead>
<tbody>
<tr>
<td style="border-right: 1px black solid; padding: 0 14px;">yes</td>
<td style="border-right: 1px black solid; padding: 0 14px;">less than 2</td>
<td style="padding: 0 14px;">no</td>
</tr>
<tr>
<td style="border-right: 1px black solid; padding: 0 14px;">yes</td>
<td style="border-right: 1px black solid; padding: 0 14px;">2</td>
<td style="padding: 0 14px;">YES</td>
</tr>
<tr>
<td style="border-right: 1px black solid; padding: 0 14px;">yes</td>
<td style="border-right: 1px black solid; padding: 0 14px;">3</td>
<td style="padding: 0 14px;">YES</td>
</tr>
<tr>
<td style="border-right: 1px black solid; padding: 0 14px;">yes</td>
<td style="border-right: 1px black solid; padding: 0 14px;">more than 3</td>
<td style="padding: 0 14px;">no</td>
</tr>
<tr>
<td style="border-right: 1px black solid; border-top: 1px black solid; padding: 0 14px;">no</td>
<td style="border-right: 1px black solid; border-top: 1px black solid; padding: 0 14px;">less than 3</td>
<td style="border-top: 1px black solid; padding: 0 14px;">no</td>
</tr>
<tr>
<td style="border-right: 1px black solid; padding: 0 14px;">no</td>
<td style="border-right: 1px black solid; padding: 0 14px;">3</td>
<td style="padding: 0 14px;">YES</td>
</tr>
<tr>
<td style="border-right: 1px black solid; padding: 0 14px;">no</td>
<td style="border-right: 1px black solid; padding: 0 14px;">more than 3</td>
<td style="padding: 0 14px;">no</td></tr>
</tbody>
</table>
</blockquote>
<div>
If we count the cell in the neighbour count, we change our truth table:</div>
<blockquote class="tr_bq">
<table style="border-collapse: collapse; border-spacing: 5px;">
<thead style="border-bottom: 1px black solid;">
<tr>
<th style="border-right: 1px black solid; padding: 0px 14px;">Live?</th>
<th style="border-right: 1px black solid; padding: 0px 14px;"># cells in 3x3 square</th>
<th style="padding: 0px 14px;">Alive in the next generation</th>
</tr>
</thead>
<tbody>
<tr>
<td style="border-right: 1px black solid; padding: 0 14px;">yes</td>
<td style="border-right: 1px black solid; padding: 0 14px;">less than 3</td>
<td style="padding: 0 14px;">no</td>
</tr>
<tr>
<td style="border-right: 1px black solid; padding: 0 14px;">yes</td>
<td style="border-right: 1px black solid; padding: 0 14px;">3</td>
<td style="padding: 0 14px;">YES</td>
</tr>
<tr>
<td style="border-right: 1px black solid; padding: 0 14px;">yes</td>
<td style="border-right: 1px black solid; padding: 0 14px;">4</td>
<td style="padding: 0 14px;">YES</td>
</tr>
<tr>
<td style="border-right: 1px black solid; padding: 0 14px;">yes</td>
<td style="border-right: 1px black solid; padding: 0 14px;">more than 4</td>
<td style="padding: 0 14px;">no</td>
</tr>
<tr>
<td style="border-right: 1px black solid; border-top: 1px black solid; padding: 0 14px;">no</td>
<td style="border-right: 1px black solid; border-top: 1px black solid; padding: 0 14px;">less than 3</td>
<td style="border-top: 1px black solid; padding: 0 14px;">no</td>
</tr>
<tr>
<td style="border-right: 1px black solid; padding: 0 14px;">no</td>
<td style="border-right: 1px black solid; padding: 0 14px;">3</td>
<td style="padding: 0 14px;">YES</td>
</tr>
<tr>
<td style="border-right: 1px black solid; padding: 0 14px;">no</td>
<td style="border-right: 1px black solid; padding: 0 14px;">more than 3</td>
<td style="padding: 0 14px;">no</td></tr>
</tbody>
</table>
</blockquote>
<div>
A cell will be alive in the next generation if it's alive and the number of live cells in the square is 3 or 4, or if the cell is dead and there are 3 cells in the square. Let's rewrite the rules... again.<br />
<br />
A cell will be alive in the next generation if<br />
<ol>
<li>The 3x3 square has exactly 3 cells</li>
<li>The 3x3 square has exactly 4 cells and the current cell is alive.</li>
</ol>
So, we'll include a cell in the next generation according to these rules. We can tell if a cell is alive by doing a left outer join on the cell table:</div>
<pre class="brush:sql">insert into cell (
select neighbour_count.generation+1, neighbour_count.x, neighbour_count.y
from neighbour_count
left outer join cell
on neighbour_count.generation = cell.generation
and neighbour_count.x = cell.x
and neighbour_count.y = cell.y
where neighbour_count.generation = (select max(generation) from cell)
and (neighbour_count.count = 3
or (neighbour_count.count = 4 and cell.x is not null)));
</pre>
<div>
Repeat the insert statement for each following generation.</div>
</div>
Nancyhttp://www.blogger.com/profile/17327927253598730674noreply@blogger.com1tag:blogger.com,1999:blog-7878631557140971594.post-25890580508442837242012-12-10T21:50:00.000-05:002012-12-10T21:51:02.289-05:00The Code RetreatOn December 8th, I attended the Montréal edition of the 2012 Code Retreat. It was organized by Mathieu Bérubé, to whom I'm very thankful. He asked the attendees for comments on the event, so here I go.<br />
<div>
<br /></div>
<div>
The format of the code retreat is that during the day, there are 6 coding session, using pairs programming. In each session, we try to implement Conways' Game of Life, using TDD principles. We can use any language or framework we want. Sometimes, only one of the partners knows the language used, and the other learns as we go. For some of the session, the leader also adds a challenge or a new guideline. After the session, we delete the code, and we all get together to discuss the session and the challenge. Mathieu had some questions for us to guide the discussion and to make us think.</div>
<div>
<br /></div>
<div>
The goal of the even, however, is not to implement the game of life, but to learn something in the process. I think we all learned a lot, technically. Some of us learned new languages, some learned new ways to approach the problem. I learned that the Game of Life is easier to solve in functional or functional-type languages, rather than with object oriented or procedural languages. I learned the problem cannot be solved by storing and infinite 2D array. I learned that MySQL has special optimisation for "IN" that it doesn't have for "BETWEEN". I learned a smattering of Haskell.<br />
<br />
But that's the sort of things one can learn in a book. What else did I learn, that's less likely to be in technology books? In all fairness, some of the following, I already knew, and is covered in management or psychology books, but those book tend to be less popular with developers.<br />
<h4>
The clock is an evil but useful master</h4>
</div>
<div>
By having only 45 minutes to complete the task, we can't afford to explore various algorithms and data structures to solve the problem - as soon as we see something that looks promising, we grab it, and run with it, until we notice a problem and try down a different path. In some cases, we even started coding without knowing where we were headed. I would normally think of this as a problem, because creativity is a good thing, and stifling it must be bad. However, having too much time usually means I'll over-design, think of all possible ways, but in the end, I may still rush through the implementation. Moreover, I assume that I'll have thought about all the possible snags that can come along, but some problems only rear their ugly heads after some code is written and the next step proves impossible. Sometimes, it's better to start moving down the wrong path, than to just stay in one spot and do nothing at all.</div>
<div>
<br /></div>
<div>
This is somewhat related the the Lean Startup methodology - test your assumptions before you make too many.</div>
<div>
<br /></div>
<div>
At one point, I asked the organizer to put up, on the projector, how much time remained in the session. He pointed out that it was a bad idea, because when we look at the clock, we're more likely to cut corners just to get something working, rather than focus on the quality of the code. This was a hard habit to ignore!</div>
<h4>
Let go, and smell the flowers</h4>
<div>
Since my first partner and I solved the problem in the first session, I was really eager to solve it the second (and third, ...) time around, in part to prove that he didn't do all the work, and I was just there to fix the syntax. But from the second session on, Mathieu gave us particular challenges to include in our coding, from "think about change-proofing your solution" to "naive ping-pong (one partner writes the test, the other does the least amount of work possible to pass the test)". As it turns out, it was really hard to completely implement the solution, writing the tests first, and factoring in the challenge. Something had to give. It was really hard to let go "complete the solution" in favor of TDD and the challenges. Recognizing that this is what I was doing certainly helped me let go, but the drive to finish the job kept nagging me. So much so that when I got home, I just <i>HAD</i> to implement the Game of Life in Scala, because I was so upset I didn't finish during the event.</div>
<div>
<br /></div>
<div>
Another aspect of this is how I interacted with my partners. When I thought I had the solution and they didn't, I just pushed on with my idea, so that we'd get the job done as fast as possible. Rushing means I didn't listen as well as I could have to what the other person had to say. You can't speak and listen at the same time. The point of Code Retreat is not to write the Game of Life, that's been done thousands of times. The point was to play with writing code, try different things, and learn something in the process.</div>
<h4>
The tools make a difference on productivity</h4>
<div>
Session after session, it became clear that for this particular problem, a functional approach makes more sense than a procedural or object-oriented one. While we can use functional programming concepts in most languages, functional languages make the task much simpler. Even though we struggled setting up the test environment for Scala, we got further than with procedural language, because once started, we just added a test, added an implementation - everything seemed to work almost on the first try.</div>
<div>
<br /></div>
<div>
Another tool that affected productivity is the editor. I'm not advocating for any particular tool, but in all the sessions, we used one participant's set up. Whoever's setup that was would edit so much faster. When using someone else's computer, I quickly got frustrated because I would type some editor command, only to realize that it's the wrong way to do what I want on <i>that</i> editor, or I had to slow down to avoid such mistakes. This happened even though I knew how to use the other person's editor. It may have worked better if we had used something like <a href="https://www.dropbox.com/" target="_blank">Dropbox</a> so we could each use our own computer, but given that IDEs tend to organize the source/project differently, it may not have worked either.</div>
<h4>
I change depending on the personality of my partner</h4>
<div>
Each team I was on had a different dynamic. This was due in part to the challenge proposed - ping-pong tends to do that, and in part to the personality of my partner. It is likely that they also took cues from my personality as well, particularly since I was generally outspoken between the sessions, so I did not necessarily get to know them well in the process. I tend to avoid being the leader of a group, but I'm also impatient. At the beginning of a session, the my partner didn't suggest something immediately, an approach, a language, etc, I'd propose something. This means that more often than not, I imposed my will on the other. I should have listened more to my partners, and I might have, if I hadn't been so intent on finishing the problem in the 45 minutes!</div>
<h4>
Deleting the code</h4>
<div>
One of the instructions in the Code Retreat is that after each session, you delete the code. This was hardest to do, the closer we got to finishing the solution. It was particularly difficult in the session when we wrote in Scala, because after the initial fumbling with the test environment, the progress was steady and fast. If <i>only</i> I had another 10 minutes, I'm <i>positive</i> we could finish! Surprisingly, the working code in MySQL was very easy to delete, possibly because it felt complete, done, over with.</div>
<div>
<br /></div>
<div>
<br /></div>
<div>
All in all, it was a useful, interesting and fun experience. I highly recommend it to any programmer!</div>
<div>
<br /></div>
Nancyhttp://www.blogger.com/profile/17327927253598730674noreply@blogger.com0tag:blogger.com,1999:blog-7878631557140971594.post-25994823988902571022012-12-09T15:59:00.003-05:002012-12-09T15:59:37.956-05:00Conway's Game of Life in... SQL?Yesterday, I attended the <a href="http://www.eventbrite.com/event/4704716935">Code Retreat</a> hosted at Notman House and organized by Mathieu Bérubé. It was a most enjoyable experience. On the first session, I paired with Christian Lavoie, and we tried to implement <a href="http://en.wikipedia.org/wiki/Conway's_Game_of_Life">Conway's Game of Life</a> using... mysql. Some people thought this was crazy, and I can't disagree. At the same time, we were able to complete the solution in under 45 minutes, not a small feat. <br />
<br />
Part of the rules of the Code Retreat is that you delete your code after each session. We did, but I thought the solution was so easy to implement, I thought I'd try to recreate it at home. I made some changes to the implementation, but the core of the idea is the same as what we wrote.
<br />
<br />
The first thing to consider is that in the Game of Life, we cannot have a fixed-length 2D array that holds the cells. Indeed, the best way is to store only the coordinates of the live cells. Any cell that's not live isn't store anywhere, since that's the state of all the cells in the infinite grid, and it's just impossible to store an infinite grid. We assume a finite number of live cells to start with (which means we'll always have a finite number of cells).<br />
<br />
These cells will be located in a rectangular area that's bounded by the minimum x, minimum y, maximum x and maximum y coordinates of the cells. This means that we can restrict our processing to the positions within a rectangle that's just a little bigger than the bounding rectangle: we need to add a border one-position wide around the whole rectangle. <br />
<br />
Then, for each cell within that rectangle, we decide if it should be alive in the next generation. We simply ignore cells that die, by not adding them to the next generation. The 4 rules of the game can be rewritten as two simpler rules:<br />
<br />
<ol>
<li>If the current cell is alive, it stays alive if it as exactly 2 or 3 neighbours who are also alive</li>
<li>If the current cell is dead, it becomes alive if it has exactly 3 neighbours.</li>
</ol>
<div>
Using a little logic processing, we can further rewrite this as the following 2 conditions to be alive in the next generation:</div>
<div>
<ol>
<li>If a cells has 3 neighbours</li>
<li>If a cell is alive and has 2 neighbours</li>
</ol>
<div>
So, we only add the cell to the next generation (insert it in the table) if it fits either of those rules.</div>
</div>
<div>
<br /></div>
<div>
Counting neighbours is also fairly easy. We find how many cells exist that have their x and y coordinates one less, equal, or one more than the current x. We have to include the current x and y to include cells exactly to the left, exactly to right, exactly above or exactly below the current cell. We must, however, exclude the current cell, so if we know it's set, we subtract 1 from the total count.</div>
<div>
<br /></div>
<div>
Here is code close to what we came up with, with some modifications that came to me after the fact.</div>
<br />
<br />
<pre class="brush: java">drop table if exists cells;
create table cells (
generation int,
x int,
y int,
primary key (generation, x, y));
drop procedure if exists iterate_generation;
delimiter $$
create procedure iterate_generation ()
begin
declare current_gen int;
declare current_x int;
declare current_y int;
declare min_x int;
declare max_x int;
declare min_y int;
declare max_y int;
declare live int;
declare neighbour_count int;
select max(generation) into current_gen from cells;
select min(x)-1, min(y)-1, max(x)+1, max(y)+1
into min_x, min_y, max_x, max_y from cells
where generation = current_gen;
set current_x := min_x;
while current_x <= max_x do
set current_y := min_y;
while current_y <= max_y do
select count(1) into live from cells
where generation = current_gen
and x = current_x
and y = current_y;
select count(1) - live into neighbour_count from cells
where generation = current_gen
and x in (current_x - 1, current_x, current_x + 1)
and y in (current_y - 1, current_y, current_y + 1);
if neighbour_count = 3 || live = 1 and neighbour_count = 2
then
insert into cells (generation, x, y)
values (current_gen+1, current_x, current_y);
end if;
set current_y := current_y + 1;
end while;
set current_x := current_x + 1;
end while;
end
$$
delimiter ;
</pre>
<br />
Crazy? well, yes. And yet, surprisingly easy. And absolutely a whole lot of fun.
Nancyhttp://www.blogger.com/profile/17327927253598730674noreply@blogger.com0tag:blogger.com,1999:blog-7878631557140971594.post-5265310051681234942011-08-01T22:10:00.000-04:002011-08-01T22:10:34.842-04:00Grails, and seemingly dirty command objects<div>I love Grails, but sometimes, the magic is a little too much.</div><br />
<div>I was trying to debug a particularly strange oddity, and as far as I could tell, Grails was reusing a dirty command object. That's not possible, right? Further investigation showed that no, it's not using a dirty command object, well, not really. Its only doing what it's supposed to: dependency injection and convention over configuration.</div><div>Here is the simplest form of the problem I have been able to put together.</div><br />
<div>The controller:</div><pre class="brush: java">def debug = { DebugCommand d ->
render new JSON(d)
}</pre><br />
<div>The command objects: I have nested commands, with DebugCommand being the outer command (used by the controller) and DebugMapCommand, a map holding some values. I'm using a LazyMap since that's why I used in my real-life problem.</div><br />
<pre class="brush: java">public class DebugCommand {
int someNum
DebugMapCommand debugMapCommand = new DebugMapCommand()
}
</pre><br />
<pre class="brush: java">@Validateable
public class DebugMapCommand {
Map things = MapUtils.lazyMap([:], FactoryUtils.instantiateFactory(String))
}
</pre><br />
<div>What happens here is that multiple calls to the controller/action result data being accumulated in the LazyMap between calls:</div><br />
<pre class="brush: jscript">nancyd $ curl 'http://localhost:8080/library/rpc/debug?someNum=5\&debugMapCommand.things\[2\]=5'
{"class":"com.example.DebugCommand",
"debugMapCommand":{"class":"com.example.DebugMapCommand",
"things":{"2":"5"}},
"someNum":5}
nancyd $ curl 'http://localhost:8080/library/rpc/debug?someNum=5\&debugMapCommand.things\[1\]=5'
{"class":"com.example.DebugCommand",
"debugMapCommand":{"class":"com.example.DebugMapCommand",
"things":{"2":"5","1":"5"}},
"someNum":5}
nancyd $ curl 'http://localhost:8080/library/rpc/debug?someNum=5\&debugMapCommand.things\[elephants\]=5'
{"class":"com.example.DebugCommand",
"debugMapCommand":{"class":"com.example.DebugMapCommand",
"things":{"2":"5","1":"5","elephants":"5"}},
"someNum":5}
</pre><br />
<div>If I gave a new value for a map entry, the new value was used.</div><br />
<div>So, what's happening? The DebugCommand's reference to the DebugMapCommand is called debugMapCommand, and Grails thinks I want a DebugMapCommand injected, so it created a singleton, and passed it to all my DebugCommand instances. Oops.</div><br />
<div>Trying to prove this wasn't too easy. It would seem that a number of factors are necessary for this particular issue to manifest:</div><br />
<ol><li>The field name must be the same as the class name with the first letter lowercased</li>
<li>The inner/sub command, DebugMapCommand, must be annotated with @Validateable</li>
<li>The inner/sub command must be in a package that is searched for "validateable" classes (in Config.groovy, you have to have <span class="Apple-style-span" style="font-family: Monaco; font-size: 11px;">grails.validateable.packages = ['com.example.yourpackage', ...])</span></li>
</ol><br />
<div>So, what's the lesson here?</div><br />
<div>Don't name your fields after their class.</div>Nancyhttp://www.blogger.com/profile/17327927253598730674noreply@blogger.com3tag:blogger.com,1999:blog-7878631557140971594.post-85380096476155343712011-06-12T23:11:00.001-04:002011-06-12T23:39:44.741-04:00Why is reading code so hard?We've all been there. Faced with lines and lines of code, written by an intern, a programmer long gone, or a vendor with whom you do not have a support contract.<br />
<br />
Code can be quite hard to read. Why is that?<br />
<br />
Without looking at the language or frameworks used, some of which are easier to read than others, there are other, more human factors that make it had to puzzle out what code does. I'm not talking about how the code was written, but how we attempt to read it.<br />
<br />
<b>1. Reading code usually involves two actions: identifying what the code does, and what it was actually meant to do.</b><br />
<br />
When we approach code, it's rarely because we're just curious; we usually want to fix bugs or improve it. We must know what the code does, but for the structure and implementation of the code to make sense, we have to figure out what the programmer intended to do. It's usually easier to figure out the intent first, then work out the discrepancies - where we think the code doesn't do what it was meant to.<br />
<br />
This can be particularly hard when we have to look at code that was edited multiple times, by multiple people with different approaches. Then, it's more of an archeological expedition. That's the situation that can lead to some pretty ugly or silly code. I remember looking at code once that, I can only imagine, was the product of too many edits:<br />
<br />
<pre class="brush: java">if (someCondition == true) {
myVar = false;
} else {
myVar = false;
}
</pre><br />
<b>2. We're talking too loud, and not listening enough</b><br />
<br />
When we see code like the one above, we laugh, we point, and our opinion of the code (and the programmer(s)) goes down. We start generalizing and thinking the worse. How can code with <i>that</i> in it be any good? And <i>what</i> were they thinking? who would wrote such poor code?<br />
<br />
And that's when we start losing faith in the code. Our disdain takes over, and our ears close. We see some odd code, and instead of genuinely asking "what were they trying to do here?", we throw our hands in the air and sigh, "what were they trying to do here!"<br />
<br />
If you want to understand the code, you must listen to what the previous programmers were trying to say. Withhold judgement, open your eyes, your mind, and assume they were trying to accomplish something. They may even have something to teach you about how to solve problems, about the business, or about the history of the code. <br />
<br />
<b>3. It's not written how we think</b><br />
<br />
If you've ever written in perl, (and even if you haven't) you know that there's more than one way to accomplish a task. Sometimes, it's a simple syntax tweak, but sometimes it's a whole approach. For example, if I were to put an apple and an orange on the table and ask you to describe what you see, would you start with "I see two fruits" or "there's an apple and an orange"? Depending on your answer, chances are you approach problems differently.<br />
<br />
The code may use programming techniques we're unfamiliar with (using functions as parameters, patterns, functional programming). Unfortunately, if we're unfamiliar with the technique, we're unlikely to recognize it it the wild, unless the programmer was kind enough to leave comments about it. This is where experience and breadth of knowledge will come handy. Keep up to date with developments in the field.<br />
<br />
<b>4. We lose track</b><br />
<br />
Not all code is nicely packaged, modular and cohesive. More often than not, we start reading code in one spot, only to realize we need to find out what a function does in another file or module. We leave the code here, investigate the code there, which takes us to another module,... and by the time we get back to the original spot, we've totally forgotten what we were reading or trying to do.å<br />
<br />
Take notes. Draw pictures. Use your IDE to find relations between code, where functions are called from. I find printing code is, unfortunately for the trees, helpful, as I then remember not only the code, but where the code is on the page; and I scribble all over the paper in various colours.<br />
<br />
<br />
<b>What can we do about it?</b><br />
<ul><li>Try to find out what the programmer wanted to do</li>
<li>Then see if the code does it</li>
<li>Keep an open mind - don't let your prejudice get in the way</li>
<li>Learn new (to you) techniques and patterns</li>
<li>When you code, try to see more than one way to solve the problem; maybe next time you try to read someone's code, they'll have used your second or third choice, and you'll recognize it more easily</li>
<li>Try to remember code you've written, before you were perfectly fluent in a new language, or when you were too rushed to go back and fix some readability issue. Maybe there's someone reading that code now; treat the code in front of you as you would have others treat yours.</li>
</ul><div><br />
</div><div>Why do you think reading code is so hard? what helps you?</div><div><br />
</div>Nancyhttp://www.blogger.com/profile/17327927253598730674noreply@blogger.com10tag:blogger.com,1999:blog-7878631557140971594.post-77146446499348396982011-01-10T21:25:00.000-05:002011-01-10T21:25:45.143-05:00Scala building blocks part 2: imports and packagesIf you're used to Java, Scala imports and packages look both familiar and all wrong and weird.<br />
<br />
<b>Imports</b><br />
<br />
The first thing that you may notice in some code you're reading is the use of <span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">_</span> in imports. The best way I've found to deal with <span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">_</span> is to replace it in my head with "whatever". It works in imports, but it also works in other cases where you encounter <span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">_</span>.<br />
<br />
So, when you see<br />
<br />
<pre class="brush: java">import com.nancydeschenes.mosaique.model._
</pre><br />
it means "import whatever you find under <span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">com.nancydeschenes.mosaique.model</span>"<br />
<br />
You can lump together multiple imports from the same package:<br />
<br />
<pre class="brush: java">import scala.xml.{ NodeSeq, Group }
</pre><br />
<br />
Imports are relative:<br />
<br />
<pre class="brush: java">import net.liftweb._
import http._
</pre><br />
imports whatever's needed in net.liftweb, and whatever's needed from net.liftweb.http.<br />
<br />
But what if I have a package called http, and don't want net.liftweb.http? use the _root_ package:<br />
<br />
<pre class="brush: java">import net.liftweb._
import _root_.http._
</pre><br />
<b>Packages</b><br />
<br />
Like Java, code goes in packages. Unlike Java, packages aren't dictated by the directory structure. You can put multiple public classes in one file, and the location of the file doesn't imply what package it will be in. Do keep things simple, tho, if you ever want to be able to re-read yourself.<br />
<br />
You can use the same package statement you would with Java:<br />
<br />
<pre class="brush: java">package com.nancydeschenes.mosaique.snippet
</pre><br />
Or, you can use the <span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">package</span> block:<br />
<br />
<pre class="brush: java">package com.nancydeschenes.mosaique {
// Some stuff
package snippet {
// stuff that ends up in com.nancydeschenes.mosaique.snippet
}
}
</pre>Nancyhttp://www.blogger.com/profile/17327927253598730674noreply@blogger.com1tag:blogger.com,1999:blog-7878631557140971594.post-21396030449980880252011-01-09T22:37:00.001-05:002011-01-10T06:53:02.149-05:00Scala building blocksWhen I first started reading about Scala, I saw a lot of very interesting looking code, but I felt lost. It looked as if I was trying to learn a foreign language with a phrasebook. I saw a number of examples, but I felt I was missing the building blocks of the language.<br />
<br />
I've been using Scala for a little while now, and this is the introduction I wish I'd had then. This post is not meant as a detailed "how things are" but just to provide a newcomer with the right frame of mind to understand the rest. There are some over-simplifications, but I find they help me understand, so I'm sharing them.<br />
<br />
<br />
<b><span class="Apple-style-span" style="font-size: large;">Classes, traits, objects, companions</span></b><br />
<br />
Everything in Scala is an object, and every object is of a particular class. Just like Java (if you ignore the pesky primitives). So, generally speaking, classes work the way you expect them. Except that there's no "static". No static method, no static values. <br />
<br />
Traits are like interfaces, but they can include fields and method implementations. <br />
<br />
Objects can be declared and are then known throughout the program, in a way that's reminiscent of dependency injection, particularly the Grails flavour. Object declarations can even include implementation, and new fields and methods.<br />
<br />
Companion objects are objects named the same as a class. This is how you handle details that you would normally want to do as static methods/fields/etc. This is very elegant: it makes it look as if you had access to static elements, while preserving a true object-oriented approach.<br />
<br />
So you may encounter code such as<br />
<br />
<pre class="brush: java">class Car extends Vehicle with PassengerAble {
val numWheels = 4
val numPassengerSeats = 6
}
object Car {
def findByLicensePlate(String plate, String emitter) : Car = {
Authorities.findEmittingAuthority(emitter).findByLicensePlate(plate);
}
}
object MyOwnCar extends Car with PassengerSideAirbags, RemoteStarter {
val numChildSeats = 2;
def honk : Unit = {
HonkSounds.dixie.play;
}
}
</pre><br />
In that example, the first <span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">Car</span> is a class. The second <span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">Car</span> is an object. <span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">MyOwnCar</span> is an object that can be addressed anywhere (same package rules apply as java), but <span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">MyOwnCar</span> has extra stuff in it: <span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">PassengerSideAirbags</span> and <span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">RemoteStarter</span> are trait (you can guess that because of the <span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">with</span> keyword). It even defines a new method so that honking it <span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">MyOwnCar</span> should remind you of the <i>Dukes of Hazzard</i>.<br />
<br />
<br />
<b><span class="Apple-style-span" style="font-size: large;">Types</span></b><br />
<br />
Unlike Java, in Scala, everything is an object. There is no such thing as a primitive.<br />
<br />
<br />
<b>Basic types</b><br />
<br />
At the top of the object hierarchy, we have <span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">Any</span>. Every object, either what you think of an object in a Java sense, or the types that are primitives in Java, every thing inherits from <span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">Any</span>.<br />
<br />
The hierarchy then splits into two: <span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">AnyVal</span> and <span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">AnyRef</span>. Primitive-like types are under <span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">AnyVal</span> and <span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">AnyRef</span> is essentially the equivalent of <span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">java.lang.Object</span>. All Java and Scala classes that you define will be under <span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">AnyRef</span>.<br />
<br />
Strings are just like Java Strings. Double-quoted. But Scala defines a few additional methods on them, and treats them as collections, too, so your String is also a list of characters. A particularly convenient method, I've found, is <span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">toInt.</span><span class="Apple-style-span" style="font-family: inherit;"> There's </span><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">toDouble</span><span class="Apple-style-span" style="font-family: inherit;"> and </span><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">toBoolean</span><span class="Apple-style-span" style="font-family: inherit;"> too.</span><br />
<br />
<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">Unit</span><span class="Apple-style-span" style="font-family: inherit;"> is what a method returns when it doesn't return anything. You can think of it as "void".</span><br />
<br />
<span class="Apple-style-span" style="font-family: inherit;">Null as you know it is a value, but in Scala, every value has type, so it's of type Null. And Null extends every single class, so that null (the one and only instance of Null) can be assigned to any </span><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">AnyRef</span><span class="Apple-style-span" style="font-family: inherit;"> object. It sounds crazy, but if you let it sink in, it will make sense. Null is actually a trait, not a class.</span><br />
<br />
<span class="Apple-style-span" style="font-family: inherit;">Nothing is the absolute bottom of the hierarchy. Nothing doesn't have any instances.</span><br />
<br />
<br />
<b>Numeric Types</b><br />
<br />
Integers are of type Int.<br />
<br />
Doubles are Doubles, floats are Float. <br />
<br />
A litteral in the code is treated an object of the appropriate type. Things just work, without "autoboxing" or other convolutions.<br />
<br />
Strings and numeric types are immutable.<br />
<br />
<br />
<b>Collections</b><br />
<br />
Collections come in mutable and immutable variations.<br />
<br />
The operation you can perform on collections are probably easier to understand and get used to when you remember lisp/scheme. Or perl. Try to view collections are a whole, and not so much as an object with a few methods, the way we tend to in Java. The think of the methods as operations on the whole. It may also help to dust out set theory concepts.<br />
<br />
A special kind of collection is the Tuple. It's an ordered group of N items that can be of the same or of different types. They are defined for N=2 to N=22. You can access the <i>j</i>-th element of the tuple with ._<i>j</i> (ex: the first is myTuple._1, the third is myTuple._3)<br />
<br />
<b>Options</b><br />
<br />
The first thing you have to realize about options is that they're everywhere, so you better get used to the idea. Lift uses Box instead, but it serves the same purpose.<br />
<br />
The second thing you have to realize is that Options (or Box) is the right way to handle multiple scenarios, but you've spent your programming life working around that fact.<br />
<br />
Let's take a simple example. You want to implement a method that computes the square root of the parameter it receives. What should that method return? a Double. So you start:<br />
<br />
<pre class="brush: java">def sqrt (x: Double) : Double = {
// ...
}
</pre><br />
You start implementing, maybe by writing some tests first... Hm... what happens if x is a negative number? you may think "I'll just return null" or "I'll throw an exception". If you return null, chances are the caller wont bother checking, and bad things will happen. If you throw an exception, you slow things down a bit (exceptions should be for exceptional condition). If you throw an unchecked exception, who knows where in the caller's code that will be handled. If you throw a checked exception, the caller's probably already sick of catching every exception every where and has a standard, no-thought solution (ignore, wrap in a RuntimeException, etc)<br />
<br />
Options tell you that there are multiple outcomes possible. The case where a regular value is returned, the Option is actually a Some (subclass of Option), with the value in it. In cases when no value can be returned, the Option is actually None (an object). Of course, Options can be used in contexts other than returning a value from a method, but that's an easy way to see their usefulness.<br />
<br />
Once you have an Option, you can test it for Some or None, or you can try to find what's in it: myOption.get will return the content of the Some (or throw an exception if it's None, so don't do that unless you know). If you're not sure, you can use myOption.getOrElse(defaultVal) which will return the contents of the Some, or gracefully (and elegantly) use the default you provided.<br />
<br />
Or, you can use matching to decide what to do:<br />
<br />
<pre class="brush: java">MathHelper.sqrt(x) match {
case Some(y) => "The square root of " + x + " is " + y
case None => "The value " + x + " does not have a square root"
}
</pre>Nancyhttp://www.blogger.com/profile/17327927253598730674noreply@blogger.com0tag:blogger.com,1999:blog-7878631557140971594.post-19130504700368049812011-01-03T23:19:00.001-05:002011-01-03T23:20:41.020-05:00Ruminations on RejectionA few months ago, I attended a Montreal Geek Girl Dinner about "Women in technology". I was hoping to meet like-minded women and maybe some men, but I was surprised that the majority of attendant were what I consider technology users, rather than technology producers. These are women who use technology to provide content, who mange technology production, who sell it, who bring it to all of us, making our lives easier, more interesting, or more fun. I was glad I came, even tho it wasn't what I had expected.<br />
<br />
At one point, the issue of the few women speakers at conferences came up. One of the the organizers of ConFoo (one of the brave men in attendance) asked for ways to get more speakers, because very few women step up. I thought about it, and I think maybe I'm one of those women who just do not step up to be heard. I want to do it, but.. surely, there's someone better than me out there, surely there's nothing special I can bring to a crowd... I'm just a developer - a good one, but why me? What would make me step up?<br />
<br />
I'm not exactly shy. Well, okay, maybe a little, but when I see a need, I step up. I usually let others lead, but when I know I can do better, I speak up, and guide the situation the way I think will work best. So what would make me volunteer as a speaker? a void; a need. I went to the organizer of ConFoo, and told him that maybe, instead of sending out vague requests for speakers, they should suggest specific topic to specific women, showing them the need. Which he promptly turned around on me, and suggested I do a Grails talk at ConFoo. <br />
<br />
I considered it for some time, trying to convince myself I could do it. I know Groovy and Grails well, I like it, and I think I can communicate my enthusiasm to other developers. I took a deep breath, and proposed the talk. And felt all giddy. And started thinking about how I'd do the presentation. Then I realized I'm also pretty good at SQL, from a programmer's perspective. How you can't tune a database on it's own, but you have to look at it in the context of the application; sometimes you have to change the logic in your program instead of tossing another index at the problem. How sometimes, it's better if a process takes longer, if it's less intrusive on the other users of the system. And how to write and rewrite queries until they do what you want, and how you want. After the rush of the first proposal (and a few words of encouragement) I proposed a session on SQL for programmers.<br />
<br />
Finally, I had most recently started working with Scala and Lift, and I could see the potential. I submitted a session for this too, because I thought it should be presented, but I was hoping I wouldn't get selected - I have so little experience with it, and none in a proper "work" context, that I thought it was pushing it a little. Still, no better way to learn than when thinking "and how do I explain that to someone else?"<br />
<br />
So I submitted three talks, and waited. I started writing notes about how I wanted to design each presentation, what aspects I particularly didn't want to forget, etc. Just in case I was selected. They did say they wanted a session on Grails, and they did say they wanted more women. I wasn't expecting to get a session due to my gender alone, but I thought my chances were pretty good. But I also knew very well I had no experience to show for, no visible accomplishment. And I was worried that I would get selected! Would I have enough time to prepare as well as I'd like?<br />
<br />
And then, the decision came. The list of speakers was published, and I couldn't find my name on it. I looked and looked and.. nope! nothing. Not for the Scala talk, not for the Grails talk, not for the SQL talk.<br />
<br />
I was surprised at how disappointed I was. It's not like I was promised anything. There were quite a number of proposals, many by professional speakers, or by people directly involved in the making of the technology discussed. I was able to confirm later that there will be a talk on Grails, and at least a talk on SQL (by someone whose blog I've consulted on many occasions, so he's a lot more of an authority than I am, let's face it). I didn't see anything about Scala/Lift, but I may have missed it. And it's very new, and definitely a serious paradigm shift for anyone doing Java or PHP, and even Python.<br />
<br />
<b>So, why was I so disappointed?</b><br />
<br />
Probably because in order to even dare proposing a session, I had to convince myself that it was needed, and that I was the only one who could do it. I wasn't. I don't like taking chances, I don't like selling myself. People should just realize how awesome I am, without me ever having to brag. Yeah, that's not how it works.. I have done very well for myself with that philosophy, but I have also not done anything particularly visible, cool, amazing... Oh, I've done some really impressive stuff. I wrote one of the first CMS (but you wouldn't know it) and I worked one some pretty cool sites (like Heat.net - but you probably don't remember it). I wrote one of the first applets that kept track of who was on-line - well before anyone spoke of "Web 2.0". Well, if I want to be seen, be recognized by my peers, I'll have to do a lot more than wait for someone to offer me a session at a conference.<br />
<br />
<b>What now?</b><br />
<br />
Now that I've tasted the thrill of proposing sessions at a conference, and now that I know that rejection sucks, but you survive, dust yourself off, put a band-aid on the bruised ego and move on... now, I've decided that working alone in my office and gathering knowledge and skills is not enough. I want more. I will be more. I will take risks, and put myself out there. I will not stop at "what I'm supposed to do". I will also listen to what I want to do. And I will try to share what I know, as best I can. And there are plenty of other conferences. And there's next year. <br />
<br />
I know that whenever we do something, we "practice" doing it - we get better at it, it becomes easier. So it's time for me to start practicing risk taking. At least a little.<br />
<br />
Isn't it convenient that this is happening at the turning of the year?<br />
<br />
Here's to 2011!Nancyhttp://www.blogger.com/profile/17327927253598730674noreply@blogger.com10tag:blogger.com,1999:blog-7878631557140971594.post-20425358688235765542010-09-14T20:31:00.007-04:002010-09-14T21:25:20.389-04:00Pulling the configuration for the mail plugin for grails from the databaseI have a grails application that sometimes needs to email users. I am using the <a href="http://www.grails.org/Mail+plugin">mail plugin</a>, but that expects the configuration (SMTP server, etc) configuration to be in the application's Config.groovy file. I wanted to make it possible for the site administrator to change the configuration. This way, they could create a specific email account with Google just to send email for the application.<br />
<div><br />
</div><div>After some research, I discovered that the configuration could be altered at runtime by getting the mailSender injected into my code, and setting its properties as needed.</div><div><br />
</div><div>Next, I needed a domain object to represent my configuration. I tried using the @Singleton annotation, but that does not play well with domain objects. I ended up writing getInstance() myself:</div><div><br />
</div><div><div></div></div><br />
<pre class="brush: java">static long instanceId = 1l;
static EmailServerConfig instance;
static synchronized getInstance() {
if (!instance) {
instance = EmailServerConfig.get(instanceId);
if (!instance) {
instance = new EmailServerConfig()
instance.id = instanceId
instance.save()
}
}
return instance;
}
</pre><div>This can only work with </div><pre class="brush: java">static mapping = {
id generator:'assigned'
}
</pre><br />
<div><br />
</div><div>and even with that, I was unable pass the id parameter to the constructor, that's why I set it separately after the EmailServerConfig object is created.</div><div><br />
</div><div>Then all I need is to define the GORM event handlers afterLoad, afterInsert and afterUpdate to apply the values from the database to the mailSender.</div><div><br />
</div><div>Finally, I made sure to encrypt the SMTP authentication password on its way into the database, and to decrypt it when retreiving it. Thanks to Geoff Lane for this <a href="http://www.zorched.net/2008/02/03/encryption-codecs-and-unit-tests-in-grails/">blog post</a> on how to handle that with codecs:</div><pre class="brush: java">class EmailServerConfig {
String password
String passwordEncoded
//...
def afterLoad = {
password = passwordEncoded?.decodeSecure()
updateMailSender()
}
def beforeUpdate = {
passwordEncoded = password?.encodeAsSecure()
}
//...
}
</pre><br />
<div>Then all I had to do was write the controller to let site admins edit those values. The controller uses EmailServerConfig.getInstance(), since we're simulating a singleton.</div><div><br />
</div><div>Things to remember:</div><div><ul><li>onLoad is called before the values are loaded into the object, so the values are null; use afterLoad instead</li>
<li>beforeInsert, beforeUpdate and beforeDelete are called only once the object is validated, so the constraints have to allow a null value for passwordEncoded</li>
<li>Grails tries to instantiate domain classes at startup, and @Singleton prevents that, that's why you can't have @Singleton on a domain class</li>
<li>If you don't create an EmailServerConfig in the Bootstrap, and you do not provide any configuration in Config.groovy, the mailSender will default to trying to send mail through localhost:25. This may work, depending on your setup.</li>
</ul></div>Nancyhttp://www.blogger.com/profile/17327927253598730674noreply@blogger.com1tag:blogger.com,1999:blog-7878631557140971594.post-73920436935578790602010-07-03T21:30:00.001-04:002010-07-03T21:51:12.341-04:00RoCoCo 2010 in Montreal - Recap and Impressions<div><div>The Recent Changes Camp (also called RoCoCo) was held last weekend (June 25-17) in Montreal. I'm not sure how I heard about it. Possibly someone I follow on twitter commented on tikiwiki, and I checked it out and saw that they were sponsoring a conference near me. I do not "wiki". We use one at work, but I have felt no drive to get involved in the open ones such as wikipedia or wikiHow. But I decided not too long ago to be move involved in what's happening near me, and to actually meet people face to face once in a while. So I went. Their website made it look open enough.</div><div><div><br /></div><div>It turns out, that was a good idea.</div><div><br /></div><div>The first few people I met were welcoming and friendly, so I stayed. "I don't really have anything to do with wikis" was met with "that's cool", and "whoever ends up being there is whoever was meant to be there". I learned first-hand about the openspace technology (well, I'd call it more a philosophy or concept, but it seems that it's usually referred to as a technology). When we got together to set the agenda, I expected people to act like I've always seen people act, shy: "you go first" "no you do". But they couldn't wait for the presenter to give them the floor to introduce the sessions they wanted to host. I suppose I shouldn't have been surprised; many are active wiki or open software contributors, so they do not wait for others to do what they want done - they are doers. Still, for me that set the tone do the day - a very proactive sort of tone. Which eventually led me to co-host a talk (at Mark Dillon's invitation). I hadn't planned on coming back on the Saturday, but I was learning, I was talking to people, I felt part of the group, so I came back.</div></div><div><br /></div><div><b>Why wiki, why not wiki, and why don't more people contribute?</b></div><div><br /></div><div>The first session I attended was led by <a href="http://www.aboutus.org/MarkDilley">Mark Dillon</a>, and asked "<a href="http://rococo2010.org/wiki/Why_Wiki%3F">Why wiki?</a>". Many issues were discussed, as you can see from the notes. We discussed how things are, how people use wikis, and how it can make things better. We also looked at some reasons why people do not wiki. The technical aspect came up (wiki syntax can be cumbersome), but I felt they were leaving the "people aspect" out of it a bit- being shy, or... something. We did cover a lot of the features and how they can act to invite users to contribute, or add to the "conversation". After the talk, Mark asked if I would co-host another one on <a href="http://rococo2010.org/wiki/Barriers_to_Entry">barriers to entry</a>. I don't know if it was his strategy to gently push a newcomer, of it was just the action of a natural leader - either way, it worked, and I accepted. The session happened the next day. I think we covered a lot of "personal" aspects. I personally feel that while the technical complexity may keep some people away, many just don't want to write, either because they are shy, or do not feel the drive to do so. I wanted to explore these in more details, and we certainly did. What came out of it for me, why I think many of us don't contribute, is that we feel we need the permission to edit someone else's text. Even when we know how the system works, we may want to make sure we're not going to hurt the other person's feelings, or possibly miss an important point they were making, or an angle they were trying to give. Another major obstacle is the lack of feedback. If we don't believe that others will review our work and improve on it, there is little to motivate us. What I didn't know is how much of a community the contributors end up creating, and that it is an important factor to current contributors. A very interesting and enlightening set of discussions.</div><div><br /></div><div>Since then, I have read an <a href="http://research.microsoft.com/en-us/um/redmond/groups/connect/cscw_10/docs/p107.pdf">article</a> (thanks to <a href="http://openresearch.sebpaquet.net/">Seb Paquet</a> for pointing it out) showing some empirical measurement of the benefits of methods used to encourage people to contribute. I have also encountered the concept of "diffusion of responsibility" and "the bystander effect". The feeling that we don't have to do something; someone else will. I was somewhat familiar with the concept, but now it has a name. And I'm sure it plays a role in whether one contributes to wikis, as well as pretty much any open venture.</div><div><br /></div><div><b>Structured wikis, semantic wikis, Semantic web</b></div><div><br /></div><div>Here, I mostly took notes, trying furiously to make sense of all the information provided. Structured wikis are those where contributors are asked to fill in fields, rather than (or as well as) come up with the text of the article. It may feel more like entering data into a database. For example, for an entry on an author, the user may be asked for a date of birth, a date of death, schools attended, genre, and a list of titles.</div><div><br /></div><div>A semantic wiki is one where the occurrence of information with a particular meaning ("this is a city", "this is a person", "this is a date") is annotated as such. This then allows the software to make links between other things that also have that information, such as other authors who were born in the same city, or events that occurred on the same date.</div><div><br /></div><div>The power of both these wiki styles is greatly improved when they are combined - structured semantic wikis create a wealth of information that can be interrelated by a machine to create a rich set of information.</div><div><br /></div><div>This is also where I learned about the existence RDF, and the RDF triple: a relation is expressed as 3 components: the subject, the predicate, and the object. I was taken back to 6th grade grammar, but of course it makes sense. If you want to describe a relation you need the the origin of the relation, the type of relation, and the target of the relation: "Bob knows Peter", "Steven King wrote The Stand". I believe someone brought up microformats, which can encode the same information, but differently, in a way that's more accessible on the web. There is so much here to try to make sense of, I'll be spending some serious time puzzling it out. But I think the potential there is obvious. Calling it "Web 3.0" may be an exaggeration, but I don't think it's far off.</div><div><br /></div><div><b>Open companies and reputation systems</b></div><div><br /></div><div><a href="http://bayleshanks.com/">Bayle Shanks</a> presented the concept of open companies where employees are those who want to work on the company's project, and they get paid according to a rating system by their peers. When I first sat in that session, I expected it to be about open companies in the sense of information flow, not a true open source parallel. Before the talk, I would have thought the whole concept simply crazy, but the culture of open spaces (or this particular one?) is such that we all listened, commented, suggested, brought up issues, without anyone being offensive or dismissive. I'm still not sure it can work in a general setting, but I applaud Bayle for wanting to give it a shot, and I can see some applications where it has some definite potential.</div><div><br /></div><div>The reputation system he wants to use is quite intriguing. The system sounds simple enough, but I'm not following all the repercussions of money distribution scheme. The interesting bits is that the people who contribute the most also end up being the ones who have the bigger influence on the distribution of rewards (money, reputation, gold stars). This can be useful in a number of non-money applications, too, as a way to recognize the contribution of volunteers, for example. Maybe all wikis should have that!</div><div><br /></div><div>And here is why keeping an open mind pays. If I had chosen not to listen to the open company part of the session I would never have heard about the reputation system. And boy am I glad I did!</div><div><br /></div><div><b>Multilingual wikis</b></div><div><br /></div><div>The resources on the net are still mostly in English, but the web as a whole is getting a lot better. At least now, a number of HTTP requests include an Accept-Language header that makes sense for the context. Still, users do not always want to browse a particular site in the language configured in their browsers.</div><div><br /></div><div>The question was, "how do you handle multilingual wikis"? This can be particularly hard to do when original content can come from any of the supported languages. If someone updates the French version, how do you make sure the changes are included in the English version? <a href="http://wiki-translation.com/">Wiki translation</a> shows some promise, but I think there are still more questions than answers on that topic, both for wikis and for websites and social networks in general. I still haven't figured out how to Facebook or Twitter bilingually.</div><div><br /></div><div><b>Intent Map</b></div><div><br /></div><div>In another session, Seb Paquet introduced the idea of a way to find people who want to work on the same sort of things you want to work on. We discussed this, and by the end of the session, we had agreed to turn this into a <a href="http://www.aboutus.org/IntentMap.org">project</a>. Others in the group were already familiar with RDF (see section above on semantic web). Someone else brought up <a href="http://xmlns.com/foaf/spec/">FOAF</a>, a specification for identifying people and relations between people. Someone else brought up <a href="http://trac.usefulinc.com/doap">DOAP</a>. Microformats came up again. I try write down everything I'm going to have to learn about. And yet, I volunteered to code it all. Code what? well, that's the question! I'm not sure what I got myself into. During the session, I mentioned that one way to get widespread visibility would be with a Facebook application, so I have started playing with writing a Facebook application. Since I don't want to worry about hosting the application (and the scraper, and the database that will be needed to support it all) I also started learning about Google App Engine. I even wrote a very simple application that displays inside Facebook, but I'm still sorting out authentication and permissions. It is quite a challenge, but I need to get out of my comfort zone, so this is perfect. I get to play with new (to me) technologies, learn new specifications, and tons of new concepts. I hope I don't disappoint my teammates. I better get coding.</div><div><br /></div><div><b>What now?</b></div><div><br /></div><div>I met tons of new people. I hosted a session. I am now an official contributor to the RoCoCo2010.org wiki (I wrote up some session notes). I volunteered to implement something around a spec that doesn't even exist, with tools and APIs I don't know. This is not the same-old, same-old, but I'm okay with that. And I'm going to do it again, when the opportunity arises again. Thanks to everyone who was there for making it so energizing.</div><div><br /></div></div>Nancyhttp://www.blogger.com/profile/17327927253598730674noreply@blogger.com0tag:blogger.com,1999:blog-7878631557140971594.post-85459273622567626382010-06-27T16:04:00.006-04:002010-09-14T21:18:11.536-04:00Unordered notes from the RoCoCo unconference in Montreal this weekendI decided to attend the <a href="http://rococo2010.org/">Recent Changes Camp 2010: Montreal</a><br />
Here are a few notes I made for myself, and that I'm sharing now, at least until I get around to writing a proper entry:<br />
<br />
Wikis (well, wiki software) could be a way to implement <a href="http://blog.addventure.com/">addventure</a> (a "you are the hero" collaborative story telling game originally written by Allen Firstenberg). Wiki red links are very much like "this episode has not been written yet".<br />
<br />
Wikis synthesize (focus), where forums divide (or disperse in their focus).<br />
<div><div><br />
</div><div>Ontology vs folksonomy.<br />
<br />
<b>Look into:<br />
</b>HTLit</div><div>Inform 7<br />
<a href="http://universaleditbutton.org/">Universal Edit Button</a><br />
Etherpad<br />
Semantic web; the semantic triple: [subject, predicate, object]</div><div>Resource Definition Framework (RDF), SPARQL (query language for RDF)<br />
<a href="http://www.confoo.ca/">confoo</a><br />
<a href="http://www.appropedia.org/">appropedia</a></div><div><a href="http://dbpedia.org/">dbpedia</a></div><div>Google wheel</div><div>microformats</div><div><br />
</div><div><br />
<b>To read:</b><br />
The wisdom of crowds</div><div><div><a href="http://is.njit.edu/pubs/delphibook/index.html">The Delphi Method</a></div><div><br />
</div><br />
I also got to lead a <a href="http://rococo2010.org/wiki/Barriers_to_Entry">session</a> (which is a lot easier than you might expect since all the participants are interested in the topic anyway - or they leave, and because they participate willingly). And we started a new <a href="http://intentmap.org/">project</a>!</div></div>Nancyhttp://www.blogger.com/profile/17327927253598730674noreply@blogger.com0tag:blogger.com,1999:blog-7878631557140971594.post-63496649298434441762010-06-10T22:47:00.008-04:002010-09-14T21:18:28.114-04:00How to transform one type of object to another in Groovy/Grails (as long as it's not a domain object)<div>I've been working on a system that will be using remote calls to communicate between a client (browser, mobile phone, possitbly a GWT client) and the server. The client sends a request, and a grails controller returns a grails domain object encoded using JSON. Relatively straight-forward stuff, but I hit a few snags. I was thankful when I discovered <a href="http://blog.lourish.com/">http://blog.lourish.com</a>/ which goes into some details into how to make it happen. Detailed post are <a href="http://blog.lourish.com/2010/01/29/rendering-json-using-grails-part-1-collections-testing-and-the-jsonbuilder/">here</a>, <a href="http://blog.lourish.com/2010/02/08/rendering-json-in-grails-part-2-plain-old-groovy-objects-and-domain-objects/">here</a>, and <a href="http://blog.lourish.com/2010/02/15/rendering-json-in-grails-part-3-customise-your-json-with-object-marshallers/">here</a>.</div><br />
<div>I debated using the ObjectMarshaller to restrict the data sent (afterall, the client doesn't need to know the class name of my objects), but in the end, I decided to use Data Transfer Objects. I can see a future development where these objects will be used as commands, for example.</div><div><br />
</div><div>The problem that's been keeping me awake tonight, tho, is in the translation from domain object to DTO. Based on my reading, it looked like I could transform any kind of object into any other kind of object, as long as the initial object knew what to do.</div><pre class="brush: java">class User {
// grails will contribute fields for id and version
String lastName
String firstName
Address workAddress //
Address homeAddress // The client does not need that info and SHOULD NOT ever see it
static hasMany [roles: Role, groups: Groups] // etc
doThis() {
//..
}
doThat() {
//...
}
}
class UserDTO {
String lastName
String firstName
}
</pre><div>How do you take a User object and make a UserDTO out of it? Well, you should certainly have a look at Peter Ledbrook's <a href="http://www.grails.org/plugin/dto">DTO plugin</a>. But for my needs, I thought I'd stick with something simpler. Just use the groovy "as" operator.</div><div></div><div>All you need to do something like</div><pre class="brush: java">def dto = User as DTO
</pre><div>is to have User implement asType(Class clazz) and to handle (by hand) the case where clazz is DTO:</div><pre class="brush: java">class User {
// same fields as before, etc
Object asType(Class clazz) {
if (clazz.isAssignableFrom(UserDTO)) {
return new UserDTO(lastName: lastName, firstName:firstName)
} else {
return super.asType(clazz)
}
}
}
</pre><div>All works well. Unit tests confirm, there's nothing to it.</div><pre class="brush: java">void testUserAsUserDTO() {
String lastName = 'Lovelace'
String firstName = 'Ada'
User u = new User(lastName: lastName, firstName: firstName);
UserDTO dto = u as UserDTO;
assertEquals(UserDTO.class, dto.class)
assertEquals(lastName, dto.lastName);
assertEquals(firstName, dto.firstName);
}
</pre><div>Integration test. I want to make sure my controller sends the right data</div><div>The controller:</div><pre class="brush: java">def whoAmI = {
def me = authenticateService.userDomain() // acegi plugin; this returns a User
if (me) {
def dto = me as UserDTO
render dto as JSON
} else {
render [error: "You are not logged in"] as JSON
}
}
</pre><div>The test:</div><pre class="brush: java">class RpcWhoAmITest extends ControllerUnitTestCase {
void testWhoAmI() {
String lastName = 'Lovelace';
String firstName = 'Ada';
User u = new User(lastName: lastName, firstName: firstName)
mockDomain(User.class,[u])
mockLoginAs(u)
controller.whoAmI()
def returnedUser = JSON.parse(controller.response.contentAsString)
assertNotNull(returnedUser)
assertEquals(lastName, returnedUser.lastName)
assertEquals(firstName, returnedUser.firstName)
}
}
</pre><div>And that... <span style="font-weight: bold;">fails!</span> The message is</div><pre>org.codehaus.groovy.runtime.typehandling.GroovyCastException: Cannot cast object 'my.package.User : 1' with class 'my.package.User' to class 'my.package.rpc.UserDTO'
at org.codehaus.groovy.runtime.typehandling.DefaultTypeTransformation.castToType(DefaultTypeTransformation.java:348)
at ...
</pre><div><br />
What went wrong? The call to mock my domain object is what went wrong. It replaces my asType(Class clazz) with its own. Fortunately, that's relatively easy to fix. I needed to override the method addConverters in grails.test.GrailsUnitTestCase to replace asType(Class) only if it didn't already exist (in my test class):</div><pre class="brush: java">@Override
protected void addConverters(Class clazz) {
registerMetaClass(clazz)
if (!clazz.metaClass.asType) {
clazz.metaClass.asType = {Class asClass ->
if (ConverterUtil.isConverterClass(asClass)) {
return ConverterUtil.createConverter(asClass, delegate, applicationContext)
}
else {
return ConverterUtil.invokeOriginalAsTypeMethod(delegate, asClass)
}
}
}
}</pre><br />
<br />
<div>Sadly, after all this work, I deploy, launch, and still get GroovyCastExceptions. It turns out that the instrumentation of domain class objects essentially throws out my "asType()" method. In the end, I switched to the DTO plugin (which post-instruments the domain object to do it's own stuff, something I considered doing, but at some point, the "quick, home-made solution" just isn't.</div>Nancyhttp://www.blogger.com/profile/17327927253598730674noreply@blogger.com0tag:blogger.com,1999:blog-7878631557140971594.post-42594848401961981742010-05-31T08:57:00.003-04:002010-09-14T21:18:41.871-04:00WebCom Part 3The third speaker in the rapid-fire keynotes was Adele <span class="blsp-spelling-error" id="SPELLING_ERROR_0">McAlear</span> with Death and <i>Digital Legacy</i>.<br />
<div><br />
</div><div>That presentation was definitely nowhere near as much fun as any of the other ones, simply due top the morbid topic. It is a brand new domain - what do you with all the electronic assets when their owner (producer, creator) dies? Who has the rights to decide what happens, and how are the service providers handling it?</div><div><br />
</div><div>First, Adele showed us the breadth of our "online footprint". From email accounts to <a href="http://www.flickr.com/"><span class="blsp-spelling-error" id="SPELLING_ERROR_1">flickr</span></a> uploads, blogs, tweets, WOW characters... Each service provider may have different policies for dealing with a deceased person's account, but in reality, only <a href="http://facebook.com/"><span class="blsp-spelling-error" id="SPELLING_ERROR_2">Facebook</span></a> has a stated policy. And what about paid subscription services? When a person dies, the credit card they used to maintain that service is cancelled, and unless a survivor has access to the account, they can't change the credit card on file (I wonder what happens in the cases where the service have "gift subscriptions", such as "buy Person a pro account"). The survivor can't gain access to the account because it is tied to an email account, to which, in all likelihood, they do not have access.</div><div><br />
</div><div>So what solutions do we have, if we want to leave something behind, if not for ourselves, for our friends, fans, followers?</div><div><br />
</div><div>First, we should make a list of our digital assets. What accounts we have, and how we'd like them to be preserved after death. For example, we may want blogs to be preserved or archived, but we may think that our twitter account history is just not worth the effort. We should make sure that our family knows about our online accounts, too, so they know what to expect.</div><div><br />
</div><div>Then we appoint a digital executor. This is someone with whom we will have discussed the matter, and who will be responsible for our digital legacy. This does not have to be same person who will execute our will. Then, we create an email account exclusively for this purpose, and set it up as a "backup email account" for our regular <span class="blsp-spelling-error" id="SPELLING_ERROR_3">emai</span>l account. This way, when the executor wants to take over our main email account, they only have to request a password reset be sent to the backup email account. The password to the backup email account should be kept with our will. From there, the executor will be able to gain access to other accounts by requesting a password reset.</div><div><br />
</div>Nancyhttp://www.blogger.com/profile/17327927253598730674noreply@blogger.com0tag:blogger.com,1999:blog-7878631557140971594.post-77881209432161555362010-05-29T22:29:00.001-04:002010-05-30T23:35:52.132-04:00WebCom Part 2Sean Power, <i>Communilytics</i><div><br /></div><div>Communilytics, is the analysis of how specific information flow through online communities. In his presentation, Sean encouraged us to look a the numbers at a deeper level than simple page-views or the number of followers. But before we can mount a successful campaign, we have to decide what we want the accomplish with that campain: make more money, gain attention/recognition, or improve our reputation. How deeply we want to get involved in the community we're targeting (whether we want to search, join, moderate or run it) will affect which tools and technologies to use. There are 8 social platforms(group/mailing list, forum, real-time chat, social network, blog, wiki, ), with different dynamics, and each can be addressed at different levels of implication. The metrics, then, will depend on the tools used. Each business is different, we know best what's right for our business.</div><div><br /></div><div>He also brought up the AARRR model by Dave McClure: Acquisition, Activation, Retention, Referral, Revenue. </div><div><br /></div><div>He then gave some examples of how information flows through communities. When one person posts a tweet, their followers see it, But if it's a tweet of interest, the recipients may want to let <i>their</i> followers know about it, and re-tweet it. The reach of a message, then is the followers, those who receive the message as a retweet, and those who receive the retweet retweeted, etc. But some people may cross cross social platform - they may put a tweet on Facebook, or send it through email. </div><div><br /></div><div>This presentation is where I also found out the format definition of "going viral". That's when the average number a person tells the message to is greater than one. (So on average, everyone who gets this message will forward it).</div><div><br /></div><div>To get a wide reach, sometimes the best way is to find a few seeds who, because of their respectability and following, will insure a wide, receptive audience for the message. The sites <a href="http://twinfluence.com/">Twinfluence</a>, <a href="http://tweetreach.com/">tweetreach</a> and <a href="http://twitteranalyzer.com/">TwitterAnalyer</a> can help find out the reach of tweeter user and messages.</div><div><br /></div><div><br /></div>Nancyhttp://www.blogger.com/profile/17327927253598730674noreply@blogger.com0tag:blogger.com,1999:blog-7878631557140971594.post-45478022396930898462010-05-25T07:45:00.005-04:002010-09-14T21:19:20.665-04:00WebCom Montreal<div>I was lucky enough to find out about this event a few days before the fact. I only participated in the free portion: 5 presentations of 15-20 minutes about different aspects of Web 2.0 and social networks.</div><div><div><br />
</div><div>Here are some notes and thoughts about the presentations:</div><div><br />
</div><div>Chris Heuer, <i>Serve the Market</i></div><div><br />
</div><div>Originally, organisations served their community: the blacksmith, milkman, general store were all there to serve the needs of the community. The market has now shifted to products. Many still provide a service, but this isn't how we view the market anymore; but we should. He pointed out that how we chose to interact with organisations is through "filters" that become thiner with trust; the more flow, information flow, the deeper the relation, and the more likely people will buy.</div><div><br />
</div><div style="text-align: center;"><b>Serving the market is leadership, not management</b></div><div><br />
</div></div><div>and the parting quesiton, </div><div><br />
</div><div style="text-align: center;"><b>is profit the only purpose of business? or are we able to transcend our current thinking?</b></div><div style="text-align: center;"><br />
</div><div><br />
</div><div>This was a great start. I felt like screaming "Yes!! that's right!!" on many occasions. I think we most certainly can work in a market focusing first on the service we want to render, and that money is not the goal in itself. Of course, we wont be able to provide this service if we don't make enough money, so of course money is important, but all too often, we use money as a measure of our success, and that's a false indicator. The positive impact we have on our community can be in the form of the product or service rendered, but it can also be in terms of providing employment, and spreading a little bit of happiness to clients, employees, and to every member of the community.</div><div><br />
</div><div>Next: Sean Power, <i>Applied Communilytics In a Nutshell</i></div>Nancyhttp://www.blogger.com/profile/17327927253598730674noreply@blogger.com0tag:blogger.com,1999:blog-7878631557140971594.post-79975911326444244992010-05-20T20:30:00.000-04:002010-05-20T20:30:27.422-04:00MotivationFor most software developers, programming is more than just a way to earn money. What puts a smile on our faces as we think about upcoming tasks? What makes us think about the current problem when we wait in line, while we're driving, or as we fall asleep? Sure, we do it because it has to be done, but often there are much more personal reasons. Where does the satisfaction come from? We are all different, and different things make us tic, but all the cases fit in 3 categories: personal, interpersonal, and global. The fun is in figure out who we are based on what's important to us<br /><br /><span class="Apple-style-span" style="font-size: large;">Personal<br /></span><br /><div><ul><li>Feeling smart: This is a very good feeling, whether it's because we've beat the machine into submission, or because we've found a whole new way to use an old tool. It doesn't mean outsmarting another person, but lining up ideas in a productive way</li><li>Aesthetics: Coming up with a beautiful, elegant design. Simplifying something complicated. Making all the parts fit nicely</li><li>Achievement: Going beyond our abilities, taking it one step further</li><li>Learning: New tools, new ways of thinking. We prefer learning things that change how we thinking about the problem. The more ways we can shape our minds around an issue, the more likely we can come up with an elegant solution; or a solution at all.</li><li>The big "DONE" stamp: when we get to say something is done, out the door, complete. Sometimes we have to compromise - we'd like to tweak this a bit more, or refactor that, but like an artist, talent isn't only knowing how a piece can be made better, but also knowing when to stop.</li><li>Glory: well, okay, that's pushing it a bit, but the recognition of others, whether our peers, customers, or the whole wide world is a very powerful motivation.</li></ul><span class="Apple-style-span" style="font-size: large;">Interpersonal</span></div><div><br /></div><div>We are often seen as solitary workers, but in truth, our job cannot be done totally alone. We value good relations with our coworkers, mentors, employer, and clients.</div><div><br /></div><div><ul><li>Coworkers: we often need to rely on others, whether to show us what they've done, to discuss an idea, or do share the workload. Good relations with them come from listening to ideas, asking question, and pointing out issues in a respectful manner. It works even better when we can be friends with our coworkers, and spend time together outside the work environment, but that's not necessary.</li><li>Relations with the employer can be very productive when we know what's expected of us, what the boundaries are, and when we know we can meet our targets. We much prefer having some freedom in how we attain these objectives, and when we have input in setting the targets. When employees are asked to set the target themselves, they tend to shoot for higher accomplishment, and they are more likely to reach them. This is true not only for software developers, but in pretty much any field.</li><li>Clients (in a consulting or customization setting) are also part of the interpersonal aspect of a developer's life. Some of us hate talking to the client, but for others, knowing the person who will use the product, knowing how they will use it and why, can help us propose solutions they may not have thought of. It may require us to think differently, to use a different language so we can truly connect with the client in terms they understand, but that just keeps our minds nimble.</li></ul></div><div><span class="Apple-style-span" style="font-size: large;">Global<br /></span></div><div><br /></div><div>For some of us, the greater good is what drives our actions. We can make a difference by the work we do, whether it's through software that favors sustainability, the people we're helping, teaching/education we support, the time our software will save thousands of people, the list goes on. We all have causes we support, some more ardently than others, and when our work allows us to promote them, or help them along, we derive even more satisfaction from our efforts. We build a legacy, even if it's all too often anonymously.</div><div><br /></div><div>Clearly, money is not the only reason we develop software. If it were, there would be no Open Source movement.</div><div><br /></div><div>We all feel the pull of these motivations differently. For some, doing good for goodness's sake is plenty; others want recognition. I'm generally motivated mostly by the personal and interpersonal aspects of the work. I value the recognition of my peers more than that of the population at large.</div><div><br /></div><div>What motivates you?</div><div><br /></div>Nancyhttp://www.blogger.com/profile/17327927253598730674noreply@blogger.com0