Note
Access to this page requires authorization. You can try signing in or changing directories.
Access to this page requires authorization. You can try changing directories.
There is one thing in CCR I think should not be there in its current form and that is the SuccessFailurePort. The reason I don't like its current implementation is that it can easily become a generic container of results where really other types should be used. Before I give an example you need to know what setup I used for all tests in today's post.
1: [TestClass]
2: public class SuccessFailurePortUsage
3: {
4: private DispatcherQueue dispatcherQueue = new DispatcherQueue();
5: private PortUtility portUtility;
6:
7: [TestInitialize]
8: public void Setup()
9: {
10: portUtility = new PortUtility(dispatcherQueue);
11: }
Now an example on what it looks like when the SuccessFailurePort is misused.
1: private SuccessFailurePort WhenItShouldNotBeUsed(string numberOfThingsOk)
2: {
3: var resultPort = new SuccessFailurePort();
4: int thingsOk = 0;
5: if (int.TryParse(numberOfThingsOk, out thingsOk))
6: {
7: resultPort.Post(new SuccessResult(thingsOk));
8: }
9: else
10: {
11: resultPort.Post(
12: new Exception("Somehting is not OK: " + numberOfThingsOk));
13: }
14: return resultPort;
15: }
16:
17: [TestMethod]
18: public void When_it_should_not_be_used()
19: {
20: using (var testCausality = new CausalityForTests(dispatcherQueue))
21: {
22: portUtility.Choice(
23: WhenItShouldNotBeUsed("42"),
24: s => Assert.AreEqual(42, s.Status),
25: e => Assert.Fail("Unexpected failure: {0}", e));
26: portUtility.Choice(
27: WhenItShouldNotBeUsed("Not a number"),
28: s => Assert.Fail("Unexpected success"),
29: CcrServiceBase.EmptyHandler);
30: }
31: }
As you can see the status field of the SuccessResult is used as a transport for a result. The correct PortSet to used in this case is really PortSet<int, Exception>. There is also the opposite situation where a SuccessFailurePort is not used but it really should be used. Typically it is a PortSet<bool, Exception> port where false (or true) is never actually posted like in this example.
1: private PortSet<bool, Exception> WhenItShouldBeUsed(bool allOk)
2: {
3: var resultPort = new PortSet<bool, Exception>();
4: if (allOk)
5: {
6: resultPort.Post(true);
7: }
8: else
9: {
10: resultPort.Post(new Exception("Somehting is not OK"));
11: }
12: return resultPort;
13: }
14:
15: [TestMethod]
16: public void When_it_should_be_used()
17: {
18: using (var testCausality = new CausalityForTests(dispatcherQueue))
19: {
20: portUtility.Choice(
21: WhenItShouldBeUsed(true),
22: CcrServiceBase.EmptyHandler,
23: e => Assert.Fail("Unexpected failure: {0}", e));
24: portUtility.Choice(
25: WhenItShouldBeUsed(false),
26: s => Assert.Fail("Unexpected success"),
27: CcrServiceBase.EmptyHandler);
28: }
29: }
In my opinion the only time you should use a SuccessFailurePort is when you use the shared instance like this.
1: private SuccessFailurePort TheRightWay(bool allOk)
2: {
3: var resultPort = new SuccessFailurePort();
4: if (allOk)
5: {
6: resultPort.Post(SuccessResult.Instance);
7: }
8: else
9: {
10: resultPort.Post(new Exception("Somehting is not OK"));
11: }
12: return resultPort;
13: }
14:
15: [TestMethod]
16: public void The_right_way()
17: {
18: using (var testCausality = new CausalityForTests(dispatcherQueue))
19: {
20: portUtility.Choice(
21: TheRightWay(true),
22: CcrServiceBase.EmptyHandler,
23: e => Assert.Fail("Unexpected failure: {0}", e));
24: portUtility.Choice(
25: TheRightWay(false),
26: s => Assert.Fail("Unexpected success"),
27: CcrServiceBase.EmptyHandler);
28: }
29: }
This is why I think the SuccessFailurePort is implemented in the wrong way. Since only the shared instance is used the SuccessFailurePort could have been implemented using the EmptyValue type like this.
1: private PortSet<EmptyValue, Exception> TheRightWayAlternative(bool allOk)
2: {
3: var resultPort = new PortSet<EmptyValue, Exception>();
4: if (allOk)
5: {
6: resultPort.Post(EmptyValue.SharedInstance);
7: }
8: else
9: {
10: resultPort.Post(new Exception("Somehting is not OK"));
11: }
12: return resultPort;
13: }
14:
15: [TestMethod]
16: public void The_right_way_alternative()
17: {
18: using (var testCausality = new CausalityForTests(dispatcherQueue))
19: {
20: portUtility.Choice(
21: TheRightWayAlternative(true),
22: CcrServiceBase.EmptyHandler,
23: e => Assert.Fail("Unexpected failure: {0}", e));
24: portUtility.Choice(
25: TheRightWayAlternative(false),
26: s => Assert.Fail("Unexpected success"),
27: CcrServiceBase.EmptyHandler);
28: }
29: }
Notice the code on line 27 in the last example? That's another good practice in CCR code. Whenever you have a handler that is empty you should use CcrServiceBase.EmptyHandler.