<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:blogger='http://schemas.google.com/blogger/2008' xmlns:georss='http://www.georss.org/georss' xmlns:gd='http://schemas.google.com/g/2005' xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-9924016</id><updated>2012-04-16T02:22:28.815+01:00</updated><title type='text'>You're a good looking blog, what's your owner's name?</title><subtitle type='html'>Richard Jonas's blog about .NET, web development and agile methodologies.</subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://richardjonasblog.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9924016/posts/default'/><link rel='alternate' type='text/html' href='http://richardjonasblog.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><link rel='next' type='application/atom+xml' href='http://www.blogger.com/feeds/9924016/posts/default?start-index=26&amp;max-results=25'/><author><name>Richard Jonas</name><uri>http://www.blogger.com/profile/14997733754093048669</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='28' src='http://www.btinternet.com/~rjonas/picsmall.jpg'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>102</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>25</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-9924016.post-4997634526345822504</id><published>2010-11-06T15:16:00.000Z</published><updated>2010-11-06T15:16:22.253Z</updated><title type='text'>Code Review Checklist</title><content type='html'>Here's a checklist for code reviews (in any language).&lt;br /&gt;&lt;br /&gt;1) Would the logic be understandable by a developer of average ability proficient with other programming languages but not this one?&lt;br /&gt;&lt;br /&gt;If it uses language features or obscure design patterns that are "clever" without good reason (e.g. something needs to have the maximum performance), then it won't be maintainable and someone will replace it or add to it badly.  We've all seen code written by someone who has just read the "Design Patterns" book and wants to use all of them.  If you want to use the latest trendy language features, think about if someone in 10 years time will know about these of if they will have fallen into obsolescence.&lt;br /&gt;&lt;br /&gt;When reviewing code, thinking about this will make long term maintainability easier. It may result in some discussion about which language features and design patterns should be used and standardising on these will mean everyone understands each other's code better.&lt;br /&gt;&lt;br /&gt;2) Are properties nouns and methods verb noun phrases.&lt;br /&gt;&lt;br /&gt;If properties are not nouns and methods not verb-noun phrases, then it's a sign that these haven't been thought about carefully and the code will be more difficult to maintain.&lt;br /&gt;&lt;br /&gt;When reviewing code it's easy to overlook this, but very quick to check.&lt;br /&gt;&lt;br /&gt;3) Is there an obvious way of testing each method.&lt;br /&gt;&lt;br /&gt;Of course we all know all methods should have unit tests but in the real world this isn't always possible. However, if there isn't one and it isn't obvious how to write one, then the method could probably be expressed better in a different way.&lt;br /&gt;&lt;br /&gt;When reviewing code, if you can ask "how will this method be tested" you can better follow the logic.  If you can't answer this question then there are more likely to be complexities that aren't picked up until it's too late.&lt;br /&gt;&lt;br /&gt;4) Do the names of properties, methods and classes match the names used elsewhere in the organisation?&lt;br /&gt;&lt;br /&gt;If the names of objects are different (e.g. your code refers to a regular customer and the business a star customer), then it will be harder to explain what you are doing and more likely that requirements will be misinterpreted.  It's a good idea to document these in a wiki to have a single point of reference for these.&lt;br /&gt;&lt;br /&gt;This also means if you are working on a method, you can say "I'm working on x in class y", and someone who knows your business area but who is not a developer know would know what you are talking about. This would improve the trust between developers and domain experts.&lt;br /&gt;&lt;br /&gt;When reviewing code, thinking about this will help you understand the business domain and make you better able to communicate with them and get accurate requirements in future.&lt;br /&gt;&lt;br /&gt;5) Is the total complexity of the system affected as little as possible? (I would define this as the number of classes * average size of each class * the total number of other classes a class has to know about).  &lt;br /&gt;&lt;br /&gt;This means if you're creating a new function that means the class it is in has to know about 3 more classes than before, the system is more complex as there are more dependencies between classes. &lt;br /&gt;&lt;br /&gt;When reviewing code, if you think about this and rewrite if necessary it will reduce the numbers of possible points of failure and mean that testing is more likely to pick up problems before anything goes live.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9924016-4997634526345822504?l=richardjonasblog.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://richardjonasblog.blogspot.com/feeds/4997634526345822504/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9924016&amp;postID=4997634526345822504' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9924016/posts/default/4997634526345822504'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9924016/posts/default/4997634526345822504'/><link rel='alternate' type='text/html' href='http://richardjonasblog.blogspot.com/2010/11/code-review-checklist.html' title='Code Review Checklist'/><author><name>Richard Jonas</name><uri>http://www.blogger.com/profile/14997733754093048669</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='28' src='http://www.btinternet.com/~rjonas/picsmall.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9924016.post-7993314394417552346</id><published>2010-11-05T12:07:00.000Z</published><updated>2010-11-05T12:07:27.187Z</updated><title type='text'>Characteristics of an effective programmer.</title><content type='html'>&lt;a href="http://www.inter-sections.net/2007/11/13/how-to-recognise-a-good-programmer/"&gt;A lot&lt;/a&gt; has been written on what makes a great programmer.&lt;br /&gt;I'd like to write about what makes an effective programmer.  The two can be different.&lt;br /&gt;&lt;br&gt;&lt;br /&gt;I would say the characteristics of an effective programmer are as follows:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;1) Do you know and care about how the application you are writing will be used, and do you have opinions about how to make it better?&lt;/li&gt;&lt;li&gt;2) Do you know about new technologies, can you recognise those that should be adopted in your current projects and can you explain them convincingly enough to get them adopted?&lt;/li&gt;&lt;li&gt;3) Can you maximise tha amout of code not written, through efficient design, reusing things that have been written before and eliminating unnecessary requirements?&lt;/li&gt;&lt;li&gt;4) Can you recognise your limitations and mitigate these, e.g. by understanding where you need to learn something new or code defensively, and where to get help from others?&lt;/li&gt;&lt;li&gt;5) Can you design and write code that can be maintained in 10 years time by someone of average ability, when tools and programming languages have moved on?&lt;/li&gt;&lt;li&gt;6) Do you understand more than just code, e.g. databases, infrastructure and can you use this understanding to make it more likely a project will be stable and reliable when it is live?&lt;/li&gt;&lt;/ul&gt;Do you agree?&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9924016-7993314394417552346?l=richardjonasblog.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://richardjonasblog.blogspot.com/feeds/7993314394417552346/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9924016&amp;postID=7993314394417552346' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9924016/posts/default/7993314394417552346'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9924016/posts/default/7993314394417552346'/><link rel='alternate' type='text/html' href='http://richardjonasblog.blogspot.com/2010/11/characteristics-of-effective-programmer.html' title='Characteristics of an effective programmer.'/><author><name>Richard Jonas</name><uri>http://www.blogger.com/profile/14997733754093048669</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='28' src='http://www.btinternet.com/~rjonas/picsmall.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9924016.post-4385194888126154764</id><published>2010-11-01T16:35:00.000Z</published><updated>2010-11-01T16:35:54.073Z</updated><title type='text'>Planning poker with Return on Investment</title><content type='html'>A lot has been written on &lt;a href="http://www.planningpoker.com"&gt;Planning Poker&lt;/a&gt; as part of an agile approach to developing web sites.&lt;br /&gt;&lt;br /&gt;I have a new take on this - Planning poker with return on investment.  I'm sure we all agree that things that give a lot of value with a small amount of work should take prioriry.&lt;br /&gt;&lt;br /&gt;This would work as follows:&lt;br /&gt;&lt;br /&gt;The stakeholders would divide into two groups, business people and developers.  Business people would use planning poker to estimate the likely return of a proposed development in "return points".  Developers would at the same time estimate the likely investment in "story points".  "Return points" would likely be related to the amount of money the proposal would make.  "Story points" would be related to the number of days development.&lt;br /&gt;&lt;br /&gt;You can then divide return by investment to get a priority.  &lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;If return is small, investment big, it's probably best to forget the proposal.&lt;/li&gt;&lt;li&gt;If return is big, investment is small, it's a no brainer and should be done.&lt;/li&gt;&lt;li&gt;If return is small, investment is small, it's a medium priority.&lt;/li&gt;&lt;li&gt;A problem occurs if return is big and investment is big. This suggests there is a risk involved.  To reduce the risk, the proposed development should be divided into smaller chunks.&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/9924016-4385194888126154764?l=richardjonasblog.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://richardjonasblog.blogspot.com/feeds/4385194888126154764/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9924016&amp;postID=4385194888126154764' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9924016/posts/default/4385194888126154764'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9924016/posts/default/4385194888126154764'/><link rel='alternate' type='text/html' href='http://richardjonasblog.blogspot.com/2010/11/planning-poker-with-return-on.html' title='Planning poker with Return on Investment'/><author><name>Richard Jonas</name><uri>http://www.blogger.com/profile/14997733754093048669</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='28' src='http://www.btinternet.com/~rjonas/picsmall.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9924016.post-8590226883355307841</id><published>2010-10-24T19:27:00.000+01:00</published><updated>2010-10-24T19:27:17.138+01:00</updated><title type='text'>Feedback loops</title><content type='html'>&lt;a href=http://www.markhneedham.com/blog/2010/10/24/feedback-loops-overcompensating/?utm_source=feedburner&amp;amp;utm_medium=feed&amp;amp;utm_campaign=Feed%3A+MarkNeedham+%28Mark+Needham%29&gt;Mark Needham&lt;/a&gt; describes overcompensating in feedback loops.  &lt;br /&gt;&lt;br /&gt;This reminded me of something from my control theory course at university many years ago.  If you are not in a desired state, you should make changes that are a percentage of the difference between your current state and the desired state.  You will gradually converge towards it, and not overcompensate for any sudden changes.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9924016-8590226883355307841?l=richardjonasblog.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://richardjonasblog.blogspot.com/feeds/8590226883355307841/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9924016&amp;postID=8590226883355307841' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9924016/posts/default/8590226883355307841'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9924016/posts/default/8590226883355307841'/><link rel='alternate' type='text/html' href='http://richardjonasblog.blogspot.com/2010/10/feedback-loops.html' title='Feedback loops'/><author><name>Richard Jonas</name><uri>http://www.blogger.com/profile/14997733754093048669</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='28' src='http://www.btinternet.com/~rjonas/picsmall.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9924016.post-4265929578113697407</id><published>2007-10-17T10:27:00.000+01:00</published><updated>2007-10-17T10:29:57.118+01:00</updated><title type='text'>Visual Studio 2005 ASP.NET F5 Debugging performance</title><content type='html'>I was experiencing a delay of about a minute between pressing F5 to start debugging my ASP.NET application (VS2005 SP1, Vista) and anything appearing in the browser.&lt;br /&gt;&lt;br /&gt;After researching this and installing various hotfixes, nothing improved.  Removing the google toolbar however seemed to make debugging return to its normal speed.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9924016-4265929578113697407?l=richardjonasblog.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://richardjonasblog.blogspot.com/feeds/4265929578113697407/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9924016&amp;postID=4265929578113697407' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9924016/posts/default/4265929578113697407'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9924016/posts/default/4265929578113697407'/><link rel='alternate' type='text/html' href='http://richardjonasblog.blogspot.com/2007/10/visual-studio-2005-aspnet-f5-debugging.html' title='Visual Studio 2005 ASP.NET F5 Debugging performance'/><author><name>Richard Jonas</name><uri>http://www.blogger.com/profile/14997733754093048669</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='28' src='http://www.btinternet.com/~rjonas/picsmall.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9924016.post-8057551192374035509</id><published>2007-09-05T11:12:00.000+01:00</published><updated>2007-09-05T11:16:35.044+01:00</updated><title type='text'>ASP/ASPX pages giving 404 errors</title><content type='html'>In case I need to do this in future... I have been trying to copy a web site to a new web server (Windows Server 2003) and getting very confused about why .ASP and .ASPX pages were giving 404 errors, but HTML pages were displaying correctly.  The reason was "ASP.NET" and "Active Server Pages" in the Web Service Extensions directory were both set to "Prohibited".&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9924016-8057551192374035509?l=richardjonasblog.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://richardjonasblog.blogspot.com/feeds/8057551192374035509/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9924016&amp;postID=8057551192374035509' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9924016/posts/default/8057551192374035509'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9924016/posts/default/8057551192374035509'/><link rel='alternate' type='text/html' href='http://richardjonasblog.blogspot.com/2007/09/aspaspx-pages-giving-404-errors.html' title='ASP/ASPX pages giving 404 errors'/><author><name>Richard Jonas</name><uri>http://www.blogger.com/profile/14997733754093048669</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='28' src='http://www.btinternet.com/~rjonas/picsmall.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9924016.post-945523355009666842</id><published>2007-08-29T13:21:00.000+01:00</published><updated>2007-08-29T13:27:39.288+01:00</updated><title type='text'>The underlying connection was closed: Could not establish trust relationship for the SSL/TLS secure channel.</title><content type='html'>I was getting an error message "The underlying connection was closed: Could not establish trust relationship for the SSL/TLS secure channel." when trying to connect to an HTTPS site using an HttpWebRequest.&lt;br /&gt;&lt;br /&gt;As the site I was connecting to was a test site from a 3rd party known to me, but not set up correctly at their end, to bypass this check I added the following line before calling GetRequestStream on my HttpWebRequest.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;ServicePointManager.ServerCertificateValidationCallback &lt;br /&gt;+= new &lt;br /&gt;System.Net.Security.RemoteCertificateValidationCallback&lt;br /&gt;(CustomValidation);&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;and added the CustomValidation function as follows:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;private static bool CustomValidation(object sender, &lt;br /&gt;X509Certificate cert, X509Chain chain, &lt;br /&gt;System.Net.Security.SslPolicyErrors error)&lt;br /&gt;{&lt;br /&gt;    return true;&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9924016-945523355009666842?l=richardjonasblog.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://richardjonasblog.blogspot.com/feeds/945523355009666842/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9924016&amp;postID=945523355009666842' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9924016/posts/default/945523355009666842'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9924016/posts/default/945523355009666842'/><link rel='alternate' type='text/html' href='http://richardjonasblog.blogspot.com/2007/08/underlying-connection-was-closed-could.html' title='The underlying connection was closed: Could not establish trust relationship for the SSL/TLS secure channel.'/><author><name>Richard Jonas</name><uri>http://www.blogger.com/profile/14997733754093048669</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='28' src='http://www.btinternet.com/~rjonas/picsmall.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9924016.post-8979379621688805412</id><published>2007-08-06T08:40:00.000+01:00</published><updated>2007-08-06T08:41:47.848+01:00</updated><title type='text'>A set of principles for taking a new assignment</title><content type='html'>&lt;a href=http://secretsofconsulting.blogspot.com target=_blank&gt;Gerald M. Weinberg&lt;/a&gt; offers a &lt;a target=_blank href=http://secretsofconsulting.blogspot.com/2007/07/working-conditions-that-prevent.html&gt; set of principles&lt;/a&gt; for taking on a new assignment.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9924016-8979379621688805412?l=richardjonasblog.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://richardjonasblog.blogspot.com/feeds/8979379621688805412/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9924016&amp;postID=8979379621688805412' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9924016/posts/default/8979379621688805412'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9924016/posts/default/8979379621688805412'/><link rel='alternate' type='text/html' href='http://richardjonasblog.blogspot.com/2007/08/set-of-principles-for-taking-new.html' title='A set of principles for taking a new assignment'/><author><name>Richard Jonas</name><uri>http://www.blogger.com/profile/14997733754093048669</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='28' src='http://www.btinternet.com/~rjonas/picsmall.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9924016.post-1628204968498951942</id><published>2007-06-12T17:05:00.000+01:00</published><updated>2007-06-12T17:10:56.886+01:00</updated><title type='text'>InternalsVisibleToAttribute, Unit Testing and Strong Names</title><content type='html'>I previously posted about using the InternalsVisibleTo attibute for testing with NUnit.&lt;br /&gt;&lt;br /&gt;I've had some problems building this with a stronly named assembly. I found the &lt;a href="http://kentb.blogspot.com/2005/11/internalsvisibletoattribute.html"&gt;following post&lt;/a&gt; on Kent Boogaart's blog that describes how you should change the code in your assemblyinfo.cs file as follows:&lt;br /&gt;&lt;br /&gt;[assembly: InternalsVisibleTo("Company")]&lt;br /&gt;&lt;br /&gt;to&lt;br /&gt;&lt;br /&gt;[assembly: InternalsVisibleTo("Company, PublicKey=xxxxxxxxxxxxxxxx")]&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9924016-1628204968498951942?l=richardjonasblog.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://richardjonasblog.blogspot.com/feeds/1628204968498951942/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9924016&amp;postID=1628204968498951942' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9924016/posts/default/1628204968498951942'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9924016/posts/default/1628204968498951942'/><link rel='alternate' type='text/html' href='http://richardjonasblog.blogspot.com/2007/06/internalsvisibletoattribute-unit.html' title='InternalsVisibleToAttribute, Unit Testing and Strong Names'/><author><name>Richard Jonas</name><uri>http://www.blogger.com/profile/14997733754093048669</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='28' src='http://www.btinternet.com/~rjonas/picsmall.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9924016.post-1789194481259313118</id><published>2007-06-12T16:35:00.000+01:00</published><updated>2007-06-12T17:04:50.053+01:00</updated><title type='text'>Adding a strong name to a third party dll</title><content type='html'>I've been trying to build an assembly with a strong name and had some problems as it referenced a 3rd party assembly which had been built without a strong name.&lt;br /&gt;&lt;br /&gt;To add a strong name I disassembled and reassembled the 3rd party assmbly as follows:&lt;br /&gt;&lt;br /&gt;ildasm /out:thirdparty.dll.il thirdparty.dll&lt;br /&gt;&lt;br /&gt;ilasm /dll /resource=thirdparty.dll.res thirdparty.dll.il /out=thirdparty.dll /key=mykey.snk&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9924016-1789194481259313118?l=richardjonasblog.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://richardjonasblog.blogspot.com/feeds/1789194481259313118/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9924016&amp;postID=1789194481259313118' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9924016/posts/default/1789194481259313118'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9924016/posts/default/1789194481259313118'/><link rel='alternate' type='text/html' href='http://richardjonasblog.blogspot.com/2007/06/adding-strong-name-to-third-party-dll.html' title='Adding a strong name to a third party dll'/><author><name>Richard Jonas</name><uri>http://www.blogger.com/profile/14997733754093048669</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='28' src='http://www.btinternet.com/~rjonas/picsmall.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9924016.post-590146512794430191</id><published>2007-06-05T14:07:00.001+01:00</published><updated>2007-06-05T14:10:08.165+01:00</updated><title type='text'>World Environment Day</title><content type='html'>To celebrate World Environment Day, we have all been given a flowerpot, some peat and some forget-me-not seeds. You can follow whether the seeds grow into a beautiful plant or not &lt;a href="http://www.richardjonas.com/vergissmeinnicht"&gt;here&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9924016-590146512794430191?l=richardjonasblog.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://richardjonasblog.blogspot.com/feeds/590146512794430191/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9924016&amp;postID=590146512794430191' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9924016/posts/default/590146512794430191'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9924016/posts/default/590146512794430191'/><link rel='alternate' type='text/html' href='http://richardjonasblog.blogspot.com/2007/06/world-environment-day.html' title='World Environment Day'/><author><name>Richard Jonas</name><uri>http://www.blogger.com/profile/14997733754093048669</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='28' src='http://www.btinternet.com/~rjonas/picsmall.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9924016.post-7420983706713370074</id><published>2007-06-05T14:01:00.000+01:00</published><updated>2007-06-05T14:05:33.958+01:00</updated><title type='text'>Refreshing Progress Bars</title><content type='html'>I've been having some problems getting a progress bar to refresh, trying various calls to Refresh() and Invalidate() without much success. The solution to this is to create the dialog containing the progress bar in another thread, as described &lt;a href="http://www.codeguru.com/forum/showthread.php?t=356916"&gt;here&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;Although the dialog is modeless, it should be displayed using ShowDialog(), not Show().&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9924016-7420983706713370074?l=richardjonasblog.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://richardjonasblog.blogspot.com/feeds/7420983706713370074/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9924016&amp;postID=7420983706713370074' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9924016/posts/default/7420983706713370074'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9924016/posts/default/7420983706713370074'/><link rel='alternate' type='text/html' href='http://richardjonasblog.blogspot.com/2007/06/refreshing-progress-bars.html' title='Refreshing Progress Bars'/><author><name>Richard Jonas</name><uri>http://www.blogger.com/profile/14997733754093048669</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='28' src='http://www.btinternet.com/~rjonas/picsmall.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9924016.post-8413014088991101338</id><published>2007-05-16T10:29:00.000+01:00</published><updated>2007-05-16T10:47:36.971+01:00</updated><title type='text'>Standard for improving Standards</title><content type='html'>&lt;a href="http://www.think-box.co.uk/blog/"&gt;Simon Baker&lt;/a&gt; suggests that &lt;a href="http://www.think-box.co.uk/blog/2007/05/does-standardisation-suppress.html"&gt;standardisation does not have to supress innovation&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;It's important to communicate the best ways of doing things, but standards are often enforced in a way that people are expected to accept without question.  However, there are often many ways of doing something, and the best way will change over time with changes in technology and changes in people.&lt;br /&gt;&lt;br /&gt;Perhaps standards should be seen as something that should be followed, but when its thought they cause a problem, judgement should be used as to the correct procedure should be followed. However, if people use judgement to deviate from the standard, any differences should be noted and their effect should be considered afterwards.&lt;br /&gt;&lt;br /&gt;The differences can then be assessed to see if deviating from the standard was the right thing with hindsight and if so, the standard should be improved.  if it was the wrong thing to do, we might need to explain the rationale behind the standard better.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9924016-8413014088991101338?l=richardjonasblog.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://richardjonasblog.blogspot.com/feeds/8413014088991101338/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9924016&amp;postID=8413014088991101338' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9924016/posts/default/8413014088991101338'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9924016/posts/default/8413014088991101338'/><link rel='alternate' type='text/html' href='http://richardjonasblog.blogspot.com/2007/05/standard-for-improving-standards.html' title='Standard for improving Standards'/><author><name>Richard Jonas</name><uri>http://www.blogger.com/profile/14997733754093048669</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='28' src='http://www.btinternet.com/~rjonas/picsmall.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9924016.post-2540437238660774071</id><published>2007-04-16T11:21:00.000+01:00</published><updated>2007-04-16T11:42:34.817+01:00</updated><title type='text'>Visual Studio 2005 - Disappearing controls on Windows Form</title><content type='html'>My computer crashed the other day and when I returned to edit my application, to my horror I noticed that the controls on a very complicated windows form that I was working on had vanished.   When I tried to edit it, all I got was an empty dialog box, but all the source code for my form was still there. &lt;br /&gt;&lt;br /&gt;I found several references to disappearing controls in VS2003, but they all said the problem had been fixed in VS2005.&lt;br /&gt;&lt;br /&gt;The cause of this turned out to be that some lines had removed themselves from the designer.cs file :-&lt;br /&gt;&lt;br /&gt;&lt;blockquote&gt;&lt;br /&gt;///&lt;br /&gt;/// formMyForm&lt;br /&gt;///&lt;br /&gt;this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);&lt;br /&gt;this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;&lt;br /&gt;this.AutoSizeMode = System.Windows.Forms.AutoSizeMode.GrowAndShrink;&lt;br /&gt;this.ClientSize = new System.Drawing.Size(869, 717);&lt;br /&gt;this.Controls.Add(this.splitContainer1);&lt;br /&gt;this.Controls.Add(this.buttonOK);&lt;br /&gt;this.Controls.Add(this.buttonCancel);&lt;br /&gt;this.Controls.Add(this.buttonAccept);&lt;br /&gt;this.Name = "formMyForm";&lt;br /&gt;this.Text = "My form title";&lt;br /&gt;&lt;/blockquote&gt;&lt;br /&gt;&lt;br&gt;&lt;br /&gt;&lt;br /&gt;Copying these lines from the version in source control seemed to restore all the controls in the dialog.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9924016-2540437238660774071?l=richardjonasblog.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://richardjonasblog.blogspot.com/feeds/2540437238660774071/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9924016&amp;postID=2540437238660774071' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9924016/posts/default/2540437238660774071'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9924016/posts/default/2540437238660774071'/><link rel='alternate' type='text/html' href='http://richardjonasblog.blogspot.com/2007/04/visual-studio-2005-disappearing.html' title='Visual Studio 2005 - Disappearing controls on Windows Form'/><author><name>Richard Jonas</name><uri>http://www.blogger.com/profile/14997733754093048669</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='28' src='http://www.btinternet.com/~rjonas/picsmall.jpg'/></author><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9924016.post-8683633351981574453</id><published>2007-03-01T16:23:00.000Z</published><updated>2007-03-01T16:27:31.941Z</updated><title type='text'>Complete years between 2 dates</title><content type='html'>A problem we have had calculating ages was due to it using the SQL Server "DateDiff" function. This counts the number of times a day crosses a boundary, e.g.&lt;br /&gt;&lt;br /&gt;DateDiff(year,'12/31/2006','1/1/2007') is 1, as it crosses the 2006-2007 boundary.&lt;br /&gt;DateDiff(year,'1/1/2006','12/31/2006') is 0 as it doesn't cross a year boundary.&lt;br /&gt;&lt;br /&gt;I have written a function "yeardiff", which calculates the number of complete years between 2 dates, so&lt;br /&gt;&lt;br /&gt;YearDiff('12/31/2006','1/1/2007') is 0&lt;br /&gt;YearDiff('1/1/2006','12/31/2006') is 0&lt;br /&gt;YearDiff('12/31/2006','1/1/2008') is 1&lt;br /&gt;&lt;br /&gt;This function works by calculating the number of days the start date is into the year, subtracting this from both start and end dates (so the start date is 1 January), and calling DateDiff on the resulting date.  &lt;br /&gt;&lt;br /&gt;Here's the source code for this function:&lt;br /&gt;&lt;br /&gt;&lt;blockquote&gt;&lt;br /&gt;CREATE FUNCTION yeardiff&lt;br /&gt;(@start as datetime, @end as datetime)&lt;br /&gt;returns int&lt;br /&gt;AS&lt;br /&gt;BEGIN&lt;br /&gt; declare @years as int&lt;br /&gt;&lt;br /&gt; declare @daysintoyear as int&lt;br /&gt; declare @firstdayofyear as datetime&lt;br /&gt; declare @newstart as datetime&lt;br /&gt; declare @newend as datetime&lt;br /&gt;&lt;br /&gt; set @firstdayofyear = convert(datetime,&lt;br /&gt;'1/1/'+convert(varchar,year(@start)))&lt;br /&gt; set @daysintoyear =datediff(day, @start, @firstdayofyear)&lt;br /&gt;&lt;br /&gt; set @newstart = dateadd(dd, @daysintoyear,@start)&lt;br /&gt; set @newend = dateadd(dd, @daysintoyear,@end)&lt;br /&gt;&lt;br /&gt; return datediff(year,@newstart,@newend) &lt;br /&gt;&lt;br /&gt;END&lt;br /&gt;&lt;/blockquote&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9924016-8683633351981574453?l=richardjonasblog.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://richardjonasblog.blogspot.com/feeds/8683633351981574453/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9924016&amp;postID=8683633351981574453' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9924016/posts/default/8683633351981574453'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9924016/posts/default/8683633351981574453'/><link rel='alternate' type='text/html' href='http://richardjonasblog.blogspot.com/2007/03/complete-years-between-2-dates.html' title='Complete years between 2 dates'/><author><name>Richard Jonas</name><uri>http://www.blogger.com/profile/14997733754093048669</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='28' src='http://www.btinternet.com/~rjonas/picsmall.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9924016.post-4572706992614129414</id><published>2007-02-06T17:04:00.000Z</published><updated>2007-02-06T17:19:12.169Z</updated><title type='text'>Nant and licensed 3rd party controls</title><content type='html'>I've been having some problems building a project containing licensed grid and graph components from ComponentOne using NAnt. The project built correctly in Visual Studio, but when built with NAnt I got a box saying the component was not licensed.&lt;br /&gt;&lt;br /&gt;I've found some others have had similar problems, but no solutions have been posted. I go it working after a lot of trial and error as follows:&lt;br /&gt;&lt;br /&gt;1) Use an &amp;lt;exec&amp;gt; task to run the license compiler (lc.exe).&lt;br /&gt;2) Ensure the /target: command does not contain a path.&lt;br /&gt;3) Ensure your &amp;lt;csc&amp;gt; task does not contain a path in its output section.&lt;br /&gt;4) Ensure the licenses file is included in the resources section. This did not work when it was included as an argument with an &amp;lt;arg value="/resource" element.&lt;br /&gt;5) Copy the file to the correct destination directory at the end.&lt;br /&gt;&lt;br /&gt;Here's the relevant part of my build file.&lt;br /&gt;&lt;br /&gt;&lt;font face=arial size=1&gt;&lt;br /&gt;  &amp;lt;target name="project" description="build project"&lt;br /&gt;    depends="..." &amp;gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;    &amp;lt;exec program="C:\Program Files\Microsoft &lt;br /&gt;Visual Studio 8\SDK\v2.0\bin\LC.exe"&lt;br /&gt;      commandline="/target:project.exe &lt;br /&gt;/complist:c:/nantcheckout/project/Properties\&lt;br /&gt;licenses.licx &lt;br /&gt;/outdir:c:/nantbuild /i:c:\nantbuild\C1.Data.2.dll &lt;br /&gt;/i:c:\nantbuild\C1.Win.C1Chart.2.dll &lt;br /&gt;/i:c:\nantbuild\C1.Win.C1Chart3D.2.dll &lt;br /&gt;/i:c:\nantbuild\CAInterfaces.dll &lt;br /&gt;/i:c:\nantbuild\CDERules.dll &lt;br /&gt;/i:c:\nantbuild\clTreeViewHashT.dll &lt;br /&gt;/i:C:\WINDOWS\Microsoft.NET\Framework\&lt;br /&gt;v2.0.50727\System.configuration.dll &lt;br /&gt;/i:C:\WINDOWS\Microsoft.NET\Framework\&lt;br /&gt;v2.0.50727\System.Data.dll &lt;br /&gt;/i:C:\WINDOWS\Microsoft.NET\Framework\&lt;br /&gt;v2.0.50727\System.Deployment.dll &lt;br /&gt;&lt;br /&gt;...&lt;br /&gt;&lt;br /&gt;/&amp;gt;&lt;br /&gt;&lt;br /&gt;    &amp;lt;csc target="winexe" &lt;br /&gt;output="PCOBrowserGE.exe" debug="false" &lt;br /&gt;define="TRACE" &amp;gt;&lt;br /&gt;      &amp;lt;sources&amp;gt;&lt;br /&gt;        &amp;lt;include name="c:/nantcheckout/&lt;br /&gt;project/*.cs" /&amp;gt;&lt;br /&gt;        &amp;lt;include name="c:/nantcheckout/&lt;br /&gt;project/Properties/*.cs" /&amp;gt;&lt;br /&gt;      &amp;lt;/sources&amp;gt;&lt;br /&gt;      &amp;lt;resources&amp;gt;&lt;br /&gt;        &amp;lt;include name="c:/nantcheckout/&lt;br /&gt;project/Properties/*.resx" /&amp;gt;&lt;br /&gt;        &amp;lt;include name="c:/nantcheckout/&lt;br /&gt;project/*.resx" /&amp;gt;&lt;br /&gt;        &amp;lt;include name="c:/nantbuild/&lt;br /&gt;project.exe.licenses" /&amp;gt;&lt;br /&gt;      &amp;lt;/resources&amp;gt;&lt;br /&gt;      &amp;lt;arg value="/reference:C:\nantbuild\&lt;br /&gt;c1.win.c1chart.2.dll" /&amp;gt;&lt;br /&gt;      &amp;lt;arg value="/reference:C:\nantbuild\&lt;br /&gt;c1.win.c1chart3d.2.dll" /&amp;gt;&lt;br /&gt;      &amp;lt;arg value="/reference:C:\nantbuild\&lt;br /&gt;c1.data.2.dll" /&amp;gt;&lt;br /&gt;    &amp;lt;/csc&amp;gt;&lt;br /&gt;&lt;br /&gt;    &amp;lt;copy file="pcobrowserge.exe" tofile="&lt;br /&gt;c:/nantbuild/project.exe" /&amp;gt;&lt;br /&gt;  &amp;lt;/target&amp;gt;&lt;br /&gt;&lt;/font&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9924016-4572706992614129414?l=richardjonasblog.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://richardjonasblog.blogspot.com/feeds/4572706992614129414/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9924016&amp;postID=4572706992614129414' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9924016/posts/default/4572706992614129414'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9924016/posts/default/4572706992614129414'/><link rel='alternate' type='text/html' href='http://richardjonasblog.blogspot.com/2007/02/nant-and-licensed-3rd-party-controls.html' title='Nant and licensed 3rd party controls'/><author><name>Richard Jonas</name><uri>http://www.blogger.com/profile/14997733754093048669</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='28' src='http://www.btinternet.com/~rjonas/picsmall.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9924016.post-7213246628104649353</id><published>2007-02-06T10:11:00.000Z</published><updated>2007-02-06T10:15:01.639Z</updated><title type='text'>10 Characteristics of a great programmer</title><content type='html'>&lt;a href="http://eureka3d.com/blog/about/"&gt;Steve Riley&lt;/a&gt; has complied a great list of the &lt;a href="http://eureka3d.com/blog/2007/the-top-10-attributes-of-a-great-programmer/"&gt;10 characteristics of a great programmer&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;I'd agree with everything on the list - the one thing that is missing is that great programmers know why they are doing what they are doing - there's no point producing an excellent solution to the wrong problem.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9924016-7213246628104649353?l=richardjonasblog.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://richardjonasblog.blogspot.com/feeds/7213246628104649353/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9924016&amp;postID=7213246628104649353' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9924016/posts/default/7213246628104649353'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9924016/posts/default/7213246628104649353'/><link rel='alternate' type='text/html' href='http://richardjonasblog.blogspot.com/2007/02/10-characteristics-of-great-programmer.html' title='10 Characteristics of a great programmer'/><author><name>Richard Jonas</name><uri>http://www.blogger.com/profile/14997733754093048669</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='28' src='http://www.btinternet.com/~rjonas/picsmall.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9924016.post-116972062289043617</id><published>2007-01-25T10:14:00.000Z</published><updated>2007-01-25T10:23:43.213Z</updated><title type='text'>Cakes</title><content type='html'>&lt;a href="http://www.redmonk.com/cote/2007/01/23/requirements-gathering-and-cakes/"&gt;Cote&lt;/a&gt; writes about requirements gathering and cakes.&lt;br /&gt;&lt;br /&gt;If your powerful boss asks you for a cake, you can't easily find out the details of what he wants.  You have to find out via secondary sources (e.g. the boss's calendar, asking the baker what sort of cakes the boss has ordered before).  The calendar may not be up to date, and the baker may not remember accurately.&lt;br /&gt;&lt;br /&gt;This takes longer and is more likely to go wrong. If there are more steps than necessary in finding out requirements, the solution is to understand what the difficulty is with asking him directly and work on reducing these difficulties.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9924016-116972062289043617?l=richardjonasblog.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://richardjonasblog.blogspot.com/feeds/116972062289043617/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9924016&amp;postID=116972062289043617' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9924016/posts/default/116972062289043617'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9924016/posts/default/116972062289043617'/><link rel='alternate' type='text/html' href='http://richardjonasblog.blogspot.com/2007/01/cakes.html' title='Cakes'/><author><name>Richard Jonas</name><uri>http://www.blogger.com/profile/14997733754093048669</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='28' src='http://www.btinternet.com/~rjonas/picsmall.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9924016.post-116965506353585696</id><published>2007-01-24T15:44:00.000Z</published><updated>2007-01-24T16:14:35.606Z</updated><title type='text'>Personal Search Filter</title><content type='html'>If you want to find out information about something, you will typically enter terms into a search engine.&lt;br /&gt;&lt;br /&gt;The search engine will determine which results are most relevant (by using a complex algorithm based on how important it thinks the pages are). Everybody using this search engine will see the same results. &lt;br /&gt;&lt;br /&gt;The things you want to see might not be the same as the things others want to see. However, you are more likely to want to see things that people "compatible with you" liked. If A likes B and B likes C, and B also likes D, then chances are that A will like D.&lt;br /&gt;&lt;br /&gt;You could filter the results of your search (from the search engine) through a personal search filter.  This would reorder your searches depending on &lt;br /&gt;&lt;br /&gt;1) Things you have liked before&lt;br /&gt;2) Things that people compatible with you have liked before.&lt;br /&gt;&lt;br /&gt;When you visit a web page, you record whether you found it valuable. This updates your personal search filter and how compatible you are with other people. If you liked page A and B didn't like page A, you will not value the opinion that B liked page C. However if B liked A, you would be compatible with B and their opinion would affect your search filter.&lt;br /&gt;&lt;br /&gt;This can be seen below:&lt;br /&gt;&lt;br /&gt;&lt;image src=http://www.richardjonas.com/images/psf.png&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9924016-116965506353585696?l=richardjonasblog.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://richardjonasblog.blogspot.com/feeds/116965506353585696/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9924016&amp;postID=116965506353585696' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9924016/posts/default/116965506353585696'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9924016/posts/default/116965506353585696'/><link rel='alternate' type='text/html' href='http://richardjonasblog.blogspot.com/2007/01/personal-search-filter.html' title='Personal Search Filter'/><author><name>Richard Jonas</name><uri>http://www.blogger.com/profile/14997733754093048669</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='28' src='http://www.btinternet.com/~rjonas/picsmall.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9924016.post-116860047515316186</id><published>2007-01-12T10:21:00.000Z</published><updated>2007-01-12T11:14:35.216Z</updated><title type='text'>Anti-tests</title><content type='html'>&lt;a href="http://fishbowl.pastiche.org/"&gt;Charles Miller&lt;/a&gt; describes the concept of an "&lt;a href="http://fishbowl.pastiche.org/2007/01/09/revenge_of_the_antitest"&gt;Anti-Test&lt;/a&gt;", which is a test that verifies a bug exists.&lt;br /&gt;&lt;br /&gt;This can be written when the problem is discovered, even if it's not going to be fixed immediately.&lt;br /&gt;&lt;br /&gt;It means that if the problem is inadvertently fixed as a result of something else, we know this has happened, have a look at why this is the case and update our records accordingly.  The test can then be changed to a normal test to make sure it doesn't go wrong again.&lt;br /&gt;&lt;br /&gt;When you're ready to fix an anti-test, you can change it to a normal test - it should now fail (and this change should be easy to make), fix the bug and make sure the test passes.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9924016-116860047515316186?l=richardjonasblog.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://richardjonasblog.blogspot.com/feeds/116860047515316186/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9924016&amp;postID=116860047515316186' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9924016/posts/default/116860047515316186'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9924016/posts/default/116860047515316186'/><link rel='alternate' type='text/html' href='http://richardjonasblog.blogspot.com/2007/01/anti-tests.html' title='Anti-tests'/><author><name>Richard Jonas</name><uri>http://www.blogger.com/profile/14997733754093048669</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='28' src='http://www.btinternet.com/~rjonas/picsmall.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9924016.post-116859696891148915</id><published>2007-01-12T10:09:00.000Z</published><updated>2007-01-12T10:16:08.926Z</updated><title type='text'>NAnt version</title><content type='html'>I've been trying to add version numbers to a &lt;a href="http://nant.sourceforge.net/"&gt;NAnt&lt;/a&gt; build script using the &lt;a href="http://nantcontrib.sourceforge.net/release/0.85-rc3/help/tasks/version.html"&gt;&amp;lt;version&amp;gt; task&lt;/a&gt;, and come across a problem with the script in &lt;a href="http://www.amazon.co.uk/Expert-Delivery-Using-Cruisecontrol-Net-Experts/dp/1590594851/sr=8-2/qid=1168596717/ref=sr_1_2/202-5030835-5298214?ie=UTF8&amp;s=books"&gt;Marc Holmes' "Expert .NET delivery" book&lt;/a&gt;. &lt;br /&gt;&lt;br /&gt;The &lt;version&gt; task increments a property called "buildnumber.version", not "sys.version". Adding the following line to the script (as described &lt;a href="http://frazzleddad.blogspot.com/2005/07/versioning-using-nant.html"&gt;here&lt;/a&gt;) seems to fix it.&lt;br /&gt;&lt;br /&gt;&amp;lt;property name="sys.version" value="${buildnumber.version}" /&amp;gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9924016-116859696891148915?l=richardjonasblog.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://richardjonasblog.blogspot.com/feeds/116859696891148915/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9924016&amp;postID=116859696891148915' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9924016/posts/default/116859696891148915'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9924016/posts/default/116859696891148915'/><link rel='alternate' type='text/html' href='http://richardjonasblog.blogspot.com/2007/01/nant-version.html' title='NAnt version'/><author><name>Richard Jonas</name><uri>http://www.blogger.com/profile/14997733754093048669</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='28' src='http://www.btinternet.com/~rjonas/picsmall.jpg'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9924016.post-116516743331551430</id><published>2006-12-03T16:22:00.000Z</published><updated>2006-12-03T17:59:49.823Z</updated><title type='text'>Using attributes to specify the contents of a menu</title><content type='html'>&lt;p&gt;Most people think it is a good idea to separate business and presentation logic in your application, so you can update one without changing the other. When you create an application with a menu bar, the menu items will often call functions in your business logic, and&amp;nbsp;if you add a new business logic function you will need to add a handler in your presentation layer and the business logic function in your business logic layer.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;This article describes how you can add attributes in your business logic layer and have these dynamically bound to a menu when your application runs. The attributes will look like the following:&lt;/p&gt;&lt;br /&gt;&lt;blockquote&gt;&lt;pre&gt;   public class MenuHandler&lt;br /&gt;    {&lt;br /&gt;        [MenuOption ("Menu Option 1")]&lt;br /&gt;        public void MenuHandler(object sender, &lt;br /&gt;EventArgs e)&lt;br /&gt;        {&lt;br /&gt;            //Business Logic&lt;br /&gt;        }&lt;br /&gt;    }&lt;/pre&gt;&lt;/blockquote&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Creating your Attribute&lt;/b&gt;&lt;br&gt;&lt;br /&gt;&lt;P&gt;The first thing you need to do is to set up your attribute. Create a class derived from System.Attribute as follows.&lt;/P&gt;&lt;br /&gt;&lt;blockquote&gt;&lt;pre&gt;    [AttributeUsage(AttributeTargets.Method)]&lt;br /&gt;    public class MenuOptionAttribute : &lt;br /&gt;System.Attribute&lt;br /&gt;    {&lt;br /&gt;        private string MenuText;&lt;br /&gt;&lt;br /&gt;        public MenuOptionAttribute(String &lt;br /&gt;menutext)&lt;br /&gt;        {&lt;br /&gt;            MenuText = menutext;&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        public string GetMenuText&lt;br /&gt;        {&lt;br /&gt;            get&lt;br /&gt;            {&lt;br /&gt;                return MenuText;&lt;br /&gt;            }&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;&lt;/pre&gt;&lt;/blockquote&gt;&lt;br /&gt;&lt;br&gt;The first line of this specifies your attribute can be applied to methods (and not to classes). The constructor takes one argument, which is a string representing the menu text.&lt;br&gt;&lt;br&gt;&lt;br /&gt;&lt;b&gt;Applying your attribute to your business logic&lt;/b&gt;&lt;br&gt;&lt;br /&gt;&lt;P&gt;Next, you write your business logic layer to use the MenuOption attribute. All you need to do is to put this before any functions you want on your menu, with the text to go on your menu:&lt;/P&gt;&lt;br /&gt;&lt;blockquote&gt;&lt;pre&gt;    public class BusinessLogic&lt;br /&gt;    {&lt;br /&gt;        [MenuOption ("Menu Option 1")]&lt;br /&gt;        public void Option1(object sender, &lt;br /&gt;EventArgs e)&lt;br /&gt;        {&lt;br /&gt;            // Option 1 code&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        [MenuOption("Option 2")]&lt;br /&gt;        public void Option2(object sender, &lt;br /&gt;EventArgs e)&lt;br /&gt;        {&lt;br /&gt;             // Option 2 code&lt;br /&gt;        }&lt;br /&gt;&lt;/pre&gt;&lt;/blockquote&gt;&lt;br /&gt;&lt;P&gt;You can add as many of these functions as you like.&lt;/P&gt;&lt;br /&gt;&lt;b&gt;Setting up your menu&lt;/b&gt;&lt;br /&gt;&lt;P&gt;Finally, you need to create your presentation layer. You can drag a MenuStrip to a form and add a title for your drop down menu. If you call the title "Main", when you add the title, it will create a ToolStripMenuItem, called "mainToolStripMenuItem" by default.&lt;/P&gt;&lt;br /&gt;&lt;P&gt;You need to use reflection to iterate over all the methods in the MenuHandler class, and see which of those methods have the MenuOptionAttribute attribute set.&lt;/P&gt;&lt;br /&gt;&lt;P&gt;If it is set, you need to call the GetMenuText() function on the attribute to find out the text to display on the menu bar and add the menu item.&lt;/P&gt;&lt;br /&gt;&lt;P&gt;Next, you need to create a delegate to your method.&lt;/P&gt;&lt;br /&gt;&lt;P&gt;Finally, you add the event handler to your newly created menu item. It's easier to understand this if you read the code example.&lt;/P&gt;&lt;br /&gt;&lt;blockquote&gt;&lt;pre&gt;  public partial class Form1 : Form&lt;br /&gt;    {&lt;br /&gt;        public Form1()&lt;br /&gt;        {&lt;br /&gt;            InitializeComponent();&lt;br /&gt;            BusinessLogic bl = new BusinessLogic();&lt;br /&gt;&lt;br /&gt;            mainToolStripMenuItem.DropDownItems.&lt;br /&gt;Clear();&lt;br /&gt;            foreach (MethodInfo method in &lt;br /&gt;(typeof (BusinessLogic)).GetMethods())&lt;br /&gt;            {&lt;br /&gt;                foreach (object attribute in &lt;br /&gt;method.GetCustomAttributes(true))&lt;br /&gt;                {&lt;br /&gt;                    if (attribute is &lt;br /&gt;MenuOptionAttribute)&lt;br /&gt;                    {&lt;br /&gt;                        ToolStripItem newitem = &lt;br /&gt;mainToolStripMenuItem.DropDownItems.Add((&lt;br /&gt;attribute as MenuOptionAttribute).GetMenuText);&lt;br /&gt;                        EventInfo ci = typeof&lt;br /&gt;(ToolStripItem).GetEvent("Click");&lt;br /&gt;                        Type tdelegate = ci.&lt;br /&gt;EventHandlerType;&lt;br /&gt;                        Delegate del = Delegate.&lt;br /&gt;CreateDelegate(tdelegate,bl,method);&lt;br /&gt;                        ci.AddEventHandler(&lt;br /&gt;newitem, del);&lt;br /&gt;                    }&lt;br /&gt;                }&lt;br /&gt;            }&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;&lt;/pre&gt;&lt;/blockquote&gt;&lt;br /&gt;You could add some code to your attribute to specify its position, and use this to order your menu items. You might want to specify more than one string, one for the heading and one for the item itself, so you can put menu items in under different headings.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9924016-116516743331551430?l=richardjonasblog.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://richardjonasblog.blogspot.com/feeds/116516743331551430/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9924016&amp;postID=116516743331551430' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9924016/posts/default/116516743331551430'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9924016/posts/default/116516743331551430'/><link rel='alternate' type='text/html' href='http://richardjonasblog.blogspot.com/2006/12/using-attributes-to-specify-contents.html' title='Using attributes to specify the contents of a menu'/><author><name>Richard Jonas</name><uri>http://www.blogger.com/profile/14997733754093048669</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='28' src='http://www.btinternet.com/~rjonas/picsmall.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9924016.post-116143330761762781</id><published>2006-10-21T13:10:00.000+01:00</published><updated>2006-10-21T13:21:48.050+01:00</updated><title type='text'>InternalsVisibleToAttribute and Unit Testing</title><content type='html'>When creating unit tests to be run with NUnit, I like to keep my tests in a separate assembly, which is not delivered when my project is deployed.  &lt;br /&gt;&lt;br /&gt;This can make it difficult to create unit tests for classes that should not be visible outside of that assembly. One of my classes uses one of 3 strategy classes that encapsulate a feature of the business logic. I would normally declare these with the intern access modifier, but to test each strategy works I've needed to make them publically available.&lt;br /&gt;&lt;br /&gt;If, however, I add the [assembly: InternalsVisibleTo("UnitTests")] line to my AssemblyInfo.cs file, any objects declared with the intern access modifier can be seen by the UnitTests assembly.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9924016-116143330761762781?l=richardjonasblog.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://richardjonasblog.blogspot.com/feeds/116143330761762781/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9924016&amp;postID=116143330761762781' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9924016/posts/default/116143330761762781'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9924016/posts/default/116143330761762781'/><link rel='alternate' type='text/html' href='http://richardjonasblog.blogspot.com/2006/10/internalsvisibletoattribute-and-unit.html' title='InternalsVisibleToAttribute and Unit Testing'/><author><name>Richard Jonas</name><uri>http://www.blogger.com/profile/14997733754093048669</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='28' src='http://www.btinternet.com/~rjonas/picsmall.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9924016.post-116051665280473441</id><published>2006-10-10T22:33:00.000+01:00</published><updated>2006-10-10T22:44:12.820+01:00</updated><title type='text'>Processes and Practices</title><content type='html'>Jared Richardson &lt;a href="http://www.jaredrichardson.net/blog/2006/10/10#simple-process"&gt;describes a process&lt;/a&gt; he wants his team to follow.   Many others have attempted the same and have reached similar conclusions, and I can't disagree with any of Jared's thoughts.  &lt;br /&gt;&lt;br /&gt;However, I think he misses out the most important part of the process which should be to regularly think about your process and what you have done and how you could have done it better. All processes and practices should be adaptable.  Different people have different strengths and new technologies mean we have to develop things in different ways.&lt;br /&gt;&lt;br /&gt;A lot has been written about &lt;a href="http://www.think-box.co.uk/blog/2005/11/repaying-technical-debt.html"&gt;technical debt&lt;/a&gt;, where if not enough time is invested in developing high quality software, it becomes harder to maintain and costs of new developments increase over time. We should also think about process debt, where if not enough time is spent improving and adapting our processes, they become less efficient and costs of new developments also increase.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9924016-116051665280473441?l=richardjonasblog.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://richardjonasblog.blogspot.com/feeds/116051665280473441/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9924016&amp;postID=116051665280473441' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9924016/posts/default/116051665280473441'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9924016/posts/default/116051665280473441'/><link rel='alternate' type='text/html' href='http://richardjonasblog.blogspot.com/2006/10/processes-and-practices.html' title='Processes and Practices'/><author><name>Richard Jonas</name><uri>http://www.blogger.com/profile/14997733754093048669</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='28' src='http://www.btinternet.com/~rjonas/picsmall.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9924016.post-116051402912989502</id><published>2006-10-10T21:42:00.000+01:00</published><updated>2006-10-10T22:00:29.200+01:00</updated><title type='text'>C# collection classes performance</title><content type='html'>I was looking for a table summarizing how different C# generic and non-generic collection classes performed, relative to one another, thought there would be hundreds available, but could not find one.  So here one is for my future reference, and for anyone else who reads this.&lt;br /&gt;&lt;br /&gt;&lt;img src=http://www.richardjonas.com/images/collections.png&gt;&lt;br /&gt;&lt;br /&gt;O(1) = constant time&lt;br /&gt;O(log n) = time proportional to the log of the number of elements in the collection&lt;br /&gt;O(n) = time proportional to the number of elements in the collection&lt;br /&gt;&lt;br /&gt;Some collections are better for smaller collections,  but don't scale to larger ones. The List, LinkedList, SortedList, Queue and Stack classes are better for smaller collections than the Dictionary, Hashtable and SortedDictionary classes.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9924016-116051402912989502?l=richardjonasblog.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://richardjonasblog.blogspot.com/feeds/116051402912989502/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9924016&amp;postID=116051402912989502' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9924016/posts/default/116051402912989502'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9924016/posts/default/116051402912989502'/><link rel='alternate' type='text/html' href='http://richardjonasblog.blogspot.com/2006/10/c-collection-classes-performance.html' title='C# collection classes performance'/><author><name>Richard Jonas</name><uri>http://www.blogger.com/profile/14997733754093048669</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='28' src='http://www.btinternet.com/~rjonas/picsmall.jpg'/></author><thr:total>3</thr:total></entry></feed>