tag:blogger.com,1999:blog-90693787363836103182024-02-21T16:00:31.321+00:00veitch.co.ukPaulhttp://www.blogger.com/profile/12188710309614367547noreply@blogger.comBlogger10125tag:blogger.com,1999:blog-9069378736383610318.post-73726026740208331582011-07-06T06:35:00.000+01:002011-07-06T06:35:50.091+01:00TFS 2010 and Visual Studio 2008 - Gated Checkins not workingThis is an infuriating issue which took me a while to track down, so I'm posting here in hope that it is useful for someone someday:<br />
<br />
<h2>Issue:</h2><br />
Gated Checkin works fine from Visual Studio 2010, however from Visual Studio 2008 with the <a href="http://www.microsoft.com/download/en/details.aspx?id=10834">Forward Compatibility Pack</a> it always turns into a Continuous Integration build.<br />
<br />
<h2>Solution:</h2><br />
Delete the Clean Build checkin policy which ensures that you can't check-in if the previous build failed. It looks like a bug as you can have this check-in policy and Gated Checkins in Visual Studio 2010Paulhttp://www.blogger.com/profile/12188710309614367547noreply@blogger.com0tag:blogger.com,1999:blog-9069378736383610318.post-47330065609879857612010-12-12T20:31:00.000+00:002010-12-12T20:31:22.854+00:00Turning DTOs into a domain layerFollowing on from this blog: <a href="http://www.veitch.co.uk/2010/10/do-wcf-data-contracts-have-relevance.html">Do WCF Data Contracts have relevance outside of WCF</a> where I talk about using WCF Data Contracts outside of service calls. This is part of a strategy for re-using DTOs for more than just a transport layer and building them for use across all layers.<br />
<br />
Obviously you will instantly think about domain object behaviours, Object Oriented Design etc. In my experience you want to separate out the behaviour of a class in different layers. For example you will want to bind your View to a Model in the UI or use persistent objects in the Data layer, additionally you will want to have business behaviours in the domain layer. What if you could share the underlying shape of the data across all of these tiers.<br />
<br />
In this article I will talk about reusing DTOs as a domain model. The obvious benefit is that you don't need to maintain 2 sets of objects and a mapping layer between them.<br />
<br />
The main premise of this model is to have the DTO model representing the data shape of the domain object and adding behaviours through the use of <a href="http://msdn.microsoft.com/en-us/library/bb383977.aspx">extension methods</a> to add this behaviour. For example you might have a Person DTO:<br />
<br />
<br />
<div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0cm; mso-layout-grid-align: none; text-autospace: none;"><span style="font-family: Consolas; font-size: 9.5pt;"><span style="mso-spacerun: yes;"> </span>[<span style="color: #2b91af;">DataContract</span>]<o:p></o:p></span></div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0cm; mso-layout-grid-align: none; text-autospace: none;"><span style="font-family: Consolas; font-size: 9.5pt;"><span style="mso-spacerun: yes;"> </span><span style="color: blue;">public</span> <span style="color: blue;">class</span> <span style="color: #2b91af;">Person</span><o:p></o:p></span></div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0cm; mso-layout-grid-align: none; text-autospace: none;"><span style="font-family: Consolas; font-size: 9.5pt;"><span style="mso-spacerun: yes;"> </span>{<o:p></o:p></span></div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0cm; mso-layout-grid-align: none; text-autospace: none;"><span style="font-family: Consolas; font-size: 9.5pt;"><span style="mso-spacerun: yes;"> </span>[<span style="color: #2b91af;">DataMember</span>(IsRequired=<span style="color: blue;">true</span>)]<o:p></o:p></span></div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0cm; mso-layout-grid-align: none; text-autospace: none;"><span style="font-family: Consolas; font-size: 9.5pt;"><span style="mso-spacerun: yes;"> </span><span style="color: blue;">public</span> <span style="color: blue;">string</span> Title { <span style="color: blue;">get</span>; <span style="color: blue;">set</span>; }<o:p></o:p></span></div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0cm; mso-layout-grid-align: none; text-autospace: none;"><br />
</div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0cm; mso-layout-grid-align: none; text-autospace: none;"><span style="font-family: Consolas; font-size: 9.5pt;"><span style="mso-spacerun: yes;"> </span>[<span style="color: #2b91af;">DataMember</span>(IsRequired = <span style="color: blue;">true</span>)]<o:p></o:p></span></div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0cm; mso-layout-grid-align: none; text-autospace: none;"><span style="font-family: Consolas; font-size: 9.5pt;"><span style="mso-spacerun: yes;"> </span><span style="color: blue;">public</span> <span style="color: blue;">string</span> FirstName { <span style="color: blue;">get</span>; <span style="color: blue;">set</span>; }<o:p></o:p></span></div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0cm; mso-layout-grid-align: none; text-autospace: none;"><span style="font-family: Consolas; font-size: 9.5pt;"><span style="mso-spacerun: yes;"> </span><o:p></o:p></span></div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0cm; mso-layout-grid-align: none; text-autospace: none;"><span style="font-family: Consolas; font-size: 9.5pt;"><span style="mso-spacerun: yes;"> </span>[<span style="color: #2b91af;">DataMember</span>(IsRequired = <span style="color: blue;">true</span>)]<o:p></o:p></span></div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0cm; mso-layout-grid-align: none; text-autospace: none;"><span style="font-family: Consolas; font-size: 9.5pt;"><span style="mso-spacerun: yes;"> </span><span style="color: blue;">public</span> <span style="color: blue;">string</span> LastName { <span style="color: blue;">get</span>; <span style="color: blue;">set</span>; }<o:p></o:p></span></div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0cm; mso-layout-grid-align: none; text-autospace: none;"><br />
</div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0cm; mso-layout-grid-align: none; text-autospace: none;"><span style="font-family: Consolas; font-size: 9.5pt;"><span style="mso-spacerun: yes;"> </span>[<span style="color: #2b91af;">DataMember</span>(IsRequired = <span style="color: blue;">true</span>)]<o:p></o:p></span></div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0cm; mso-layout-grid-align: none; text-autospace: none;"><span style="font-family: Consolas; font-size: 9.5pt;"><span style="mso-spacerun: yes;"> </span><span style="color: blue;">public</span> <span style="color: #2b91af;">DateTime</span> DateOfBirth { <span style="color: blue;">get</span>; <span style="color: blue;">set</span>; }<o:p></o:p></span></div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0cm; mso-layout-grid-align: none; text-autospace: none;"><br />
</div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0cm; mso-layout-grid-align: none; text-autospace: none;"><span style="font-family: Consolas; font-size: 9.5pt;"><span style="mso-spacerun: yes;"> </span>[<span style="color: #2b91af;">DataMember</span>(IsRequired = <span style="color: blue;">true</span>)]<o:p></o:p></span></div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0cm; mso-layout-grid-align: none; text-autospace: none;"><span style="font-family: Consolas; font-size: 9.5pt;"><span style="mso-spacerun: yes;"> </span><span style="color: blue;">public</span> <span style="color: #2b91af;">Address</span> Address { <span style="color: blue;">get</span>; <span style="color: blue;">set</span>; }<o:p></o:p></span></div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0cm; mso-layout-grid-align: none; text-autospace: none;"><br />
</div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0cm; mso-layout-grid-align: none; text-autospace: none;"><span style="font-family: Consolas; font-size: 9.5pt;"><span style="mso-spacerun: yes;"> </span>[<span style="color: #2b91af;">DataMember</span>(IsRequired = <span style="color: blue;">true</span>)]<o:p></o:p></span></div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0cm; mso-layout-grid-align: none; text-autospace: none;"><span style="font-family: Consolas; font-size: 9.5pt;"><span style="mso-spacerun: yes;"> </span><span style="color: blue;">public</span> <span style="color: #2b91af;">PersonSex</span> Sex { <span style="color: blue;">get</span>; <span style="color: blue;">set</span>; }<o:p></o:p></span></div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0cm; mso-layout-grid-align: none; text-autospace: none;"><br />
</div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0cm; mso-layout-grid-align: none; text-autospace: none;"><span style="font-family: Consolas; font-size: 9.5pt;"><span style="mso-spacerun: yes;"> </span>[<span style="color: #2b91af;">ContractInvariantMethod</span>]<o:p></o:p></span></div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0cm; mso-layout-grid-align: none; text-autospace: none;"><span style="font-family: Consolas; font-size: 9.5pt;"><span style="mso-spacerun: yes;"> </span><span style="color: blue;">private</span> <span style="color: blue;">void</span> EnforceInvariant()<o:p></o:p></span></div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0cm; mso-layout-grid-align: none; text-autospace: none;"><span style="font-family: Consolas; font-size: 9.5pt;"><span style="mso-spacerun: yes;"> </span>{<o:p></o:p></span></div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0cm; mso-layout-grid-align: none; text-autospace: none;"><span style="font-family: Consolas; font-size: 9.5pt;"><span style="mso-spacerun: yes;"> </span><span style="color: #2b91af;">Contract</span>.Invariant(<span style="color: blue;">this</span>.DateOfBirth < <span style="color: #2b91af;">DateTime</span>.Now);<o:p></o:p></span></div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0cm; mso-layout-grid-align: none; text-autospace: none;"><span style="font-family: Consolas; font-size: 9.5pt;"><span style="mso-spacerun: yes;"> </span><span style="color: #2b91af;">Contract</span>.Invariant(!<span style="color: blue;">string</span>.IsNullOrWhiteSpace(<span style="color: blue;">this</span>.FirstName));<o:p></o:p></span></div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0cm; mso-layout-grid-align: none; text-autospace: none;"><span style="font-family: Consolas; font-size: 9.5pt;"><span style="mso-spacerun: yes;"> </span><span style="color: #2b91af;">Contract</span>.Invariant(!<span style="color: blue;">string</span>.IsNullOrWhiteSpace(<span style="color: blue;">this</span>.LastName));<o:p></o:p></span></div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0cm; mso-layout-grid-align: none; text-autospace: none;"><span style="font-family: Consolas; font-size: 9.5pt;"><span style="mso-spacerun: yes;"> </span><span style="color: #2b91af;">Contract</span>.Invariant(!<span style="color: blue;">string</span>.IsNullOrWhiteSpace(<span style="color: blue;">this</span>.LastName));<o:p></o:p></span></div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0cm; mso-layout-grid-align: none; text-autospace: none;"><span style="font-family: Consolas; font-size: 9.5pt;"><span style="mso-spacerun: yes;"> </span><span style="color: #2b91af;">Contract</span>.Invariant(<span style="color: blue;">this</span>.Address != <span style="color: blue;">null</span>);<o:p></o:p></span></div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0cm; mso-layout-grid-align: none; text-autospace: none;"><br />
</div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0cm; mso-layout-grid-align: none; text-autospace: none;"><span style="font-family: Consolas; font-size: 9.5pt;"><span style="mso-spacerun: yes;"> </span><span style="color: #2b91af;">Contract</span>.Invariant(<span style="color: #2b91af;">Enum</span>.IsDefined(<span style="color: blue;">typeof</span>(<span style="color: #2b91af;">PersonSex</span>), <span style="color: blue;">this</span>.Sex));<o:p></o:p></span></div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0cm; mso-layout-grid-align: none; text-autospace: none;"><span style="font-family: Consolas; font-size: 9.5pt;"><span style="mso-spacerun: yes;"> </span>}<o:p></o:p></span></div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0cm; mso-layout-grid-align: none; text-autospace: none;"><span style="font-family: Consolas; font-size: 9.5pt;"><span style="mso-spacerun: yes;"> </span>}<o:p></o:p></span></div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0cm; mso-layout-grid-align: none; text-autospace: none;"><span style="font-family: Consolas; font-size: 9.5pt;"><br />
</span></div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0cm; mso-layout-grid-align: none; text-autospace: none;"><span class="Apple-style-span" style="font-family: inherit;">Note that this uses the code contract model that I describe in <a href="http://www.veitch.co.uk/2010/11/combing-code-contracts-with.html">Combing Code Contracts with DataContracts for better contract expressiveness and quality</a></span></div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0cm; mso-layout-grid-align: none; text-autospace: none;"><br />
</div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0cm; mso-layout-grid-align: none; text-autospace: none;">To build a domain layer on top of this you can add a set of extension methods like this to add some business logic to the class:</div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0cm; mso-layout-grid-align: none; text-autospace: none;"><br />
</div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0cm; mso-layout-grid-align: none; text-autospace: none;"></div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0cm; mso-layout-grid-align: none; text-autospace: none;"><span style="font-family: Consolas; font-size: 9.5pt;"><span style="mso-spacerun: yes;"> </span><span style="color: blue;">public</span> <span style="color: blue;">static</span> <span style="color: blue;">class</span> <span style="color: #2b91af;">PersonBusinessLayerExtensions</span><o:p></o:p></span></div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0cm; mso-layout-grid-align: none; text-autospace: none;"><span style="font-family: Consolas; font-size: 9.5pt;"><span style="mso-spacerun: yes;"> </span>{<o:p></o:p></span></div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0cm; mso-layout-grid-align: none; text-autospace: none;"><span style="font-family: Consolas; font-size: 9.5pt;"><span style="mso-spacerun: yes;"> </span><span style="color: blue;">public</span> <span style="color: blue;">static</span> <span style="color: blue;">bool</span> IsOver18(<span style="color: blue;">this</span> <span style="color: #2b91af;">Person</span> person)<o:p></o:p></span></div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0cm; mso-layout-grid-align: none; text-autospace: none;"><span style="font-family: Consolas; font-size: 9.5pt;"><span style="mso-spacerun: yes;"> </span>{<o:p></o:p></span></div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0cm; mso-layout-grid-align: none; text-autospace: none;"><span style="font-family: Consolas; font-size: 9.5pt;"><span style="mso-spacerun: yes;"> </span><span style="color: blue;">return</span> (person.DateOfBirth <= <span style="color: #2b91af;">DateTime</span>.Now.AddYears(18));<o:p></o:p></span></div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0cm; mso-layout-grid-align: none; text-autospace: none;"><span style="font-family: Consolas; font-size: 9.5pt;"><span style="mso-spacerun: yes;"> </span>}<o:p></o:p></span></div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0cm; mso-layout-grid-align: none; text-autospace: none;"><br />
</div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0cm; mso-layout-grid-align: none; text-autospace: none;"><span style="font-family: Consolas; font-size: 9.5pt;"><span style="mso-spacerun: yes;"> </span><span style="color: blue;">public</span> <span style="color: blue;">static</span> <span style="color: blue;">bool</span> LivesInUK(<span style="color: blue;">this</span> <span style="color: #2b91af;">Person</span> person)<o:p></o:p></span></div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0cm; mso-layout-grid-align: none; text-autospace: none;"><span style="font-family: Consolas; font-size: 9.5pt;"><span style="mso-spacerun: yes;"> </span>{<o:p></o:p></span></div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0cm; mso-layout-grid-align: none; text-autospace: none;"><span style="font-family: Consolas; font-size: 9.5pt;"><span style="mso-spacerun: yes;"> </span><span style="color: #2b91af;">Contract</span>.Requires(person.Address != <span style="color: blue;">null</span>);<o:p></o:p></span></div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0cm; mso-layout-grid-align: none; text-autospace: none;"><br />
</div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0cm; mso-layout-grid-align: none; text-autospace: none;"><span style="font-family: Consolas; font-size: 9.5pt;"><span style="mso-spacerun: yes;"> </span><span style="color: blue;">return</span> (<span style="color: blue;">string</span>.Compare(person.Address.Country, <span style="color: #a31515;">"UK"</span>, <span style="color: #2b91af;">StringComparison</span>.OrdinalIgnoreCase) == 0);<o:p></o:p></span></div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0cm; mso-layout-grid-align: none; text-autospace: none;"><span style="font-family: Consolas; font-size: 9.5pt;"><span style="mso-spacerun: yes;"> </span>}<o:p></o:p></span></div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0cm; mso-layout-grid-align: none; text-autospace: none;"><br />
</div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0cm; mso-layout-grid-align: none; text-autospace: none;"><span style="font-family: Consolas; font-size: 9.5pt;"><span style="mso-spacerun: yes;"> </span><span style="color: blue;">public</span> <span style="color: blue;">static</span> <span style="color: blue;">bool</span> CanVoteInUKElection(<span style="color: blue;">this</span> <span style="color: #2b91af;">Person</span> person)<o:p></o:p></span></div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0cm; mso-layout-grid-align: none; text-autospace: none;"><span style="font-family: Consolas; font-size: 9.5pt;"><span style="mso-spacerun: yes;"> </span>{<o:p></o:p></span></div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0cm; mso-layout-grid-align: none; text-autospace: none;"><span style="font-family: Consolas; font-size: 9.5pt;"><span style="mso-spacerun: yes;"> </span><span style="color: blue;">return</span> (IsOver18(person) && LivesInUK(person));<o:p></o:p></span></div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0cm; mso-layout-grid-align: none; text-autospace: none;"><span style="font-family: Consolas; font-size: 9.5pt;"><span style="mso-spacerun: yes;"> </span>}<o:p></o:p></span></div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0cm; mso-layout-grid-align: none; text-autospace: none;"><span style="font-family: Consolas; font-size: 9.5pt;"><span style="mso-spacerun: yes;"> </span>}<o:p></o:p></span></div><br />
<br />
<br />
You can see from this that we've added a bunch of methods which query some semantic value on top of the raw data, but you could easily add some modification of the state.<br />
<br />
Remember that you can combine this with the <a href="http://martinfowler.com/eaaCatalog/transactionScript.html">Transaction Script</a> pattern for longer business logic transactions spanning DTOs or other calls.<br />
<br />
One of the elements that makes it powerful is that you can add polymorphic behaviour in different layers and protect the business logic from the presentation or database layers or change the behaviour. This is enforced by deploying the appropriate assembly in the layer.<br />
<br />
<br />
<div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0cm; mso-layout-grid-align: none; text-autospace: none;"><span style="font-family: Consolas; font-size: 9.5pt;"><span style="mso-spacerun: yes;"> </span><span style="color: blue;">public</span> <span style="color: blue;">static</span> <span style="color: blue;">class</span> <span style="color: #2b91af;">PersonUIExtensions</span><o:p></o:p></span></div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0cm; mso-layout-grid-align: none; text-autospace: none;"><span style="font-family: Consolas; font-size: 9.5pt;"><span style="mso-spacerun: yes;"> </span>{<o:p></o:p></span></div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0cm; mso-layout-grid-align: none; text-autospace: none;"><span style="font-family: Consolas; font-size: 9.5pt;"><span style="mso-spacerun: yes;"> </span><span style="color: blue;">public</span> <span style="color: blue;">static</span> <span style="color: blue;">string</span> GetFullName(<span style="color: blue;">this</span> <span style="color: #2b91af;">Person</span> person)<o:p></o:p></span></div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0cm; mso-layout-grid-align: none; text-autospace: none;"><span style="font-family: Consolas; font-size: 9.5pt;"><span style="mso-spacerun: yes;"> </span>{<o:p></o:p></span></div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0cm; mso-layout-grid-align: none; text-autospace: none;"><span style="font-family: Consolas; font-size: 9.5pt;"><span style="mso-spacerun: yes;"> </span><span style="color: blue;">return</span> <span style="color: blue;">string</span>.Format(<span style="color: #2b91af;">CultureInfo</span>.InvariantCulture, <span style="color: #a31515;">"{0} {1} {2}"</span>, person.Title, person.FirstName, person.LastName);<o:p></o:p></span></div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0cm; mso-layout-grid-align: none; text-autospace: none;"><span style="font-family: Consolas; font-size: 9.5pt;"><span style="mso-spacerun: yes;"> </span>}<o:p></o:p></span></div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0cm; mso-layout-grid-align: none; text-autospace: none;"><span style="font-family: Consolas; font-size: 9.5pt;"><span style="mso-spacerun: yes;"> </span>}<o:p></o:p></span></div><br />
<br />
A potential disadvantage with this model is polymorphism of behaviours through abstract and virtual methods on the domain classes. However this can still be simulated via inheritance of the DTOs and extension methods on the base classes with extended behaviours on derived classes. This will require different names, but that can be a good thing, as sometimes polymorphism can be abused by overloading the behaviours in ways which aren't described by the method name.<br />
<br />
Your thoughts on this approach?Paulhttp://www.blogger.com/profile/12188710309614367547noreply@blogger.com0tag:blogger.com,1999:blog-9069378736383610318.post-31384370727157301272010-12-08T09:46:00.000+00:002010-12-08T09:46:08.702+00:00Sacred Cows? There are no Sacred Cows!Often on projects there are areas that individuals or teams will tell you are fine, or are things that you shouldn't look at all for very plausable reasons; these are called <a href="http://en.wikipedia.org/wiki/Sacred_cow_(idiom)">Sacred Cows</a>. <br />
<br />
It could be their favourite developer tool, their source code management system, a particular back-end or front-end system - whatever the tool, you are told that is out of scope of examination.<br />
<br />
However, work on enough projects and you soon realise that it is the Sacred Cows that will slow you down or sink your project - that is typically why they are Sacred Cows, everyone knows that they don't work, or don't work well but they are the favorites of someone more powerful in the organisation or they have been burned by other tools.<br />
<br />
Never ignore a Sacred Cow!<br />
<br />
Having said that, how do you deal with Sacred Cows? It depends on what the Sacred Cow is but above all know about them, understand them inside and out, their weaknesses and problems. Come up with a set of work-arounds, tools, standards, project management techniques, enact those that you are able to and have the others in your back-pocket so that when the issues hit you can quickly mobilise to work around the Sacred Cow.<br />
<br />
Think about the projects you have worked on, think about those that have failed or had significant issues, think of the Sacred Cows you have come across and discuss in the comments below.Paulhttp://www.blogger.com/profile/12188710309614367547noreply@blogger.com0tag:blogger.com,1999:blog-9069378736383610318.post-47967614998575231722010-11-07T22:01:00.000+00:002010-11-07T22:01:49.938+00:00Combing Code Contracts with DataContracts for better contract expressiveness and qualityI'm going to write some more about Code Contracts (<a href="http://research.microsoft.com/en-us/projects/contracts/">http://research.microsoft.com/en-us/projects/contracts/</a>) soon, but wanted to show you a neat example of using in combination with DataContracts.<br />
<br />
This shows the power of CodeContracts in enforcing more semantic information about a DataContract than is currently expressible in WSDL or DataContracts.<br />
<br />
For example take a look at this DataContract:<br />
<br />
<div class="Code"> [<span class="Type">DataContract</span>]<br />
<span class="Keyword">public class</span> <span class="Type">Address</span><br />
{<br />
[<span class="Type">DataMember</span>(IsRequired=<span class="Keyword">false</span>)]<br />
public int? HouseNumber { <span class="Keyword">get</span>; <span class="Keyword">set</span>; }<br />
[<span class="Type">DataMember</span>(IsRequired = <span class="Keyword">false</span>)]<br />
<span class="Keyword">public string</span> HouseName { <span class="Keyword">get</span>; <span class="Keyword">set</span>; }<br />
[<span class="Keyword">DataMember</span>(IsRequired = <span class="Keyword">true</span>)]<br />
<span class="Keyword">public string</span> Street { <span class="Keyword">get</span>; <span class="Keyword">set</span>; }<br />
[<span class="Type">DataMember</span>(IsRequired = <span class="Keyword">true</span>)]<br />
<span class="Keyword">public string</span> City { <span class="Keyword">get</span>; <span class="Keyword">set</span>; }<br />
[<span class="Type">DataMember</span>(IsRequired = <span class="Keyword">true</span>)]<br />
<span class="Keyword">public string</span>Region { <span class="Keyword">get</span>; <span class="Keyword">set</span>; }<br />
[<span class="Type">DataMember</span>(IsRequired = <span class="Keyword">true</span>)]<br />
<span class="Type">public string</span> Country { <span class="Keyword">get</span>; <span class="Keyword">set</span>; }<br />
[<span class="Type">DataMember</span>(IsRequired = <span class="Keyword">false</span>)]<br />
<span class="Keyword">public string</span> PostCode { <span class="Keyword">get</span>; <span class="Keyword">set</span>; }<br />
}</div><br />
Then we can see that there are several attributes which indicate that they are optional, for example the House Number and House Name. In the UK then many houses will have either one or the other or both. However no address should be missing both, the problem with this contract is that this isn't clear or enforceable.<br />
<br />
If we enhance this DataContract with CodeContracts:<br />
<br />
<div class="Code"> [<span class="Type">DataContract</span>]<br />
<span class="Keyword">public class</span> <span class="Type">Address</span><br />
{<br />
[<span class="Type">DataMember</span>(IsRequired=<span class="Keyword">false</span>)]<br />
public int? HouseNumber { <span class="Keyword">get</span>; <span class="Keyword">set</span>; }<br />
[<span class="Type">DataMember</span>(IsRequired = <span class="Keyword">false</span>)]<br />
<span class="Keyword">public string</span> HouseName { <span class="Keyword">get</span>; <span class="Keyword">set</span>; }<br />
[<span class="Keyword">DataMember</span>(IsRequired = <span class="Keyword">true</span>)]<br />
<span class="Keyword">public string</span> Street { <span class="Keyword">get</span>; <span class="Keyword">set</span>; }<br />
[<span class="Type">DataMember</span>(IsRequired = <span class="Keyword">true</span>)]<br />
<span class="Keyword">public string</span> City { <span class="Keyword">get</span>; <span class="Keyword">set</span>; }<br />
[<span class="Type">DataMember</span>(IsRequired = <span class="Keyword">true</span>)]<br />
<span class="Keyword">public string</span>Region { <span class="Keyword">get</span>; <span class="Keyword">set</span>; }<br />
[<span class="Type">DataMember</span>(IsRequired = <span class="Keyword">true</span>)]<br />
<span class="Type">public string</span> Country { <span class="Keyword">get</span>; <span class="Keyword">set</span>; }<br />
[<span class="Type">DataMember</span>(IsRequired = <span class="Keyword">false</span>)]<br />
<span class="Keyword">public string</span> PostCode { <span class="Keyword">get</span>; <span class="Keyword">set</span>; }<br />
[<span class="Type">ContractInvariantMethod</span>]<br />
<span class="Keyword">private void</span> EnforceInvariant()<br />
{<br />
<span class="Type">Contract</span>.Invariant(HouseNumber > 0);<br />
<span class="Type">Contract</span>.Invariant(!(HouseNumber == <span class="Type">null</span> && <span class="Keyword">string</span>.IsNullOrWhiteSpace(HouseName)));<br />
<span class="Type">Contract</span>.Invariant(!<span class="Keyword">string</span>.IsNullOrWhiteSpace(Street));<br />
<span class="Type">Contract</span>.Invariant(!<span class="Keyword">string</span>.IsNullOrWhiteSpace(City));<br />
<span class="Type">Contract</span>.Invariant(!<span class="Keyword">string</span>.IsNullOrWhiteSpace(Region));<br />
<span class="Type">Contract</span>.Invariant(!<span class="Keyword">string</span>.IsNullOrWhiteSpace(Country));<br />
}<br />
}</div><br />
Here you can see I have added a method that is decorated with a ContractInvariantMethod attribute. When you run the code through the Code Contract post compiler then this will ensure that at each point that the class changes that these invariants remain true. I've also added some invariants that ensure that the values are not null, empty or whitespace strings and that the house number is greater than 0. This can be analysed with a static analysis tool, with PEX and CHESS tools for testing and runtime checks.<br />
<br />
When I am working with WSDL produced from .NET WCF services then I like to get the DataContract assemblies so that these checks are possible. It is also better to go to the source rather than generating these from the WSDL - as long as the people that wrote the contracts have done the decent thing and put their DataContracts in a separate assembly to isolate it from the other layers and behaviours.<br />
<br />
What do you think of this approach - do you think it enhances the data contract? Leave some comments below.Paulhttp://www.blogger.com/profile/12188710309614367547noreply@blogger.com0tag:blogger.com,1999:blog-9069378736383610318.post-84196088823287460622010-11-04T21:21:00.000+00:002010-11-04T21:21:18.149+00:00Complexity in SoftwareI get to work with numerous clients in a variety of different industries at varying levels of maturity and I see a number of themes which lead to software complexity:<br />
<ul><li>Complex business domain</li>
<li>Large legacy of software and systems which must be integrated</li>
<li>Mismatched developer experience</li>
<li>Policy</li>
</ul><div>I wanted to point out why these areas cause complexity and how you can overcome them to deliver quality software.<br />
<br />
</div><div><h2>Complex Business Domain</h2></div><div>You typically can't change a complex business domain, except in a scenario where you see that there is an overly complex business process and there is an opportunity for you to propose simplification of the process using the software as a driver. If you can simplify the business process before you implement the software - even better because it will reduce the risk of implementation.</div><div><br />
</div><div>Having said that you can't change the complex business domain, you shouldn't verbatim create that complexity in the software, you should use your kitbag of techniques to simplify the design of the software such as using:</div><div><ul><li>Domain model</li>
<li>Service layers</li>
<li>Software Layering</li>
<li>Object Oriented development</li>
<li>Service Oriented development</li>
<li>Componentisation</li>
<li>Aspect oriented software development</li>
</ul><div>Use techniques like Single Responsibility Principal (SRP) for classes and methods as well as IoC, and make sure that you have the right unit and integration tests in place.</div><div><br />
</div><div>By using these techniques you can spread the complexity across a number of layers, components, classes or services - just be careful you introduce the right level of abstractions that you don't overcomplicate the software by using too many of the techniques or spreading the complexity too thinly.<br />
<br />
</div></div><div><h2>Complex integration environment</h2></div><div>Again, this is not something you can typically get away from, any business of some age or size will have a legacy of systems that will typically have evolved and you will just have to deal with. You can't expect them to throw away everything they have and start again - and if they did, you would just have another type of complexity on your hand - project management complexity.</div><div><br />
</div><div>To deal with a complex integration environment, your approach should be:</div><div><ul><li>Understand the software you are integrating with early and very deeply</li>
<li>Make sure you understand how you need to integrate with it</li>
<li>Consider if an integration layer (e.g. BizTalk) will simplify the integration or make it more complex</li>
<li>Have well defined interfaces (not just data and operation, but all of the other non-functional aspects of software)</li>
<li>Have a good stub strategy</li>
<li>Integrate as early as possible</li>
<li>Test as early as possible</li>
<li>Make sure your developers are testing against real services</li>
<li>Make sure your continuous integration builds are testing against real services</li>
</ul><div><br />
</div><div><h2>Mismatched Developer Experience</h2></div><div>Complexity is often introduced by developers working on the project not having the right level of knowledge of experience, and it isn't just about getting better software developers. Too inexperienced and the developers will use inappropriate technology to solve the problem which will introduce complexity through choosing lots of technologies or the wrong one. An example of this I found was using Word on a server to generate letters which caused layers of complexity which nearly derailed a multi-million pound development project.<br />
<br />
Go out and hire some very good developers and you might find that they do and build in complexity by selecting too many technologies for the job, selecting the perfect technology for each task and leaving you with a bunch of technologies you don't need. On another project I was on had 3 IoC containers because different developers liked different technologies.<br />
<br />
Choosing a range of developers that work together well and understand how to make pragmatic decisions will be invaluable to ensuring a solution which is matched to your needs, far more than highly skilled developers with large egos.<br />
<br />
Another important decision when developing the software is ensuring that the people who will maintain the software can understand it - a high-powered development team are likely to move onto other projects and technologies leaving you with software that you can't understand or maintain.<br />
<br />
<h2>Policy</h2>Often organisations will implement policies to try to manage software development, if the organisation doesn't have much experience in software development or they have had poor experiences when developing software will introduce more and more layers of policy and control without improving the outcome of software development. One organisation I worked with had 80 quality gates, would take a long time to produce simple software and would often fail to deliver working software.<br />
<br />
Other policies I have seen fail is selection of software for strategic platforms without properly understanding the technology or selecting technology because it was by the organisation favoured by senior management - regardless of whether that was right for the organisation or right-sized for the project.<br />
<br />
Policy should support the development process and shouldn't be so detailed as to hamstring projects by forcing them to pass irrelevant quality gates with documentation which adds no value and is never looked at again or using technology which has to be shoehorned in to make it work in the way which supports the project.<br />
<br />
Choose processes which support a competent development team and allow them to make the right decisions to deliver the software. Allow them to choose the right software to support the project and perform neutral evaluation. Documentation should have a purpose and help support the aim of developing high-quality software, not cover for poor management.<br />
<br />
Get a management team who have a proven record in quality software delivery projects which are on time and meet the business need as well as being supportable in the long term. Often managers who have delivered projects which are sold as products will understand this better than manager who have been sheltered in IT departments for the whole of their careers.<br />
<br />
The overwhelming message here is that policy cannot fix a broken project, poor technology selection or inexperienced developers, don't add layers just because of an issue which was experienced once.<br />
<br />
<h2>Summary</h2>So where are we with these observations and recommendations? Select the right people as your number one priority. Don't add policy to make up for bad management or poor technology selections, don't be dogmatic about your technology selections and be prepared to revise your decisions as you get more information - this could happen throughout the project. Make sure that you build continuous integration environments, have a good stub strategy and push the testing as early as possible and make sure your developers are doing it.<br />
<br />
Make sure that you use good software development factoring so that you use the right mix of complexity, layering and componentisation techniques which ensure that the software isn't overly complex either by having too much logic in one place or spreading the logic over too many code files or classes.<br />
<br />
Experience counts - make sure the people you have are experienced but have also demonstrated pragmatism in their previous projects.</div></div><div></div>Paulhttp://www.blogger.com/profile/12188710309614367547noreply@blogger.com0tag:blogger.com,1999:blog-9069378736383610318.post-17120658526401144552010-10-31T16:09:00.000+00:002010-10-31T16:09:05.888+00:00Hierarchyid column type in SQL 2008If you have ever tried to create an org chart, document structure or other type of hierarchy in SQL you will be aware of the self-join table pattern which works at a basic level but is hard to have arbitrary flexibility in the number of levels and selecting everything below a particular node.<br />
<br />
It is interesting to note that Microsoft added a new column type in SQL 2008 which allows you to represent this relationship natively in the database. I was aware of it but hadn't had much use for it or delved too deeply until I read this article:<br />
<br />
<a href="http://blogs.msdn.com/b/simonince/archive/2008/10/17/hierarchies-with-hierarchyid-in-sql-2008.aspx">http://blogs.msdn.com/b/simonince/archive/2008/10/17/hierarchies-with-hierarchyid-in-sql-2008.aspx</a><br />
<br />
This is a very powerful feature in particular the T-SQL extensions for placing the row in the hierarchy (such as hierarchyid::GetRoot()) and also the ability to select all nodes below a particular sub-tree, so finding all reports of a particular manager (direct and in-direct) is easy.<br />
<span class="Apple-style-span" style="color: #333333; font-family: 'Segoe UI', 'Lucida Grande', Verdana, Arial, Helvetica, sans-serif; font-size: 12px; line-height: 18px;"></span><br />
<blockquote>SELECT</blockquote><blockquote> Id,</blockquote><blockquote> Id.ToString() AS [Path],</blockquote><blockquote> Id.GetLevel() AS [Level],</blockquote><blockquote> Name</blockquote><blockquote>FROM EmployeeWithHierarchyID</blockquote><blockquote>WHERE Id.IsDescendantOf('/5/') = 1</blockquote>This does not replace the need for a hierarchical database, but it does make SQL server more versatile and meets a key need for document repositories. I wonder if and when SharePoint will use this for a range of features such as document repositories.Paulhttp://www.blogger.com/profile/12188710309614367547noreply@blogger.com0tag:blogger.com,1999:blog-9069378736383610318.post-36558405924357565982010-10-01T17:07:00.001+01:002010-10-01T17:10:29.138+01:00Do WCF Data Contracts have relevance outside of WCFIn working with <a href="http://msdn.microsoft.com/en-us/netframework/aa663324.aspx">WCF</a> you will come across <a href="http://msdn.microsoft.com/en-us/library/system.runtime.serialization.datacontractattribute.aspx">DataContract attributes</a> which decorate <a href="http://en.wikipedia.org/wiki/Data_transfer_object">DTOs</a>. DataContracts are great because they allow you to specify the WCF contract and are much more flexible than the <a href="http://msdn.microsoft.com/en-us/library/system.xml.serialization.xmlserializer.aspx">XML serializer</a> used by the original web services in .NET in that you can specify the attributes on prvate fields so you don't need to break encapsulation. It also supports versioning, optional parameters and a much fuller XSD model<br />
<br />
However, can we take this feature which appears to have been created for WCF and use it more generically?<br />
<br />
My view and way that I use this is for any sort of data contracts between layers of an application, so between the UI and the business tier, between services, between service layers and even into serialized persistent stores (e.g. XML datatype in the database).<br />
<br />
<strong>Why?</strong><br />
<br />
<ul><li>It is flexible in terms of versioning, optionality and data encapsulation</li>
<li>It is faster than Binary or XML Serialization (in my testing)</li>
<li>It creates compact, concise output</li>
</ul>It seems Microsoft had this in mind when they created the <span style="background-color: white;">class as it is placed in the System.Runtime.Serialization namespace.</span><br />
<br />
<span style="background-color: white;">So I would recommend that you use data contracts when passing data between any layer of an application and enforce that contract to ensure compatibility.</span><br />
<br />
<span style="background-color: white;">This relates to a number of upcoming articles, so stick with me while I evolve the story around DataContracts and how you might use them across the application from the data tier, to the UI and avoid writing lots of mappers between domain objects, DTOs and persistent entities.</span><br />
<br />
<span style="background-color: white;">Feel free to give your views on this, either positive or negative in the comments below</span>Paulhttp://www.blogger.com/profile/12188710309614367547noreply@blogger.com0tag:blogger.com,1999:blog-9069378736383610318.post-60838080883763970482010-09-29T17:40:00.001+01:002010-09-29T18:15:05.066+01:00Loosly coupled systemsRicco recently posted an article: <a href="http://blogs.msdn.com/b/ricom/archive/2010/09/27/less-loosely-coupled-than-meets-the-eye.aspx">Less Loosely Coupled Than Meets The Eye</a> which talks about something I have been thinking about for a long time from another perspective. We all try to write loosly coupled systems, and to some extent this is possible, for example using interfaces in code or Web Services to de-couple things.<br />
<br />
This works to some extent, and is getting better with features such as <a href="http://research.microsoft.com/en-us/projects/contracts/">Code Contracts</a> in .NET or <a href="http://msdn.microsoft.com/en-us/library/ms733127.aspx">Data Contracts </a>in Web Services and WCF, however there are always unwritten or assumed behaviours of an API which create dependencies that the architect or developer are unaware of and could cause you to have to re-write and recompile parts or all of your application because of that implied behaviour.<br />
<br />
Ways around this can be by using Unit Tests to assert various expectations on the behaviour of dependent code. Mocking frameworks are useful in this situation, but often don't help you to identify when a subtle behaviour in the upstream or downstream system or dependency has changed. Integration testing can certainly help, but it can't ever truely capture all of these complex behaviours in systems.<br />
<br />
Ricco says:<br />
<blockquote><em>"I don’t know that it is possible to write anything like a unitary software</em><br />
<em>system in a way that is truly loosely coupled. It’s not that you can’t make</em><br />
<em>boxes and lines that are cleanly separated in all sorts of pretty ways, though</em><br />
<em>that’s hard enough. The problem is that even if you manage to do that, what you</em><br />
<em>end up with is actually still pretty tightly coupled.</em><br />
<em><br />
</em><br />
<em>What do I mean?</em><br />
<em><br />
</em><br />
<em>Well, let me use Visual Studio as an example. It’s made up of all kinds of<br />
extensions which communicate through formal interfaces. Putting aside the warts<br />
and just looking at how it was intended to work it seems pretty good. You can<br />
make and replace pieces independently, there is a story for how now features<br />
light up; it’s all pretty good. Yes, it could be better but let’s for the moment<br />
idealize what is there. But is it loosely coupled, really?</em><br />
<em><br />
</em><br />
<em>Well the answer is heck no."</em><br />
<br />
</blockquote>He is correct in that unitary software (e.g. software hosted on the same machine or process or even on the same network) can not be isolated by impact from another part of the system becoming errant and impacting on your perfectly tested, perfectly working software.<br />
<br />
The closest we can probably get at the moment with the tools, processes and software we have is to isolate key parts of the system or other systems behind a buffered queue and having data and operation contracts which provide isolation of data changes, to some extent behavioural changes, process memory requirements and CPU time as well as timing and race conditions by ensuring that we only depend on the behaviour of the messaging system (still we are relying on subtle behaviours of the message queue technology).<br />
<br />
<strong>Does it matter?</strong><br />
<br />
In simple systems, probably not. Just ensure that your classes have low cohesion by using interfaces and dependency injection along with unit testing and a mocking framework to verify the state and behaviour of the system. <br />
<br />
For medium sized projects you are going to have to do all of the above, plus ensure that you have low cohesion between the systems involved as well as defining your data, operation and version contracts.<br />
<br />
For large systems, these are always going to require complex testing of end-to-end systems. However where I think we can make advances is in the testing of the Interface specification.<br />
<br />
In interfaces today we go away and write a specification, then each end of the integration go away and write their part, each side will use a stub or driver to ensure that it works while the other side completes their work. Then comes the big-bang integration which costs lots of money and time and usually only results in a system which works for the tested scenario. This is why systems integration projects are so difficult.<br />
<br />
Think of an analogy to this: HTML and CSS. This is a 20 year old spec which has gone through five versions and yet browser manufacturers still render the same HTML very differently. They are moving in the right direction with the <a href="http://acid3.acidtests.org/">ACID </a>and the <a href="http://www.w3.org/Style/CSS/Test/">W3C test suites</a> which allow the implementations to be tested.<br />
<br />
So this presents a way forward. Write a spec for your interface; define the data and operation contracts as well as the versioning story. Then write a program which can sit between the sides of the interface and can provide a common set of behaviours between the two. At least then the systems will be dealing with the same "bugs" in the behaviour. Don't have each implementor write a stub or driver which will differ, but provide something they can actually run against.Paulhttp://www.blogger.com/profile/12188710309614367547noreply@blogger.com1tag:blogger.com,1999:blog-9069378736383610318.post-29767064887379204522010-09-27T22:17:00.000+01:002010-09-27T22:17:22.549+01:00First Great Western ticket machines rooted?I was in Paddington Station recently and went to pick up tickets at one of the machines. I noticed that it was out of service but there was an interesting window in the bottom right hand corner:<br />
<br />
<div class="separator" style="clear: both; text-align: left;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiXcep9YTzIB2uTKkacHF9Rr9zRElZIr-Mt_ovjGKlNMWdoTXWHAxt9MIDVjEReQ8mcftP30iKLHEIR5D2Q4xBPm3o5qur1U6BHEm4_zn_K3e8AcD30oFMVqQr6AHkKP1sZ_NWBLDHSAz2w/s1600/IMG_0220.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="240" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiXcep9YTzIB2uTKkacHF9Rr9zRElZIr-Mt_ovjGKlNMWdoTXWHAxt9MIDVjEReQ8mcftP30iKLHEIR5D2Q4xBPm3o5qur1U6BHEm4_zn_K3e8AcD30oFMVqQr6AHkKP1sZ_NWBLDHSAz2w/s320/IMG_0220.JPG" width="320" /></a></div><div class="separator" style="clear: both; text-align: left;"><br />
</div><div class="separator" style="clear: both; text-align: left;">Interesting I thought, maybe a standard virus scan, so I took a closer look:</div><div class="separator" style="clear: both; text-align: left;"><br />
</div><div class="separator" style="clear: both; text-align: left;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjtYyFgvPpJp_3piO0fJ9lTMO1uCgsvi2LPUJPHKT3MD2gW_naiWz0fi9y0BwYn6m2zZzlBJk3igT_c64ql66MewCMBixaVh15Wx8fye47n33U6g9BaTqbwvC7sJzPwYj2-wvUN-xCZPt3U/s1600/photo.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="240" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjtYyFgvPpJp_3piO0fJ9lTMO1uCgsvi2LPUJPHKT3MD2gW_naiWz0fi9y0BwYn6m2zZzlBJk3igT_c64ql66MewCMBixaVh15Wx8fye47n33U6g9BaTqbwvC7sJzPwYj2-wvUN-xCZPt3U/s320/photo.jpg" width="320" /></a></div><div class="separator" style="clear: both; text-align: left;"><br />
</div><div class="separator" style="clear: both; text-align: left;">They are running a Downadup (otherwise known as Confiker) removal tool, I watched for a little bit longer and noticed that someone was running pcAnywhere, and there was a real human running this remotely. They rebooted after the scan and I noticed that they were running Windows 2000.</div><div class="separator" style="clear: both; text-align: left;"><br />
</div><div class="separator" style="clear: both; text-align: left;">So here is what I see wrong with this:</div><div class="separator" style="clear: both; text-align: left;"></div><ol><li>They are running Windows 2000 (not embedded Windows, but full Windows)</li>
<li>They obviously have had infections because they are not scanning, but running a removal tool</li>
<li>The machines can be remotely accessed via a remote control software</li>
<li>These machines have personal information in them and in particular: they have a credit card reader with PIN pad.</li>
</ol><div>This means that some of these machines have been rooted by a trojan horse and Windows 2000 can't be patched because it is not supported by Microsoft.</div>Paulhttp://www.blogger.com/profile/12188710309614367547noreply@blogger.com0tag:blogger.com,1999:blog-9069378736383610318.post-60530468414128260842010-09-23T09:48:00.000+01:002010-09-23T10:44:55.204+01:00New begininingsWelcolme to the new veitch.co.uk. I've had this website for over 10 years and it has been through various incarnations, however it has been pretty stagnant for the last 5 years.<br />
<br />
From today it will have a new life hosting my blog where I will be talking about the various aspects of what I am up to and anything interesting I find along the way. I won't be naming any of my clients or revealing any secrets, but I hope to spread some of what I learn.<br />
<br />
So, watch this space for upcoming new material!Paulhttp://www.blogger.com/profile/12188710309614367547noreply@blogger.com0