Monthly Archives: March 2009

Getting to Cadence

We are on the verge of catching a stride on the SnupNow team. Yes, that is me doing positive self-talk. We have a team that I believe will gel, but has not yet, so I am about to add ice. [Yes, I know there is a very small audience for that comment of those who have ever had to speed up jello.]  Several decisions I made have contributed to this pace, and I am not sorry I made them. I am in this for the long haul, and I know it will take persistence.

DECISION: I decided not to write software alone. I just snipped a justification for this decision. Some of you will understand without such, and those who don’t understand will be bored by the rationale.

DECISION: I decided where to go to seek angel developers (sweat-equity partners). I went to the group that I know and that knows me, the MultiValue (MV) space.

DECISION: I selected a not-yet-generally available platform. Cache’ is the newest and most expansive of the MV offerings. It is expansive because it was there before the MV feature set was added. It is bigger than MV and includes an AJAX framework, with the combination of AJAX and MV in general availability as of the last quarter of last year. 

DECISION: From those who applied to be partners, I ended up selecting and/or being selected by only people who live more than 10 hours away from me and from each other by car. The two closest currently active developers are more than 8 hours apart. Everyone has met me, but no two other developers have met each other, ever.

DECISION: I did not require that developers have all necessary skillsets before joining up. There are many reasons for this, but I’ll just mention one. MV developers typically do not chase technology, they solve business problems. They are more likely to understand the complexities in a name, address, and birthdate, along with more complex requirements, than be able to list the latest buzzwords. Most of the other team members have no object-oriented programming background, nor javascript, css, and in some cases no html or xml either. None of us have ever worked with Cache’ before. All are seasoned professionals, which, by the way, is what I call myself instead of saying that I’m an old coot.

I knew it would take some time to form this team. I did not know how long it would take developers working only a few hours a week to be ready to jump in, whether due to their time constraints, the learning curve, the fuzzy requirements and high level design, if any, or perhaps not finding the project fun or satisfying while in the learning curve.

Teams take time to form, even longer with a distributed team of seasoned professionals working odd hours who have never met each other and are working with tools they do not know, oh, and who are not getting paid actual money.  

Now for a team update.

I mentioned Bonnie earlier, prior to her dropping off the planet. After my failed attempts to reach her just to be sure she was OK, figuring she had decided not to participate, but prefering that such things be stated, I asked Ken to try. Ken knew Bonnie a little bit and had suggested we talk to her initially, and he didn’t know what happened to her either, but she never got off the ground in working on the project after her machine died early on. I told him I just wanted to be sure that nothing bad had happened, since it didn’t seem like she would just cut out without taking my calls or responding to emails. As it turns out, it was one of those “mom  has reason to worry” moments. It seems she was hit by a car, which is the most fantastic excuse coming from this team yet. It beats Bobby’s email to me this past week about missing our Saturday morning meeting:

“hey Saturday morning I was working outside on my workshop and put a framing nail through my left hand with a pneumatic nailer.  After trip to ER, I’ve been in and out all weekend on hydrocodone.”

Well, Bonnie had just returned from the hospital and was back to work when Ken touched base with her there. She had been in the hospital for 3 weeks. With a need to recover, among other things, she said she would not be joining us at this point, which is definitely understandable.

WOW, bummer. I certainly wish her the best in her recovery, and I am glad we finally heard from her. I’m thinking I should get the email address for the spouses or a friend of each partner. If someone is not responding, what do I do? I had this with one other partner early on and simply dropped him from the company when I had done due diligence. I’m pleased that I have met the spouses of all those who are active on the project. 

Active might be an overstatement. At this point, I think that five of us have contributed at least one line of code into at least one of the 25 builds we have had. Tom has contributed a lot more than that. Ken has worked on other aspects of the project and has contributed code, and Bobby and John are just beginning to write code. If we add them all up, I would estimate that about 10% of the deployed lines of code in our current build came from these 4 partners. 

