HealthVault Uses XML Storage

Via EricGu:

From the "perhaps this might be interesting" file...

Since the end of the HealthVault Solution Providers confererence in early June - and the subsequent required recharging - I've been spending the bulk of my time working on HealthVault data types, along with one of the PMs on the partner team. It interesting work - there's a little bit of schema design (all our data types are stored in XML on the server), a little bit of data architecture (is this one data type, or four?), a fair amount of domain-specific learning (how many ways are there to measure body fat percentage?), a bit of working directly with partners (exactly what is this type for?), a lot of word-smithing (should this element be "category", "type", or "area"?), and other things thrown in now and then (utility writing, class design, etc.). [1]

Definitely in the "interesting file." Please post more details :) I would love to hear more about this.

[1] http://blogs.msdn.com/ericgu/archive/2008/07/29/healthvault-data-type-design.aspx

 

Posted by Jesse Ezell with no comments
Filed under: , ,

Agile Development: Warning Signs

Alok Srivastava has an excellent post discussing agile development and areas that can put agile projects at risk. I'm currently doing clean up on an agile project gone south, and I wholeheartedly agree that the issues he points out should be warning signs if you are considering agile development. That's not to say that agile is bad by any means, just that you should think carefully before you make the jump, especially if your project will have the issues Alok mentions:

http://blogs.msdn.com/isv/archive/2008/07/29/agile-methodology-and-new-product-development-four-key-issues.aspx

 

Making the Possible More Impossible

Jared Parsons thought it would be nice if we could have a ReadOnlyList object in our generic template instead of IEnumerable. I think that's an excellent idea, so a few minor modifications and we have an even better solution, not requiring the generic constraint TWrite : TRead:

    public interface ILockedObject<TRead, TWrite> 
    {
        void Read(Action<TRead> action);
        void Write(Action<TWrite> action);
        void Replace(ReplaceAction<TWrite> action);
    }
        
    public class ReaderWriterLockedObject<TRead, TWrite> : ILockedObject<TRead,TWrite>
    {
        public ReaderWriterLockedObject(TWrite value, Converter<TWrite, TRead> makeReadOnly)
        {
            MakeReadOnly = makeReadOnly;
            _value = value;
        }

        public Converter<TWrite, TRead> MakeReadOnly
        {
            get;
            private set;
        }

        TWrite _value;
        ReaderWriterLockSlim _rwLock = new ReaderWriterLockSlim();
        
        #region ILockedObject<T> Members

        public void Read(Action<TRead> action)

        {
            _rwLock.EnterReadLock();
            try
            {
                action(MakeReadOnly(_value));
            }
            finally
            {
                _rwLock.ExitReadLock();
            }
        }

        public void Write(Action<TWrite> action)
        {
            _rwLock.EnterWriteLock();
            try
            {
                action(_value);
            }
            finally
            {
                _rwLock.ExitWriteLock();
            }
        }

        public void Replace(ReplaceAction<TWrite> action)
        {
            _rwLock.EnterWriteLock();
            try
            {
                action(ref _value);
            }
            finally
            {
                _rwLock.EnterWriteLock();
            }
        }

        #endregion
    }

    public delegate void ReplaceAction<T>(ref T value);

 

Oh, and here is a ReadOnlyList<T> class to go along:

        public class ReadOnlyList<T> : IEnumerable<T>
        {
            IList<T> _list;
            public ReadOnlyList(IList<T> list)
            {
                _list = list;
            }

            public T this[int index]
            {
                get
                {
                    return _list[index];
                }
            }

            public int Count
            {
                get
                {
                    return _list.Count;
                }
            }
            
            #region IEnumerable<T> Members

            public IEnumerator<T> GetEnumerator()
            {
                return _list.GetEnumerator();
            }

            #endregion

            #region IEnumerable Members

            System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
            {
                return _list.GetEnumerator();
            }

            #endregion
        }

So now we can do this:

ReaderWriterLockedObject<ReadOnlyList<Customer>, List<Customer>> lockedObject = new ReaderWriterLockedObject<ReadOnlyList<Customer>, List<Customer>>(l, c =>  new ReadOnlyList<Customer> (c));            

If we really want to be slick, we could take it a step further... protecting the elements inside our list:

ReaderWriterLockedObject<ReadOnlyList<ReadOnlyCustomer>, List<Customer>> lockedObject = new ReaderWriterLockedObject<ReadOnlyList<ReadOnlyCustomer>, List<Customer>>(l, wl =>  new ReadOnlyList<ReadOnlyCustomer> (wl, wc => (ReadOnlyCustomer)wc)); 

Making the Possible Impossible

Have you ever gone to a restraunt with a menu that was just too big? Every once and a while I wind up at a place with a huge menu and it takes forever to choose what kind of food I'm going to eat. That's not a problem when I go to a steak house. When I go to a steak house, I know exactly what I want. A rib-eye medium well with a side of mashed potatoes. Removing options always makes it easier to choose the right thing.

Programming is the same way. A lot of complexity in code exists only because we give ourselves too many options. For instance, consider the following code:

List<object> myList = new List<object>();

public void DoSomething()
{
  foreach(object o in myList) { Console.WriteLine(o); }
}

public void DoSomethingElse()
{
  myList.Add(new object());
}

This all looks fine and dandy, until two threads hit these methods at the same time and your app crashes. We can try to make this better like so:

public void DoSomething()
{
  lock(myList)
  {
    foreach(object o in myList) { Console.WriteLine(o); }
  }
}

