March, 2008

Posts
  • Eric Gunnerson's Compendium

    Uncanny valley

    • 0 Comments

    Try this on your second monitor...

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

  • Eric Gunnerson's Compendium

    International Dance Party

    • 1 Comments

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

    International Dance Party

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

  • Eric Gunnerson's Compendium

    Project managers for agile teams...

    • 1 Comments

    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.

     

  • Eric Gunnerson's Compendium

    Job openings in the HealthVault team...

    • 1 Comments

    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.

     

  • Eric Gunnerson's Compendium

    Scheming for Schema

    • 3 Comments

    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
  • Eric Gunnerson's Compendium

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

    • 1 Comments

    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?

  • Eric Gunnerson's Compendium

    Dealing with PersonalImage

    • 2 Comments

    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);
                }
            }
    
    
Page 1 of 1 (7 items)