When setting up the structure of the company, I computed my expected worth at a 5 (think “days”) with the total for these 4 developers of 6. The 90:10 current ratio compared to the anticipated 5:6, or 1:1 ratio (when factoring in communication) doesn’t mean to me that I computed incorrectly, but rather that we have not yet hit that stride. These guys are good at what they do in their day jobs. They will get good at snupping too and at fitting it into their routine. We will get there.

We are still in a very-un-Silicon-Valley-like gear-up phase, as some of those watching might think that more than a year is too long. We have no venture capital. While we do not have our initial software offering written yet, we keep moving forward, not spinning. We are simply moving slowly. We need to hit a stride, find our cadence.

To mix things up a bit, I am hoping to hire a college student as a contract programmer to significantly alter the average age of the development team, hopefully also writing some code. This would give me someone local and actually paid to work. I do not have a lot of cash for such an arrangement, so if you hear me indicate that I’ve taken any paying gigs in the future, it is not a lack of sticking with this project. I met with a student yesterday who I am hoping will jump in. He asked no questions and took no notes when I gave him a quick tour of the development environment, and yet I was pretty sure he caught on. There is something to be said for youth.

We also have two developers as owners (partners in the LLC) who are sitting on the bench by their own choice right now, and I am letting them do so by my choice at this point. Occasionally I make an effor to entice one or both to join us. Eventually they will, or not.

There is one more not-yet-a-partner who might sign on for a 1/4% of the company (not to be confused with 1/4 of the company), who is a long-time colleague from all those years ago working at the University of North Carolina, Chapel Hill (go Tar Heels). He is a one-man team with two software products, live ones, with paying customers and everything. He was a VP of a software company before starting out on his own. I have a weekly phone call with him to discuss our respective challenges.  In the plus column for him, he has revenue. In the plus column for me, I can go on vacation without figuring out how customers will be covered during that time.

I can see I’m writing too much right now, so I’ll mention what is working and save what isn’t for a rainy day. Some of the tools that are working and will help us get to that point of being a gelled team are:

Instant Messaging.  I use digsby, others use pidgin, sometimes gmail chat from the day job. This is how we know who is “in the office.”

Trac. We use this for requirements, tasks, and bug-tracking “tickets” as well as our project wiki. We are install the agilo add-in soon.

Conferencing. Occasionally we have used Go To Meeting or other meeting software, but I’ll admit we have typically used someone’s free days.

Phone conferencing. We use nocostconference.com for a weekly conference call where everyone available calls in, typically with their free mobile phone long distance, while some have to pay a little for the call.

VC/m. Version Control from georgejames.com. This has been very helpful from a team perspective since people know whether someone else is working on a class or not. I mentioned it in https://snupnow.wordpress.com/2009/01/04/software-builds-if-we-build-it/

I was going to mention techniques that have helped and some that have not, but I need to wrap this up and click Publish ASAP. I’m headed out on vacation tomorrow after our SnupNow meeting tomorrow morning. When I return, my top priority will be to help our team get into a groove, find a cadence. More important than that, however, is that I get to hit the road tomorrow to go see Cady, our beautiful 7-month old granddaughter. I just can’t wait to get to Cadence!

Let’s Just Have a Party

If you are one of those folks who has never dealt with normalizing data for an RDBMS implementation, then count yourself among the lucky. Because I have, I can feel blessed to work with an object database (yeah, that’s what the marketing lit says, so I can roll with it) like Cache’ or any other MultiValued database tools.

A Party is a person or an organization. We don’t always care whether an organization or person is purchasing something, for example, so there are reasons to abstract these into the same entity in our data model. Take a look at what the RDBMS folks think is good form for an implementation of a Party

http://www.tsjensen.com/blog/2009/01/03/Party+Role+And+Party+Type+In+Data+Model.aspx

