Since I tend to be lazy, err... I mean efficient, I tend to communicate through pictures.
Whether brainstorming, planning or conveying ideas, I spend a lot of time at the whiteboard. At the end of one such session, a team member will snap a picture of the board and drop it into our corporate wiki.
From there, two things can happen. Either a zealous developer (or architect), will make a beautiful diagram out of the picture (we use omnigraffle which by the way I highly recommend as an alternative for visio). Or the picture will not get touched until someone needs it, and since my white board handwriting is a step down to my already poor handwriting, it will most likely leave the reader guessing as to what exactly we meant then.
Clearly, having a diagram buff is the better of the two options, but doesn't go without drawbacks: it's easy to get side tracked (gradient background anyone?) and waste precious time.
There's an alternative to drawing diagrams by hand. For example graphviz is a great tool to generate renderings of oriented graphs. It uses a domain specific language call 'dot' which looks like this:
digraph G {
start -> a0;
start -> b0;
a1 -> b3;
b2 -> a3;
a3 -> a0;
a3 -> end;
b3 -> end;
}It supports all sorts of cool features which you can discover here, but again, it's not specific enough and always end up fiddling with fonts, colors etc.Finally, there's an interesting website I stumbled upon recently called yuml.me. It is essentially a web service to generate UML diagrams. The bummer is that there are 3 diagram types supported so far: activity, class and use case diagrams. Most diagramming I do revolves around components and their interaction. Close but not quite.
Wouldn't it be great if I could express components, interfaces and interactions using domain specific notations too? Maybe something like this:
ICustomer, IXML [Customer] IOrder, IXML [Order] [Customer] persitence -> IPersistence [Persitence] [Customer] orders -> IOrder [Order] [XML] convertCusts -> IXML [Customer] [XML] convertOrders -> IXML [Order]The syntax above language can be defined as follow (using a pseudo-BNF notation):
<identifier> ::= [a-zA-Z]+ <componentid> ::= "[" <identifier> "]" <relationid> ::= <identifier> <interfaceid> ::= <identifier> <expr> ::= [<component> <relation> "->"] <interface> <component> <multiexpr> ::= <expr> [ <exp> "\r\n" ]*Then, translating to Scala using the parser combinators library:
class CDiagram extends JavaTokenParsers {
def identifier = "[a-zA-Z]+".r
def component = "[" ~> identifier <~ "]"
def interface = identifier
def relation = identifier
def interfaceRefs = repsep(interface, ",") ~ component
def relationDef = component ~ relation
def expr = opt(relationDef <~ "->") ~ interfaceRefs
def multilineExpr = rep(expr)
}As you can see, it's pretty close to the BNF notation (complete source)."[a-zA-Z]+".r : regular expression matching a series of 1 or more letters.
a ~ b: matches a followed by b
a ~> b: matches a followed by b where a is relevant only to the syntax (and discarded at interpretation time)
repsep(a, b): matches a repetition of a separated by b
opt(a): matches a optionally
Very little more magic is all it took to build a converter between the diagram DSL and the dot language. Here's an example of the dot output:
digraph G {
node [shape=record];
Customer[label="{<icustomer> ICustomer|<ixml> IXML} | \<\<component\>\>\nCustomer"];
Customer -> Persitence:IPersistence [label="persitence"];
Customer -> Order:IOrder [label="orders"];
Order[label="{<ixml> IXML|<iorder> IOrder} | \<\<component\>\>\nOrder"];
Persitence[label="{<ipersistence> IPersistence} | \<\<component\>\>\nPersitence"];
XML[label="{} | \<\<component\>\>\nXML"];
XML -> Customer:IXML [label="convertCusts"];
XML -> Order:IXML [label="convertOrders"];
}And here's the final rendering:
You can access the full source code for the whole example runnable using SBT on github.
Nice work, Anthony! Looking forward to playing with this.
ReplyDelete@Thomas There's a whole lot more coming, stay tuned!
ReplyDelete