Being Cellfish

Stuff I wished I've found in some blog (and sometimes did)

December, 2009

Change of Address
This blog has moved to blog.cellfish.se.
Posts
  • Being Cellfish

    2009 Advent Calendar December 15th

    • 0 Comments

    So instead of the generic for the lock we had yesterday we can add a default constructor for convenience in the code and keep the constructor injection for the test code:

    1: public class ImportantProvider<T> where T : ImportantInterface, new() 2: { 3: private T _importantObject = new T(); 4: private Lock _lock; 5:   6: public ImportantProvider() : this(new MutexLock()) 7: { 8: 9: } 10:   11: public ImportantProvider(Lock aLock) 12: { 13: _lock = aLock; 14: } 15:   16: public Transaction Transaction 17: { 18: get 19: { 20: return new Transaction(_importantObject, _lock); 21: } 22: } 23: }
  • Being Cellfish

    2009 Advent Calendar December 14th

    • 0 Comments

    But if we're using generics; why not do it for the lock too:

    1: public class ImportantProvider<T,L> where T : ImportantInterface, new() where L : Lock,new() 2: { 3: private T _importantObject = new T(); 4: private L _lock = new L(); 5:   6: public Transaction Transaction 7: { 8: get 9: { 10: return new Transaction(_importantObject, _lock); 11: } 12: } 13: }

    But that leads to test code with static fields for verification. And I didn't like that before either... So it is a good idea to back that change out event though the ImportantProvider looks very neat with it IMHO.

  • Being Cellfish

    2009 Advent Calendar December 13th

    • 0 Comments

    One problem I see with how ImportantProvider turned out yesterday is that I have to give it the ImportantObject to provide. Hence I cannot be sure that all use of the ImportantObject is protected by the provider in the future. It is still too easy to bypass the thread safe ImportantProvider. We can fix this by using generics:

    1: public class ImportantProvider<T> where T : ImportantInterface,new() 2: { 3: private T _importantObject = new T(); 4: private Lock _lock; 5:   6: public ImportantProvider(Lock aLock) 7: { 8: _lock = aLock; 9: } 10:   11: public Transaction Transaction 12: { 13: get 14: { 15: return new Transaction(_importantObject, _lock); 16: } 17: } 18: }

    And here is an example of how it is used in the tests:

    1: _importantProvider = new ImportantProvider<DummyObject>(_lock);

    Combine this by making the ImportantObject internal and keep it in an assembly with the provider and we know that nobody will use ImportantObject in an unsafe way (from a thread safety perspective).

  • Being Cellfish

    2009 Advent Calendar December 12th

    • 0 Comments

    So now we need to fix the broken ImportantProvider making sure it uses one lock:

    1: public class Given_two_transactions_from_the_same_ImportantProvider 2: { 3: private FakeLock _lock; 4: private ImportantProvider _importantProvider; 5: private Transaction _transaction1; 6: private Transaction _transaction2; 7:   8: public Given_two_transactions_from_the_same_ImportantProvider() 9: { 10: _lock = new FakeLock(); 11: _importantProvider = new ImportantProvider(new DummyObject(), _lock); 12: _transaction1 = _importantProvider.Transaction; 13: _transaction2 = _importantProvider.Transaction; 14: } 15:   16: [Fact] 17: void It_should_be_two_different_transactions() 18: { 19: Assert.NotSame(_transaction1, _transaction2); 20: } 21:   22: [Fact] 23: void It_should_be_the_same_ImportantObject_returned_by_both_transactions() 24: { 25: Assert.Same(_transaction1.ImportantObject, _transaction2.ImportantObject); 26: } 27:   28: [Fact] 29: void It_should_take_lock_once_for_each_transaction() 30: { 31: Assert.Equal(2, _lock.NumberOfLocks); 32: } 33: }

    As you can see in the test I've chosen constructor injection for the lock in this case:

    1: public class ImportantProvider 2: { 3: private ImportantInterface _importantObject; 4: private Lock _lock; 5:   6: public ImportantProvider(ImportantInterface importantObject, Lock aLock) 7: { 8: _lock = aLock; 9: _importantObject = importantObject; 10: } 11:   12: public Transaction Transaction 13: { 14: get 15: { 16: return new Transaction(_importantObject, _lock); 17: } 18: } 19: }
  • Being Cellfish

    2009 Advent Calendar December 11th

    • 0 Comments

    Like yesterday I only have a passing test to add today:

    1: public class Given_two_transactions_from_the_same_ImportantProvider 2: { 3: private ImportantProvider _importantProvider; 4: private Transaction _transaction1; 5: private Transaction _transaction2; 6:   7: public Given_two_transactions_from_the_same_ImportantProvider() 8: { 9: _importantProvider = new ImportantProvider(new DummyObject()); 10: _transaction1 = _importantProvider.Transaction; 11: _transaction2 = _importantProvider.Transaction; 12: } 13:   14: [Fact] 15: void It_should_be_two_different_transactions() 16: { 17: Assert.NotSame(_transaction1, _transaction2); 18: } 19:   20: [Fact] 21: void It_should_be_the_same_ImportantObject_returned_by_both_transactions() 22: { 23: Assert.Same(_transaction1.ImportantObject, _transaction2.ImportantObject); 24: } 25: }

    You might have noticed that the ImportantProvider creates a new lock for each transaction. That is no good. Tomorrow I'll fix that.

  • Being Cellfish

    2009 Advent Calendar December 10th

    • 0 Comments

    Today I'm just adding a passing test.

    1: public class Given_two_transactions_from_the_same_ImportantProvider 2: { 3: private ImportantProvider _importantProvider; 4: private Transaction _transaction1; 5: private Transaction _transaction2; 6:   7: public Given_two_transactions_from_the_same_ImportantProvider() 8: { 9: _importantProvider = new ImportantProvider(new DummyObject()); 10: _transaction1 = _importantProvider.Transaction; 11: _transaction2 = _importantProvider.Transaction; 12: } 13:   14: [Fact] 15: void It_should_be_two_different_transactions() 16: { 17: Assert.NotSame(_transaction1, _transaction2); 18: } 19: }

    So why do I add a passing test? Well, I want to specify the behavior of my ImportantProvider.

  • Being Cellfish

    2009 Advent Calendar December 9th

    • 0 Comments

    With the solution we have from yesterday we still have a big problem. Whoever uses ImportantObject must also create the transaction. That is really a bad idea since it is too easy to use the ImportantObject in an unsafe way (i.e. not using transactions at all). To fix this I'm going to introduce an ImportantProvider:

    1: public class Given_an_ImportantProvider 2: { 3: private ImportantProvider _importantProvider = new ImportantProvider(new DummyObject()); 4:   5: [Fact] 6: void It_should_return_a_transaction() 7: { 8: Assert.NotNull(_importantProvider.Transaction); 9: } 10: } 11:   12: public class ImportantProvider 13: { 14: private ImportantInterface _importantObject; 15:   16: public ImportantProvider(ImportantInterface importantObject) 17: { 18: _importantObject = importantObject; 19: } 20:   21: public Transaction Transaction 22: { 23: get 24: { 25: return new Transaction(_importantObject, new MutexLock()); 26: } 27: } 28: }
  • Being Cellfish

    2009 Advent Calendar December 8th

    • 0 Comments

    So far we've kind of assumed for most of the time that the ImportantObject is easy to create. If not you probably want to create an interface for the ImportantObject. And creating an interface is probably a good idea anyway. So this is a refactoring of all code we have from yesterday.

    1: public interface ImportantInterface 2: { 3: void ImportantMethod(); 4: } 5:   6: public class ImportantObject : ImportantInterface 7: { 8: public void ImportantMethod() 9: { 10: // Do things. 11: } 12: } 13:   14: public interface Lock 15: { 16: void Lock(); 17: void Unlock(); 18: } 19:   20: public class MutexLock : Lock 21: { 22: private readonly Mutex _lock = new Mutex(); 23:   24: public void Lock() 25: { 26: _lock.WaitOne(); 27: } 28:   29: public void Unlock() 30: { 31: _lock.ReleaseMutex(); 32: } 33: } 34:   35: public class Transaction : IDisposable 36: { 37: private readonly Lock _lock; 38: public ImportantInterface ImportantObject { get; private set; } 39:   40: public Transaction(ImportantInterface importantObject, Lock aLock) 41: { 42: ImportantObject = importantObject; 43: _lock = aLock; 44: _lock.Lock(); 45: } 46:   47: public void Dispose() 48: { 49: _lock.Unlock(); 50: } 51: } 52:   53: class FakeLock : Lock 54: { 55: public bool IsLocked { get; private set; } 56:   57: public FakeLock() 58: { 59: IsLocked = false; 60: } 61:   62: public void Lock() 63: { 64: IsLocked = true; 65: } 66:   67: public void Unlock() 68: { 69: IsLocked = false; 70: } 71: } 72:   73: class DummyObject : ImportantInterface 74: { 75: public void ImportantMethod() 76: { 77: Assert.True(false, "Dummy should never be used"); 78: } 79: } 80:   81: public class When_using_a_transaction 82: { 83: private FakeLock _lock; 84:   85: public When_using_a_transaction() 86: { 87: _lock = new FakeLock(); 88: } 89:   90: [Fact] 91: void It_should_take_lock_when_created() 92: { 93: Assert.False(_lock.IsLocked); 94: using (Transaction transaction = new Transaction(new ImportantObject(), _lock)) 95: { 96: Assert.True(_lock.IsLocked); 97: } 98: } 99:   100: [Fact] 101: void It_should_release_lock_when_leaving_scope() 102: { 103: using (Transaction transaction = new Transaction(new ImportantObject(), _lock)) 104: { 105: Assert.True(_lock.IsLocked); 106: } 107: Assert.False(_lock.IsLocked); 108: } 109: } 110:   111: public class Given_a_transaction 112: { 113: private Transaction _transaction = new Transaction(new DummyObject(), new FakeLock()); 114:   115: [Fact] 116: void It_should_return_an_ImportantObject() 117: { 118: Assert.NotNull(_transaction.ImportantObject); 119: } 120: }
  • Being Cellfish

    2009 Advent Calendar December 7th

    • 0 Comments

    Now that we have a working transaction from yesterday we need to add the important object to it. So let's use the initial implementation of the important object:

    1: public class ImportantObject 2: { 3: public void ImportantMethod() 4: { 5: // Do things. 6: } 7: }

    Then we want a new test on the transaction:

    1: public class Given_a_transaction 2: { 3: private Transaction _transaction = new Transaction(new ImportantObject(), new FakeLock()); 4:   5: [Fact] 6: void It_should_return_an_ImportantObject() 7: { 8: Assert.NotNull(_transaction.ImportantObject); 9: } 10: }

    And the implementation:

    1: public class Transaction : IDisposable 2: { 3: private readonly Lock _lock; 4: public ImportantObject ImportantObject { get; private set; } 5:   6: public Transaction(ImportantObject importantObject, Lock aLock) 7: { 8: ImportantObject = importantObject; 9: _lock = aLock; 10: _lock.Lock(); 11: } 12:   13: public void Dispose() 14: { 15: _lock.Unlock(); 16: } 17: }
  • Being Cellfish

    2009 Advent Calendar December 6th

    • 0 Comments

    Since I want the transaction we're creating to take the lock when created I also want to release the lock when the transaction is disposed:

    1: public class When_using_a_transaction 2: { 3: class FakeLock : Lock 4: { 5: public bool IsLocked { get; private set; } 6:   7: public FakeLock() 8: { 9: IsLocked = false; 10: } 11:   12: public void Lock() 13: { 14: IsLocked = true; 15: } 16:   17: public void Unlock() 18: { 19: IsLocked = false; 20: } 21: } 22:   23: private FakeLock _lock; 24:   25: public When_using_a_transaction() 26: { 27: _lock = new FakeLock(); 28: } 29:   30: [Fact] 31: void It_should_take_lock_when_created() 32: { 33: Assert.False(_lock.IsLocked); 34: using (Transaction transaction = new Transaction(_lock)) 35: { 36: Assert.True(_lock.IsLocked); 37: } 38: } 39:   40: [Fact] 41: void It_should_release_lock_when_leaving_scope() 42: { 43: using (Transaction transaction = new Transaction(_lock)) 44: { 45: Assert.True(_lock.IsLocked); 46: } 47: Assert.False(_lock.IsLocked); 48: } 49: }

    And the transaction implementation:

    1: public class Transaction : IDisposable 2: { 3: private readonly Lock _lock; 4:   5: public Transaction() 6: : this(new MutexLock()) 7: { 8:   9: } 10:   11: public Transaction(Lock aLock) 12: { 13: _lock = aLock; 14: _lock.Lock(); 15: } 16:   17: public void Dispose() 18: { 19: _lock.Unlock(); 20: } 21: }
Page 2 of 3 (25 items) 123