That’s six tables before getting to phone numbers, addresses and other demographic data about the party. Now, guess how many MultiValue files, specified by Cache’ classes, I made for pretty much this same data. Since I know I advertised this blog very narrowly, I think you guessed it on the nose. One. Uno.

While there is just one file for the data about each Party, whether it is an organization or a person, there are other related files, of course. There can be multiple Profiles (aligned with an e-mail address) or multiple Orgs (aligned with a URL home page).

How can we get away with such simplicity when the RDBMS folks have such complexities? Simple, we cheat. We, that being I, break the rules as taught to CS majors around the world. There are three or four rules I broke here on purpose, depending on how you count them. If there are others, then, well,  oops, my bad.

First, I allow null values (yes null values not to be confused with nulls because I am using two-valued logic, see http://www.tincat-group.com/mewsings/2006/03/better-to-have-no-values.html) and violate “the key, the whole key, and nothing but the key” by putting First and Last name fields in the Party record. These have a value of “” in the case of an Org and have first and last names in them in the case of a person. So sue me.

To top that off, there is a full Name field in the Party record too, not to be confused with a Name column in a Party table (at least smile when you read that). And get this–when this is a person, that Name is derived from the First and Last names and then stored.  Hah, redundant data, gotta love it.

Not only did I violate those arbitrary RDBMS rules that we continue to teach as if they were sent to Moses on tablets, I also violated an Agile development rule of thumb on that one. A possible future feature is to permit someone to have a first and last name that do not sum up to their full name. The full name could include a title, for example, or they might wish to use a nickname in one place or the other. If such a feature were to be implemented, the redundancy would go away, and having thought past my nose would have paid off. In the mean time, I can do a listing of all Parties with Names and see names for both people and organizations, which means this name field will come in handy in many places, I suspect, redundant or not.

That’s two or three, depending on whether you count the “” and functional dependency issue (only people have First names, not orgs) as one or two violations. The final one is more obvious, perhaps, in that I have a multi-valued list of phone numbers. I am using an MV database, after all. A list of phone numbers and types (an associated multivalue in MV terminology, an embedded child table) is sitting right there in the Party class. RDBMS data modelers don’t typically muddy the waters by showing phone numbers when showing a Party pattern, but I had to do a real implementation, not just pictures of one. Plus, there is no need with MV to have yet another class/table/file for phone numbers and types. 

Additionally, if we ever need those Roles (so far I’ve kept them out), we can add ’em in, but when someone needs to select from organizations, they select through the Org record, which points to a Party. Most other foreign keys are to the Profile or Org records, not to Party, unless we don’t care if it is a person or an organization, which was a reason for pouring them together in the first place.

There has been no need so far to determine based on simply the Party record whether it is a person or an organization, but if we ever really needed to do so, I can tell them apart. The right way to do so would be to see if there were Org or Profile records associated with the Party record (there must be one or the other and cannot be both), but cheaters know, although the DBMS does not, that those First and Last names are required for people and always empty for Orgs. Yeah, I really do know how wrong that is, and yet…

Are you disgusted with me? Ah phooey. I’m having a bad day anyway, so what do I care? It was such a bad day that I thought maybe I could put a smile on both your face and mine if I invited you to my Party. It’s a small Party–just one room. You can see its class diagram by drawing a square on a piece of paper and writing Party in the header. Oh, and could you shake me up a vodka martini? That’s all I need now–one square and one triangle is all I need to be one Party girl.

About One Simple Page

The following is the simplest page class in our current build. This might be of interest only to SnupNow team members getting started with coding in Zen, but I figured I would put it out here for anyone else interested too. First I’ll show the source code for the class, then show an altered picture of the page (where you can see what has been grayed out), then add a few comments regarding the code.

This page is not in its final form. [What software is?] One of our open tickets is to swap the tabs, adding a tab so a user can submit comments or questions. Before we do any of the pending enhancements, this should be good for showing a minimalist page. This page was written using the Cache’ Zen framework.

There are links to each of the tabs on this page on every page, including this one. You can see them at the bottom in the screenshot. While it might be nice to remove those when on this page, I’m not planning to do that. Sloppy? I don’t think so. Consistency has its charm too. I do see that I put copyright information on this tab and have it at the bottom of the page. That would be OK, I guess, since that is About information, but having two different dates–now THAT is sloppy. Details, details.

With apologies for some of the format here, particularly the loss of indents, if you review the code below, you will get an idea of the structure of a page class.

/// About Page, Keep build number accurate here
Class About.StartPage Extends Util.Template.Page [ Language = mvbasic ]
{

/*
* About.StartPage
* ******************
* Change History *
* Name…… Date…… Summary of Change…..
* dawnw 2008/09/16 Created [other change comments have been removed]
* ******************
*/
Parameter APPLICATION = “About.App”;

Parameter PAGENAME = “SnupNow, About”;

Parameter CSSINCLUDES = “../../dev/page-template.css,../../dev/page-about.css”;

Property ClipboardTitle As %ZEN.Datatype.string [ InitialExpression = “About” ];

Property ClipboardInstructionsName As %ZEN.Datatype.string [ InitialExpression = “About” ];

Property tabby As %ZEN.Datatype.integer(ZENURL = “tabby”) [ InitialExpression = 1 ];

XData vcontentPane
{
<pane xmlns=http://www.intersystems.com/zen&#8221; cellSize=“stretch”>
<tabGroup id=“tabGroup” showTabBar=“true” onshowTab=“zenPage.updatebuttons” remember=“true” cellStyle=“padding:20px”>
<tab id=“tab1” title=“tab1” caption=“About”>
<pane paneName=“Tab1Pane”/>
</tab>
<tab id=“tab2” title=“tab2” caption=“Contact”>
<pane paneName=“Tab2Pane”/>
</tab>
</tabGroup>
</pane>
}

XData Tab1Pane
{
<pane xmlns=http://www.intersystems.com/zen&#8221; xmlns:s=http://www.snupnow.com/component&#8221; >
<s:form id=“bform” name=“bform” groupClass=“snupform” enclosingClass=“snupencform”
width=“570px” labelPosition=“top” hidden=“false”>
<label controlClass=“componentTitle” enclosingClass=“componentHeader”
value=“SnupNow is brought to you by the Snupnow LLC team” />
<s:fieldSet id=“bfieldset” groupClass=“snupfs” enclosingClass=“snupencfl”
labelPosition=“top”>
<label controlClass=“componentSubtitle”
enclosingClass=“componentSubheader” value=“SnupNow 0.1.22” />
<hgroup height=“1” />
<label value=“SnupNow Version 0.1 Build 22” />
<hgroup height=“1” />
<label value=“Copyright©2009 Snupnow LLC” />
</s:fieldSet>
</s:form>

</pane>
}

XData Tab2Pane
{
<pane xmlns=http://www.intersystems.com/zen&#8221; xmlns:s=http://www.snupnow.com/component&#8221; >
<s:form id=“aform” name=“aform” groupClass=“snupform” enclosingClass=“snupencform”
width=“570px” labelPosition=“top” hidden=“false”>
<label controlClass=“componentTitle” enclosingClass=“componentHeader” value=“Contact Us” />
<s:fieldSet id=“afieldset” groupClass=“snupfs” enclosingClass=“snupencfl” labelPosition=“top”>
<label controlClass=“componentSubtitle” enclosingClass=“componentSubheader” value=“Contact Information” />
<hgroup height=“1” />
<label value=“Send questions or comments to snupnow at gmail dot com” />
<hgroup height=“1” />
<label value=“Or feel free to contact:” />
<hgroup height=“1” />
<label value=“Dawn Wolthuis, Managing Partner of Snupnow LLC” />
<hgroup height=“1” />
<label value=“Mobile: 616.901.6293” />
<hgroup height=“1” />
<label value=“Email: dwolt at tincat-group dot com” />
</s:fieldSet>
</s:form>
</pane>
}

Method %OnDrawHTMLHead() As %Status
{
print ‘<meta name=”description” content=”About SnupNow”>’
print ‘<script src=”http://www.google-analytics.com/urchin.js&#8221; type=”text/javascript”>’
print ‘</script>’
print ‘<script type=”text/javascript”>’
print ‘ _uacct = “UA-removed;’
print ‘ urchinTracker();’
print ‘</script>’
return 1
}

Method onloadHandler() [ Language = javascript ]
{
gotab = zenPage.tabby;
if (gotab != 1)
{
zen(‘tabGroup’).showTab(gotab);
}
return
}

}

A Screenshot

This is an unrefined page, but it looks pretty enough with our new look, designed by an actual graphic designer. As I knew most, perhaps every, web page designer would, he objected to having objects on the far left and others on the far right, with the white space between them, but this girl has her reasons, which we can discuss sometime.

About Page

About Page


Comments:
/// About Page, Keep build number accurate here
The three-slash comments show up in the DocBook view of the page. While this might be ho-hum for some, and I took it for granted when writing Java classes, I am delighted to have DocBook included in this platform with no work from us. We can view the doc for classes in libraries delivered by InterSystems the same way we can view doc about our own classes.

The class declaration: Class About.StartPage Extends Util.Template.Page [ Language = mvbasic ]
About.StartPage.cls is the “fully qualified” name of the class, with About being the package name. The “.cls” is used in the name in the URL to this page, where in many other places the page is referred to as simply About.StartPage.

You might wonder where the upper right hand menu and the footer are in the code since they are not specified in this class. They are specified in a superclass of this one. The hierarchy is that this class extends (aka subclasses) the Util.Template.Page. Every page in our current build subclasses Util.Template.Page, either directly or by subclassing Util.Template.SecurePage, which is a subclass of Util.Template.Page.

The template includes a bunch of possible clipboard links along the right hand side so that the css for this page “turns on” the ones that will show on this page. Everything above the tabs, the right hand side of the page, and the footer are all specified in the superclass. Every page in our current build is all about the tabs, with forms, tables, and various user interactions going on within that tabbed pane.

There are some methods in the template to do common functions, such as putting instructions on the page. You might wonder about having the javascript logic in this page for showing the second tab instead of the first based on a URL parameter, rather than putting that in the template for all pages to use. This is the only page we currently have where we link into something other than the first tab (by adding ?tabby=2 after the URL), however, so there has been no need to abstract this logic to date.

The class declaration includes [ Language = mvbasic ]. Unless otherwise specified, every method in this class will be written in MultiValue BASIC, aka DataBASIC.

The change history comment block:
/*
* About.StartPage
* ******************
* Change History * etc
This block can go into any source code — any class, external stylesheets, external javascript documents, and MVBASIC subroutines, for example. The latter is the reason for the asterisks at the start of each line, with the outer /*   */ comment block lines removed in that case.

One thing to get accustomed to with these Zen pages is that there are so many ways to put a comment in the code, and how you can specify a comment depends on where you are in the code. If you are in the XData section, written in XML, you use those funky XML comments <!– comment here –> while if you are in the class structure you have three-slash, two-slash, and /* comment here */ style comments. In a JavaScript method you have typical js comments and in an mvbasic method you have typical mvbasic comments.

Everything else:
You can see how much I can write about the class declaration and the comments above and below it, so I’ll stop here with the explanations except to indicate the outline for the rest of the class. We have a block of Parameters (for the compiler) and Properties for the class. Following that is a section of XML, specifying our tabs and what is on each tab. Following that are any methods we have, typically with mvbasic methods first, followed by javascript methods. Most of our classes have far more of these than this one has.

This tour of a Zen page might not have been very entertaining, but should give a hint at the framework we are using for building our software. [Hey Dawn, why do you call it software when it is just a web site?]