Welcome to MSDN Blogs Sign in | Join | Help

Individual Empowerment and agile...

(Interestingly, I find myself writing more about agile and team stuff now that I'm not on a development team....)

 

This is in response to a question about how you balance individual empowerment with the collaborative approach on a agile tem... 

 

*** 

 

Agile is all about the team, and being on an agile team requires participants to give up some autonomy towards the team. The team is empowered to do what they need to do to reach their goal. If there are issues around how things should be done or what decision is right, the team needs to come to a decision, and I would encourage management to let the team try to do it.  Further, the team needs to “meta rules” around how to make decisions, and they also need to develop those.

 

This is very different than the “alpha geek” culture that exists in some groups, where a small number of developers are interested in wielding power. There are some individuals who just aren’t willing/able to work collaboratively – I’ve worked with a few, and if you are trying to run an agile team, they are likely better in a different position.

 

One of the teams I was on basically came to this agreement:

 

Developers are expected to use their best judgement when deciding what advice to seek when they are doing development.   There are no rules around when you should seek advice, but as a rough guideline, extending functionality under existing patterns is something you can safely do on your own, and big refactorings or new components are areas when you should definitely seek advice. In between, think about the implications of any design choices you might make, and act accordingly.

 

The other approach is to adopt pair programming, which is a bigger cultural change, but generally if you get two people thinking about decisions they usually make the right decision about involving others.

Posted by ericgu | 1 Comments
Filed under: ,

HealthVault Vocabulary Browser

I wrote a little utility to browse vocabularies that I thought you might be interested in.

It uses the HelloWorld app id, so you should just be able to dump it to a directory and run it.

Posted by ericgu | 1 Comments
Filed under:

Being greener

For most of my life, I've been a "small e" environmentalist. I'm not outspoken on my views, but I really hate to see needless waste. For me, that's meant keeping cars for a long time rather than replacing them, spending a little more on stuff that will last so I don't need to throw as much stuff away, and getting books at the library. Stuff like that.

I haven't, however, put as much effort into applying the same principles to my profession, and over the past few months, I've been working to be more reasonable in that area as well.

I've come up with a few practices that I thought I'd pass along, as part of what I'm calling "Green Programming - Simple practices to make the world a better place..."

Practice #1:

Consider the following code:

    if (x > 5)
    {
        i++;
    }

Now, if I need to change it so that 2 is added to the value of i rather than one, I would probably do the following:

First, I'd select the line with the increment:

    if (x > 5)
    {
        i++;
    }

hit "delete":

    if (x > 5)
    {
    }

and then type in the new line:

    if (x > 5)
    {
        i = i + 2;
    }

I've done that sort of thing millions of times in my career. But not any more. Here's what I do now:

First, delete the characters that I no longer need. In this case, it's just the second "+" sign:

    if (x > 5)
    {
        i+;
    }

 then, insert " = i "

    if (x > 5)
    {
        i = i +;
    }

 and finally, " 2":

    if (x > 5)
    {
        i = i + 2;
    }

In my first version, I deleted 12 characters (plus a carriage return and linefeed), and then added 20 new characters. With my new approach, I deleted 1 character and added 7 characters. That small change reduced my deletion percentage by 91.67%, and my new character percentage by a less impressive but still impactful 65.00%.

Practice #2:

The first practice made some great improvements, but I thought there was more to be had. I found that I could keep open a session of notepad, and rather than deleting the characters from my code, I would copy them to notepad, for possible reuse later. Unfortunately, since I write a lot of new code, I tended to exhaust this resource fairly quickly, and was forced to fall back on typing new characters.

Practice #3:

To give me a better source of recycled characters, I came up with a new approach. Not only do I copy characters to notepad before deleting them, when I need to delete a source file, I copy *all* of it's contents to my notepad buffer before deleting the file.

I am proud to report that I now am justified in believing that I am "character neutral" in all of my coding. That made me quite happy, until I realized that I still had a problem.

It was my blogging. I tend to write a fair bit on my blogs (3-5 depending on how you count them), but because of my natural eloquence and low quality standards, I rarely delete stuff, and therefore keeping a buffer for my blog writing was problematic. I tried using my programming one - it certainly is sufficiently full that it won't run out quickly - but I found that I tended to have some problems with expression ("I regret I have but one life to give foreach my country"), not to mention developing having to write lines like this:

(){=();="");(<,>){=.;=..;=..;<>=<>();(());(..()){=;}}

to use up some of the excess punctuation.

So, that clearly wasn't workable, but just yesterday I came up with a great idea. I'm now recycling all the contact spam that is *already generated* by my blog into my blog buffer, and I'm considering re-using the splog links I keep getting, which would be especially convenient as they already have the words that I like to use.

So, that's my little contribution, because as I like to say, if you're not part of the solution, you're part of the problem. Or the precipitate.

Future Ideas:

I haven't thought all of these through fully, but here's a list of other ways you might "recycle and reuse":

  • Don't throw away that command window you're using and create a new one. Reuse the existing one.
  • Keep old classes around to use as the starting point for new ones.
  • As some believe in "Peak Oil", I fear that we've already reached "Peak Guid", and that the days of $4 guids are in sight. I therefore recommend that you save all of the guids that you generate. Sure, it may be 15 years before the software that you used them in is gone and you're free to reuse them, but if you're the guy with 500 guids in your pocket during the Guid crisis of 2025, you're going to be sitting pretty.

What practices can you add?

(composed of 100% post-consumer characters)

Posted by ericgu | 8 Comments
Filed under:

Uncanny valley

Try this on your second monitor...

(yes, I know it's not fully rendered, but "Ew")

Posted by ericgu | 0 Comments

International Dance Party

What a nice build. Make sure to watch the video:

International Dance Party

 and you might want to take a look at the manual...

Posted by ericgu | 0 Comments

Project managers for agile teams...

A recent question about skill requirements for project managers of agile teams led me to write this:

In traditional project management, “project manager” means “person who is in charge”. In other words, that person makes the decisions, with varying degrees of depth (sometimes it’s high-level, sometimes it’s micro-management).

 

Agile doesn’t have somebody in change – inherent in the concept of agile is that the group is responsible and the group decides.

 

There *is* somebody who facilates (scrummaster in scrum, coach in XP), but their job is very explicitly not to make decisions. That means that the person who takes that role needs to be mindful of that and willing to push any decisions that rise up back down to the time. If the person has previous experience (and a preference) for “being in charge”, they are unlikely to do a good job in that role. If they aren’t thoughful about group dynamics in general, they may not do a good job in that role.

 

Double that comment if the group is not experienced with making decisions together. If they tend to defer upwards and the facilitator is used to making decisions, you probably won’t get a good result.

 

Posted by ericgu | 1 Comments
Filed under:

Job openings in the HealthVault team...

Long-time readers (who I like to refer to as "those three guys") know that I rarely blog about job openings, but I've decided to make an exception.

The HealthVault team is building a platform to solve "real important" HealthCare problems that affect the lives of "real people". We're a small but growing group that still has that "new group" smell to it, and we're looking for people who would do well in that sort of environment.

If you want to find out more information, you can find it at the Microsoft Career site (choose "Health Solutions Group" as the product). If you don't want to find out more information, you can find it at the bottom of a locked filing cabinet stuck in a discused lavatory with a sign on the door saying "Beware of the Leopard".

Or so I'm told.

 

Posted by ericgu | 1 Comments

Scheming for Schema

As many of you know, we already provide access to the schema for the healthvault types through the Type Schema Browser and the Raw XML API reference page.

If those pages don't do exactly what you want - say, you want to look at all the schemas together in a tool - you can access the schemas programmatically. The schema for a data type is built on some lower-level schemas (or types, if you wish):

The first one can be fetched programmatically, and the second and third you will need to download directly from the links I provided.

Access to the schema is provided through the ItemTypeManager class. You can call GetBaseHealthRecordItemTypeDefinition() to get the base schema (base.xsd), and then use GetHealthRecordItemTypeDefinition() to get the xsd for a specific type.

And, you can get a list of all the types from the "thing-types" vocabulary, thusly:

Vocabulary thingTypes = ApplicationConnection.GetVocabulary("thing-types");

Here's a bit of code that I wrote to fetch all of the schemas and store them in separate files:

    protected void Page_Load(object sender, EventArgs e)
    {
        HealthRecordItemTypeDefinition baseTypes = ItemTypeManager.GetBaseHealthRecordItemTypeDefinition(ApplicationConnection);
        SaveTypeXSD(baseTypes, "base");
        Vocabulary thingTypes = ApplicationConnection.GetVocabulary("thing-types");
        foreach (KeyValuePair<string, VocabularyItem> item in thingTypes)
        {
            Guid thingType = new Guid(item.Key);
            HealthRecordItemTypeDefinition definition = ItemTypeManager.GetHealthRecordItemTypeDefinition(thingType, ApplicationConnection);
            SaveTypeXSD(definition, definition.Name);
        }
        int k = 12;
    }
    void SaveTypeXSD(HealthRecordItemTypeDefinition definition, string name)
    {
        string directoryName = MapPath("platform");
        Directory.CreateDirectory(directoryName).CreateSubdirectory("web").CreateSubdirectory("xsd");
        string filename = MapPath(@"platform\web\xsd\" + name + ".xsd");
        using (StreamWriter writer = System.IO.File.CreateText(filename))
        {
            string schema = definition.XmlSchemaDefinition;
            writer.Write(schema);
        }
    }
Note that it puts the schema definitions in a directory named platform\web\xsd. This is the same structure that the schemas use in our source tree, and this makes sure things work correctly
Posted by ericgu | 3 Comments
Filed under:

Work on your Vocabulary. The word for today is "CodableValue"

Vocabulary and CodableValue are two of the somewhat interesting types in the HealthVault platform, and I thought I'd spend a little time discussing them.

So, here's the problem they're designed to solve.

In medicine, there are sometimes long lists. The kinds of lab tests you can order, the kinds of medication that can be prescribed, or the specialties of physicians. Unfortunately, the actual names can be a bit unwieldy. For the last example, you see things like:

  • Medical Toxicology - Emergency Medicine
  • Neurodevelopmental Disabilities (Pediatrics)
  • Adult Reconstructive Orthopedics

So, to make things simpler, there are a set of codes - using one to three letters in this case - that are the "standard" ways of encoding the longer string (what I'll call the "Display Text"). Take that code, put it together with the display text (and sometimes an abbreviation), and you get a Vocabulary item. Create a list of a bunch of VocabularyItems (along with some other information I'll talk about in a minute), and you get a Vocabulary, which defines both a list of possible options and the accepted way of encoding them (the key).

To be a bit more concrete, here's how we can fetch a vocabulary describing the different kinds of aerobic activities:

Vocabulary vocabulary = ApplicationConnection.GetVocabulary("aerobic-activites");

foreach (KeyValuePair<string, VocabularyItem> item in vocabulary)
{
    string key = item.Key;
    string displayText = item.Value.DisplayText;
    string abbreviation = item.Value.AbbreviationText;
}

If you looked closely at the foreach part, you noticed that item.Value is really a VocabularyItem, and that's where DisplayText and AbbreviationText came from.

Here's what I got back from executing that code:

 

Key DisplayText AbbreviationText
run running run
jog jogging jog
hike hiking hike
bike bicycling bike
spin spinning spin
swim swimming swim
walk walking walk
row rowing row

 

In addition to the information on a specific vocabulary item, there is some general information on the Vocabulary type.

Culture

The culture tells you the culture of the vocabulary. When you fetch a vocabulary, it comes back for the current Culture, and you can control whether there is a fallback to other culture's if there's not one specific to the current culture. Note that the key is culture-invariant, and therefore may not make sense to users in your current culture.

Family

Family defines the overall source for the vocabulary. If it's from HL7, this would presumably be for that. Or perhaps it might say "AMA", or something else. The family lets you understand where the vocabulary came from.  If it's something the HealthVault team defined, the family is "wc".

Name

The name of the vocabulary. Together with the family, that should fully identify the source

Version

A string defining a version of the vocabulary.  

 

Coded and Codable Values

How is a reference to a specific vocabulary item stored in HealthVault?

It is done through the CodedValue type. A quick look at the type shows the following properties:

  • Family
  • Value
  • Version
  • VocabularyName

As you probably figured out, Family, Version, and VocabularyName are used to indicate what vocabulary we are using, and Value is used to store the key for the specific vocabulary item. An application can figure out exactly you mean by looking at the CodedValue.

That works well when we have a vocabulary and we know exactly what code to use. But there are two more scenarios we need to support.

First, we might have an item to store, and it's either not in the vocabulary or we don't know what the appropriate vocabulary is. I might want to store my juggling exercise data, but that's not part of aerobic-activities vocabulary. Or, I'm adding the over-the-counter allergy medicine I take, and all I know is the name on the box.

In other words, sometimes we have very precise information, and sometimes it's less precise, but in both cases the platform and the applications that use the platform need to handle it well.

The second scenario - and this one's rarer - is that there are times where a single entry might need to store multiple values.

Both of these scenarios are supported through the CodableValue type, and that's the type that you'll see used in the data types.  It provides a Text property and a way of having multiple coded values.

CodableValue.Text is always set for all codable values, and that's the one that you display when you're showing that value to a user. Any underlying CodedValue instances are of a "more information" category - the application can use them to find out more information about that Text.

All Vocabularies

You can fetch the list of all vocabularies with the following:

ReadOnlyCollection<VocabularyKey> keys = ApplicationConnection.GetVocabularyKeys();

Why would you want to do this? Well, it's useful for browsing to see if the vocabularly that you want is currently defined in the system. If there's one that's not in the system, you can request a new vocabulary using the same process you'd use to request a new data type.

Best Practices

  1. Always set the Text property on the Codable value, even if there are CodedValues underneath.
  2. Always display the Text property as the high-level summary of the CodableValue.
  3. Be thoughtful about displaying the key to a vocabulary item to the user. It might be a number - in which case it is probably okay - but it also might be a string that only works well in one locale.  

Translation

One of the nice things about vocabularies is that there is are so many to choose from. There are several different coding systems - and therefore possible vocabularies - for medication. We've talked about providing translation services between different vocabularies - so that an application could easily get hte information in the vocabulary it understands best.

Would you find that to be a useful feature?

Posted by ericgu | 1 Comments
Filed under:

Dealing with PersonalImage

PersonalImage is a type that encapsulates the picture that shows up for a person in the health record.

My current image is this:

With the power to... Melt!

(those interested into why that is my current image should post the results of their research in the comments)

PersonalImage is what is called a Singleton type, which - as you've probably already figured out - means that there can only be one of them. But, there might be none of them, so code needs to handle this case as well.

Here's some code you might find useful.

        using (Stream imageStream = System.IO.File.OpenRead(@"C:\Documents and Settings\ericgu\My Documents\My Pictures\213.jpg"))
        {
            HealthRecordItemCollection collection = PersonInfo.SelectedRecord.GetItemsByType(PersonalImage.TypeId, HealthRecordItemSections.All);

            PersonalImage image = null;

            if (collection.Count != 0)
            {
                image = collection[0] as PersonalImage;

                using (Stream currentImageStream = image.ReadImage())
                {
                    byte[] imageBytes = new byte[currentImageStream.Length];
                    currentImageStream.Read(imageBytes, 0, (int)currentImageStream.Length);

                    using (FileStream outputImage = System.IO.File.OpenWrite(@"g:\213.jpg"))
                    {
                        outputImage.Write(imageBytes, 0, imageBytes.Length);
                    }
                }
            }


            if (image == null)
            {
                image = new PersonalImage();
                image.WriteImage(imageStream, "image/jpg");
                PersonInfo.SelectedRecord.NewItem(image);
            }
            else
            {
                image.WriteImage(imageStream, "image/jpg");
                PersonInfo.SelectedRecord.UpdateItem(image);
            }
        }

Posted by ericgu | 2 Comments
Filed under:

HealthVault and openness

Yesterday - while I was taking a day off skiing with my wife and daughter - we announced our plans around openness and interoperabiity for HealthVault.

I'm pretty excited about this. I'm especially excited about making the current .NET client library available under the Microsoft reference license, as I remember how useful it was to step through the MFC or ATL source when I was trying to figure out how things worked (or, more usually, what I had done wrong).

Posted by ericgu | 1 Comments
Filed under:

Uploading a file to HealthVault

I came across a question asking how to upload a file to HealthVault, and decided to write a quick example.

Files, like everything else in HealthVault, are stored in XML, and in fact, the File class is really a pretty thin wrapper over the underlying type. The File type stores the name of the file, the size, and the type of the content in the file.  The contents of the file is then stored in the "OtherData" member as a base-64 encoded string.

Here's some code:

FileInfo fileInfo = new FileInfo(@"C:\Documents and Settings\ericgu\My Documents\My Pictures\lame.jpg");
using (FileStream stream = System.IO.File.OpenRead(fileInfo.FullName))
{
   
BinaryReader reader = new BinaryReader(stream);
    byte[] fileContents = reader.ReadBytes((int) fileInfo.Length);
    string encodedString = Convert.ToBase64String(fileContents);

    Microsoft.Health.ItemTypes.File file = new Microsoft.Health.ItemTypes.File();
    file.Name = fileInfo.Name;
    file.Size = fileInfo.Length;
    file.ContentType =
new CodableValue("image/jpg");
    file.OtherData =
new OtherItemData();
    file.OtherData.ContentEncoding =
"base-64";
   
file.OtherData.ContentType = @"image/jpg";

    file.OtherData.Data = encodedString;

    PersonInfo.SelectedRecord.NewItem(file);
}

That will get the data up into HealthVault. Remember that the OtherData section doesn't come down by default, so if you want to get the contents of the file back, you'll need to specify:

filter.View.Sections = HealthRecordItemSections.All;

(or another version of the Sections mask that includes HealthRecordItems.OtherData).

Posted by ericgu | 1 Comments
Filed under:

The correct answer is "snowblower"

As some guessed, a snowblower.

More specifically, an Ariens 824E snowblower, from SnowblowersDirect.com.

Some of you know that I ski in the winter, and keep a ski cabin to make ski mornings much nicer. The ski cabin is at about 1000', and traditionally, there really isn't that much snow at that elevation around here - it tends to snow a bit, and then warm up.

But - as we've found over the last few years - if you have a house that sits on the north side of a hill, you don't get any solar radiation at all, and any snow that you do get is amazingly resilient - it will stick around for months. Though I can usually push the outback into our driveway with the new snow, it doesn't really work on deep slop, unless you're fond of severe drivetrain abuse and the smell of burning clutch(es).

So, we park at a small spot on the road to our lot. If it's snowed, I have to either move the plowed snow to the side before we park, or just muscle over it. And I need to cut a path through the snow to the cabin so we don't slip and fall over.

We've had this tentative plan to get an ATV and put a small plow on it, but I pretty much just lazed on that one. And then it started snowing, and snowing, and snowing around here, and I started thinking in terms of snowpack. We've probably had a good 4-5 feet of snow fall, and the snowpack is around 24-30" right now (it was a bit higher a week or so ago). I'm tired of digging.

Hence the snowblower. I couldn't find any stock here or close on the east side of cascades, so I ended up buying online, which was surprisingly easy. The blower showed up on Friday, we took it up Saturday, and found that it's a nice machine. And, amazingly, it started on the first pull in 20 degree weather, which shows that small engines have improved a bit since the lawn-mowing days of my youth.

It made quick work of the top 8" of snow, which was still sort of powderly. I had little luck at all with what was underneath, but given the fact that the blower doesn't sink into the snowpack, I'm not surprised. It would have been fine if I could have attacked it incrementally, and I'm hopeful that when it warms up a bit, the pack will soften and I'll be able to get back into the driveway.

Or, I could try to borrow one of these...

Posted by ericgu | 2 Comments

Ninja Warrior

My daughter found some broadcasts of a show named "Ninja Warrior" (originally named Sasuke in its Japanese broadcast), which is currently running on G4TV. It's an elaborate obstacle course show, with an English voiceover on top of the Japanese commentary.

Not only do you get to see some really talented athletes, you also get to see ordinary people crash and burn on the first stage, falling into the muddy water.

Recommended.

Posted by ericgu | 8 Comments
More Posts Next page »
 
Page view tracker