public void DoSomethingElse()
{
  lock(myList)
  {
    myList.Add(new object());
  }
}

Which again works, but you always have to remember to lock the object. Some times you might forget. Why? Because you can. Nothing in the compiler and nothing in the .NET framework will tell you that you have to lock the object, it just assumes you are a threading wizard. There must be a better way... a way that we can gaurentee that we will never forget to lock our objects, but not make our code a complete mess at the same time. How about explicitly coding our intentions. Something like:

public void DoSomething()
{
  myList.Read(list =>  {
    foreach(object o in list) { Console.WriteLine(o); }
  });
}

public void DoSomethingElse()
{
  myList.Write(list =>  {
    list.Add(new object());
  }
}

Now, you might look at this code and say, "But I could still write to the list in the read block". Well, again, that is only if you give yourself that option. We can prevent that kind of situation completely with this little class I put together after reflecting on some comments from Eyal (http://blogs.microsoft.co.il/blogs/eyal/archive/2008/07/27/esb-on-iserviceoriented.aspx):

    public interface ILockedObject<TRead, TWrite> where TWrite : TRead
    {
        void Read(Action<TRead> action);
        void Write(Action<TWrite> action);
        void Replace(ReplaceAction<TWrite> action);
    }

    public class ReaderWriterLockedObject<TRead, TWrite> : ILockedObject<TRead,TWrite> where TWrite : TRead
    {
        public ReaderWriterLockedObject()
        {            
        }
        public ReaderWriterLockedObject(TWrite value)
        {
            _value = value;
        }
        TWrite _value;
        ReaderWriterLockSlim _rwLock = new ReaderWriterLockSlim();
        

        public void Read(Action<TRead> action)
        {
            _rwLock.EnterReadLock();
            try
            {
                action(_value);
            }
            finally
            {
                _rwLock.ExitReadLock();
            }
        }

        public void Write(Action<TWrite> action)
        {
            _rwLock.EnterWriteLock();
            try
            {
                action(_value);
            }
            finally
            {
                _rwLock.ExitWriteLock();
            }
        }

        public void Replace(ReplaceAction<TWrite> action)
        {
            _rwLock.EnterWriteLock();
            try
            {
                action(ref _value);
            }
            finally
            {
                _rwLock.EnterWriteLock();
            }
        }

    }

    public delegate void ReplaceAction<T>(ref T value);
 

Now simply change your code to define the list as:

ILockedObject<IEnumerable<object>, IList<object>> _list = new ReaderWriterLockedObject<IEnumerable<object>, IList<object> >(new List<object>());

And it will be impossible for you to access the list without locking it and impossible  for you to write to the list when you requested a read lock (ok, not impossible because you could make a bonehead move and cast it back to list or something, but it is much harder to mess up now). You'll still need to deal with other threading issues, but you'll have one less bad choice to worry about.

All Clouds Are Not Made Equal

As we rollout Microsoft Online Services this becomes a crucial factor especially when you begin to delve in to the laws and regulations of each country and how they implement data privacy.

What’s my point here? My point is that all clouds are not made equal and it’s not a simple thing to flip from being a consumer cloud vendor to an enterprise cloud vendor. The rules and expectations are very different. Flipping the other way, enterprise to consumer is a damn sight easier I’d say.

[1] http://blogs.msdn.com/stevecla01/archive/2008/07/25/are-all-clouds-created-equal.aspx

Posted by Jesse Ezell with 4 comment(s)

Publish / Subscribe with WCF

I'm working on a series of articles about building an ESB on your own.

http://www.iserviceoriented.com/blog/post/Building+Our+Own+ESB+-+Publish+Subscribe+Part+1.aspx
http://www.iserviceoriented.com/blog/post/Building+Our+Own+ESB+-+Publish+Subscribe+Part+2.aspx
http://www.iserviceoriented.com/blog/post/Building+Our+Own+ESB+-+Publish+Subscribe+Part+3.aspx

When at the end of each group of articles, I'll be providing downloadable source code to play with. Keep in mind this is simply to teach some concepts like message queueing, building extensible systems, and WCF. Though you are free to use any of the sample code, it is sample code, not a fully tested and supported product. If you want a great fully functional ESB, I highly recommend checking out Neuron. Anything Sam works on is gaurenteed to kick ass.

NServiceBus = Fail?

Finally had a chance to dig into the NServiceBus code. My thoughts are here if you care (I'm sure Udi will respond with his thoughts, so comment there instead of here if you think I'm off base):

http://tech.groups.yahoo.com/group/nservicebus/message/1012

Basic summation: code is potentially buggy, doesn't follow standard .NET naming conventions (not uncommon but annoys me when public projects don't) and not really production quality (I saw numerous potential crashes and basic threading problems just in the two core classes I read through).

I do still think Udi is a really smart guy and has a lot of good stuff to say, I just don't like the code.

Update: Udi likes the feedback and will be looking at addressing these issues. I'll try to find some time to work through the rest of NServiceBus to find other potential issues.

Posted by Jesse Ezell with no comments
Filed under: ,

Don't Mix Lambda Expressions and Using Statements

Lambda expressions are really cool, but they present some interesting problems because they aren't really inline code blocks like they appear:

http://blogs.msdn.com/jaredpar/archive/2008/07/16/don-t-mix-using-statements-and-lambda-expressions.aspx

 

More Posts « Previous page - Next page »