<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~d/styles/atom10full.xsl"?><?xml-stylesheet type="text/css" media="screen" href="http://feeds.feedburner.com/~d/styles/itemcontent.css"?><feed xmlns="http://www.w3.org/2005/Atom" xmlns:openSearch="http://a9.com/-/spec/opensearch/1.1/" xmlns:georss="http://www.georss.org/georss" xmlns:gd="http://schemas.google.com/g/2005" xmlns:thr="http://purl.org/syndication/thread/1.0" xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" gd:etag="W/&quot;DEEGQXYyeSp7ImA9WhRQEU0.&quot;"><id>tag:blogger.com,1999:blog-5356363081772370386</id><updated>2011-12-05T09:37:00.891-08:00</updated><category term="NUnit" /><category term="SOLID" /><category term="LINQ" /><category term="Visual Studio" /><category term="kata" /><category term="refactoring" /><category term="Unit Test" /><category term="scrum.org" /><category term="logiciel libre" /><category term="PSM" /><category term="MSTest" /><category term="Java" /><category term="IDE" /><category term="général" /><category term="moteur de recherche" /><category term="TDD" /><category term="CQRS" /><category term="coaching" /><category term="Scrum" /><category term="coding dojo" /><category term="PSD" /><category term="agile testing" /><category term="DDD" /><category term="training" /><category term="ATDD" /><title>Ernst's Thoughts</title><subtitle type="html">On things such as agile development, web development, .Net, Java, etc.</subtitle><link rel="http://schemas.google.com/g/2005#feed" type="application/atom+xml" href="http://ernststhoughts.blogspot.com/feeds/posts/default" /><link rel="alternate" type="text/html" href="http://ernststhoughts.blogspot.com/" /><author><name>Ernst Perpignand</name><uri>http://www.blogger.com/profile/16268268503536377997</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="31" height="32" src="http://3.bp.blogspot.com/-JMKo3fl9wV0/TYyN0W1rRwI/AAAAAAAAAC0/oeMf_zY8fEI/s220/profil-400px.jpg" /></author><generator version="7.00" uri="http://www.blogger.com">Blogger</generator><openSearch:totalResults>16</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>25</openSearch:itemsPerPage><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" type="application/atom+xml" href="http://feeds.feedburner.com/ErnstsThoughts" /><feedburner:info uri="ernststhoughts" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com/" /><entry gd:etag="W/&quot;A0AFQ3gycSp7ImA9WxFWFUQ.&quot;"><id>tag:blogger.com,1999:blog-5356363081772370386.post-7599323651729238739</id><published>2010-06-03T13:36:00.001-07:00</published><updated>2010-06-03T14:15:12.699-07:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2010-06-03T14:15:12.699-07:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="DDD" /><category scheme="http://www.blogger.com/atom/ns#" term="training" /><category scheme="http://www.blogger.com/atom/ns#" term="CQRS" /><title>3 days with Greg Young</title><content type="html">&lt;a href="http://lh6.ggpht.com/_G-s-S83TooA/TAgSOfksPeI/AAAAAAAAAB4/Yjt7rp2qivY/s1600-h/IMG_2720%5B5%5D.jpg"&gt;&lt;img align="left" alt="IMG_2720" border="0" height="184" src="http://lh5.ggpht.com/_G-s-S83TooA/TAgSOz1BIVI/AAAAAAAAAB8/e4AIE4rL_MU/IMG_2720_thumb%5B3%5D.jpg?imgmax=800" style="border-bottom: 0px; border-left: 0px; border-right: 0px; border-top: 0px; display: inline; margin-left: 0px; margin-right: 0px;" title="IMG_2720" width="244" /&gt;&lt;/a&gt; Last week &lt;a href="http://www.pyxis-tech.com/"&gt;Pyxis&lt;/a&gt; hosted an intensive three days immersion into &lt;a href="http://codebetter.com/blogs/gregyoung/"&gt;Greg Young's&lt;/a&gt; Applied DDD course. This course is amazingly packed with tips and tricks on how to come up with an architecture that delivers business value customers have come to expect from their investments in software systems. Powered by Greg’s energetic tone, this course challenged my assumptions of how software should be designed and I would recommend it to anyone interested in architecture innovations surrounding &lt;a href="http://domainlanguage.com/ddd/index.html"&gt;Domain Driven Design&lt;/a&gt;. Following is an overview of the topics we’ve tackled during the training. &lt;br /&gt;
&lt;h4&gt;DDD recap&lt;/h4&gt;The first day was spent refreshing some of the fundamental but often misunderstood concepts of Domain Driven Design. We were reminded that Strategic Design is essential while embarking on a Domain Driven Design project as we must make sure that the value we get out from it is well worth the effort. Notions such as Bounded Contexts and Core Domain allow highly knowledgeable teams to focus on value added development work while leaving less crucial aspects of the software to others.&lt;br /&gt;
Another topic that stroke a chord with me was Greg’s presentation of Aggregates and the role the play in well crafted software systems. Aggregates exist to provide transaction boundaries around the behaviors of domain objects. Aggregate roots provide the sole entry point to this grouping of domain behaviors and encapsulate validation logic as well as invariant consistency inside the aggregate.&lt;br /&gt;
&lt;h4&gt;CQRS&lt;/h4&gt;&lt;a href="http://lh5.ggpht.com/_G-s-S83TooA/TAgSPKi4GUI/AAAAAAAAACA/jsciSEGzk7o/s1600-h/EventSourcing%5B5%5D.jpg"&gt;&lt;img align="left" alt="EventSourcing" border="0" height="196" src="http://lh4.ggpht.com/_G-s-S83TooA/TAgSPumRvaI/AAAAAAAAACE/IJTven-l2KY/EventSourcing_thumb%5B3%5D.jpg?imgmax=800" style="border-bottom: 0px; border-left: 0px; border-right: 0px; border-top: 0px; display: inline; margin-left: 0px; margin-right: 0px;" title="EventSourcing" width="272" /&gt;&lt;/a&gt;We spent the second day learning about Command Query Responsibility Segregation and Event Sourcing. CQRS is different then Command Query Separation (Bertrand Meyer) which advocates that methods that change state should be separated from functions that return value. CQRS takes the same principle and applies it to the hole architecture. In this style of design some objects (write model) represents the commands the domain respond to and other objects (read model) handles the queries and their results. Having separate models for these concerns brings a lot of benefits that I will bring up in later posts. &lt;br /&gt;
&lt;h5&gt;The write model&lt;/h5&gt;It’s common OO knowledge that objects should be designed around behaviors in a domain. Having a dedicated write model consisting of aggregates that define transaction boundaries around the behaviors in the domain focuses work on the most valuable part of the system. This is the place to maximize the return on the work of your most skilled developers aided by domain experts.&lt;br /&gt;
&lt;h5&gt;The read model &lt;/h5&gt;The query side doesn’t have a domain as it’s mostly straightforward boilerplate code. The preferred implementation of a read model is having request DTOs going through a thin query layer that projects directly off of a data source. This is way simpler that using the domain model to do the same. This way pre-fetched paths and optimizing ORMs queries are avoided.&lt;br /&gt;
&lt;h5&gt;Event Sourcing &lt;/h5&gt;Event sourcing can be seen as a way to “standardize” thus reduce the cost of implementing separated read and write models. The basic idea is that all domain can be modeled as receiving commands that and producing associated events. These events can be stored as a log of what happened in the system and also be used to update the read model.&lt;br /&gt;
&lt;a href="http://lh4.ggpht.com/_G-s-S83TooA/TAgSPy8YD9I/AAAAAAAAACI/Rnytz8CwMfw/s1600-h/IMG_2717%5B3%5D.jpg"&gt;&lt;img align="left" alt="IMG_2717" border="0" height="184" src="http://lh6.ggpht.com/_G-s-S83TooA/TAgSQfhQmOI/AAAAAAAAACM/OS-CUX32bxU/IMG_2717_thumb%5B1%5D.jpg?imgmax=800" style="border-bottom: 0px; border-left: 0px; border-right: 0px; border-top: 0px; display: inline; margin-left: 0px; margin-right: 0px;" title="IMG_2717" width="244" /&gt;&lt;/a&gt; While exposing concurrency issues and ways to handle them Greg showed us a merging algorithm that’s quite simple and clever. Probably, the only piece of code Greg would ever write with a Goto statement as you can see in the picture.&lt;br /&gt;
&lt;h4&gt;Fine tuning the architecture&lt;/h4&gt;The third day was spent analyzing the properties of this architecture and how it could be fine tuned to produce low latency, high availability and high reliability systems. Most notably &lt;a href="http://codebetter.com/blogs/gregyoung/archive/2010/02/20/cqrs-and-cap-theorem.aspx"&gt;CQRS architecture can used to get around&lt;/a&gt; &lt;a href="http://www.julianbrowne.com/article/viewer/brewers-cap-theorem"&gt;CAP theorem&lt;/a&gt; issues which states that you can’t guarantee all three &lt;strong&gt;C&lt;/strong&gt;onsistency, &lt;strong&gt;A&lt;/strong&gt;vailability and &lt;strong&gt;P&lt;/strong&gt;artitionability in one system. Look &lt;a href="http://guysblogspot.blogspot.com/2008/09/cap-solution-proving-brewer-wrong.html"&gt;here&lt;/a&gt; for another treatment on how to get around CAP.&lt;br /&gt;
All these architecture talks made me realize that using DDD and CQRS is a lot of work. And it’s no wonder that they should be applied to core domains. Now most companies I’ve worked with deal with multiple domains such as Sales, Security, Insurance, etc... And it would have been difficult to single out the one that constitutes their core domain. But every company must have a core domain otherwise it would not have a competitive advantage. Turns out a lot of companies derive their competitive advantage from their business process that integrate all of the domains they deal with. This is the place their core domain reside and that’s where &lt;a href="http://www.rgoarchitects.com/Files/SOAPatterns/Saga.pdf"&gt;Sagas&lt;/a&gt; help.&lt;br /&gt;
&lt;h4&gt;Pyxis source of high quality technical learning&lt;/h4&gt;&lt;a href="http://lh4.ggpht.com/_G-s-S83TooA/TAgSQs9hQ8I/AAAAAAAAACQ/EHD5VGA3lSQ/s1600-h/IMG_2719%5B6%5D.jpg"&gt;&lt;img align="right" alt="IMG_2719" border="0" height="184" src="http://lh6.ggpht.com/_G-s-S83TooA/TAgSRHQNIpI/AAAAAAAAACU/k3fPvqnugBw/IMG_2719_thumb%5B4%5D.jpg?imgmax=800" style="border-bottom: 0px; border-left: 0px; border-right: 0px; border-top: 0px; display: inline; margin-left: 0px; margin-right: 0px;" title="IMG_2719" width="244" /&gt;&lt;/a&gt; All in all, these three days were packed with useful technical knowledge and eye opening discussions with an expert in his craft. The participants enjoyed the learning experience in Pyxis’ agile environment where they got a close up look at our facilities supporting agile teams. Pyxis is proud to have sponsored this event and is dedicated to bringing high quality technical training to the public.&lt;br /&gt;
Other technical trainings :&lt;br /&gt;
&lt;ul&gt;&lt;li&gt;&lt;a href="http://www.pyxis-tech.com/en/services/formation/liste-de-cours/scrum-developer-dotnet/"&gt;Professional Scrum Developer (.NET)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://www.pyxis-tech.com/en/services/formation/liste-de-cours/modelisation-agile/"&gt;Agile Modeling&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://www.pyxis-tech.com/en/services/formation/liste-de-cours/ddd/"&gt;Domain-Driven Design (DDD)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://www.pyxis-tech.com/en/services/formation/liste-de-cours/tdd/"&gt;Test-Driven Development (TDD)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://www.pyxis-tech.com/en/services/formation/liste-de-cours/pratiques-dutilisabilite/"&gt;Usability Practices&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://www.pyxis-tech.com/en/services/formation/liste-de-cours/specifications-executables/"&gt;Executable Specifications with GreenPepper&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5356363081772370386-7599323651729238739?l=ernststhoughts.blogspot.com' alt='' /&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/pJpnRx29nxG8E0TK_0P1sR7kaRE/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/pJpnRx29nxG8E0TK_0P1sR7kaRE/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/pJpnRx29nxG8E0TK_0P1sR7kaRE/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/pJpnRx29nxG8E0TK_0P1sR7kaRE/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/ErnstsThoughts/~4/WDn8_GI58bs" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://ernststhoughts.blogspot.com/feeds/7599323651729238739/comments/default" title="Publier les commentaires" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=5356363081772370386&amp;postID=7599323651729238739" title="0 commentaires" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/5356363081772370386/posts/default/7599323651729238739?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/5356363081772370386/posts/default/7599323651729238739?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/ErnstsThoughts/~3/WDn8_GI58bs/3-days-with-greg-young.html" title="3 days with Greg Young" /><author><name>Ernst Perpignand</name><uri>http://www.blogger.com/profile/16268268503536377997</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="31" height="32" src="http://3.bp.blogspot.com/-JMKo3fl9wV0/TYyN0W1rRwI/AAAAAAAAAC0/oeMf_zY8fEI/s220/profil-400px.jpg" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://lh5.ggpht.com/_G-s-S83TooA/TAgSOz1BIVI/AAAAAAAAAB8/e4AIE4rL_MU/s72-c/IMG_2720_thumb%5B3%5D.jpg?imgmax=800" height="72" width="72" /><thr:total>0</thr:total><feedburner:origLink>http://ernststhoughts.blogspot.com/2010/06/3-days-with-greg-young.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DEIASXs6cCp7ImA9WxFRGUk.&quot;"><id>tag:blogger.com,1999:blog-5356363081772370386.post-1396797453980384829</id><published>2010-05-03T21:15:00.001-07:00</published><updated>2010-05-03T21:15:48.518-07:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2010-05-03T21:15:48.518-07:00</app:edited><title>My presentation at the Toronto Code Camp 2010</title><content type="html">&lt;p&gt;I had a blast meeting new people and sharing experiences writing software. I especially liked Barry Gervin’s keynote on successful product management and Todd Anglin’s talk on HTML5. &lt;/p&gt;  &lt;p&gt;As for me, I did and introductory talk on &lt;a href="http://www.slideshare.net/eperpignand/scrum-in-vs2010"&gt;Scrum and Visual Studio 2010&lt;/a&gt; briefly touching on some of the content of the Professional Scrum Developer course. The training has already started in several countries around the globe: Brazil, Australia and US. I’ll be teaching the &lt;a href="http://pyxis-tech.com/en/services/formation/liste-de-cours/scrum-developer-dotnet/"&gt;Montreal edition&lt;/a&gt; that’s coming in June 7th. It’s going to be awesome!&lt;/p&gt;  &lt;h2&gt;&lt;/h2&gt;  &lt;h3&gt;About the Professional Scrum Developer Course&lt;/h3&gt;  &lt;p&gt;The Scrum Developer course is a unique and intensive five-day experience for software developers. The course guides teams on how to turn product requirements into potentially shippable increments of software using the Scrum framework, Visual Studio 2010, and modern software engineering practices. Attendees will work in self-organizing, self-managing teams using a common instance of Visual Studio Team Foundation Server 2010 to achieve this goal. &lt;/p&gt;  &lt;p&gt;Course attendees are prepared to take an assessment at course completion and then become Certified Professional Scrum Developers.&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5356363081772370386-1396797453980384829?l=ernststhoughts.blogspot.com' alt='' /&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/MTDMwc7hj4hG11k2QIZH26TPZQY/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/MTDMwc7hj4hG11k2QIZH26TPZQY/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/MTDMwc7hj4hG11k2QIZH26TPZQY/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/MTDMwc7hj4hG11k2QIZH26TPZQY/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/ErnstsThoughts/~4/1gu3Bk02aeI" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://ernststhoughts.blogspot.com/feeds/1396797453980384829/comments/default" title="Publier les commentaires" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=5356363081772370386&amp;postID=1396797453980384829" title="0 commentaires" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/5356363081772370386/posts/default/1396797453980384829?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/5356363081772370386/posts/default/1396797453980384829?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/ErnstsThoughts/~3/1gu3Bk02aeI/my-presentation-at-toronto-code-camp.html" title="My presentation at the Toronto Code Camp 2010" /><author><name>Ernst Perpignand</name><uri>http://www.blogger.com/profile/16268268503536377997</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="31" height="32" src="http://3.bp.blogspot.com/-JMKo3fl9wV0/TYyN0W1rRwI/AAAAAAAAAC0/oeMf_zY8fEI/s220/profil-400px.jpg" /></author><thr:total>0</thr:total><feedburner:origLink>http://ernststhoughts.blogspot.com/2010/05/my-presentation-at-toronto-code-camp.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CEUDR3czcCp7ImA9WxBaFU4.&quot;"><id>tag:blogger.com,1999:blog-5356363081772370386.post-1281787189227569957</id><published>2010-03-25T08:51:00.000-07:00</published><updated>2010-03-25T08:51:16.988-07:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2010-03-25T08:51:16.988-07:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="scrum.org" /><category scheme="http://www.blogger.com/atom/ns#" term="training" /><category scheme="http://www.blogger.com/atom/ns#" term="PSD" /><title>Professional Scrum Developper Training</title><content type="html">&lt;span class="Apple-style-span" style="font-family: Arial; font-size: small;"&gt;&lt;span class="Apple-style-span" style="font-size: 13px;"&gt;&lt;span class="Apple-style-span" style="font-family: 'Times New Roman';"&gt;&lt;span class="Apple-style-span" style="font-size: medium;"&gt;&lt;span class="Apple-style-span" style="font-family: Arial; font-size: small;"&gt;&lt;span class="Apple-style-span" style="font-size: 13px;"&gt;Dates are now open for the &lt;a href="http://courses.scrum.org/about/ernst-perpignand"&gt;Professional Scrum Developper on the .Net&lt;/a&gt; platform training in the Montreal and Toronto areas. This training is fully packed with knowledge and hands-on exercices that are important for today's developers, architects and testers working in agile teams.&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-family: Arial; font-size: small;"&gt;&lt;span class="Apple-style-span" style="font-size: 13px;"&gt;&lt;span class="Apple-style-span" style="font-family: 'Times New Roman';"&gt;&lt;span class="Apple-style-span" style="font-size: medium;"&gt;&lt;span class="Apple-style-span" style="font-family: Arial; font-size: small;"&gt;&lt;span class="Apple-style-span" style="font-size: 13px;"&gt;&lt;br /&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-family: Arial; font-size: small;"&gt;&lt;span class="Apple-style-span" style="font-size: 13px;"&gt;&lt;span class="Apple-style-span" style="font-family: 'Times New Roman';"&gt;&lt;span class="Apple-style-span" style="font-size: medium;"&gt;&lt;span class="Apple-style-span" style="font-family: Arial; font-size: small;"&gt;&lt;span class="Apple-style-span" style="font-size: 13px;"&gt;&lt;span class="Apple-style-span" style="color: #555555; font-family: 'Lucida Sans Unicode', 'Lucida Grande', Tahoma, sans-serif; font-size: 12px; line-height: 21px;"&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-family: Arial; font-size: small;"&gt;&lt;span class="Apple-style-span" style="font-family: 'Times New Roman';"&gt;&lt;span class="Apple-style-span" style="font-family: Arial; font-size: small;"&gt;&lt;blockquote&gt;Scrum Developer course is a unique and intensive five-day experience for software developers. The course guides teams on how to turn product requirements into potentially shippable increments of software using the Scrum framework, Visual Studio 2010, and modern software engineering practices. Attendees will work in self-organizing, self-managing teams using a common instance of Visual Studio Team Foundation Server 2010 to achieve this goal.&lt;/blockquote&gt;&lt;blockquote&gt;Course attendees are prepared to take an assessment at course completion and then become Certified Professional Scrum Developers.&lt;/blockquote&gt;You can register via &lt;a href="http://courses.scrum.org/about/ernst-perpignand"&gt;scrum.org&lt;/a&gt;&lt;br /&gt;
&lt;br /&gt;
Hope to see you there!&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5356363081772370386-1281787189227569957?l=ernststhoughts.blogspot.com' alt='' /&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/p_TxaoLHyfNIUPkGjWmjk-zhAZY/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/p_TxaoLHyfNIUPkGjWmjk-zhAZY/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/p_TxaoLHyfNIUPkGjWmjk-zhAZY/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/p_TxaoLHyfNIUPkGjWmjk-zhAZY/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/ErnstsThoughts/~4/ozrd8qZAgbs" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://ernststhoughts.blogspot.com/feeds/1281787189227569957/comments/default" title="Publier les commentaires" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=5356363081772370386&amp;postID=1281787189227569957" title="0 commentaires" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/5356363081772370386/posts/default/1281787189227569957?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/5356363081772370386/posts/default/1281787189227569957?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/ErnstsThoughts/~3/ozrd8qZAgbs/professional-scrum-developper-training.html" title="Professional Scrum Developper Training" /><author><name>Ernst Perpignand</name><uri>http://www.blogger.com/profile/16268268503536377997</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="31" height="32" src="http://3.bp.blogspot.com/-JMKo3fl9wV0/TYyN0W1rRwI/AAAAAAAAAC0/oeMf_zY8fEI/s220/profil-400px.jpg" /></author><thr:total>0</thr:total><feedburner:origLink>http://ernststhoughts.blogspot.com/2010/03/professional-scrum-developper-training.html</feedburner:origLink></entry><entry gd:etag="W/&quot;D0QGRnoyeyp7ImA9WxBaEUQ.&quot;"><id>tag:blogger.com,1999:blog-5356363081772370386.post-913154292711998293</id><published>2010-03-21T11:15:00.000-07:00</published><updated>2010-03-21T11:15:27.493-07:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2010-03-21T11:15:27.493-07:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="ATDD" /><category scheme="http://www.blogger.com/atom/ns#" term="agile testing" /><category scheme="http://www.blogger.com/atom/ns#" term="TDD" /><title>Agile Testing</title><content type="html">I've just watch this &lt;a href="http://www.youtube.com/watch?v=bqrOnIECCSg&amp;amp;NR=1"&gt;talk&lt;/a&gt; from &lt;a href="http://www.qualitytree.com/company/elisabeth/"&gt;Elizabeth Hendrickson&lt;/a&gt;. Very interesting content on &lt;a href="http://testobsessed.com/wordpress/wp-content/uploads/2008/08/AgileTestingOverview.pdf"&gt;Agile Testing&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5356363081772370386-913154292711998293?l=ernststhoughts.blogspot.com' alt='' /&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/UVwUAStK-cfByHgffAEQyOTdAuw/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/UVwUAStK-cfByHgffAEQyOTdAuw/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/UVwUAStK-cfByHgffAEQyOTdAuw/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/UVwUAStK-cfByHgffAEQyOTdAuw/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/ErnstsThoughts/~4/bs58yp8EEzs" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://ernststhoughts.blogspot.com/feeds/913154292711998293/comments/default" title="Publier les commentaires" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=5356363081772370386&amp;postID=913154292711998293" title="0 commentaires" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/5356363081772370386/posts/default/913154292711998293?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/5356363081772370386/posts/default/913154292711998293?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/ErnstsThoughts/~3/bs58yp8EEzs/agile-testing.html" title="Agile Testing" /><author><name>Ernst Perpignand</name><uri>http://www.blogger.com/profile/16268268503536377997</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="31" height="32" src="http://3.bp.blogspot.com/-JMKo3fl9wV0/TYyN0W1rRwI/AAAAAAAAAC0/oeMf_zY8fEI/s220/profil-400px.jpg" /></author><thr:total>0</thr:total><feedburner:origLink>http://ernststhoughts.blogspot.com/2010/03/agile-testing.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CkEDRX8zeyp7ImA9WxBaEUk.&quot;"><id>tag:blogger.com,1999:blog-5356363081772370386.post-375716256987826882</id><published>2010-03-20T19:43:00.000-07:00</published><updated>2010-03-20T20:04:34.183-07:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2010-03-20T20:04:34.183-07:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="scrum.org" /><category scheme="http://www.blogger.com/atom/ns#" term="PSM" /><category scheme="http://www.blogger.com/atom/ns#" term="PSD" /><title>Professional Scrum Master Level II</title><content type="html">&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://3.bp.blogspot.com/_G-s-S83TooA/S6WMoSw2_vI/AAAAAAAAABo/XLhf-S5ssLk/s1600-h/ScrumDeveloperTrainer_200px.png" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="66" src="http://3.bp.blogspot.com/_G-s-S83TooA/S6WMoSw2_vI/AAAAAAAAABo/XLhf-S5ssLk/s200/ScrumDeveloperTrainer_200px.png" width="200" /&gt;&lt;/a&gt;&lt;/div&gt;I've just received confirmation from Ken Schwaber that I've successfully completed the &lt;a href="http://www.scrum.org/scrummaster/"&gt;Professional Scrum Master Level II assessment&lt;/a&gt; available on &lt;a href="http://scrum.org/"&gt;Scrum.org&lt;/a&gt;. I'm very proud of announcing that I'm also a &lt;a href="http://www.scrum.org/scrumdeveloper/"&gt;.Net &amp;nbsp;Professional Scrum Developper&lt;/a&gt; Trainer and that I will be delivering this &lt;a href="http://courses.scrum.org/classes/title/professional-scrum-developer-net"&gt;course&lt;/a&gt; in Canada in May and June. Stay tuned for the official dates.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5356363081772370386-375716256987826882?l=ernststhoughts.blogspot.com' alt='' /&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/c8MRtk5CZeBPPpgAjL_7hf0ac9c/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/c8MRtk5CZeBPPpgAjL_7hf0ac9c/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/c8MRtk5CZeBPPpgAjL_7hf0ac9c/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/c8MRtk5CZeBPPpgAjL_7hf0ac9c/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/ErnstsThoughts/~4/_iI9RL1rN6U" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://ernststhoughts.blogspot.com/feeds/375716256987826882/comments/default" title="Publier les commentaires" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=5356363081772370386&amp;postID=375716256987826882" title="0 commentaires" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/5356363081772370386/posts/default/375716256987826882?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/5356363081772370386/posts/default/375716256987826882?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/ErnstsThoughts/~3/_iI9RL1rN6U/professional-scrum-master-level-ii.html" title="Professional Scrum Master Level II" /><author><name>Ernst Perpignand</name><uri>http://www.blogger.com/profile/16268268503536377997</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="31" height="32" src="http://3.bp.blogspot.com/-JMKo3fl9wV0/TYyN0W1rRwI/AAAAAAAAAC0/oeMf_zY8fEI/s220/profil-400px.jpg" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://3.bp.blogspot.com/_G-s-S83TooA/S6WMoSw2_vI/AAAAAAAAABo/XLhf-S5ssLk/s72-c/ScrumDeveloperTrainer_200px.png" height="72" width="72" /><thr:total>0</thr:total><feedburner:origLink>http://ernststhoughts.blogspot.com/2010/03/professional-scrum-master-level-ii.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CEcHRn07fyp7ImA9WxBbGU4.&quot;"><id>tag:blogger.com,1999:blog-5356363081772370386.post-7273345514926993818</id><published>2010-03-18T09:48:00.001-07:00</published><updated>2010-03-18T10:07:17.307-07:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2010-03-18T10:07:17.307-07:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="Unit Test" /><category scheme="http://www.blogger.com/atom/ns#" term="Visual Studio" /><category scheme="http://www.blogger.com/atom/ns#" term="MSTest" /><category scheme="http://www.blogger.com/atom/ns#" term="TDD" /><title>Automated Unit Tests as Documentation</title><content type="html">&lt;h2&gt;&lt;/h2&gt;&lt;h4&gt;Introduction&lt;/h4&gt;In our quest to produce quality software and our relentless use of automated unit tests in our development activities, we’ve come to realize they possess other virtues as well. One of those being they stand as a documentation of the system being developed. I’ve taught this idea in &lt;a href="http://pyxis-tech.com/en/services/formation/liste-de-cours/ddd/"&gt;several&lt;/a&gt; &lt;a href="http://pyxis-tech.com/en/services/formation/liste-de-cours/modelisation-agile/"&gt;agile&lt;/a&gt; and &lt;a href="http://pyxis-tech.com/en/services/formation/liste-de-cours/tdd/"&gt;TDD&lt;/a&gt; courses. In this blog I want to give you an example of how that may be. I’m purposely not discussing &lt;a href="http://www.agilemodeling.com/essays/executableSpecifications.htm"&gt;executable specifications&lt;/a&gt; and &lt;a href="http://behaviour-driven.org/Introduction"&gt;Behaviour Driven Development&lt;/a&gt; as it would make this blog too long. My goal is to show how using some convention and Visual Studio 2010 can go a long way in cranking up your unit tests another notch.&lt;br /&gt;
&lt;h4&gt;Documentation of API usage&lt;/h4&gt;One clever use of unit tests is for learning a new API or even a new language. Writing several assertions to validate our understanding and assumptions about an API usage is very rewarding as the feedback is rapid and progress towards a goal is constantly measured. These learning tests may be kept around to document the assumptions made that constitute the basis of our solution. Here is an example of a learning test for the Character.IsWhiteSpace() method of the BCL.&lt;br /&gt;
&lt;span style="font-family: 'Courier New';"&gt;[TestMethod]      &lt;br /&gt;
[Description(@"White spaces are the following characters: ' ', '\t', '\n', '\r'")]       &lt;br /&gt;
public void May_be_a_white_space()       &lt;br /&gt;
{       &lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; Assert.IsTrue(char.IsWhiteSpace(' '));       &lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; Assert.IsTrue(char.IsWhiteSpace('\n'));       &lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; Assert.IsTrue(char.IsWhiteSpace('\t'));       &lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; Assert.IsTrue(char.IsWhiteSpace('\r')); &lt;/span&gt;&lt;br /&gt;
&lt;span style="font-family: 'Courier New';"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; Assert.IsFalse(char.IsWhiteSpace('A'));      &lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; Assert.IsFalse(char.IsWhiteSpace('+'));       &lt;br /&gt;
}&lt;/span&gt;&lt;br /&gt;
A test can also document how to use the classes we create in our solutions. The following is an example of such a test. In our chess software, this unit test documents the way of obtaining a chess piece which is to call the NewPiece() factory method and passing it a color (either Color.White or Color.Black) and a Kind (such as Kind.Pawn) as arguments.&lt;br /&gt;
&lt;span style="font-family: 'Courier New';"&gt;[TestMethod]      &lt;br /&gt;
[Description("A chess piece consists of a kind and a color that are specified when the piece is created")]       &lt;br /&gt;
public void Should_retain_its_color()       &lt;br /&gt;
{       &lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; Piece pawn =       &lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Piece.NewPiece(Color.Black, Kind.Pawn);       &lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; Assert.IsTrue(pawn.IsBlack);       &lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; Assert.IsFalse(pawn.IsWhite); &lt;/span&gt;&lt;br /&gt;
&lt;span style="font-family: 'Courier New';"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; pawn = Piece.NewPiece(Color.White, Kind.Pawn);      &lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; Assert.IsTrue(pawn.IsWhite);       &lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; Assert.IsFalse(pawn.IsBlack);       &lt;br /&gt;
}&lt;/span&gt;&lt;br /&gt;
&lt;h4&gt;Documentation of behaviours&lt;/h4&gt;Unit tests document behaviours of our code. &lt;span style="font-family: verd;"&gt;Test classes should&amp;nbsp; be given names that provide context for all the test methods they contain.&lt;/span&gt;&lt;br /&gt;
&lt;span style="font-family: 'Courier New';"&gt;[TestClass]     &lt;br /&gt;
public class When_displaying_a_board      &lt;br /&gt;
{      &lt;br /&gt;
&lt;/span&gt;&lt;span style="font-family: 'Courier New';"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; [TestMethod]     &lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; public void A_black_queen_should_show_as_Q()      &lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; {      &lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; …&lt;/span&gt;&lt;span style="font-family: 'Courier New';"&gt;     &lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; }      &lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="font-family: 'Courier New';"&gt;…&lt;/span&gt;      &lt;br /&gt;
}&lt;/span&gt;&lt;br /&gt;
Test methods should also be named in such a way that the behaviour they validate is evident.&lt;br /&gt;
&lt;span style="font-family: 'Courier New';"&gt;[TestMethod]      &lt;br /&gt;
[Description("The board is displayed on 8 lines with blacks pieces on line 8 and 7 and white pieces on lines 1 and 2")]       &lt;br /&gt;
public void It_should_show_all_pieces_in_their_initial_position()       &lt;br /&gt;
{       &lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; Assert.AreEqual(       &lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; "RNBQKBNR".Line() +       &lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; "PPPPPPPP".Line() +       &lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; "........".Line() +       &lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; "........".Line() +       &lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; "........".Line() +       &lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; "........".Line() +       &lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; "pppppppp".Line() +       &lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; "rnbqkbnr".Line(),       &lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; board.ToString()       &lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; );       &lt;br /&gt;
}&lt;/span&gt;&lt;br /&gt;
Notice that, instead of writing comments, I’m using the Description attribute to tie the behaviour being tested with some requirement or specification of the system. Personally, I’m not doing anything fancy with these descriptions, but you can imagine using a pattern that would provide more traceability in your environment as in the following.&lt;br /&gt;
&lt;span style="font-family: 'Courier New';"&gt;[TestMethod]     &lt;br /&gt;
[Description("US 234: Black pawns are shown as P, white pawns are shown as p")]       &lt;br /&gt;
public void A_white_pawn_should_show_as_p()       &lt;br /&gt;
{       &lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; Piece whitePawn = Piece.NewPiece(       &lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Color.White,       &lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;&lt;span style="font-family: 'Courier New';"&gt;Kind.Pawn);      &lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; Assert.AreEqual("p", whitePawn.ToString());       &lt;br /&gt;
}&lt;/span&gt;&lt;br /&gt;
&lt;h4&gt;Documentation of design specifications&lt;/h4&gt;Now comes the fun part! Because of the thought we’ve put in selecting meaningful names when the tests are executed in Visual Studio we get a result screen that looks like this.&lt;br /&gt;
&lt;br /&gt;
&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://2.bp.blogspot.com/_G-s-S83TooA/S6JaDE4lZ4I/AAAAAAAAABA/QI3dgfeaHhg/s1600-h/TADoc-naming.PNG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="186" src="http://2.bp.blogspot.com/_G-s-S83TooA/S6JaDE4lZ4I/AAAAAAAAABA/QI3dgfeaHhg/s400/TADoc-naming.PNG" width="400" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;
Notice how combining our test class and method names reads like a phrase that documents the design of our software. If we group the results by Description, we get a list of all the requirements of our software.&lt;br /&gt;
&lt;br /&gt;
&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://4.bp.blogspot.com/_G-s-S83TooA/S6JbgqhpxCI/AAAAAAAAABY/lToBAO6XZX8/s1600-h/TADoc-specifications.PNG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="257" src="http://4.bp.blogspot.com/_G-s-S83TooA/S6JbgqhpxCI/AAAAAAAAABY/lToBAO6XZX8/s640/TADoc-specifications.PNG" width="640" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;
If we expand one of the requirements, we see all the tests that validate it so we can trace back to the code that implements it.&lt;br /&gt;
&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://1.bp.blogspot.com/_G-s-S83TooA/S6JaaWQLLMI/AAAAAAAAABQ/hlI3U8J_ikk/s1600-h/TADoc-pawns.PNG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="63" src="http://1.bp.blogspot.com/_G-s-S83TooA/S6JaaWQLLMI/AAAAAAAAABQ/hlI3U8J_ikk/s400/TADoc-pawns.PNG" width="400" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;h4&gt;Conclusion&lt;/h4&gt;I hope I’ve convinced you that tests can serve as documentation using simple tricks, conventions and tooling you may already have at your disposal. Because this documentation is embedded in code it has a lot more chance of being maintained as the code evolves. These techniques require agreement amongst team members but they foster good practices of choosing explicit names and tying development work with planning activities for traceability purposes.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5356363081772370386-7273345514926993818?l=ernststhoughts.blogspot.com' alt='' /&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/1Xm7EtHnMm-BUYBQL2qZyHjoxIY/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/1Xm7EtHnMm-BUYBQL2qZyHjoxIY/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/1Xm7EtHnMm-BUYBQL2qZyHjoxIY/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/1Xm7EtHnMm-BUYBQL2qZyHjoxIY/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/ErnstsThoughts/~4/eHjPaX_wX3s" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://ernststhoughts.blogspot.com/feeds/7273345514926993818/comments/default" title="Publier les commentaires" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=5356363081772370386&amp;postID=7273345514926993818" title="0 commentaires" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/5356363081772370386/posts/default/7273345514926993818?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/5356363081772370386/posts/default/7273345514926993818?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/ErnstsThoughts/~3/eHjPaX_wX3s/automated-unit-tests-as-documentation.html" title="Automated Unit Tests as Documentation" /><author><name>Ernst Perpignand</name><uri>http://www.blogger.com/profile/16268268503536377997</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="31" height="32" src="http://3.bp.blogspot.com/-JMKo3fl9wV0/TYyN0W1rRwI/AAAAAAAAAC0/oeMf_zY8fEI/s220/profil-400px.jpg" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://2.bp.blogspot.com/_G-s-S83TooA/S6JaDE4lZ4I/AAAAAAAAABA/QI3dgfeaHhg/s72-c/TADoc-naming.PNG" height="72" width="72" /><thr:total>0</thr:total><feedburner:origLink>http://ernststhoughts.blogspot.com/2010/03/automated-unit-tests-as-documentation.html</feedburner:origLink></entry><entry gd:etag="W/&quot;Dk8HRX8yfyp7ImA9WxBbE0g.&quot;"><id>tag:blogger.com,1999:blog-5356363081772370386.post-3011085340618748093</id><published>2010-03-11T16:44:00.001-08:00</published><updated>2010-03-11T16:47:14.197-08:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2010-03-11T16:47:14.197-08:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="IDE" /><category scheme="http://www.blogger.com/atom/ns#" term="Java" /><title>Coding and Debugging in Bubbles</title><content type="html">&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://1.bp.blogspot.com/_G-s-S83TooA/S5mO5W0Mh6I/AAAAAAAAAA4/77JAI64ikVo/s1600-h/800px-Bubble_brokenchopstick.jpg" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://1.bp.blogspot.com/_G-s-S83TooA/S5mO5W0Mh6I/AAAAAAAAAA4/77JAI64ikVo/s320/800px-Bubble_brokenchopstick.jpg" /&gt;&lt;/a&gt;&lt;/div&gt;A new concept for the modern IDE, &lt;a href="http://www.cs.brown.edu/people/acb/codebubbles_site.htm"&gt;Code Bubbles&lt;/a&gt; allows developers to see and work different fragments of code as one unit. Debugging sessions can be associated with those units save and retrieved later for continued work. Quite impressive! It’s really a departure from the IDEs we’ve been using so far. Of course, this is not mainstream yet. Nevertheless,&amp;nbsp; I would like to try something like that and it would probably be interesting to have the equivalent in the .Net space.&lt;br /&gt;
I have to wonder though, what the impact will be on Object Oriented Programming and encapsulation if developers are lead to think of their code as fragments of functionality scattered in their code base…&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5356363081772370386-3011085340618748093?l=ernststhoughts.blogspot.com' alt='' /&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/s8yCSQkwVrvlO4oEa5oh2WQqyD8/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/s8yCSQkwVrvlO4oEa5oh2WQqyD8/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/s8yCSQkwVrvlO4oEa5oh2WQqyD8/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/s8yCSQkwVrvlO4oEa5oh2WQqyD8/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/ErnstsThoughts/~4/c6dYoyDxQh8" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://ernststhoughts.blogspot.com/feeds/3011085340618748093/comments/default" title="Publier les commentaires" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=5356363081772370386&amp;postID=3011085340618748093" title="0 commentaires" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/5356363081772370386/posts/default/3011085340618748093?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/5356363081772370386/posts/default/3011085340618748093?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/ErnstsThoughts/~3/c6dYoyDxQh8/coding-and-debugging-in-bubbles.html" title="Coding and Debugging in Bubbles" /><author><name>Ernst Perpignand</name><uri>http://www.blogger.com/profile/16268268503536377997</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="31" height="32" src="http://3.bp.blogspot.com/-JMKo3fl9wV0/TYyN0W1rRwI/AAAAAAAAAC0/oeMf_zY8fEI/s220/profil-400px.jpg" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://1.bp.blogspot.com/_G-s-S83TooA/S5mO5W0Mh6I/AAAAAAAAAA4/77JAI64ikVo/s72-c/800px-Bubble_brokenchopstick.jpg" height="72" width="72" /><thr:total>0</thr:total><feedburner:origLink>http://ernststhoughts.blogspot.com/2010/03/coding-and-debugging-in-bubbles.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CEQBQ3o7fSp7ImA9WxBbGU4.&quot;"><id>tag:blogger.com,1999:blog-5356363081772370386.post-8250996073635140310</id><published>2010-02-13T14:54:00.000-08:00</published><updated>2010-03-18T10:12:32.405-07:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2010-03-18T10:12:32.405-07:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="coding dojo" /><category scheme="http://www.blogger.com/atom/ns#" term="refactoring" /><category scheme="http://www.blogger.com/atom/ns#" term="kata" /><category scheme="http://www.blogger.com/atom/ns#" term="LINQ" /><category scheme="http://www.blogger.com/atom/ns#" term="SOLID" /><title>FizzBuzz à la façon LINQ</title><content type="html">Dernièrement mes collègues et moi exécutions le Kata &lt;a href="http://www.codingdojo.org/cgi-bin/wiki.pl?KataFizzBuzz"&gt;FizzBuzz&lt;/a&gt; dans le cadre de notre Dojo &lt;a href="http://pyxis-tech.com/fr/expertises/pratiques-dingenierie/"&gt;pratiques d’ingénierie&lt;/a&gt;. L’objectif était de pratiquer le développement piloté par les tests. Je dois avouer que ce fut fort amusant et la solution à laquelle nous sommes arrivés est tout à fait adéquate et présente un modèle objet élégant qui résoud le problème.&amp;nbsp; &lt;br /&gt;
La séquence FizzBuzz est générée par la méthode &lt;span style="font-family: 'Courier New';"&gt;CountTo&lt;/span&gt; de la classe &lt;span style="font-family: 'Courier New';"&gt;FizzBuzz&lt;/span&gt;. Cette dernière utilise un ensemble de règles qui vérifient si elles s’appliquent et transforment, le cas échéant, l’entier question soit en “Fizz”, “Buzz” ou “FizzBuzzz”.&lt;br /&gt;
&lt;span style="font-family: 'Courier New'; font-size: xx-small;"&gt;class FizzBuzz&amp;nbsp; &lt;br /&gt;
{&amp;nbsp; &lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; private readonly IRule[] _rules = new IRule[] {&amp;nbsp; &lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; new FizzBuzzRule(),&amp;nbsp; &lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; new BuzzRule(),&amp;nbsp; &lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; new FizzRule()&amp;nbsp; &lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; }; &lt;/span&gt;&lt;br /&gt;
&lt;span style="font-family: 'Courier New'; font-size: xx-small;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; private readonly IRule _defaultRule = new NumberRule(); &lt;/span&gt;&lt;br /&gt;
&lt;span style="font-family: 'Courier New'; font-size: xx-small;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; public string[] CountTo(int upperBound)&amp;nbsp; &lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; {&amp;nbsp; &lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; var sequence = new List&amp;lt;string&amp;gt;(); &lt;/span&gt;&lt;br /&gt;
&lt;span style="font-family: 'Courier New'; font-size: xx-small;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; foreach (var n in NumbersUpTo(upperBound))&amp;nbsp; &lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&amp;nbsp; &lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; sequence.Add(Interpret(n));&amp;nbsp; &lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; } &lt;/span&gt;&lt;br /&gt;
&lt;span style="font-family: 'Courier New'; font-size: xx-small;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; return RespondWith(sequence);&amp;nbsp; &lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; } &lt;/span&gt;&lt;br /&gt;
&lt;span style="font-family: 'Courier New'; font-size: xx-small;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; private static IEnumerable&amp;lt;int&amp;gt; NumbersUpTo(int n)      &lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; {       &lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; for ( int i = 1; i &amp;lt;= n; i++)       &lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; {       &lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; yield return i;       &lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }       &lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; } &lt;/span&gt;&lt;br /&gt;
&lt;span style="font-family: 'Courier New'; font-size: xx-small;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; private string Interpret(int n)&amp;nbsp; &lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; {&amp;nbsp; &lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; foreach (var rule in _rules)&amp;nbsp; &lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&amp;nbsp; &lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; if (rule.Applies(n)) return rule.Apply(n);&amp;nbsp; &lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&amp;nbsp; &lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; return _defaultRule.Apply(n);&amp;nbsp; &lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; } &lt;/span&gt;&lt;br /&gt;
&lt;span style="font-family: 'Courier New'; font-size: xx-small;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; private string[] RespondWith(List&amp;lt;string&amp;gt; result)&amp;nbsp; &lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; {&amp;nbsp; &lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; return result.ToArray();&amp;nbsp; &lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; }&amp;nbsp; &lt;br /&gt;
}&lt;/span&gt;&lt;br /&gt;
La classe &lt;span style="font-family: 'Courier New';"&gt;FizzRule&lt;/span&gt; est un exemple d’implémentation d’une rèlge.&lt;br /&gt;
&lt;span style="font-family: 'Courier New'; font-size: xx-small;"&gt;class FizzRule : IRule      &lt;br /&gt;
{       &lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; public bool Applies(int number)       &lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; {&amp;nbsp; &lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; return ShouldSayFizz(number);       &lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; } &lt;/span&gt;&lt;br /&gt;
&lt;span style="font-family: 'Courier New'; font-size: xx-small;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; private static bool ShouldSayFizz(int n)      &lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; {       &lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; return IsDivisibleByThree(n) || ContainsThree(n);       &lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; } &lt;/span&gt;&lt;br /&gt;
&lt;span style="font-family: 'Courier New'; font-size: xx-small;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; private static bool IsDivisibleByThree(int number)      &lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; {       &lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; return number % 3 == 0;       &lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; } &lt;/span&gt;&lt;br /&gt;
&lt;span style="font-family: 'Courier New'; font-size: xx-small;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; private static bool ContainsThree(int n)      &lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; {       &lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; return n.ToString().Contains("3");       &lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/span&gt;&lt;br /&gt;
&lt;span style="font-family: 'Courier New'; font-size: xx-small;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; public string Apply(int number)      &lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; {       &lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; return SayFizz();       &lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; } &lt;/span&gt;&lt;br /&gt;
&lt;span style="font-family: 'Courier New'; font-size: xx-small;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; private static string SayFizz()      &lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; {       &lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; return Fizz;       &lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/span&gt;&lt;br /&gt;
&lt;span style="font-family: 'Courier New'; font-size: xx-small;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; private const string Fizz = "fizz";&lt;/span&gt;&lt;br /&gt;
&lt;span style="font-family: 'Courier New'; font-size: xx-small;"&gt;}&lt;/span&gt;&lt;br /&gt;
Plus tard, je me suis demandé de quoi aurait l’air la solution si j’utilisais les fonctionnalités du langage C# 3.0 telles que LINQ, les expressions lambda et les méthodes d’extension. Avec notre batterie de tests comme garde-fou je me suis lancé dans une session de refactorisation au bout de laquelle je suis arrivé à la solution que je présente plus loin.&lt;br /&gt;
Les premières pistes que je choisis d’explorer sont les méthodes que Resharper suggère de changer en méthodes statiques. En fait, les méthodes statiques me font toujours penser à des méthodes utilitaires qui en général sont très réutilisables. C’est le cas par exemple des méthodes &lt;span style="font-family: 'Courier New';"&gt;IsDivisibleByThree&lt;/span&gt; et &lt;span style="font-family: 'Courier New';"&gt;ContainsThree&lt;/span&gt; de la classe &lt;span style="font-family: 'Courier New';"&gt;FizzRule&lt;/span&gt; plus haut. Je les rassemble donc dans la classe &lt;span style="font-family: 'Courier New';"&gt;IntExtensions&lt;/span&gt; après avoir introduit un peu de généricité pour qu’elles soient utilisables également dans la classe &lt;span style="font-family: 'Courier New';"&gt;BuzzRule&lt;/span&gt;&lt;strong&gt;.&lt;/strong&gt;&lt;br /&gt;
&lt;span style="font-family: 'Courier New'; font-size: xx-small;"&gt;public static class IntExtensions      &lt;br /&gt;
{       &lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; public static bool Contains(this int n, int number)       &lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; {       &lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; return n.ToString().Contains(number.ToString());       &lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; } &lt;/span&gt;&lt;br /&gt;
&lt;span style="font-family: 'Courier New'; font-size: xx-small;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; public static bool IsDivisibleBy(this int number, int dividend)      &lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; {       &lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; return number % dividend == 0;       &lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; }       &lt;br /&gt;
} &lt;/span&gt;&lt;br /&gt;
Avec ces modifications, la méthode &lt;span style="font-family: 'Courier New';"&gt;ShouldSayFizz&lt;/span&gt; se lit comme suit:&lt;br /&gt;
&lt;span style="font-family: 'Courier New'; font-size: xx-small;"&gt;private static bool ShouldSayFizz(int n)    &lt;br /&gt;
{     &lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; return n.IsDivisibleBy(3) || n.Contains(3);     &lt;br /&gt;
} &lt;/span&gt;  &lt;br /&gt;
Je suis content car la lisibilité du code n’en souffre pas. Je m’attaque de la même façon à la méthode &lt;span style="font-family: 'Courier New';"&gt;NumbersUpTo&lt;/span&gt; de la classe &lt;span style="font-family: 'Courier New';"&gt;FizzBuzz&lt;/span&gt;. J’en fais une méthode d’extension que je rajoute à la classe &lt;span style="font-family: 'Courier New';"&gt;IntExtensions&lt;/span&gt;. Je prends le soin de renommer la méthode &lt;span style="font-family: 'Courier New';"&gt;FirstNumbers&lt;/span&gt; pour une meilleure lecture du code client qui se lira &lt;br /&gt;
&lt;span style="font-family: 'Courier New'; font-size: xx-small;"&gt;foreach(int number in n.FirstNumbers()) { … }&lt;/span&gt;&lt;br /&gt;
Cela me rappelle mon cours d’analyse et la série des n premiers nombres entiers… En fouillant un peu dans MSDN, je retrouve comment générer une suite d’entiers grâce à la classe &lt;span style="font-family: 'Courier New';"&gt;Ennumerable&lt;/span&gt; et je modifie mon implémentation en conséquence. J’obtiens le résultat suivant&lt;br /&gt;
&lt;span style="font-family: 'Courier New'; font-size: xx-small;"&gt;public static class IntExtensions      &lt;br /&gt;
{       &lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; public static IEnumerable&amp;lt;int&amp;gt; FirstNumbers(this int n)       &lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; {       &lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; return Enumerable.Range(1, n);       &lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/span&gt;&lt;br /&gt;
&lt;span style="font-family: 'Courier New'; font-size: xx-small;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; public static bool Contains(this int n, int number)      &lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; {       &lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; return n.ToString().Contains(number.ToString());       &lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; } &lt;/span&gt;&lt;br /&gt;
&lt;span style="font-family: 'Courier New'; font-size: xx-small;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; public static bool IsDivisibleBy(this int number, int dividend)      &lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; {       &lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; return number % dividend == 0;       &lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; }       &lt;br /&gt;
}&lt;/span&gt;&lt;br /&gt;
Avec ces méthodes utilitaires hors de la classe &lt;span style="font-family: 'Courier New';"&gt;FizzRule&lt;/span&gt;, la responsabilité de celle-ci devient plus évidente et je la simplifie pour arriver au résultat suivant&lt;br /&gt;
&lt;span style="font-family: 'Courier New'; font-size: xx-small;"&gt;class FizzRule : IRule      &lt;br /&gt;
{       &lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; public const string Fizz = "fizz";       &lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; private const int Three = 3;&lt;/span&gt;&lt;br /&gt;
&lt;span style="font-family: 'Courier New'; font-size: xx-small;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; public bool AppliesTo(int number)      &lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; {       &lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; return number.IsDivisibleBy(Three) ||&amp;nbsp; number.Contains(Three);       &lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/span&gt;&lt;br /&gt;
&lt;span style="font-family: 'Courier New'; font-size: xx-small;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; public string Apply(int number)      &lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; {       &lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; return Fizz;       &lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; }       &lt;br /&gt;
}&lt;/span&gt;&lt;br /&gt;
Une bonne chose de faite! Je tourne mon attention vers la classe &lt;span style="font-family: 'Courier New';"&gt;FizzBuzz&lt;/span&gt;. Même si j’ai sorti la génération des nombres entiers hors de cette classe, elle a encore trop de responsabilités:&amp;nbsp; maintenir la liste des règles FizzBuzz, appliquer les règles qui conviennent, formater le résultat. C’est une violation évidente du principe de responsabilité unique (&lt;a href="http://en.wikipedia.org/wiki/Single_responsibility_principle"&gt;Single Responsibility Principle&lt;/a&gt;) de l’oncle &lt;a href="http://objectmentor.com/omTeam/martin_r.html"&gt;Bob&lt;/a&gt;. Je décide donc séparer tout ce qui touche à la transformation FizzBuzz dans une classe à part. Les règles et tranformations FizBuzz sont maintenant rendues dans la classe &lt;span style="font-family: 'Courier New';"&gt;FizzzBuzzExtensions&lt;/span&gt;. J’ai changé l’implémentation pour utiliser LINQ étant donnée que le résultat est plus compacte et tout de même très lisible.&lt;br /&gt;
&lt;span style="font-family: 'Courier New'; font-size: xx-small;"&gt;static class FizzBuzzExtensions      &lt;br /&gt;
{       &lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; internal static IEnumerable&amp;lt;string&amp;gt; AsFizzBuzzSequence      &lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;&lt;span style="font-family: 'Courier New'; font-size: xx-small;"&gt;(this IEnumerable&amp;lt;int&amp;gt; sequence)      &lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; {       &lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; return sequence.Select(numeral =&amp;gt; Transform(numeral));       &lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; } &lt;/span&gt;&lt;br /&gt;
&lt;span style="font-family: 'Courier New'; font-size: xx-small;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; private static string Transform(int n)      &lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; {       &lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; return FirstRuleThatApliesTo(n).Apply(n);       &lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; } &lt;/span&gt;&lt;br /&gt;
&lt;span style="font-family: 'Courier New'; font-size: xx-small;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; private static IRule FirstRuleThatApliesTo(int n)      &lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; {       &lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; return Rules.First(r =&amp;gt; r.AppliesTo(n));       &lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; } &lt;/span&gt;&lt;br /&gt;
&lt;span style="font-family: 'Courier New'; font-size: xx-small;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; private static readonly IRule[] Rules = new IRule[] {      &lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; new FizzBuzzRule(),       &lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; new BuzzRule(),       &lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; new FizzRule(),       &lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; new NumberRule()       &lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; };       &lt;br /&gt;
} &lt;/span&gt;&lt;br /&gt;
L’astuce d’encapsuler cette fonctionnalité en arrière d’une méthode d’extension facilite grandement la lecture de la classe &lt;span style="font-family: 'Courier New';"&gt;FizzBuzz&lt;/span&gt; qui devient &lt;br /&gt;
&lt;span style="font-family: 'Courier New'; font-size: xx-small;"&gt;class FizzBuzz      &lt;br /&gt;
{       &lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; public string[] CountTo(int n)       &lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; {       &lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; return RespondWith(n.FirstNumbers().AsFizzBuzzSequence());       &lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; } &lt;/span&gt;&lt;br /&gt;
&lt;span style="font-family: 'Courier New'; font-size: xx-small;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; internal static string[] RespondWith(IEnumerable&amp;lt;string&amp;gt; result)      &lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; {       &lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; return result.ToArray();       &lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; }       &lt;br /&gt;
}&lt;/span&gt;&lt;br /&gt;
Séparer ainsi les responsabilités dans différentes classes a grandement augmenté la clareté du design. De plus l’utilisation de LINQ et des méthodes d’extension fait en sorte que le code est très compacte quoique très expressif.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5356363081772370386-8250996073635140310?l=ernststhoughts.blogspot.com' alt='' /&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/xz4b2Mi262K2RAwilUWPDrFdiOk/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/xz4b2Mi262K2RAwilUWPDrFdiOk/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/xz4b2Mi262K2RAwilUWPDrFdiOk/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/xz4b2Mi262K2RAwilUWPDrFdiOk/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/ErnstsThoughts/~4/QQRCYBIIxN4" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://ernststhoughts.blogspot.com/feeds/8250996073635140310/comments/default" title="Publier les commentaires" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=5356363081772370386&amp;postID=8250996073635140310" title="0 commentaires" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/5356363081772370386/posts/default/8250996073635140310?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/5356363081772370386/posts/default/8250996073635140310?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/ErnstsThoughts/~3/QQRCYBIIxN4/fizzbuzz-la-facon-linq.html" title="FizzBuzz à la façon LINQ" /><author><name>Ernst Perpignand</name><uri>http://www.blogger.com/profile/16268268503536377997</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="31" height="32" src="http://3.bp.blogspot.com/-JMKo3fl9wV0/TYyN0W1rRwI/AAAAAAAAAC0/oeMf_zY8fEI/s220/profil-400px.jpg" /></author><thr:total>0</thr:total><feedburner:origLink>http://ernststhoughts.blogspot.com/2010/02/fizzbuzz-la-facon-linq.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DEQGQ3o-eSp7ImA9WxBXF0Q.&quot;"><id>tag:blogger.com,1999:blog-5356363081772370386.post-5696951531110591996</id><published>2010-01-29T09:27:00.001-08:00</published><updated>2010-01-29T12:18:42.451-08:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2010-01-29T12:18:42.451-08:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="coaching" /><category scheme="http://www.blogger.com/atom/ns#" term="Scrum" /><title>A Coaching Session</title><content type="html">Following is a conversation I had with a new Scum Master that had me thinking about how coaching works. It's not about telling people what to do but allowing them to figure out what needs to bo done. One powerful tool to do just that is changing perspectives. Reliving the facts as they happened but from a different angle may generate insights that open new opportunities for the coachee. Below is the conversation as I remember it. I hope it generates some insights for you as well.&lt;br /&gt;
&lt;br /&gt;
&lt;strong&gt;SM: &lt;/strong&gt;So what do you think about the sprint planning the other day ?&lt;br /&gt;
&lt;strong&gt;Coach: &lt;/strong&gt;Well one thing I noticed, and I did mention it on the spot, the team was about to bend some process improvement rules they agreed on implementing during the last retrospective. Your role as a Scrum Master is to make sure that the team follows its own process so that they may inspect and adapt it if need be. If the team partially implements the process in some cases and fully in some others, than interpretation of the results is more difficult and it will be harder to see what to improve next. You want to be careful when introducing changes to a process so that you know what you will be inspecting in the end.&lt;br /&gt;
&lt;strong&gt;SM: &lt;/strong&gt;Well you are right. Sticking to our decision not to include &lt;em&gt;big &lt;/em&gt;or&lt;em&gt; unclear stories &lt;/em&gt;in the sprint made us realise that we were accepting to tackle underspecified functionality. No wonder our estimates were off and we were not able to complete all the stories in the sprint.&lt;br /&gt;
&lt;strong&gt;Coach: &lt;/strong&gt;Good. But what about you ? What do you think about the sprint planning meeting ?&lt;br /&gt;
&lt;strong&gt;SM: &lt;/strong&gt;Well, one thing that bugs me is that team members don’t participate in the process.&lt;br /&gt;
&lt;strong&gt;Coach: &lt;/strong&gt;Oh? What do you mean ?&lt;br /&gt;
&lt;strong&gt;SM: &lt;/strong&gt;I mean they don’t seem to care or are not motivated. For instance, in our Scrum Masters group we thought it would be a good idea to let developers take turn at the Scrum Master’s role in the daily meeting so that they realize what we are dealing with. When I asked my team if one of them would like to take my place I had to wait for a long time before someone reluctantly offered to conduct the daily.&lt;br /&gt;
&lt;strong&gt;Coach: &lt;/strong&gt;So you want them to feel what it’s like to wear your shoes ?&lt;br /&gt;
&lt;strong&gt;SM: &lt;/strong&gt;It’s not that. It’s just that team members are not getting involved. You witnessed what happened at the sprint planning meeting. When I asked them if they were able to commit on delivering the sprint backlog, I didn’t get an answer.&lt;br /&gt;
&lt;strong&gt;Coach: &lt;/strong&gt;Well your organisation has a culture in which developers have been told what to do, when and how to do things. The change to self organisation is not going to happen overnight.&lt;br /&gt;
&lt;strong&gt;SM: &lt;/strong&gt;I know. That’s why I want them to get involved in the process but they don’t want to get onboard.&lt;br /&gt;
&lt;strong&gt;Coach: &lt;/strong&gt;And why do you think the don’t want to get onboard ?&lt;br /&gt;
&lt;strong&gt;SM: &lt;/strong&gt;I don’t know. And that’s why I’m asking you this because I’m running out of ideas.&lt;br /&gt;
&lt;strong&gt;Coach:&lt;/strong&gt; So… What are you doing that’s impeding them from getting involved in the process ?&lt;br /&gt;
&lt;strong&gt;SM: &lt;/strong&gt;I’m not sure I understand the question… What do you mean ?&lt;br /&gt;
&lt;strong&gt;Coach:&lt;/strong&gt; When you are not getting the response you’re expecting from others it’s often useful to consider that you are the one causing them to act the way they do. This empowers to make some changes instead of waiting for others to change their behaviour.&lt;br /&gt;
&lt;strong&gt;SM:&lt;/strong&gt; I’m not following you at all…&lt;br /&gt;
&lt;strong&gt;Coach: &lt;/strong&gt;Ok. So let’s go back to that sprint planning meeting. Remember how the room was laid out and where everyone was sitting. You remember ?&lt;br /&gt;
&lt;strong&gt;SM: &lt;/strong&gt;Yeah…&lt;br /&gt;
&lt;strong&gt;Coach: &lt;/strong&gt;Let’s say you take John’s place. What do you see ?&lt;br /&gt;
&lt;strong&gt;SM:&lt;/strong&gt; I’m really not sure where you want to go with this… But the only thing I see is that the monitor is too far away and its difficult to read.&lt;br /&gt;
&lt;strong&gt;Coach:&lt;/strong&gt; Well that’s something to consider. And what are you doing in the meantime ?&lt;br /&gt;
&lt;strong&gt;SM:&lt;/strong&gt; I’m updating the backlog and moving stuff around.&lt;br /&gt;
&lt;strong&gt;Coach: &lt;/strong&gt;And how do you think John is perceiving this given the organisational culture ?&lt;br /&gt;
&lt;strong&gt;SM: &lt;/strong&gt;I see… So we should probably use index cards that team members will be able to play with and update themselves.&lt;br /&gt;
&lt;strong&gt;Coach: &lt;/strong&gt;Good! That way you solve two problems. By giving the team access to the sprint backlog you allow them to grasp more fully and own its content. They’ll probably feel more comfortable committing to it at the end.&lt;br /&gt;
&lt;strong&gt;SM (not really listening anymore):&lt;/strong&gt; I can even update the backlog in the tool afterwards so that the flow is not interrupted. Thank you. That’s a great idea!&lt;br /&gt;
&lt;strong&gt;Coach:&lt;/strong&gt; Well you know it wasn’t my idea. It’s yours. You just had to change your perspective on things.&lt;br /&gt;
&lt;strong&gt;SM (already leaving): &lt;/strong&gt;Good. I’ll let you know how it turns out. Talk to you soon.&lt;br /&gt;
&lt;strong&gt;Coach (to himself): &lt;/strong&gt;I’m not really sure what he saw exactly, but changing his perspective really allowed him to find new ideas on how to tackle this issue. This coaching stuff really works… I should blog this…&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5356363081772370386-5696951531110591996?l=ernststhoughts.blogspot.com' alt='' /&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/U0fccLZqSqBDgGhB22CT3csT9Z8/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/U0fccLZqSqBDgGhB22CT3csT9Z8/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/U0fccLZqSqBDgGhB22CT3csT9Z8/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/U0fccLZqSqBDgGhB22CT3csT9Z8/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/ErnstsThoughts/~4/gdGyGO3PvCQ" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://ernststhoughts.blogspot.com/feeds/5696951531110591996/comments/default" title="Publier les commentaires" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=5356363081772370386&amp;postID=5696951531110591996" title="0 commentaires" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/5356363081772370386/posts/default/5696951531110591996?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/5356363081772370386/posts/default/5696951531110591996?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/ErnstsThoughts/~3/gdGyGO3PvCQ/coaching-session.html" title="A Coaching Session" /><author><name>Ernst Perpignand</name><uri>http://www.blogger.com/profile/16268268503536377997</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="31" height="32" src="http://3.bp.blogspot.com/-JMKo3fl9wV0/TYyN0W1rRwI/AAAAAAAAAC0/oeMf_zY8fEI/s220/profil-400px.jpg" /></author><thr:total>0</thr:total><feedburner:origLink>http://ernststhoughts.blogspot.com/2010/01/coaching-session.html</feedburner:origLink></entry><entry gd:etag="W/&quot;AkMARH89fSp7ImA9WxBREkU.&quot;"><id>tag:blogger.com,1999:blog-5356363081772370386.post-2089760106825326600</id><published>2009-12-31T11:27:00.001-08:00</published><updated>2009-12-31T11:40:45.165-08:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-12-31T11:40:45.165-08:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="général" /><title>De retour après un long mutisme…</title><content type="html">&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://2.bp.blogspot.com/_G-s-S83TooA/Szz7dRV2uOI/AAAAAAAAAAM/1cuKBEmFNEI/s1600-h/lezard.jpg" imageanchor="1" style="clear: left; cssfloat: left; float: left; margin-bottom: 1em; margin-right: 1em;"&gt;&lt;img border="0" ps="true" src="http://2.bp.blogspot.com/_G-s-S83TooA/Szz7dRV2uOI/AAAAAAAAAAM/1cuKBEmFNEI/s320/lezard.jpg" /&gt;&lt;/a&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div align="left"&gt;Voilà deux ans que je m’adonne à d’autres choses intéressantes. Et comme&amp;nbsp;ce lézard, aujourd’hui je refais tranquillement surface pour partager les idées qui me trottent dans la tête. &lt;br /&gt;
Beaucoup de nouveautés depuis! De nos jours, je me consacre presqu’uniquement au développement logiciel sur la plateforme .Net et à l’accompagnement d’équipes qui effectuent une transition agile. La compagnie pour laquelle je bosse est en pleine croissance et de nouveaux défis se profilent à l’horizon. Je vais donc avoir plein de matières à réflexion à vous proposer: Windows 7, .Net 4.0, pratiques d’ingénierie agile... &lt;br /&gt;
&lt;/div&gt;&lt;div align="left"&gt;Je m’approprie, donc les nouveaux outils de blogue à ma disposition et je vous reviens bientôt.&lt;br /&gt;
&lt;/div&gt;&lt;div align="left"&gt;Joyeux temps des fêtes!&lt;br /&gt;
&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5356363081772370386-2089760106825326600?l=ernststhoughts.blogspot.com' alt='' /&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/dzJPmr-5zrocjRyFZuxgZ5S4Jto/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/dzJPmr-5zrocjRyFZuxgZ5S4Jto/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/dzJPmr-5zrocjRyFZuxgZ5S4Jto/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/dzJPmr-5zrocjRyFZuxgZ5S4Jto/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/ErnstsThoughts/~4/vxAD53ob4h0" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://ernststhoughts.blogspot.com/feeds/2089760106825326600/comments/default" title="Publier les commentaires" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=5356363081772370386&amp;postID=2089760106825326600" title="0 commentaires" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/5356363081772370386/posts/default/2089760106825326600?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/5356363081772370386/posts/default/2089760106825326600?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/ErnstsThoughts/~3/vxAD53ob4h0/de-retour-apres-un-long-mutisme.html" title="De retour après un long mutisme…" /><author><name>Ernst Perpignand</name><uri>http://www.blogger.com/profile/16268268503536377997</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="31" height="32" src="http://3.bp.blogspot.com/-JMKo3fl9wV0/TYyN0W1rRwI/AAAAAAAAAC0/oeMf_zY8fEI/s220/profil-400px.jpg" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://2.bp.blogspot.com/_G-s-S83TooA/Szz7dRV2uOI/AAAAAAAAAAM/1cuKBEmFNEI/s72-c/lezard.jpg" height="72" width="72" /><thr:total>0</thr:total><feedburner:origLink>http://ernststhoughts.blogspot.com/2009/12/de-retour-apres-un-long-mutisme.html</feedburner:origLink></entry><entry gd:etag="W/&quot;Ak8ARH45fCp7ImA9WB5QEUs.&quot;"><id>tag:blogger.com,1999:blog-5356363081772370386.post-515290613714092052</id><published>2007-06-29T18:49:00.000-07:00</published><updated>2007-06-29T19:00:45.024-07:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2007-06-29T19:00:45.024-07:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="NUnit" /><category scheme="http://www.blogger.com/atom/ns#" term="TDD" /><title>NUnit devient plus expressif</title><content type="html">J'ai téléchargé la dernière version de NUnit 2.4 et je suis content des améliorations apportées à l'API. Le nouveau &lt;a href="http://nunit.com/index.php?p=constraintModel&amp;r=2.4.1"&gt;modèle d'assertion basé sur les contraintes&lt;/a&gt; rend les tests plus expressifs.&lt;br /&gt;Je n'écrirai plus les assertions du type:&lt;br /&gt;&lt;blockquote&gt;&lt;/blockquote&gt;&lt;span style="font-family:courier new;"&gt;Assert.AreEqual(myString, "Hello");&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:Courier New;"&gt;&lt;/span&gt;&lt;br /&gt;&lt;span &gt;mais plutôt:&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;Assert.That(myString, Is.Equal("Hello"));&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;ou mieux encore si ma classe de test hérite de AssertionHelper, je pourrai écrire&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;Expect(myString, EqualTo("Hello"));&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Il me semble que cette syntaxe est plus lisible&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5356363081772370386-515290613714092052?l=ernststhoughts.blogspot.com' alt='' /&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/2EB30zqCCLQT-cDFtiD3vk3sSDs/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/2EB30zqCCLQT-cDFtiD3vk3sSDs/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/2EB30zqCCLQT-cDFtiD3vk3sSDs/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/2EB30zqCCLQT-cDFtiD3vk3sSDs/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/ErnstsThoughts/~4/BGPv9ey05w4" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://ernststhoughts.blogspot.com/feeds/515290613714092052/comments/default" title="Publier les commentaires" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=5356363081772370386&amp;postID=515290613714092052" title="3 commentaires" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/5356363081772370386/posts/default/515290613714092052?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/5356363081772370386/posts/default/515290613714092052?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/ErnstsThoughts/~3/BGPv9ey05w4/nunit-devient-plus-expressif.html" title="NUnit devient plus expressif" /><author><name>Ernst Perpignand</name><uri>http://www.blogger.com/profile/16268268503536377997</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="31" height="32" src="http://3.bp.blogspot.com/-JMKo3fl9wV0/TYyN0W1rRwI/AAAAAAAAAC0/oeMf_zY8fEI/s220/profil-400px.jpg" /></author><thr:total>3</thr:total><feedburner:origLink>http://ernststhoughts.blogspot.com/2007/06/nunit-devient-plus-expressif.html</feedburner:origLink></entry><entry gd:etag="W/&quot;AkYFRX47fSp7ImA9WB5QEUs.&quot;"><id>tag:blogger.com,1999:blog-5356363081772370386.post-9114206902035642575</id><published>2007-06-29T18:24:00.000-07:00</published><updated>2007-06-29T18:48:34.005-07:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2007-06-29T18:48:34.005-07:00</app:edited><title>Classification des tests</title><content type="html">&lt;a href="http://grabbagoft.blogspot.com/"&gt;Jimmy Bogard&lt;/a&gt; a un excellent message sur la &lt;a href="http://grabbagoft.blogspot.com/2007/06/classifying-tests.html"&gt;classification des tests&lt;/a&gt;:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Les tests unitaires vérifient le bon fonctionnement d'une méthode/fonction en isolation du reste du système. Ils doivent s'exécuter rapidement et n'avoir qu'une cause d'échec. Pour ce genre de tests on évite d'impliquer une base de données, un service web ou tout autre système externe. &lt;/li&gt;&lt;li&gt;Les tests d'intégration vérifient le bon fonctionnement d'un système lorsqu'il est intégré avec les systèmes externes tels qu'une base de données par exemple. En général, ces tests vérifient que les données sont bien mises à jours dans la base de données ou qu'un courriel a bien été envoyé.&lt;/li&gt;&lt;li&gt;Les tests fonctionnels vérifient le bon fonctionnement de l'application dans son ensemble du point de vue de l'usager.&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;À lire également le message de &lt;a href="http://codebetter.com/blogs/jeffrey.palermo/archive/2007/06/28/levels-of-automated-testing-within-a-single-application.aspx"&gt;Jeffrey Palermo&lt;/a&gt; sur le sujet&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5356363081772370386-9114206902035642575?l=ernststhoughts.blogspot.com' alt='' /&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/ZtB9oY5bDB7dvxGwyTg9jCBXoDg/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/ZtB9oY5bDB7dvxGwyTg9jCBXoDg/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/ZtB9oY5bDB7dvxGwyTg9jCBXoDg/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/ZtB9oY5bDB7dvxGwyTg9jCBXoDg/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/ErnstsThoughts/~4/Z7wfnkZvMX8" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://ernststhoughts.blogspot.com/feeds/9114206902035642575/comments/default" title="Publier les commentaires" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=5356363081772370386&amp;postID=9114206902035642575" title="0 commentaires" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/5356363081772370386/posts/default/9114206902035642575?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/5356363081772370386/posts/default/9114206902035642575?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/ErnstsThoughts/~3/Z7wfnkZvMX8/classification-des-tests.html" title="Classification des tests" /><author><name>Ernst Perpignand</name><uri>http://www.blogger.com/profile/16268268503536377997</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="31" height="32" src="http://3.bp.blogspot.com/-JMKo3fl9wV0/TYyN0W1rRwI/AAAAAAAAAC0/oeMf_zY8fEI/s220/profil-400px.jpg" /></author><thr:total>0</thr:total><feedburner:origLink>http://ernststhoughts.blogspot.com/2007/06/classification-des-tests.html</feedburner:origLink></entry><entry gd:etag="W/&quot;A0YESHk7cCp7ImA9WB5SF0U.&quot;"><id>tag:blogger.com,1999:blog-5356363081772370386.post-2536387814890562428</id><published>2007-06-13T19:20:00.000-07:00</published><updated>2007-06-13T19:45:09.708-07:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2007-06-13T19:45:09.708-07:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="DDD" /><title>Pourquoi introduire de nouveaux acronymes ?</title><content type="html">J'ai visioné une présentation de Dan Ver Johnsson sur les &lt;a href="http://www.bejug.org/confluenceBeJUG/display/PARLEYS/Get+Value+Objects+right+for+Domain+Driven+Design?showComments=true"&gt;Domain Logical Value Objects&lt;/a&gt;. C'est une présentation sur la manière d'introduire le Domain Driven Design dans du code patrimonial. En gros, le présentateur propose de commencer à rendre explicite les valeurs significatives pour le domaine en question: numéro de téléphone, taux de change, etc. De cette manière on peut rapidement bénéficier des améliorations suivantes:&lt;br /&gt;&lt;ol&gt;&lt;li&gt;Clareté des API de Service&lt;/li&gt;&lt;li&gt;Validation et gestion d'erreurs proches des données&lt;/li&gt;&lt;li&gt;Simplification du code de la logique de métier&lt;/li&gt;&lt;li&gt;Tests&lt;/li&gt;&lt;/ol&gt;&lt;p&gt;Même si je suis d'accord avec les points présentés, je regrette toutefois que le présentateur aie ressenti le besoin de fournir un autre acronyme/terme technique: Domain Logical Value Object. Il me semble que tout ce dont il a parlé c'est des Value Object tels que présentés par Eric Evans dans son livre sur le DDD. &lt;/p&gt;&lt;p&gt;Par ailleurs, à un moment donné il propose un exercice pour trouver les situations où l'application du DDD est opportune. Selon moi, la réponse est que cela dépend toujours du contexte dans lequel ces projets sont entrepris. On ne peut répondre juste en se basant sur l'énoncé du domaine. Il faut impliquer les experts afin de connaître où ils en tirent le plus de valeur.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5356363081772370386-2536387814890562428?l=ernststhoughts.blogspot.com' alt='' /&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/KNrqAa19J0WK1gMhlg05Z0911Qw/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/KNrqAa19J0WK1gMhlg05Z0911Qw/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/KNrqAa19J0WK1gMhlg05Z0911Qw/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/KNrqAa19J0WK1gMhlg05Z0911Qw/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/ErnstsThoughts/~4/NN84pSNb_u0" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://ernststhoughts.blogspot.com/feeds/2536387814890562428/comments/default" title="Publier les commentaires" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=5356363081772370386&amp;postID=2536387814890562428" title="0 commentaires" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/5356363081772370386/posts/default/2536387814890562428?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/5356363081772370386/posts/default/2536387814890562428?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/ErnstsThoughts/~3/NN84pSNb_u0/pourquoi-introduire-de-nouveaux.html" title="Pourquoi introduire de nouveaux acronymes ?" /><author><name>Ernst Perpignand</name><uri>http://www.blogger.com/profile/16268268503536377997</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="31" height="32" src="http://3.bp.blogspot.com/-JMKo3fl9wV0/TYyN0W1rRwI/AAAAAAAAAC0/oeMf_zY8fEI/s220/profil-400px.jpg" /></author><thr:total>0</thr:total><feedburner:origLink>http://ernststhoughts.blogspot.com/2007/06/pourquoi-introduire-de-nouveaux.html</feedburner:origLink></entry><entry gd:etag="W/&quot;Ak4ESHg6eip7ImA9WB5QEUs.&quot;"><id>tag:blogger.com,1999:blog-5356363081772370386.post-3462188988594193042</id><published>2007-06-12T20:20:00.000-07:00</published><updated>2007-06-29T19:01:49.612-07:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2007-06-29T19:01:49.612-07:00</app:edited><title>Domain Driven Design et Spécifications éxécutables</title><content type="html">Dernièrement, je donnais un cours sur le &lt;a href="http://www.domainlanguage.com/ddd/index.html"&gt;Domain Driven Design&lt;/a&gt;. Pour les exercices pratiques j'ai utilisé &lt;a href="http://www.greenpeppersoftware.com/"&gt;GreenPepper&lt;/a&gt; afin de pouvoir spécifier les fonctionnalités à accomplir sans pour autant imposer un design aux participants. Je dois avouer que je suis un peu perplexe quant au résultat de cette expérience. Les participants ont eu l'air de s'intéresser plus au produit qu'aux techniques présentées dans le cours afin de mieux cerner le domaine. Sans compter que l'apprentissage de l'outil peut constituer une barrière importante à la bonne conduite de l'exercice. Pourtant une approche basée sur des tests unitaires fournis ne me semble pas idéale car le design serait alors imposé. Les spécifications exécutables, par contre, se situent plus au niveau du modèle et du langage et de ce fait me paraissent encore plus appropriées...&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5356363081772370386-3462188988594193042?l=ernststhoughts.blogspot.com' alt='' /&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/Zdroj5cKAoJzGcaud3mPngQknuo/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/Zdroj5cKAoJzGcaud3mPngQknuo/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/Zdroj5cKAoJzGcaud3mPngQknuo/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/Zdroj5cKAoJzGcaud3mPngQknuo/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/ErnstsThoughts/~4/P1LDAflDLpM" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://ernststhoughts.blogspot.com/feeds/3462188988594193042/comments/default" title="Publier les commentaires" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=5356363081772370386&amp;postID=3462188988594193042" title="0 commentaires" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/5356363081772370386/posts/default/3462188988594193042?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/5356363081772370386/posts/default/3462188988594193042?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/ErnstsThoughts/~3/P1LDAflDLpM/domain-driver-design-et-spcifications.html" title="Domain Driven Design et Spécifications éxécutables" /><author><name>Ernst Perpignand</name><uri>http://www.blogger.com/profile/16268268503536377997</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="31" height="32" src="http://3.bp.blogspot.com/-JMKo3fl9wV0/TYyN0W1rRwI/AAAAAAAAAC0/oeMf_zY8fEI/s220/profil-400px.jpg" /></author><thr:total>0</thr:total><feedburner:origLink>http://ernststhoughts.blogspot.com/2007/06/domain-driver-design-et-spcifications.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CEYFQ3o-fCp7ImA9WB5TFEQ.&quot;"><id>tag:blogger.com,1999:blog-5356363081772370386.post-3292219103215601039</id><published>2007-05-29T19:23:00.001-07:00</published><updated>2007-05-29T19:28:32.454-07:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2007-05-29T19:28:32.454-07:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="logiciel libre" /><category scheme="http://www.blogger.com/atom/ns#" term="moteur de recherche" /><title>Krugle - un moteur de recherche pour le logiciel libre</title><content type="html">Aujourd'hui j'ai découvert &lt;a href="http://www.krugle.com"&gt;krugle&lt;/a&gt; un moteur de recherche dédié au logiciel libre. Ce site permet d'effectuer des recherches sur une multitudes de dépots de sources de projets du domaine public. Adieu les recherches sur Google...&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5356363081772370386-3292219103215601039?l=ernststhoughts.blogspot.com' alt='' /&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/PaeDUendmPQDBxANnz0qZBu76z4/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/PaeDUendmPQDBxANnz0qZBu76z4/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/PaeDUendmPQDBxANnz0qZBu76z4/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/PaeDUendmPQDBxANnz0qZBu76z4/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/ErnstsThoughts/~4/M56KoFZAGfU" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://ernststhoughts.blogspot.com/feeds/3292219103215601039/comments/default" title="Publier les commentaires" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=5356363081772370386&amp;postID=3292219103215601039" title="0 commentaires" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/5356363081772370386/posts/default/3292219103215601039?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/5356363081772370386/posts/default/3292219103215601039?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/ErnstsThoughts/~3/M56KoFZAGfU/krugle-un-moteur-de-recherche-pour-le.html" title="Krugle - un moteur de recherche pour le logiciel libre" /><author><name>Ernst Perpignand</name><uri>http://www.blogger.com/profile/16268268503536377997</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="31" height="32" src="http://3.bp.blogspot.com/-JMKo3fl9wV0/TYyN0W1rRwI/AAAAAAAAAC0/oeMf_zY8fEI/s220/profil-400px.jpg" /></author><thr:total>0</thr:total><feedburner:origLink>http://ernststhoughts.blogspot.com/2007/05/krugle-un-moteur-de-recherche-pour-le.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CkIDQnY_cCp7ImA9WBFaGU4.&quot;"><id>tag:blogger.com,1999:blog-5356363081772370386.post-5329812243075562015</id><published>2007-05-23T07:25:00.000-07:00</published><updated>2007-05-23T07:29:33.848-07:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2007-05-23T07:29:33.848-07:00</app:edited><title>My first walk in the blogosphere</title><content type="html">Hey,&lt;br /&gt;&lt;br /&gt;I'm new to this! In the following weeks, I'll try to share some of my ideas with you. Hope you find them interesting...&lt;br /&gt;&lt;br /&gt;Ernst&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5356363081772370386-5329812243075562015?l=ernststhoughts.blogspot.com' alt='' /&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/Bp51H0imvgkbTKa6fnrF0WgjXyw/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/Bp51H0imvgkbTKa6fnrF0WgjXyw/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/Bp51H0imvgkbTKa6fnrF0WgjXyw/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/Bp51H0imvgkbTKa6fnrF0WgjXyw/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/ErnstsThoughts/~4/3TxAU1co354" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://ernststhoughts.blogspot.com/feeds/5329812243075562015/comments/default" title="Publier les commentaires" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=5356363081772370386&amp;postID=5329812243075562015" title="0 commentaires" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/5356363081772370386/posts/default/5329812243075562015?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/5356363081772370386/posts/default/5329812243075562015?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/ErnstsThoughts/~3/3TxAU1co354/my-first-walk-in-blogosphere.html" title="My first walk in the blogosphere" /><author><name>Ernst Perpignand</name><uri>http://www.blogger.com/profile/16268268503536377997</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="31" height="32" src="http://3.bp.blogspot.com/-JMKo3fl9wV0/TYyN0W1rRwI/AAAAAAAAAC0/oeMf_zY8fEI/s220/profil-400px.jpg" /></author><thr:total>0</thr:total><feedburner:origLink>http://ernststhoughts.blogspot.com/2007/05/my-first-walk-in-blogosphere.html</feedburner:origLink></entry></feed>

