In Agile, there’s no design. Everyone knows that. So why is there so much design in Agile, and how can they go so fast?

For The Record
The blurb is lying when it says there is no design in Agile. It’s not lying when it says there is so much design in Agile, and the answer to the last question is “because there is so much design in Agile”.

Of course, if you read my stuff at all, you know that I’m always thinking about the design, feeling whether the code is helping me or getting in my way. You know that when I find that it’s getting in the way, I improve the design to make my work easier. I try to be designing all the time that I’m at the keyboard.

As GeePaw Hill puts it, “the code works for you, you don’t work for the code”.

The trick with going as fast as we reasonably can is to be working with a design which is as close to “just right” as we can make it. To do that, we start with a simple design, just enough for our first story, and then we enhance and improve the design as we go along. When the design doesn’t get improved enough as we go, we slow down, because we’re working with code that doesn’t want to do what we want. If we pay attention to how things feel when the design is with us and when it’s against us, we can detect very quickly that things are getting out of line.

Detecting it isn’t the same as fixing it. Often, even though we know better, we just need to get these one or two things done and then we can work on the design. So the design we have and the design we need get further apart, and we become less likely to bring them back into alignment. It is easy to fall into that trap. I fall into it often, probably every day.

In defense against that very human trait, I also think about the design in my copious free time, such as the minutes between waking up and getting up. For me, that often gets me to the keyboard with a good idea and a renewed focus on improving the design, and I do a little improving before I get down to the next story.

Your own approach needs to fit your style and habits. Not everyone gets up at oh-dark-thirty ready to code. But if I gave recommendations, which I do not, I would recommend that folks develop a habit of thinking about the design, and finding a time during the day when they have the energy to do something about it.

Sorry. It is Sunday. We often get a bit of a homily on Sunday. And on other days. Let’s talk about today’s design thoughts, before I forget them.

Hexes and Squares

Naturally, since I’m facing the somewhat daunting task of getting the Dung program to work with both hex and square tiles, that’s on my mind. So this morning, when most people would be going back to sleep, or doing something more earthy, I was thinking about my Tiles.

Recall that the Dungeon has a collection of Tiles, and that Tiles have rather a lot of functionality, across more areas than is probably ideal. They are central to the design, but not as cohesive as they might be.

Now I have been thinking and writing about the new design, and working in the direction of the Tile having, owning, a Hex or a Square, and deferring various operations down to that object. And the D3 spike has implemented Hex, and Square, and some Point and Direction objects to match.

What came to me this morning was the idea that maybe we don’t need Hex or Square at all. Tiles now contain x and y, as well as a contents collection and some properties like whether they are a floor tile or a wall tile, and whether they are visible. So it came to me that maybe all we need to change is the x and y.

What if we replace x and y with a Point, either a CartesianPoint or a HexPoint? And what if we moved between Tiles by always using a Direction, either a CartesianDirection or a HexDirection?

To that point, what do we do now? Interestingly enough, a button press converts to a w, a, s, or d, and that letter is looked up in this table:

PlayerSteps = {a=vec2(-1,0), w=vec2(0,1), s=vec2(0,-1), d=vec2(1,0)}

And that value is sent to moveBy, which looks like this:

function Player:moveBy(aStep)
    self.runner:resetVisibility()
    local tile = self:getTile():legalNeighbor(self,aStep)
    tile:moveObject(self)
    tile:illuminate()
end

The legalNeighbor method returns, either the current tile, resulting in no move, or the targeted tile aStep away. Ultimately, we fetch that new tile like this:

function Tile:getNeighbor(aVector)
    local newPos = self:pos() + aVector
    return self.runner:getTile(newPos)
end

What have we here? We have a Point and a Direction.

There’s a bit of foofaraw here, because the tile doesn’t know its collection, so it asks the runner, which asks the dungeon, which knows how to index the collection:

function GameRunner:getTile(aPosition)
    return self:getDungeon():getTile(aPosition)
end

function Dungeon:getTile(pos)
    return self:privateGetTileXY(pos.x, pos.y)
end

function Dungeon:privateGetTileXY(x,y)
    if x<=0 or x>self.tileCountX or y<=0 or y>self.tileCountY then
        return Tile:edge(x,y, self.runner)
    end
    return self.tiles[x][y]
end

So there I was, at oh-dark-thirty1, thinking that if I were to plug hex arithmetic into that self:pos()+aVector, the whole game would start drawing its little squares on hex points instead of cartesian. It would look odd, but it seems that it should “just work”.

Therefore, What?

Well, therefore, that’s what I’m going to try. Not today, though. Today is Sunday, with its special rituals around breakfast and old-people TV like CBS Sunday Morning and such. And I don’t want to program and write about it today, I just want to write about thinking about programming.

There remain at least a few little concerns, and I’m sure there will be a fair number of surprises. We’ll certainly need to work on illumination, and on distance calculations. But those will all be local changes. Even illumination, which is hard to get right, is an isolated bit.

One concern that is on my mind is that I’ve been building up my hex map in concentric rings, and the square tile map is built in a rectangular array of rows and columns. Since vectors work, even our cubic ones, the shape of the overall map shouldn’t matter, and we just saw in the code above that we return “edge” whenever we access outside the map.

But I’m still wondering if I’d rather have a pseudo-rectangular hex array. And I’m drawn by the two coordinates, x and y, toward the two-coordinate form of hex addressing, “axial” coordinates, which just take two parameters, usually called q and r. It just seems like the similarity in handling might be nice.

But I suspect that’s an illusion, because axial coordinate directions and addition don’t really work the same as cartesian. My current plan is to resist that temptation, at least as far as storing things by tab[q][r] goes. It might be worth working out the math for q-r. That said, my current storage scheme, though odd, is probably just fine.

As a reminder, I store the hex (21,35,42) at the string key “21,35,42” in a table. This was a bit of ad-hocery that has so far not been a problem. We would create quite a few strings this way, so maybe something else would be better, but at this moment I don’t have a better idea.

Enough. Let’s sum up.

Summary

The bottom line is “thinking is good”, and sometimes, thinking while not typing is useful. If I had set out to follow yesterday’s plan, I think it would likely have gone well enough, but today’s idea seems solid, and certainly simpler.

Tomorrow, all things being equal, I’ll try it. Unless I decide to spike axial coordinates first. Why? Because I could perhaps store them more easily. And I know that Amit recommends axial, with conversion to cube as needed. But the conversion the other way is easy as well. If I really want to store [x][y] and [q][r], it’s easy to get q and r: they are x and z.

We’ll see. Maybe the thing is to spike better ways of storing. But why? The one we have will work. If there’s a problem, it’ll be isolated to one or two tiny classes.

Yeah. If I’m a good person, I’ll start plugging in coordinates tomorrow.

See you then!


  1. “There I was, naked as a jay bird.” – GeePaw Hill