<?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: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-6458135603295822938</id><updated>2012-01-06T00:47:04.393-08:00</updated><title type='text'>Synersov Alive</title><subtitle type='html'></subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://synersov.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6458135603295822938/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://synersov.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>aahkam</name><uri>http://www.blogger.com/profile/11579245596035586334</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>22</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-6458135603295822938.post-1903090527843689260</id><published>2011-11-14T03:02:00.000-08:00</published><updated>2011-11-14T03:38:59.558-08:00</updated><title type='text'>Micro Management vs Macro Management</title><content type='html'>More than often, we heard of these terms. How many of us try understand these definition and see how it impacts and influence the day to day activities.&lt;br /&gt;&lt;br /&gt;&lt;h1 align="center"&gt;By Definition&lt;/h1&gt;&lt;hr /&gt;Micro Management - Require one to enforce every of his/her staffs to report on their progress very frequently and reluctantly to delegate decisions. Also known as Bully Approach.&lt;br /&gt;&lt;br /&gt;Macro Management - Delegate decisions to his/her staffs and monitor on the progress less aggressively. However, it is often that one delegates too much of decisions without some necessity knowledge of work.&lt;br /&gt;&lt;br /&gt;Often we learnt about a leader when we start working in a team. We then come across many different style of management. Each style tells us, indirectly, what type of leader we work with.&lt;br /&gt;&lt;br /&gt;&lt;h1 align="center"&gt;Micromanage suitable only if: -&lt;/h1&gt;&lt;hr /&gt;&lt;ul&gt;&lt;li&gt;Start up company&lt;/li&gt;&lt;li&gt;Incompetent team members&lt;/li&gt;&lt;li&gt;Mission critical but proprietary knowledge of work&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;Manager with micromanage style suggests that he/she is still a better person to take on every lower level tasks assigned. Company with managers of tendency to micromanage suffers opportunities of losing their better employee to be a manager who does not manage well but love detail work.&lt;br /&gt;&lt;br /&gt;&lt;h1 align="center"&gt;Macromanage suitable only if: -&lt;/h1&gt;&lt;hr /&gt;&lt;ul&gt;&lt;li&gt;Well established company&lt;/li&gt;&lt;li&gt;Not only competent but knowledge independent team members&lt;/li&gt;&lt;li&gt;Generally all type of works&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;Manager with macromanage style suggests that he/she trusts the team members being knowledge independent and capable of producing good work. Decisions and rights are trustfully given with minimal supervision. However, that may also suggest that many manager involves in Macro Management style would lost his initial stint within the business and overly relying on his/her team members which results in decision dependencies and politically driven decision/outcome. Company must love these managers as they made themselves out of job while growing people to out cast themselves.&lt;br /&gt;&lt;br /&gt;&lt;h1 align="center"&gt;Conclusion&lt;/h1&gt;&lt;hr /&gt;While micromanaging managers suggest to delegate only risks to his/her staffs and claiming all credits to himself/herself when succeeded, macromanaging managers suggest to delegates credits to his/her staffs and taking the risks on their own.&lt;br /&gt;&lt;br /&gt;Either way, you are either too good only to yourself or too good to your people. That only leads you into one way, failure! Yes, you got me right, it is failure! With micromanaging, higher management would have learnt and noticed that they can't scale in your department. You are too important that they need to find someone to manage you. You just missed the promotion by that. With macromanaging however, everyone is doing right and perform well enough to replace you, because you made them too good to put yourself out of job. You have higher pay then others, and why should I pay more if they are equally good as you with better details, but miles cheaper?&lt;br /&gt;&lt;br /&gt;You need to struck a balance in your style. You have great people, do more macromanagement and learning the details from your team via some suitably application of micromanage. This way, you won't be thrown away by your people in your business knowledge, while letting them to take their deserved credit.&lt;br /&gt;&lt;br /&gt;If you have average people, depends on how much the average is, apply the micromanage as you see fits while not letting the opportunity to slip away for your people to learn and excel with some  delegation through macromanagement.&lt;br /&gt;&lt;br /&gt;Speaking of a company perspective, I would love to have as many macromanaging managers than micromanaging managers. At least, I'm not tightening up my options on resources.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6458135603295822938-1903090527843689260?l=synersov.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://synersov.blogspot.com/feeds/1903090527843689260/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://synersov.blogspot.com/2011/11/micro-management-vs-macro-management.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6458135603295822938/posts/default/1903090527843689260'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6458135603295822938/posts/default/1903090527843689260'/><link rel='alternate' type='text/html' href='http://synersov.blogspot.com/2011/11/micro-management-vs-macro-management.html' title='Micro Management vs Macro Management'/><author><name>aahkam</name><uri>http://www.blogger.com/profile/11579245596035586334</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6458135603295822938.post-4057490888633823695</id><published>2011-04-12T05:46:00.000-07:00</published><updated>2011-04-12T05:54:40.207-07:00</updated><title type='text'>SCRUM - Manage Your User Story</title><content type='html'>&lt;h1 align="center"&gt;Background&lt;/h1&gt;&lt;hr /&gt;We usually have some number of user stories to deliver in each sprint. Often, the user stories were created to our best knowledge about some business values that we are going to deliver. It then gets updated with clearer detail over the time as it turns higher at priority over the time. However it is very often that not all details can be gathered before we started to work on a user story. Very often too, there are some new discoveries as we progressing to complete a user story. These are risks, the risks may be preventing a user story from getting complete. If it prevents the completion of the current user story, how we handle it? Can I have a story extends all the way to the next sprint or couple of sprint?&lt;br /&gt;&lt;br /&gt;&lt;h1 align="center"&gt;Manage your new found risks in a user story&lt;/h1&gt;&lt;hr /&gt;In agile, we don't like a large user story that spread well over several sprints without a concrete indication of where we are. This does not manage the risks well. However, if it is a main (big) user story that has several not too large but measurable sub user stories where each of them can be completed either concurrently or independently within a sprint, I believe that is very much acceptable and the way I *think* it should be. This makes the user story, whether the main user story or its sub user stories, more accountable, quantifiable and manageable. It then makes things transparent as to when can I expect certain deliverable based on what we know best now. However, many people would argue that this is in fact a dependency of user story and the dependency management usually needs project planning and that is not agile after all. If you think so, you have mistaken my points I am trying to make here.&lt;br /&gt;&lt;br /&gt;Say a developer is going to deliver a user story "A" in this sprint and halfway thru the process, he discovered an impediment, say "A'", that prevents him from getting user story "A" done. He has no additional bandwidth or capacity of getting "A'" done this sprint, so he has discussed with SCRUM Master and it seems nobody has better knowledge than he does to handle it, so what a SCRUM Master would normally do is to get Product Owner into this discussion. If nothing much has changed, what should the Product Owner do to this User Story "A" and the impediment "A'"?&lt;br /&gt;&lt;br /&gt;As I would suggest: -&lt;br /&gt;&lt;ol&gt;&lt;li&gt; The Product Owner should split the user story "A" into 2 separate sub user stories, say "A1" and "A2", and ensure it is associating back to the original user story "A".&lt;br /&gt;&lt;ul&gt;&lt;li&gt; Eg. A = A1 + A2&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;li&gt;Then, ensure in user story "A1", it covers what we need to get done initially are covered with some mocking functionality of "A2" in a very high abstraction (Hard coded may be?)&lt;br /&gt;&lt;ul&gt;&lt;li&gt; Eg. A1 = A1' + A''&lt;/li&gt;&lt;li&gt;A1' =&gt; What we supposed to do initially in A, but with a bit changes in abstraction to cater for the coming impediment of A' we discovered during this iteration.&lt;/li&gt;&lt;li&gt;A'' =&gt; Mocking functionality or resolution to impediment A' that we discovered.&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;/ol&gt;&lt;br /&gt;Then within this sprint, we can have the developer to complete the user story A1 and moving the user stories A and A2 to next sprint or re-prioritize as it sees fits.&lt;br /&gt;&lt;br /&gt;&lt;h1 align="center"&gt;Questions&lt;/h1&gt;&lt;hr /&gt;&lt;ol&gt;&lt;li&gt;Are we not agile?&lt;br /&gt;&lt;ul&gt;&lt;li&gt;No, we are. We still follow "just in time" (as we discovered it) and "just enough" (just the mocking of functionality for now) and "just because" (mocking because we can't handle it now, but later)&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;li&gt;Are we doing project planning in advance to identify the dependency?&lt;br /&gt;&lt;ul&gt;&lt;li&gt;No, we don't. We let it happens naturally without factoring in any additional effort in advance to predict.&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;li&gt;More importantly, do we need to emphasis on Agile to be Agile?&lt;br /&gt;&lt;ul&gt;&lt;li&gt;No, Agile is the thought process of getting things done and SCRUM is a framework to do things in agile. They are like best practices recommended to be followed, however you must only follow the practices if that makes sense to you. Ultimately, it is the principle of being continuously transparent, lean in thinking, ready for changes and managing risks with adaptive sprint planning that eventually driving us to the release we planned that makes sense to the business.&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;/ol&gt;&lt;br /&gt;&lt;h1 align="center"&gt;Hints&lt;/h1&gt;&lt;hr /&gt;We need a real worker in Agile and SCRUM and not a philosopher.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6458135603295822938-4057490888633823695?l=synersov.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://synersov.blogspot.com/feeds/4057490888633823695/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://synersov.blogspot.com/2011/04/scrum-manage-your-user-story.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6458135603295822938/posts/default/4057490888633823695'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6458135603295822938/posts/default/4057490888633823695'/><link rel='alternate' type='text/html' href='http://synersov.blogspot.com/2011/04/scrum-manage-your-user-story.html' title='SCRUM - Manage Your User Story'/><author><name>aahkam</name><uri>http://www.blogger.com/profile/11579245596035586334</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6458135603295822938.post-1519262918395990930</id><published>2011-03-30T05:16:00.000-07:00</published><updated>2011-03-30T05:16:23.387-07:00</updated><title type='text'>SCRUM - Definition of Done?</title><content type='html'>&lt;h1 align="center"&gt;Background&lt;/h1&gt;&lt;hr /&gt;Definition of done in software development companies varies one after another. Some company has additional constraints to fulfil while others may be very little. Definition of done is crucial and one must do it right and customized according to the needs to ensure continuous deliverable. For instance, in TDD environment, we usually need some unit tests per feature introduced with sufficient tests coverage that is predefined (usually &amp;gt; 90%). Next, we need some code review and have the code checked in after the review and yet has the Continuous Integration Build completed and all unit tests passed.&lt;br /&gt;&lt;br /&gt;&lt;h1 align="center"&gt;Do we need one in SCRUM?&lt;/h1&gt;&lt;hr /&gt;Certainly we need one. Indeed, we need it to a much wider extends. In SCRUM, we create user stories and then planned out the deliverables in the release plan and the sprint plan. At the end of each sprint, we will mark whichever user stories that are "done" as done. The business users can then expect a somewhat "workable" solution to be delivered.&lt;br /&gt;&lt;br /&gt;The question now is, how much do we need to constraint when we are in SCRUM? How much do we want our business users to be able to expect from the delivered "workable" solution at each sprint?&lt;br /&gt;&lt;br /&gt;If a solution that works but may be with many defects due to not properly tested is considered acceptable by the business users as a potential deliverable, you can then schedule your QA tests to come in after the sprint!&lt;br /&gt;&lt;br /&gt;In many occasions, in fact in SCRUM, this is not acceptable. You cannot say you've completed a user story where it is highly potential with defects, especially the functionality or workability defects. When you mentioned a done to the user story, we are expecting it to be stable, workable with minimal functional defects and met some level of quality measure.&lt;br /&gt;&lt;br /&gt;So in Agile or SCRUM, we do tests much sooner and users stories that failed the tests can never be made DONE. We bring the test team into our SCRUM team and they are in our team. Soon as we completed the development work, the tester will do the tests according to the user story's needs. We don't delay the tests and wait till the end-of-sprint and packaged the deliverable to test. Many SCRUM teams failed, one of the key reason is that we do post sprint test approach. You always need to factor in additional period of time for the tester to tests and the defects of this sprint can only get fixed next at sprint. Your SCRUM fails, you are running waterfall approach (miniature waterfall style). So, for the SCRUM Master, please change this to in-sprint testing for the better success; for the Product Owner, please voice your concern of having it (defects and quality) delayed to next sprint. You don't always have that next sprint and worst, you are always wasting a sprint in addition!&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;h1 align="center"&gt;Compulsory Items in SCRUM DoD List&lt;/h1&gt;&lt;hr /&gt;&lt;ol&gt;&lt;li&gt;Automated Unit Tested with Good Coverage (above 90%)&lt;/li&gt;&lt;li&gt;Continuously Integrated and Successful Build&lt;/li&gt;&lt;li&gt;Automated Integration Tested&lt;/li&gt;&lt;li&gt;QA Tested (with Test Team)&lt;/li&gt;&lt;li&gt;All Defects Fixed.&lt;/li&gt;&lt;/ol&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6458135603295822938-1519262918395990930?l=synersov.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://synersov.blogspot.com/feeds/1519262918395990930/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://synersov.blogspot.com/2011/03/scrum-definition-of-done.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6458135603295822938/posts/default/1519262918395990930'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6458135603295822938/posts/default/1519262918395990930'/><link rel='alternate' type='text/html' href='http://synersov.blogspot.com/2011/03/scrum-definition-of-done.html' title='SCRUM - Definition of Done?'/><author><name>aahkam</name><uri>http://www.blogger.com/profile/11579245596035586334</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6458135603295822938.post-1148138064440680528</id><published>2011-03-29T05:35:00.001-07:00</published><updated>2011-03-29T05:44:29.379-07:00</updated><title type='text'>SCRUM - Endlessly Growing Product Backlog</title><content type='html'>&lt;h1 align="center"&gt;Background&lt;/h1&gt;&lt;hr /&gt;Often when we have run our SCRUM over a period of time (a year or two), we noticed the product backlog gets expanded at an increasing velocity. Up from some 1 or 2 new user stories introduced to several tens of new user stories introduced within a sprint. Is this a good indication or worries that one should look into?&lt;br /&gt;&lt;br /&gt;User stories within product backlog indicates some missing business features or value that one must look into and plan out properly to ensure the business satisfaction. This usually has to be inline with the product roadmap and how we want to grow the product over the time. This roadmap can be changed as time comes, to ensure it meets the current and near future (not too far in the future) business needs. Remember that phrase we talked about, &lt;a href="http://www.jessefewell.com/2010/12/27/just-enough-just-in-time-and-sometimes-just-because/"&gt;Just in time", "Just enough" and "Just because"!!!&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;h1 align="center"&gt;Why It Happens&lt;/h1&gt;&lt;hr /&gt;&lt;ul&gt;&lt;li&gt; Everyone raises a user story they "think" it is value added.&lt;/li&gt;&lt;li&gt; No clear inidcation of product roadmap telling where we want to be within a fixed schedule.&lt;/li&gt;&lt;li&gt; No planned out of fixed schedules.&lt;/li&gt;&lt;li&gt; Overloaded with too many technical driven user stories&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;h1 align="center"&gt;How to Turn It Around&lt;/h1&gt;&lt;hr /&gt;&lt;ol&gt;&lt;li&gt; Who can raise user stories?&lt;/li&gt;We must ensure and limits the people with ability to raise a user story to those who posses business interests. We are dealing with delivering genuine business values that benefits the business users, not architects, developers, consultants.&lt;li&gt; Where we want to be at a bird's eye view?&lt;/li&gt;There must be a fixed schedule and a fixed cost. I'm not talking about short term plan like a sprint or a release, but a very high-level objective that we want to achieve to fulfil the business after several releases. This is a directive measure, a pool of resources as part of the costs and how are we planned to spend these costs to achieve our business direction or intends (roadmap). Important to note here, I'm not suggesting a fixed or permanent roadmap that cannot be altered, rather a roadmap for everyone to follow if nothing is suggesting a change needs. If there is a change, we prioritized some and deprioritized some in and out of the roadmap. If it is too far in future, we may opt to drop that from the product backlog if it is not at all important or its value depreciated over the time. Why waste effort of tracing some potentially not needed features if it is not at all fullfilling the business now and near future. Remember, &lt;a href="http://www.jessefewell.com/2010/12/27/just-enough-just-in-time-and-sometimes-just-because/"&gt;Just in time", "Just enough" and "Just because"!!!&lt;/a&gt;&lt;li&gt; Where we want to be at a bird's eye view with a minimal lookahead?&lt;/li&gt;Just like what we have discussed above but we need to know the pipeline of the fixed schedules. However, lookahead lightly and at a higher level of abstract then the current fixed schedule.&lt;li&gt; Should we raise technical user stories?&lt;/li&gt;We can get endless of technical driven user stories, especially true for the sake of perfection. Not saying we cannot have a task nailing down some technical or architecture aspects, but it all must be driven by the business value.   Example, I need to have an Online Store that serves all my customers and I have 20 thousand customers with my company loyalty card membership.   This suggests the needs to load balance the Web Application and there is a need of scaling out. We may need a proper cache (distributed) or if we have a highly clustered database farms that is durable, reliable and efficient. However, we are not creating it as a primary citizen in the product backlog. This at best is a supporting (dependent) user story to fullfil the first user story above it. Whenever the business value gets deprioritized, all its supporting user story goes the same direction, unless you have no better things to do.  &lt;/ol&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6458135603295822938-1148138064440680528?l=synersov.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://synersov.blogspot.com/feeds/1148138064440680528/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://synersov.blogspot.com/2011/03/scrum-endlessly-growing-product-backlog.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6458135603295822938/posts/default/1148138064440680528'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6458135603295822938/posts/default/1148138064440680528'/><link rel='alternate' type='text/html' href='http://synersov.blogspot.com/2011/03/scrum-endlessly-growing-product-backlog.html' title='SCRUM - Endlessly Growing Product Backlog'/><author><name>aahkam</name><uri>http://www.blogger.com/profile/11579245596035586334</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6458135603295822938.post-8106639371216159066</id><published>2011-03-18T00:48:00.000-07:00</published><updated>2011-03-18T00:52:50.060-07:00</updated><title type='text'>Never write you own Message Queuing Framework</title><content type='html'>Software development is fun. Especially true if you are developing an Enterprise Application. There will be many challenges, world class challenges! High throughput, efficiency and low roll out cost and many sophisticated and complex business logic and workflow that goes beyond what you have learned and practiced in the past. If you are not ready for them, you better look elsewhere.&lt;br /&gt;&lt;br /&gt;Very common in enterprise solutions to have distributed application support that require high response time and yet reliable communication and services to deliver the requests. Secured, durable and reliable messages encapsulating business operational messages that get processed at the distributed end, usually the server tiers, are common. These are normally done with many ready made Messaging Framework, such as MSMQ, AppFrabic Service Bus, Enterprise Service Bus, WebSphere MQ. There are also a couple opensource messaging framework like RabbitMQ, ZeroMQ, AMQP.&lt;br /&gt;&lt;br /&gt;We have more than enough varieties in MQ selection however, there always some techy developers or architects would like to invent one them-self within their own team. Often, the discussion is surrounding the fact of freedom and lightweight modules that suits best into the solutions, teams or the company. It is always good to have the experience of developing such framework in your resume, but that is often bad for the team, and company.&lt;br /&gt;&lt;br /&gt;Never invent one there is a ready made solution.&lt;br /&gt;It takes several years for a framework to be matured and tested against many genuine requirements within the businesses and made many fixes, enhancements, simplification, optimization, customization, usability and security tests while accomplishing the needs of being orderable, durable, reliable and securable. Developing one yourself is a short sighted move. You are ignoring the facts that a framework takes millions of hour and efforts to be matured and testified. You are thinking that one man view is always better than the effort of a group of people. You might be right for the first few months, but as your solution becoming more matured and many more challenges coming onboard, you will quickly find that you were shooting at your own feet for the decision you made.&lt;br /&gt;&lt;br /&gt;You often find that your invented MQ framework does not scale as good. Has many shortcomings in throttling, failed-safe, and security. Does not have a dead letter policy supports. Loosing the sight of dynamic expansion of queues. Priority overwrites and poison message control. Worst when you have no idea to maintain/support disastrous recovery. Worst when you find your own MQ framework does not support distributed transaction, transaction flow (distributed but integrated transaction model) and does not log properly and not autonomous. Your solution may ended up just a distributed but serialized messaging gateway that processes messages from different sources in a single queued fashion and starts to suffers when a business starts growing large.&lt;br /&gt;&lt;br /&gt;Other than business factors consideration, you owe your team or your company at large by requiring many innocent teammates to endlessly support and fixing defects that were common but long fixed in the matured framework. You start to find yourself heading to where other frameworks is doing by doing more work and getting less throughput. You burn many pricey man-hours for the company to get less. You tricked your team members with more long working hour to support and defect fixing to deliver sub-standard solution to the users. You make your product less competitive to the competitors and you shifted the team focus from product development to platform components that are no better but long available. You sincerely given your competitors a chance to close up your leading role or gap in the industry. You put your team to loose enthusiasm. You bid your company and the team to the losing end to only build a good resume in you.&lt;br /&gt;&lt;br /&gt;From the business, team, and product perspective, there are no reason for one to develop your own messaging framework. Unless you would want to compete with the giant in the market, this is not your cup of tea. Just stay away from losing sight, you should and must maintain your business focus and continuing your industry leading role.&lt;br /&gt;&lt;br /&gt;Final words, don't reinvent the wheel if this is not your strength and does not record in your business roadmap. Do what you do best and leave the worries to the experts.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6458135603295822938-8106639371216159066?l=synersov.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://synersov.blogspot.com/feeds/8106639371216159066/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://synersov.blogspot.com/2011/03/never-write-you-own-message-queuing.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6458135603295822938/posts/default/8106639371216159066'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6458135603295822938/posts/default/8106639371216159066'/><link rel='alternate' type='text/html' href='http://synersov.blogspot.com/2011/03/never-write-you-own-message-queuing.html' title='Never write you own Message Queuing Framework'/><author><name>aahkam</name><uri>http://www.blogger.com/profile/11579245596035586334</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6458135603295822938.post-3035008021874194754</id><published>2011-03-14T21:43:00.000-07:00</published><updated>2011-03-17T23:49:13.574-07:00</updated><title type='text'>Test Like A User</title><content type='html'>Often, for a developer to be good, one must think like a user. Same goes to the testers.&lt;br /&gt;&lt;br /&gt;So, what it says, before you start writing your test cases, you must think, "If I am one of the users, I would want something to work like this. It must not allow me to proceed if I ever mistakenly committed certain things. Best if it can give me some alert (warning).". I know many would say to me, this is a user requirement my friend, and testers are testing the product based on the requirement! Well, yes and no.&lt;br /&gt;&lt;br /&gt;Do you how many good requirement surfaced during test phases. Users may have overlooked, and testers is to tests whether that is going to be painless experience for a user other than the workability. I know many users created many requirements which eventually they themselves find it not useful and painful to use. They may have mistaken one or two steps which unfortunately were not noticed.&lt;br /&gt;&lt;br /&gt;As a tester, you must ensure you know the context of the topic you are testing. If it involves Integration Layer with Integrations testing, you must ensure you understand how this integration is done. Why it was done like that (the flows and steps) and can it be better?&lt;br /&gt;&lt;br /&gt;Many times, the tester came back to the developers, and asked things like: -&lt;br /&gt;"Why when I'm migrating my Database from the console application, I need to tell which server I'm migrating to and what new name my database is going to be?"&lt;br /&gt;&lt;br /&gt;"I'm testing on a command to restore a database which optionally takes a database synonyms fixes. Why must I specified the synonyms when I'm restoring it to a different database name?"&lt;br /&gt;&lt;br /&gt;I often ask my testers right after they asked questions. Such as, do you know what is a database migration? Do you know what is a synonyms?&lt;br /&gt;&lt;br /&gt;Sadly, the answers I often get from the testers are "No" or something like, "I'm not certain" or telling me something that is totally irrelevant. I'm just thinking, how can you do the tests as a tester if you don't even know what you are going to expect and how it is going to behave. Worst when one can't even tell me what errors can they expect as a tester.&lt;br /&gt;&lt;br /&gt;Testers are not a dump "machine" who runs routine works and verifies the outcome with a predefined results only. It is so much broader so the testers can act like a user and telling the developers/users/BA or even the genuine users themselves with something like this: -&lt;br /&gt;"Look, what is done is good, but I certainly think as a user I would want something additional to make it more useful (usability) and informational (support). I understand this is not as important compared to many other features, but certainly we need to be more painless to use it."&lt;br /&gt;&lt;br /&gt;Hey testers, wake up. Stop your routine boring tasks of matching results. Try step out of the box and thinking like a genuine user and use the product like you are owning one later. You can make a different!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6458135603295822938-3035008021874194754?l=synersov.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://synersov.blogspot.com/feeds/3035008021874194754/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://synersov.blogspot.com/2011/03/test-like-user.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6458135603295822938/posts/default/3035008021874194754'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6458135603295822938/posts/default/3035008021874194754'/><link rel='alternate' type='text/html' href='http://synersov.blogspot.com/2011/03/test-like-user.html' title='Test Like A User'/><author><name>aahkam</name><uri>http://www.blogger.com/profile/11579245596035586334</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6458135603295822938.post-1074485325232545979</id><published>2010-12-02T20:15:00.000-08:00</published><updated>2010-12-04T10:27:14.469-08:00</updated><title type='text'>SCRUM Principles</title><content type='html'>&lt;h1 align="center"&gt;Background&lt;/h1&gt;&lt;hr /&gt;Attended the SCRUM Workshop, in short, it is a must for all developers/Architects/PM/Program Manager/Tester/BA.&lt;br /&gt;&lt;h1 align="center"&gt;SCRUM Values&lt;/h1&gt;&lt;hr /&gt;In SCRUM, we value: -&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Individuals and interactions over processes and tools&lt;/li&gt;&lt;li&gt;Completed functionality over comprehensive documentation&lt;/li&gt;&lt;li&gt;Customer collaboration over contract negotiation&lt;/li&gt;&lt;li&gt;Responding to change over following a plan&lt;/li&gt;&lt;/ul&gt;&lt;h1 align="center"&gt;How SCRUM Helps?&lt;/h1&gt;&lt;hr /&gt;&lt;ol&gt;&lt;li&gt;Works Transparency - Everything is transparent to the corresponding stake holder, customers and even to the team. &lt;a href="http://www.scrumalliance.org/articles/39#1127"&gt;Burn Down Chart&lt;/a&gt;, &lt;a href="http://www.scrumalliance.org/articles/39-glossary-of-scrum-terms#1110"&gt;Team Velocity&lt;/a&gt;.&lt;/li&gt;&lt;li&gt;Self Empowered and Organized - &lt;a href="http://www.scrumalliance.org/articles/39-glossary-of-scrum-terms#1112"&gt;SCRUM Team&lt;/a&gt; work as a whole to estimate and agree on deliverable achievable.&lt;/li&gt;&lt;li&gt;Collaboration - The transparency of the progress, status and facts allows the SCRUM team to collaborate and interact more to the stake holders, customers on change plan without over optimistically committing to the request too easily.&lt;/li&gt;&lt;li&gt;Recognize the needs to change - The only thing remain unchanged in this world is the change. It recognizes it and put focus on what is best known currently and do it while anticipate future changes is needed.&lt;/li&gt;&lt;li&gt;Incremental Release - Encourage frequent release with each release being workable deliverable as a whole, in a smaller but manageable incremental scope.&lt;/li&gt;&lt;li&gt;More and frequent planning - SCRUM does more planning, &lt;a href="http://www.scrumalliance.org/articles/39-glossary-of-scrum-terms#1125"&gt;Product Road Map&lt;/a&gt;, &lt;a href="http://www.scrumalliance.org/articles/39-glossary-of-scrum-terms#1120"&gt;Release Plan&lt;/a&gt;, &lt;a href="http://www.scrumalliance.org/articles/39-glossary-of-scrum-terms#1114"&gt;Sprint Plan&lt;/a&gt;. However, only the highest priority which needs immediate work gets the detail plan, tasks, estimation and etc.&lt;/li&gt;&lt;li&gt;More Meeting - &lt;a href="http://www.scrumalliance.org/articles/39-glossary-of-scrum-terms#1128"&gt;Daily SCRUM meeting&lt;/a&gt;. Daily SCRUM meeting on What is done, what is not, what is on your way.&amp;nbsp; &lt;/li&gt;&lt;li&gt;More Frequent Reviews - Sprint Reviews at the end of each Sprint on what is completed and what is not by adhering to Definition of Done.&lt;/li&gt;&lt;li&gt; &lt;a href="http://www.scrumalliance.org/articles/39-glossary-of-scrum-terms#1113"&gt;Sprint Retrospective Meeting&lt;/a&gt; - After the sprint reviews with Product Owner excluded. Discussed on what's good and bad as project is still ongoing. To know the problem earlier, learn and improve as a continuous effort and avoid repeating the same mistake within the coming Sprint.&lt;/li&gt;&lt;li&gt;&lt;a href="http://www.scrumalliance.org/articles/39-glossary-of-scrum-terms#1122"&gt;Product Owner&lt;/a&gt; - Single person to have final authority representing the customer's  interest in backlog prioritization and requirements questions. This ensure no missing link or tear down at communication.&lt;/li&gt;&lt;li&gt;&lt;a href="http://www.scrumalliance.org/articles/39-glossary-of-scrum-terms#1121"&gt;SCRUM Master&lt;/a&gt; - As a facilitator to work with the product owner and the team to orchestrate the SCRUM ceremony.&lt;/li&gt;&lt;/ol&gt;&lt;h1 align="center"&gt;Untrue SCRUM/Agile Myth&lt;/h1&gt;&lt;hr /&gt;&lt;ol&gt;&lt;li&gt;SCRUM does not do documents or reporting for communication!&lt;/li&gt;&lt;li&gt;SCRUM is only focus on the worker (developers) not the business!&lt;/li&gt;&lt;li&gt;SCRUM does not need a Leader!&lt;/li&gt;&lt;li&gt;SCRUM makes impossible turns possible!&lt;/li&gt;&lt;li&gt;SCRUM prevents problems and it is a "silver bullet"!&lt;/li&gt;&lt;li&gt;SCRUM is self organized and self empowered, so, "Do whatever you like!"&lt;/li&gt;&lt;li&gt;Agile Fragile! No planning and architecture needed.&lt;/li&gt;&lt;li&gt;Agile is just an iterative and incremental process.&lt;/li&gt;&lt;li&gt;Adopting Agile means betraying PMI.&lt;/li&gt;&lt;li&gt;Agile means no/avoid commitment.&lt;/li&gt;&lt;/ol&gt;&lt;h1 align="center"&gt;Reality to Untrue SCRUM/Agile Myth&lt;/h1&gt;&lt;hr /&gt;Reality to Myth #1:&lt;br /&gt;In SCRUM, we emphasize on automated and integrated workspace. We produce artifacts such as: -&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Product/Release/Sprint Back Log&lt;/li&gt;&lt;li&gt;Product/Release/Sprint Burn Down Chart&lt;/li&gt;&lt;li&gt;Team Velocity Matrix&lt;/li&gt;&lt;li&gt;Estimation&lt;/li&gt;&lt;/ul&gt;These artifacts are meant to be showing to everyone, where we are, how are we doing and how far we are from the sprint/release/product goal. Product backlog with each itemized entry prioritized showing the road-map of&amp;nbsp; a given product and the planning of getting it done accordingly.&lt;br /&gt;&lt;br /&gt;Reality to Myth #2: -&lt;br /&gt;SCRUM is highly business value driven approach. It focus on business values to the customer than the scope or what customer "think" they want. It ensure the customer is not buying just a set of feature scopes, but the business values to the customer, sooner and earlier. Often, we see projects delivered all the scopes their respective customers wanted but the customer isn't happy in the end because it does not fulfill the business need. This is what SCRUM is trying to avoid.&lt;br /&gt;&lt;br /&gt;Reality to Myth #3: -&lt;br /&gt;In SCRUM, we are changing the game plan. Managers are too used to Directed management style. These managers need followers. They ensure the best arrangement of work to candidate who they think best working with. Often, their best people usually does not work best under such "arrangement". Think again, the best people who does well in their work are already put on to manage role, so is there anymore best people? So, in SCRUM, we coach, mentor and lead by example. We value facilitator management than directed management. This requires a capable leader with great leadership skills and interpersonal skills to make possible.&lt;br /&gt;&lt;br /&gt;Reality to Myth #4: -&lt;br /&gt;In SCRUM, we value transparency and we focus on start delivering sooner with multiple release that ships incremental of workable solution subsets. This usually help to discover and manage the impossible sooner and allow the customers to justify their decision quicker and change of game plan earlier. Hence it helps to see the fails sooner to avoid greater lost because the nature of identifying risks/impossibles sooner, the customers often can then make justifiable decision to counter the issues earlier and has higher success rate than those that can't help in identifying risk earlier.&lt;br /&gt;&lt;br /&gt;Reality to Myth #5: -&lt;br /&gt;In SCRUM, no way you can prevent problems. However, its emphasize of being transparency will let the problems to surface earlier than one would expect. These surfaced problem are &lt;a href="http://www.scrumalliance.org/articles/39-glossary-of-scrum-terms#1126"&gt;Impediments&lt;/a&gt; in SCRUM which requires the SCRUM master with great skills to help facilitating with the team. This impediment may be impacting the productivity of the team but SCRUM allows it to be surfaced sooner and dealt with earlier and quicker. However, to some extent, people often associate this nature as a SCRUM problem itself.&lt;br /&gt;&lt;br /&gt;Reality to Myth #6: -&lt;br /&gt;In SCRUM, we need a highly discipline members that stay focus and continue productivity with consistent pace for predictable estimation. SCRUM team works closely achieving Goals and Expectation put up front by Product Owner who represents the Customers with Customers interests and expectations. SCRUM Master as a facilitator is trying to collaborate between Product Owner and the team and orchestrating the each SCRUM ceremony. Everyone has their role and game plan and this discipline must be closely adhered to.&lt;br /&gt;&lt;br /&gt;Reality to Myth #7: -&lt;br /&gt;In SCRUM, we do more planning. Product/Release/Sprint Planning. We do more risk management. Product/Release/Sprint Burn Down. We do more reviews and we do more retrospective meeting (postmortem) than anyone else, however this are done interactively within each sprint and making us so efficient in dealing with problems because we see problems sooner, efficient in learning because we see our weakness earlier, and etc. In SCRUM we need architecture to work best, however, &lt;b&gt;we avoid architecture details being too detail too soon because we recognize the only thing remain unchanged is "change"&lt;/b&gt;.&lt;br /&gt;&lt;br /&gt;Reality to Myth #8: -&lt;br /&gt;In SCRUM, we measure our productivity velocity based on facts (the earlier Sprints' velocity from the burn down) and commit to tasks within our capability. We aimed to deliver potentially shippable solution with a current subsets of product features that delivered business values where our customers need it NOW, not just want. It is not as simple as incremental, but it has a lot to do with customers' business plans and strategy and delivering the needed business values.&lt;br /&gt;&lt;br /&gt;Reality to Myth #9: -&lt;br /&gt;Wrong. We see there are many rooms for Agile PM. While PMI emphasize on: -&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Project Integration Management&lt;/li&gt;&lt;li&gt;Project Scope Management&lt;/li&gt;&lt;li&gt;Project Time Management&lt;/li&gt;&lt;li&gt;Project Cost Management&lt;/li&gt;&lt;li&gt;Project Quality Management&lt;/li&gt;&lt;li&gt;Project Human Resource Management&lt;/li&gt;&lt;li&gt;Project Communications Management&lt;/li&gt;&lt;li&gt;Project Risk Management&lt;/li&gt;&lt;li&gt;Project Procurement Management&lt;/li&gt;&lt;/ul&gt;In SCRUM/Agile, we adopts lean process, thinking and techniques and we are just focusing on facilitating and empowering the team to help elevate, surface and addressing these issues much sooner and quicker. This would help a qualified project manager to deal/elevate/stay transparent with the risks in the interests of customers, stake holders and the company. Please visit &lt;a href="http://www.jessefewell.com/%22"&gt;Jesse Fewell's Agile PM&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;Reality to Myth #10: -&lt;br /&gt;In SCRUM, we commit to deliver the agreed task items in sprint planning that was put forward together with Product Owner, SCRUM Master and the team. We commit to stay focus and deliver potentially shippable working incremental subsets of solution features. We valued transparency and we work well with fixed cost fixed schedule projects and we collaborate with the customers on business values needed than the scope wanted. Estimates derives from the past velocity remains "estimates" and in short we practiced Agile Principle by working on estimation with commitment and remain transparent, at the same time willing to adapt to the change by encouraging collaboration with customers based on facts collected from the SCRUM artifacts.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6458135603295822938-1074485325232545979?l=synersov.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://synersov.blogspot.com/feeds/1074485325232545979/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://synersov.blogspot.com/2010/12/scrum-principles.html#comment-form' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6458135603295822938/posts/default/1074485325232545979'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6458135603295822938/posts/default/1074485325232545979'/><link rel='alternate' type='text/html' href='http://synersov.blogspot.com/2010/12/scrum-principles.html' title='SCRUM Principles'/><author><name>aahkam</name><uri>http://www.blogger.com/profile/11579245596035586334</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6458135603295822938.post-8875426880853329109</id><published>2010-10-14T01:07:00.000-07:00</published><updated>2010-10-14T01:13:40.704-07:00</updated><title type='text'>Be careful with Linq within Exception Handling Block</title><content type='html'>Exception handling try {} catch {} finally {} in .NET always guarantee the finally clause will be executed. However, deferred execution of Linq prove to be able to make a difference, once again thanks to the side effects of linq like I've discussed in the past.&lt;br /&gt;&lt;br /&gt;Consider the code block below: -&lt;br /&gt;&lt;pre&gt;&lt;code class=" cs"&gt;        &lt;span class=keyword&gt;protected&lt;/SPAN&gt; &lt;span class=keyword&gt;override&lt;/SPAN&gt; IEnumerable&amp;lt;&lt;span class=keyword&gt;byte&lt;/SPAN&gt;[]&amp;gt;  DoReadAsRaw()&lt;br /&gt;        {&lt;br /&gt;         &lt;span class=keyword&gt;try&lt;/SPAN&gt;&lt;br /&gt;         {&lt;br /&gt;          &lt;span class=keyword&gt;return&lt;/SPAN&gt; _settings&lt;br /&gt;           .FieldInfos&lt;br /&gt;           .Select(item =&amp;gt; _innerReader.ReadBytes(_innerReader.ReadInt32()));&lt;br /&gt;         }&lt;br /&gt;         &lt;span class=keyword&gt;catch&lt;/SPAN&gt; (EndOfStreamException)&lt;br /&gt;         {&lt;br /&gt;          &lt;span class=keyword&gt;return&lt;/SPAN&gt; &lt;span class=keyword&gt;null&lt;/SPAN&gt;;&lt;br /&gt;         }&lt;br /&gt;        }&lt;/CODE&gt;&lt;/PRE&gt;This is to read out an Enumerable of byte array. I have another code block below that will call into this method and utilizing the Enumerable of byte array as such: -&lt;br /&gt;&lt;pre&gt;&lt;code class=" cs"&gt;         &lt;span class=keyword&gt;var&lt;/SPAN&gt; rawData = DoReadAsRaw();&lt;br /&gt;&lt;br /&gt;         &lt;span class=keyword&gt;return&lt;/SPAN&gt; rawData == &lt;span class=keyword&gt;null&lt;/SPAN&gt; ? &lt;span class=keyword&gt;null&lt;/SPAN&gt; : &lt;span class=keyword&gt;new&lt;/SPAN&gt; Record&amp;lt;&lt;span class=keyword&gt;byte&lt;/SPAN&gt;[]&amp;gt;(_settings.FieldInfos, rawData);&lt;/CODE&gt;&lt;/PRE&gt;Within the Record Constructor, I have the codeblock to iterate thru the enumerable byte array as such: -&lt;br /&gt;&lt;pre&gt;&lt;code class=cs&gt;        &lt;span class=keyword&gt;public&lt;/SPAN&gt; Record(IEnumerable&amp;lt;FieldInfo&amp;gt; fieldInfos, IEnumerable&amp;lt;T&amp;gt; values)&lt;br /&gt;        {&lt;br /&gt;            &lt;span class=keyword&gt;if&lt;/SPAN&gt; (fieldInfos == &lt;span class=keyword&gt;null&lt;/SPAN&gt;)&lt;br /&gt;            {&lt;br /&gt;                &lt;span class=keyword&gt;throw&lt;/SPAN&gt; &lt;span class=keyword&gt;new&lt;/SPAN&gt; ArgumentNullException(&lt;span class=string&gt;"fieldInfos"&lt;/SPAN&gt;);&lt;br /&gt;            }&lt;br /&gt;&lt;br /&gt;            &lt;span class=keyword&gt;if&lt;/SPAN&gt; (values == &lt;span class=keyword&gt;null&lt;/SPAN&gt;)&lt;br /&gt;            {&lt;br /&gt;                &lt;span class=keyword&gt;throw&lt;/SPAN&gt; &lt;span class=keyword&gt;new&lt;/SPAN&gt; ArgumentNullException(&lt;span class=string&gt;"values"&lt;/SPAN&gt;);&lt;br /&gt;            }&lt;br /&gt;&lt;br /&gt;            &lt;span class=keyword&gt;var&lt;/SPAN&gt; fieldInfoArray = fieldInfos.ToArray();&lt;br /&gt;            &lt;span class=keyword&gt;var&lt;/SPAN&gt; valueArray = values.ToArray();&lt;br /&gt;&lt;br /&gt;            &lt;span class=comment&gt;// checks the length of field and data to ensure their length is matching.&lt;/SPAN&gt;&lt;br /&gt;            &lt;span class=keyword&gt;if&lt;/SPAN&gt; (fieldInfoArray.Length != valueArray.Length)&lt;br /&gt;            {&lt;br /&gt;                &lt;span class=keyword&gt;var&lt;/SPAN&gt; message = &lt;span class=keyword&gt;string&lt;/SPAN&gt;.Format(&lt;span class=string&gt;"Fields and values count mistmatched. Expected {0} fields but was {1}."&lt;/SPAN&gt;,&lt;br /&gt;                                            fieldInfoArray.Length, valueArray.Length);&lt;br /&gt;                &lt;span class=keyword&gt;throw&lt;/SPAN&gt; &lt;span class=keyword&gt;new&lt;/SPAN&gt; IndexOutOfRangeException(message);&lt;br /&gt;            }&lt;br /&gt;&lt;br /&gt;            _fields = &lt;span class=keyword&gt;new&lt;/SPAN&gt; T[fieldInfoArray.Length];&lt;br /&gt;            _itemNameIndexMap = &lt;span class=keyword&gt;new&lt;/SPAN&gt; Dictionary&amp;lt;&lt;span class=keyword&gt;string&lt;/SPAN&gt;, &lt;span class=keyword&gt;int&lt;/SPAN&gt;&amp;gt;();&lt;br /&gt;&lt;br /&gt;            &lt;span class=keyword&gt;for&lt;/SPAN&gt; (&lt;span class=keyword&gt;var&lt;/SPAN&gt; i = &lt;span class=number&gt;0&lt;/SPAN&gt;; i &amp;lt; fieldInfoArray.Length; i++)&lt;br /&gt;            {&lt;br /&gt;                &lt;span class=keyword&gt;var&lt;/SPAN&gt; currentFieldInfo = fieldInfoArray[i];&lt;br /&gt;&lt;br /&gt;                _fields[i] = valueArray[i];&lt;br /&gt;                _itemNameIndexMap.Add(currentFieldInfo.Name, i);&lt;br /&gt;&lt;br /&gt;                &lt;span class=keyword&gt;if&lt;/SPAN&gt; (!currentFieldInfo.IsKeyField) &lt;span class=keyword&gt;continue&lt;/SPAN&gt;;&lt;br /&gt;&lt;br /&gt;                IdentifierFieldIndex = i;&lt;br /&gt;                IdentifierFieldName = currentFieldInfo.Name;&lt;br /&gt;            }&lt;br /&gt;        }&lt;/CODE&gt;&lt;/PRE&gt;Guess what when unit testing?&lt;br /&gt;&lt;b&gt;EndOfStreamException was not handled!&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;the past experience of Linq's side effects helps me to quickly identifying that the culprit was the absent of ToArray() or ToList() call right after the linq statement within the try-catch block.&lt;br /&gt;&lt;br /&gt;Soon as ToArray() is added into the code, it works beautifully and passed the unit test.&lt;br /&gt;&lt;br /&gt;So, best practise for Linq Statement within the try catch block I would recommend is: -&lt;br /&gt;&lt;br /&gt;&lt;b&gt;If you are returning anything to the caller after the try catch block, ensure you always force create real collection by calling to ToArray() or ToList().&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;Thank you.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6458135603295822938-8875426880853329109?l=synersov.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://synersov.blogspot.com/feeds/8875426880853329109/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://synersov.blogspot.com/2010/10/be-careful-with-linq-within-exception.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6458135603295822938/posts/default/8875426880853329109'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6458135603295822938/posts/default/8875426880853329109'/><link rel='alternate' type='text/html' href='http://synersov.blogspot.com/2010/10/be-careful-with-linq-within-exception.html' title='Be careful with Linq within Exception Handling Block'/><author><name>aahkam</name><uri>http://www.blogger.com/profile/11579245596035586334</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6458135603295822938.post-4338101808848936724</id><published>2010-09-27T11:50:00.000-07:00</published><updated>2010-09-27T11:50:15.823-07:00</updated><title type='text'>Test Driven Approach - Positive Impact for Developers - Conclusion</title><content type='html'>Going thru this lengthy of workshop series on TDD, I hoped I have covered enough here on positives impact from TDD approach. It takes a developer to practice it to see its worth.&lt;br /&gt;&lt;br /&gt;Often in software development, we fall into traps like: -&lt;br /&gt;Lengthy requirement gathering period.&lt;br /&gt;Lengthy conceptualizing and creating over detail blueprint (architecture).&lt;br /&gt;Over design/engineering a software component at early stages.&lt;br /&gt;Lost focus on interactivity between requirement/conceptual model/design phases due to lengthy period.&lt;br /&gt;Less integrability due to disconnected phases.&lt;br /&gt;&lt;br /&gt;All these can be nicefully addressed with Agile and TDD.&lt;br /&gt;Agile and TDD are just complementing each other and bringing developers closer to users and hence business.&lt;br /&gt;&lt;br /&gt;Final question, why would one insert a break point at several area to debug when a defect was raised? Write a unit test to automate that checks please. Thank you.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6458135603295822938-4338101808848936724?l=synersov.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://synersov.blogspot.com/feeds/4338101808848936724/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://synersov.blogspot.com/2010/09/test-driven-approach-positive-impact_1686.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6458135603295822938/posts/default/4338101808848936724'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6458135603295822938/posts/default/4338101808848936724'/><link rel='alternate' type='text/html' href='http://synersov.blogspot.com/2010/09/test-driven-approach-positive-impact_1686.html' title='Test Driven Approach - Positive Impact for Developers - Conclusion'/><author><name>aahkam</name><uri>http://www.blogger.com/profile/11579245596035586334</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6458135603295822938.post-9178602161395110182</id><published>2010-09-27T11:39:00.000-07:00</published><updated>2010-09-27T20:27:23.153-07:00</updated><title type='text'>Test Driven Approach - Positive Impact for Developers - Workshop IV</title><content type='html'>Now we need to implement the Calculate method within Core.Calculator.&lt;br /&gt;&lt;br /&gt;So, there are many ways this can be done and whether this method is developed to its best code is not the interest of the workshop. Here is my sample: -&lt;br /&gt;&lt;pre&gt;&lt;code class="cs"&gt;&lt;span class="keyword"&gt;using&lt;/span&gt; System;&lt;br /&gt;&lt;span class="keyword"&gt;using&lt;/span&gt; System.Collections.Generic;&lt;br /&gt;&lt;span class="keyword"&gt;using&lt;/span&gt; System.Linq;&lt;br /&gt;&lt;br /&gt;&lt;span class="keyword"&gt;namespace&lt;/span&gt; Calculator.Core&lt;br /&gt;{&lt;br /&gt;    &lt;span class="keyword"&gt;public&lt;/span&gt; &lt;span class="keyword"&gt;class&lt;/span&gt; Calculator&lt;br /&gt;    {&lt;br /&gt;        &lt;span class="keyword"&gt;private&lt;/span&gt; &lt;span class="keyword"&gt;const&lt;/span&gt; &lt;span class="keyword"&gt;string&lt;/span&gt; Add = &lt;span class="string"&gt;"+"&lt;/span&gt;;&lt;br /&gt;        &lt;span class="keyword"&gt;private&lt;/span&gt; &lt;span class="keyword"&gt;const&lt;/span&gt; &lt;span class="keyword"&gt;string&lt;/span&gt; Sub = &lt;span class="string"&gt;"-"&lt;/span&gt;;&lt;br /&gt;        &lt;span class="keyword"&gt;private&lt;/span&gt; &lt;span class="keyword"&gt;const&lt;/span&gt; &lt;span class="keyword"&gt;string&lt;/span&gt; Div = &lt;span class="string"&gt;"/"&lt;/span&gt;;&lt;br /&gt;        &lt;span class="keyword"&gt;private&lt;/span&gt; &lt;span class="keyword"&gt;const&lt;/span&gt; &lt;span class="keyword"&gt;string&lt;/span&gt; Mul = &lt;span class="string"&gt;"*"&lt;/span&gt;;&lt;br /&gt;        &lt;span class="keyword"&gt;private&lt;/span&gt; &lt;span class="keyword"&gt;const&lt;/span&gt; &lt;span class="keyword"&gt;string&lt;/span&gt; Sqrt = &lt;span class="string"&gt;"sqrt"&lt;/span&gt;;&lt;br /&gt;        &lt;span class="keyword"&gt;private&lt;/span&gt; &lt;span class="keyword"&gt;const&lt;/span&gt; &lt;span class="keyword"&gt;string&lt;/span&gt; Percent = &lt;span class="string"&gt;"%"&lt;/span&gt;;&lt;br /&gt;        &lt;span class="keyword"&gt;private&lt;/span&gt; &lt;span class="keyword"&gt;const&lt;/span&gt; &lt;span class="keyword"&gt;string&lt;/span&gt; Reciproc = &lt;span class="string"&gt;"reciproc"&lt;/span&gt;;&lt;br /&gt;        &lt;span class="keyword"&gt;private&lt;/span&gt; &lt;span class="keyword"&gt;const&lt;/span&gt; &lt;span class="keyword"&gt;string&lt;/span&gt; Pow = &lt;span class="string"&gt;"pow"&lt;/span&gt;;&lt;br /&gt;&lt;br /&gt;        &lt;span class="keyword"&gt;private&lt;/span&gt; &lt;span class="keyword"&gt;readonly&lt;/span&gt; &lt;span class="keyword"&gt;string&lt;/span&gt;[] _keywords = &lt;span class="keyword"&gt;new&lt;/span&gt; []{ Add, Sub, Div, Mul, Sqrt, Percent, Reciproc, Pow, &lt;span class="string"&gt;"("&lt;/span&gt;, &lt;span class="string"&gt;")"&lt;/span&gt;, &lt;span class="string"&gt;","&lt;/span&gt;};&lt;br /&gt;&lt;br /&gt;        &lt;span class="keyword"&gt;private&lt;/span&gt; &lt;span class="keyword"&gt;readonly&lt;/span&gt; &lt;span class="keyword"&gt;string&lt;/span&gt;[] _operatorKeywords = &lt;span class="keyword"&gt;new&lt;/span&gt;[] { Add, Sub, Div, Mul, Sqrt, Percent, Reciproc, Pow };&lt;br /&gt;&lt;br /&gt;        &lt;span class="keyword"&gt;private&lt;/span&gt; &lt;span class="keyword"&gt;static&lt;/span&gt; &lt;span class="keyword"&gt;readonly&lt;/span&gt; Dictionary&amp;lt;&lt;span class="keyword"&gt;string&lt;/span&gt;, Math.MathOperatorHandler&amp;gt; Operators;&lt;br /&gt;&lt;br /&gt;        &lt;span class="keyword"&gt;static&lt;/span&gt; Calculator()&lt;br /&gt;        {&lt;br /&gt;            Operators = &lt;span class="keyword"&gt;new&lt;/span&gt; Dictionary&amp;lt;&lt;span class="keyword"&gt;string&lt;/span&gt;, Math.MathOperatorHandler&amp;gt;&lt;br /&gt;                             {&lt;br /&gt;                                 {Add, Math.Add},&lt;br /&gt;                                 {Reciproc, Math.Reciproc},&lt;br /&gt;                                 {Pow, Math.Pow},&lt;br /&gt;                                 {Sub, Math.Subtract},&lt;br /&gt;                                 {Div, Math.Divide},&lt;br /&gt;                                 {Mul, Math.Multiply},&lt;br /&gt;                                 {Sqrt, Math.SquareRoot},&lt;br /&gt;                                 {Percent, Math.Percent}&lt;br /&gt;                             };&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        &lt;span class="keyword"&gt;public&lt;/span&gt; &lt;span class="keyword"&gt;string&lt;/span&gt; Calculate(&lt;span class="keyword"&gt;string&lt;/span&gt; formula)&lt;br /&gt;        {&lt;br /&gt;            &lt;span class="keyword"&gt;double&lt;/span&gt; temp;&lt;br /&gt;            &lt;span class="keyword"&gt;if&lt;/span&gt; (&lt;span class="keyword"&gt;double&lt;/span&gt;.TryParse(formula, &lt;span class="keyword"&gt;out&lt;/span&gt; temp))&lt;br /&gt;            {&lt;br /&gt;                &lt;span class="keyword"&gt;return&lt;/span&gt; formula;&lt;br /&gt;            }&lt;br /&gt;            &lt;span class="keyword"&gt;var&lt;/span&gt; values = formula.Split(_keywords, StringSplitOptions.RemoveEmptyEntries);&lt;br /&gt;            &lt;span class="keyword"&gt;if&lt;/span&gt; (values.Length == &lt;span class="number"&gt;0&lt;/span&gt;)&lt;br /&gt;            {&lt;br /&gt;                &lt;span class="keyword"&gt;var&lt;/span&gt; msg = &lt;span class="keyword"&gt;string&lt;/span&gt;.Format(&lt;span class="string"&gt;"No values to be calculated. Values length is zero for formula {0}."&lt;/span&gt;, formula);&lt;br /&gt;                &lt;span class="keyword"&gt;throw&lt;/span&gt; &lt;span class="keyword"&gt;new&lt;/span&gt; UnexpectedCalculationException(msg);&lt;br /&gt;            }&lt;br /&gt;&lt;br /&gt;            &lt;span class="keyword"&gt;var&lt;/span&gt; subPart = formula.TrimStart(values[&lt;span class="number"&gt;0&lt;/span&gt;].ToCharArray());&lt;br /&gt;            &lt;span class="keyword"&gt;var&lt;/span&gt; opCode = _operatorKeywords.FirstOrDefault(subPart.StartsWith);&lt;br /&gt;&lt;br /&gt;            &lt;span class="keyword"&gt;if&lt;/span&gt; (&lt;span class="keyword"&gt;string&lt;/span&gt;.IsNullOrEmpty(opCode))&lt;br /&gt;            {&lt;br /&gt;                &lt;span class="keyword"&gt;var&lt;/span&gt; msg = &lt;span class="keyword"&gt;string&lt;/span&gt;.Format(&lt;span class="string"&gt;"No calculation operator found in formula {0}."&lt;/span&gt;, formula);&lt;br /&gt;                &lt;span class="keyword"&gt;throw&lt;/span&gt; &lt;span class="keyword"&gt;new&lt;/span&gt; UnexpectedCalculationException(msg);&lt;br /&gt;            }&lt;br /&gt;&lt;br /&gt;            Math.MathOperatorHandler mo;&lt;br /&gt;&lt;br /&gt;            &lt;span class="comment"&gt;// this is only possible when there is a %.&lt;/span&gt;&lt;br /&gt;            &lt;span class="keyword"&gt;if&lt;/span&gt; (subPart.EndsWith(Percent))&lt;br /&gt;            {&lt;br /&gt;                &lt;span class="keyword"&gt;if&lt;/span&gt; (!Operators.TryGetValue(Percent, &lt;span class="keyword"&gt;out&lt;/span&gt; mo))&lt;br /&gt;                {&lt;br /&gt;                    &lt;span class="keyword"&gt;var&lt;/span&gt; msg = &lt;span class="keyword"&gt;string&lt;/span&gt;.Format(&lt;span class="string"&gt;"Cannot resolve calculation operator of {0}."&lt;/span&gt;, Percent);&lt;br /&gt;                    &lt;span class="keyword"&gt;throw&lt;/span&gt; &lt;span class="keyword"&gt;new&lt;/span&gt; UnexpectedCalculationException(msg);&lt;br /&gt;                }&lt;br /&gt;                values[values.Length - &lt;span class="number"&gt;1&lt;/span&gt;] = mo(values.Select(item =&amp;gt; &lt;span class="keyword"&gt;double&lt;/span&gt;.Parse(item))).ToString();&lt;br /&gt;            }&lt;br /&gt;&lt;br /&gt;            &lt;span class="keyword"&gt;if&lt;/span&gt; (!Operators.TryGetValue(opCode, &lt;span class="keyword"&gt;out&lt;/span&gt; mo))&lt;br /&gt;            {&lt;br /&gt;                &lt;span class="keyword"&gt;var&lt;/span&gt; msg = &lt;span class="keyword"&gt;string&lt;/span&gt;.Format(&lt;span class="string"&gt;"Cannot resolve calculation operator of {0}."&lt;/span&gt;, opCode);&lt;br /&gt;                &lt;span class="keyword"&gt;throw&lt;/span&gt; &lt;span class="keyword"&gt;new&lt;/span&gt; UnexpectedCalculationException(msg);&lt;br /&gt;            }&lt;br /&gt;            &lt;span class="keyword"&gt;var&lt;/span&gt; valueArray = values.Select(item =&amp;gt; &lt;span class="keyword"&gt;double&lt;/span&gt;.Parse(item));&lt;br /&gt;            &lt;span class="keyword"&gt;var&lt;/span&gt; result = mo(valueArray);&lt;br /&gt;            &lt;span class="keyword"&gt;return&lt;/span&gt; result.ToString();&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;}&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;But what is more interesting is at the supporting class below: -&lt;br /&gt;&lt;pre&gt;&lt;code class="cs"&gt;    &lt;span class="keyword"&gt;internal&lt;/span&gt; &lt;span class="keyword"&gt;static&lt;/span&gt; &lt;span class="keyword"&gt;class&lt;/span&gt; Math&lt;br /&gt;    {&lt;br /&gt;        &lt;span class="keyword"&gt;private&lt;/span&gt; &lt;span class="keyword"&gt;delegate&lt;/span&gt; T TryExecuteHandler&amp;lt;&lt;span class="keyword"&gt;out&lt;/span&gt; T&amp;gt;();&lt;br /&gt;&lt;br /&gt;        &lt;span class="keyword"&gt;internal&lt;/span&gt; &lt;span class="keyword"&gt;delegate&lt;/span&gt; &lt;span class="keyword"&gt;double&lt;/span&gt; MathOperatorHandler(IEnumerable&amp;lt;&lt;span class="keyword"&gt;double&lt;/span&gt;&amp;gt; values);&lt;br /&gt;&lt;br /&gt;        &lt;span class="keyword"&gt;private&lt;/span&gt; &lt;span class="keyword"&gt;static&lt;/span&gt; &lt;span class="keyword"&gt;double&lt;/span&gt; Handle(TryExecuteHandler&amp;lt;&lt;span class="keyword"&gt;double&lt;/span&gt;&amp;gt; handler)&lt;br /&gt;        {&lt;br /&gt;            &lt;span class="keyword"&gt;try&lt;/span&gt;&lt;br /&gt;            {&lt;br /&gt;                &lt;span class="keyword"&gt;return&lt;/span&gt; handler();&lt;br /&gt;            }&lt;br /&gt;            &lt;span class="keyword"&gt;catch&lt;/span&gt;(FormatException e)&lt;br /&gt;            {&lt;br /&gt;                &lt;span class="keyword"&gt;throw&lt;/span&gt; &lt;span class="keyword"&gt;new&lt;/span&gt; IncompatibleDataTypeFormulaException(&lt;span class="string"&gt;"Unexpected data format."&lt;/span&gt;, e);&lt;br /&gt;            }&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        &lt;span class="keyword"&gt;internal&lt;/span&gt; &lt;span class="keyword"&gt;static&lt;/span&gt; &lt;span class="keyword"&gt;double&lt;/span&gt; Add(IEnumerable&amp;lt;&lt;span class="keyword"&gt;double&lt;/span&gt;&amp;gt; values)&lt;br /&gt;        {&lt;br /&gt;            &lt;span class="keyword"&gt;return&lt;/span&gt; Handle(() =&amp;gt; values.Sum());&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        &lt;span class="keyword"&gt;internal&lt;/span&gt; &lt;span class="keyword"&gt;static&lt;/span&gt; &lt;span class="keyword"&gt;double&lt;/span&gt; Subtract(IEnumerable&amp;lt;&lt;span class="keyword"&gt;double&lt;/span&gt;&amp;gt; values)&lt;br /&gt;        {&lt;br /&gt;            &lt;span class="keyword"&gt;return&lt;/span&gt; Handle(() =&amp;gt;&lt;br /&gt;                              {&lt;br /&gt;                                  &lt;span class="keyword"&gt;var&lt;/span&gt; valueArray = values.ToArray();&lt;br /&gt;                                  &lt;span class="keyword"&gt;var&lt;/span&gt; result = valueArray[&lt;span class="number"&gt;0&lt;/span&gt;];&lt;br /&gt;                                  &lt;span class="keyword"&gt;for&lt;/span&gt; (&lt;span class="keyword"&gt;var&lt;/span&gt; i = &lt;span class="number"&gt;1&lt;/span&gt;; i &amp;lt; valueArray.Length; i++)&lt;br /&gt;                                  {&lt;br /&gt;                                      result -= valueArray[i];&lt;br /&gt;                                  }&lt;br /&gt;                                  &lt;span class="keyword"&gt;return&lt;/span&gt; result;&lt;br /&gt;                              });&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        &lt;span class="keyword"&gt;internal&lt;/span&gt; &lt;span class="keyword"&gt;static&lt;/span&gt; &lt;span class="keyword"&gt;double&lt;/span&gt; Multiply(IEnumerable&amp;lt;&lt;span class="keyword"&gt;double&lt;/span&gt;&amp;gt; values)&lt;br /&gt;        {&lt;br /&gt;            &lt;span class="keyword"&gt;return&lt;/span&gt; Handle(() =&amp;gt;&lt;br /&gt;                              {&lt;br /&gt;                                  &lt;span class="keyword"&gt;var&lt;/span&gt; valueArray = values.ToArray();&lt;br /&gt;                                  &lt;span class="keyword"&gt;var&lt;/span&gt; result = valueArray[&lt;span class="number"&gt;0&lt;/span&gt;];&lt;br /&gt;                                  &lt;span class="keyword"&gt;for&lt;/span&gt; (&lt;span class="keyword"&gt;var&lt;/span&gt; i = &lt;span class="number"&gt;1&lt;/span&gt;; i &amp;lt; valueArray.Length; i++)&lt;br /&gt;                                  {&lt;br /&gt;                                      result *= valueArray[i];&lt;br /&gt;                                  }&lt;br /&gt;                                  &lt;span class="keyword"&gt;return&lt;/span&gt; result;&lt;br /&gt;                              });&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        &lt;span class="keyword"&gt;internal&lt;/span&gt; &lt;span class="keyword"&gt;static&lt;/span&gt; &lt;span class="keyword"&gt;double&lt;/span&gt; Divide(IEnumerable&amp;lt;&lt;span class="keyword"&gt;double&lt;/span&gt;&amp;gt; values)&lt;br /&gt;        {&lt;br /&gt;            &lt;span class="keyword"&gt;return&lt;/span&gt; Handle(() =&amp;gt;&lt;br /&gt;                              {&lt;br /&gt;                                  &lt;span class="keyword"&gt;var&lt;/span&gt; valueArray = values.ToArray();&lt;br /&gt;                                  &lt;span class="keyword"&gt;var&lt;/span&gt; result = valueArray[&lt;span class="number"&gt;0&lt;/span&gt;];&lt;br /&gt;                                  &lt;span class="keyword"&gt;for&lt;/span&gt; (&lt;span class="keyword"&gt;var&lt;/span&gt; i = &lt;span class="number"&gt;1&lt;/span&gt;; i &amp;lt; valueArray.Length; i++)&lt;br /&gt;                                  {&lt;br /&gt;                                      result /= valueArray[i];&lt;br /&gt;                                  }&lt;br /&gt;                                  &lt;span class="keyword"&gt;return&lt;/span&gt; result;&lt;br /&gt;                              });&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        &lt;span class="keyword"&gt;internal&lt;/span&gt; &lt;span class="keyword"&gt;static&lt;/span&gt; &lt;span class="keyword"&gt;double&lt;/span&gt; SquareRoot(IEnumerable&amp;lt;&lt;span class="keyword"&gt;double&lt;/span&gt;&amp;gt; values)&lt;br /&gt;        {&lt;br /&gt;            &lt;span class="keyword"&gt;return&lt;/span&gt; Handle(() =&amp;gt;&lt;br /&gt;                              {&lt;br /&gt;&lt;br /&gt;                                  &lt;span class="keyword"&gt;var&lt;/span&gt; valueArray = values.ToArray();&lt;br /&gt;                                  &lt;span class="keyword"&gt;if&lt;/span&gt; (valueArray.Length &amp;gt; &lt;span class="number"&gt;1&lt;/span&gt;)&lt;br /&gt;                                  {&lt;br /&gt;                                      &lt;span class="keyword"&gt;var&lt;/span&gt; msg = &lt;span class="keyword"&gt;string&lt;/span&gt;.Format(&lt;span class="string"&gt;"Expect valueArray of length 1 but was {0}."&lt;/span&gt;, valueArray.Length);&lt;br /&gt;                                      &lt;span class="keyword"&gt;throw&lt;/span&gt; &lt;span class="keyword"&gt;new&lt;/span&gt; UnexpectedCalculationException(msg);&lt;br /&gt;                                  }&lt;br /&gt;&lt;br /&gt;                                  &lt;span class="keyword"&gt;return&lt;/span&gt; System.Math.Sqrt(valueArray[&lt;span class="number"&gt;0&lt;/span&gt;]);&lt;br /&gt;                              });&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        &lt;span class="keyword"&gt;internal&lt;/span&gt; &lt;span class="keyword"&gt;static&lt;/span&gt; &lt;span class="keyword"&gt;double&lt;/span&gt; Pow(IEnumerable&amp;lt;&lt;span class="keyword"&gt;double&lt;/span&gt;&amp;gt; values)&lt;br /&gt;        {&lt;br /&gt;            &lt;span class="keyword"&gt;return&lt;/span&gt; Handle(() =&amp;gt;&lt;br /&gt;                              {&lt;br /&gt;                                  &lt;span class="keyword"&gt;var&lt;/span&gt; valueArray = values.ToArray();&lt;br /&gt;                                  &lt;span class="keyword"&gt;var&lt;/span&gt; result = valueArray[&lt;span class="number"&gt;0&lt;/span&gt;];&lt;br /&gt;                                  &lt;span class="keyword"&gt;for&lt;/span&gt; (&lt;span class="keyword"&gt;var&lt;/span&gt; i = &lt;span class="number"&gt;1&lt;/span&gt;; i &amp;lt; valueArray.Length; i++)&lt;br /&gt;                                  {&lt;br /&gt;                                      result = System.Math.Pow(result, valueArray[i]);&lt;br /&gt;                                  }&lt;br /&gt;                                  &lt;span class="keyword"&gt;return&lt;/span&gt; result;&lt;br /&gt;                              });&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        &lt;span class="keyword"&gt;internal&lt;/span&gt; &lt;span class="keyword"&gt;static&lt;/span&gt; &lt;span class="keyword"&gt;double&lt;/span&gt; Reciproc(IEnumerable&amp;lt;&lt;span class="keyword"&gt;double&lt;/span&gt;&amp;gt; values)&lt;br /&gt;        {&lt;br /&gt;            &lt;span class="keyword"&gt;return&lt;/span&gt; Handle(() =&amp;gt;&lt;br /&gt;                              {&lt;br /&gt;                                  &lt;span class="keyword"&gt;var&lt;/span&gt; valueArray = values.ToArray();&lt;br /&gt;                                  &lt;span class="keyword"&gt;if&lt;/span&gt; (valueArray.Length &amp;gt; &lt;span class="number"&gt;1&lt;/span&gt;)&lt;br /&gt;                                  {&lt;br /&gt;                                      &lt;span class="keyword"&gt;var&lt;/span&gt; msg = &lt;span class="keyword"&gt;string&lt;/span&gt;.Format(&lt;span class="string"&gt;"Expect valueArray of length 1 but was {0}."&lt;/span&gt;, valueArray.Length);&lt;br /&gt;                                      &lt;span class="keyword"&gt;throw&lt;/span&gt; &lt;span class="keyword"&gt;new&lt;/span&gt; UnexpectedCalculationException(msg);&lt;br /&gt;                                  }&lt;br /&gt;&lt;br /&gt;                                  &lt;span class="keyword"&gt;return&lt;/span&gt; &lt;span class="number"&gt;1&lt;/span&gt;/valueArray[&lt;span class="number"&gt;0&lt;/span&gt;];&lt;br /&gt;                              });&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        &lt;span class="keyword"&gt;internal&lt;/span&gt; &lt;span class="keyword"&gt;static&lt;/span&gt; &lt;span class="keyword"&gt;double&lt;/span&gt; Percent(IEnumerable&amp;lt;&lt;span class="keyword"&gt;double&lt;/span&gt;&amp;gt; values)&lt;br /&gt;        {&lt;br /&gt;            &lt;span class="keyword"&gt;return&lt;/span&gt; Handle(() =&amp;gt;&lt;br /&gt;                              {&lt;br /&gt;                                  &lt;span class="keyword"&gt;var&lt;/span&gt; valueArray = values.ToArray();&lt;br /&gt;                                  &lt;span class="keyword"&gt;if&lt;/span&gt; (valueArray.Length != &lt;span class="number"&gt;2&lt;/span&gt;)&lt;br /&gt;                                  {&lt;br /&gt;                                      &lt;span class="keyword"&gt;var&lt;/span&gt; msg = &lt;span class="keyword"&gt;string&lt;/span&gt;.Format(&lt;span class="string"&gt;"Expect valueArray of length 2 but was {0}."&lt;/span&gt;, valueArray.Length);&lt;br /&gt;                                      &lt;span class="keyword"&gt;throw&lt;/span&gt; &lt;span class="keyword"&gt;new&lt;/span&gt; UnexpectedCalculationException(msg);&lt;br /&gt;                                  }&lt;br /&gt;                                  &lt;span class="keyword"&gt;return&lt;/span&gt; valueArray[&lt;span class="number"&gt;0&lt;/span&gt;]*valueArray[&lt;span class="number"&gt;1&lt;/span&gt;]/&lt;span class="number"&gt;100&lt;/span&gt;;&lt;br /&gt;                              });&lt;br /&gt;        }&lt;br /&gt;    }&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;In the unit tests, we expected two different kinds of exceptions as such: -&lt;br /&gt;&lt;pre&gt;&lt;code class="cs"&gt;    [Serializable]&lt;br /&gt;    &lt;span class="keyword"&gt;public&lt;/span&gt; &lt;span class="keyword"&gt;class&lt;/span&gt; IncompatibleDataTypeFormulaException : Exception&lt;br /&gt;    {&lt;br /&gt;        &lt;span class="keyword"&gt;public&lt;/span&gt; IncompatibleDataTypeFormulaException(&lt;span class="keyword"&gt;string&lt;/span&gt; message, Exception innerException)&lt;br /&gt;            :&lt;span class="keyword"&gt;base&lt;/span&gt;(message, innerException)&lt;br /&gt;        {&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    &lt;span class="comment"&gt;&lt;span class="xmlDocTag"&gt;///&lt;/span&gt; &lt;span class="xmlDocTag"&gt;&amp;lt;summary&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class="comment"&gt;&lt;span class="xmlDocTag"&gt;///&lt;/span&gt; &lt;span class="xmlDocTag"&gt;&amp;lt;see cref="UnexpectedCalculationException"/&amp;gt;&lt;/span&gt; - Exception indicates that there were some unexpected internal calculation error.&lt;/span&gt;&lt;br /&gt;    &lt;span class="comment"&gt;&lt;span class="xmlDocTag"&gt;///&lt;/span&gt; &lt;span class="xmlDocTag"&gt;&amp;lt;/summary&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;    [Serializable]&lt;br /&gt;    &lt;span class="keyword"&gt;public&lt;/span&gt; &lt;span class="keyword"&gt;class&lt;/span&gt; UnexpectedCalculationException:ApplicationException&lt;br /&gt;    {&lt;br /&gt;        &lt;span class="keyword"&gt;public&lt;/span&gt; UnexpectedCalculationException(&lt;span class="keyword"&gt;string&lt;/span&gt; message)&lt;br /&gt;            :&lt;span class="keyword"&gt;base&lt;/span&gt;(message)&lt;br /&gt;        {&lt;br /&gt;        }&lt;br /&gt;    }&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;Now that I don't want to make the case complicated by implementing a FormulaParser and FormulaToken all that sorts just for a simple calculator, I opted for the static class implementation named Math. This supporting class is never in my mind that will be shared. It is my internal calculation logic that is for abstraction. It has very high chances that I want improve it in the future. &lt;br /&gt;&lt;br /&gt;&lt;b&gt;This class should never be unit tested.&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;If you do, you will quickly find you do owe yourself for a blame. Unit testing your abstraction logic will pressurize on your responsibility of maintaining highest potential to change API, process workflow, class design and etc. You ended do a lot of work and then undone many work that you were spending day and night maintaining it.&lt;br /&gt;&lt;br /&gt;Best practice of TDD said, let those highly changeable code (abstraction logic) automatically covered by just unit testing your public API. If it was not covered automatically, you have written unplanned code and that is the risk for defects or bugs. You will be helped by the coverage to uncover the statistic for this area of risk to you.&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://3.bp.blogspot.com/_DSopvqyYd9M/TKDrw0fePlI/AAAAAAAAABI/akBNBlRuyCQ/s1600/Calculator.Core.Tests.Coverage.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img style="cursor: pointer; width: 320px; height: 173px;" border="0" src="http://3.bp.blogspot.com/_DSopvqyYd9M/TKDrw0fePlI/AAAAAAAAABI/akBNBlRuyCQ/s1600/Calculator.Core.Tests.Coverage.jpg" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://2.bp.blogspot.com/_DSopvqyYd9M/TKDrzWjUe5I/AAAAAAAAABM/MYFnJut1Knc/s1600/Calculator.Tests.Coverage.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img style="cursor: pointer; width: 320px; height: 173px;" border="0" src="http://2.bp.blogspot.com/_DSopvqyYd9M/TKDrzWjUe5I/AAAAAAAAABM/MYFnJut1Knc/s1600/Calculator.Tests.Coverage.jpg" /&gt;&lt;/a&gt;&lt;/div&gt;Note: The only place that is not well-tested is at UI.&lt;br /&gt;&lt;br /&gt;Next, look at the abstraction logic again, there is a pattern of repeatedly throwing exception is needed for most of the function like Add, Divide, Multiply etc, this just comes naturally that I will need some aspect oriented programming for exception handling in this function. Hey, now I need to use AOP design patterns with Code Injection facility.&lt;br /&gt;&lt;br /&gt;This is awesomely beautiful isn't it, doing it TDD?&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6458135603295822938-9178602161395110182?l=synersov.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://synersov.blogspot.com/feeds/9178602161395110182/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://synersov.blogspot.com/2010/09/test-driven-approach-positive-impact_9772.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6458135603295822938/posts/default/9178602161395110182'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6458135603295822938/posts/default/9178602161395110182'/><link rel='alternate' type='text/html' href='http://synersov.blogspot.com/2010/09/test-driven-approach-positive-impact_9772.html' title='Test Driven Approach - Positive Impact for Developers - Workshop IV'/><author><name>aahkam</name><uri>http://www.blogger.com/profile/11579245596035586334</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/_DSopvqyYd9M/TKDrw0fePlI/AAAAAAAAABI/akBNBlRuyCQ/s72-c/Calculator.Core.Tests.Coverage.jpg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6458135603295822938.post-3489018474771619173</id><published>2010-09-27T11:09:00.000-07:00</published><updated>2010-09-27T11:13:14.190-07:00</updated><title type='text'>Test Driven Approach - Positive Impact for Developers - Workshop III (Part  B)</title><content type='html'>Now, lets us try to compile and run the test again. As expected, it won't compile at all. We need refactoring to the unit tests at Calculator.Tests as such: -&lt;br /&gt;&lt;pre&gt;&lt;code class="cs"&gt;&lt;span class="keyword"&gt;using&lt;/span&gt; Calculator.Core;&lt;br /&gt;&lt;span class="keyword"&gt;using&lt;/span&gt; Calculator.Presenter;&lt;br /&gt;&lt;span class="keyword"&gt;using&lt;/span&gt; NUnit.Framework;&lt;br /&gt;&lt;br /&gt;&lt;span class="keyword"&gt;namespace&lt;/span&gt; Calculator.Tests&lt;br /&gt;{&lt;br /&gt;    &lt;span class="keyword"&gt;public&lt;/span&gt; &lt;span class="keyword"&gt;class&lt;/span&gt; CalculatorMockView : ICalculatorView&lt;br /&gt;    {&lt;br /&gt;        &lt;span class="keyword"&gt;public&lt;/span&gt; &lt;span class="keyword"&gt;string&lt;/span&gt; Result { &lt;span class="keyword"&gt;get&lt;/span&gt;; &lt;span class="keyword"&gt;set&lt;/span&gt;; }&lt;br /&gt;        &lt;span class="keyword"&gt;public&lt;/span&gt; &lt;span class="keyword"&gt;string&lt;/span&gt; Formula { &lt;span class="keyword"&gt;get&lt;/span&gt;; &lt;span class="keyword"&gt;set&lt;/span&gt;; }&lt;br /&gt;    }&lt;br /&gt;    &lt;br /&gt;    [TestFixture]&lt;br /&gt;    &lt;span class="keyword"&gt;public&lt;/span&gt; &lt;span class="keyword"&gt;class&lt;/span&gt; CalculatorTester&lt;br /&gt;    {&lt;br /&gt;        &lt;span class="keyword"&gt;private&lt;/span&gt; Presenter.Calculator _calculator;&lt;br /&gt;        &lt;span class="keyword"&gt;private&lt;/span&gt; ICalculatorView _view;&lt;br /&gt;&lt;br /&gt;        [SetUp]&lt;br /&gt;        &lt;span class="keyword"&gt;public&lt;/span&gt; &lt;span class="keyword"&gt;void&lt;/span&gt; SetUp()&lt;br /&gt;        {&lt;br /&gt;            _view = &lt;span class="keyword"&gt;new&lt;/span&gt; CalculatorMockView();&lt;br /&gt;            _calculator = &lt;span class="keyword"&gt;new&lt;/span&gt; Presenter.Calculator(_view);&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        [TestCase(&lt;span class="string"&gt;"6"&lt;/span&gt;, &lt;span class="string"&gt;"6"&lt;/span&gt;)]&lt;br /&gt;        [TestCase(&lt;span class="string"&gt;"5 + 6"&lt;/span&gt;, &lt;span class="string"&gt;"11"&lt;/span&gt;)]&lt;br /&gt;        [TestCase(&lt;span class="string"&gt;"3 - 2"&lt;/span&gt;, &lt;span class="string"&gt;"1"&lt;/span&gt; )]&lt;br /&gt;        [TestCase(&lt;span class="string"&gt;"5 * 6"&lt;/span&gt;, &lt;span class="string"&gt;"30"&lt;/span&gt;)]&lt;br /&gt;        [TestCase(&lt;span class="string"&gt;"12 / 6"&lt;/span&gt;, &lt;span class="string"&gt;"2"&lt;/span&gt;)]&lt;br /&gt;        [TestCase(&lt;span class="string"&gt;"5 + 6%"&lt;/span&gt;, &lt;span class="string"&gt;"5.3"&lt;/span&gt;)]&lt;br /&gt;        [TestCase(&lt;span class="string"&gt;"reciproc(2)"&lt;/span&gt;, &lt;span class="string"&gt;"0.5"&lt;/span&gt;)]&lt;br /&gt;        [TestCase(&lt;span class="string"&gt;"pow(2,3)"&lt;/span&gt;, &lt;span class="string"&gt;"8"&lt;/span&gt;)]&lt;br /&gt;        [TestCase(&lt;span class="string"&gt;"sqrt(4)"&lt;/span&gt;, &lt;span class="string"&gt;"2"&lt;/span&gt;)]&lt;br /&gt;        [TestCase(&lt;span class="string"&gt;"12 / 6 / 8"&lt;/span&gt;, &lt;span class="string"&gt;"0.25"&lt;/span&gt;)]&lt;br /&gt;        [TestCase(&lt;span class="string"&gt;"reciproc(2,3,2)"&lt;/span&gt;, &lt;span class="string"&gt;""&lt;/span&gt;, ExpectedException = &lt;span class="keyword"&gt;typeof&lt;/span&gt;(UnexpectedCalculationException))]&lt;br /&gt;        [TestCase(&lt;span class="string"&gt;"sqrt(4, 21)"&lt;/span&gt;, &lt;span class="string"&gt;""&lt;/span&gt;, ExpectedException = &lt;span class="keyword"&gt;typeof&lt;/span&gt;(UnexpectedCalculationException))]&lt;br /&gt;        [TestCase(&lt;span class="string"&gt;"A + B + C"&lt;/span&gt;, &lt;span class="string"&gt;""&lt;/span&gt;, ExpectedException = &lt;span class="keyword"&gt;typeof&lt;/span&gt;(IncompatibleDataTypeFormulaException))]&lt;br /&gt;        [TestCase(&lt;span class="string"&gt;"HelloWorld(2,3,2)"&lt;/span&gt;, &lt;span class="string"&gt;""&lt;/span&gt;, ExpectedException = &lt;span class="keyword"&gt;typeof&lt;/span&gt;(UnexpectedCalculationException))]&lt;br /&gt;        [TestCase(&lt;span class="string"&gt;"2 3 2"&lt;/span&gt;, &lt;span class="string"&gt;""&lt;/span&gt;, ExpectedException = &lt;span class="keyword"&gt;typeof&lt;/span&gt;(UnexpectedCalculationException))]&lt;br /&gt;        &lt;span class="keyword"&gt;public&lt;/span&gt; &lt;span class="keyword"&gt;void&lt;/span&gt; EvaluationTest(&lt;span class="keyword"&gt;string&lt;/span&gt; formula, &lt;span class="keyword"&gt;string&lt;/span&gt; expected)&lt;br /&gt;        {&lt;br /&gt;            _view.Formula = formula;&lt;br /&gt;            _calculator.Evaluate();&lt;br /&gt;            Assert.AreEqual(_view.Result, expected);&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;And Calculator.Core.Tests as such: -&lt;br /&gt;&lt;pre&gt;&lt;code class="cs"&gt;&lt;span class="keyword"&gt;using&lt;/span&gt; NUnit.Framework;&lt;br /&gt;&lt;br /&gt;&lt;span class="keyword"&gt;namespace&lt;/span&gt; Calculator.Core.Tests&lt;br /&gt;{&lt;br /&gt;    [TestFixture]&lt;br /&gt;    &lt;span class="keyword"&gt;public&lt;/span&gt; &lt;span class="keyword"&gt;class&lt;/span&gt; CalculatorTests&lt;br /&gt;    {&lt;br /&gt;        &lt;span class="keyword"&gt;readonly&lt;/span&gt; Calculator _calculator = &lt;span class="keyword"&gt;new&lt;/span&gt; Calculator();&lt;br /&gt;&lt;br /&gt;        [TestCase(&lt;span class="string"&gt;"6"&lt;/span&gt;, &lt;span class="string"&gt;"6"&lt;/span&gt;)]&lt;br /&gt;        [TestCase(&lt;span class="string"&gt;"5 + 6"&lt;/span&gt;, &lt;span class="string"&gt;"11"&lt;/span&gt;)]&lt;br /&gt;        [TestCase(&lt;span class="string"&gt;"3 - 2"&lt;/span&gt;, &lt;span class="string"&gt;"1"&lt;/span&gt;)]&lt;br /&gt;        [TestCase(&lt;span class="string"&gt;"5 * 6"&lt;/span&gt;, &lt;span class="string"&gt;"30"&lt;/span&gt;)]&lt;br /&gt;        [TestCase(&lt;span class="string"&gt;"12 / 6"&lt;/span&gt;, &lt;span class="string"&gt;"2"&lt;/span&gt;)]&lt;br /&gt;        [TestCase(&lt;span class="string"&gt;"5 + 6%"&lt;/span&gt;, &lt;span class="string"&gt;"5.3"&lt;/span&gt;)]&lt;br /&gt;        [TestCase(&lt;span class="string"&gt;"reciproc(2)"&lt;/span&gt;, &lt;span class="string"&gt;"0.5"&lt;/span&gt;)]&lt;br /&gt;        [TestCase(&lt;span class="string"&gt;"pow(2,3)"&lt;/span&gt;, &lt;span class="string"&gt;"8"&lt;/span&gt;)]&lt;br /&gt;        [TestCase(&lt;span class="string"&gt;"sqrt(4)"&lt;/span&gt;, &lt;span class="string"&gt;"2"&lt;/span&gt;)]&lt;br /&gt;        [TestCase(&lt;span class="string"&gt;"12 / 6 / 8"&lt;/span&gt;, &lt;span class="string"&gt;"0.25"&lt;/span&gt;)]&lt;br /&gt;        [TestCase(&lt;span class="string"&gt;"reciproc(2,3,2)"&lt;/span&gt;, &lt;span class="string"&gt;""&lt;/span&gt;, ExpectedException = &lt;span class="keyword"&gt;typeof&lt;/span&gt;(UnexpectedCalculationException))]&lt;br /&gt;        [TestCase(&lt;span class="string"&gt;"sqrt(4, 21)"&lt;/span&gt;, &lt;span class="string"&gt;""&lt;/span&gt;, ExpectedException = &lt;span class="keyword"&gt;typeof&lt;/span&gt;(UnexpectedCalculationException))]&lt;br /&gt;        [TestCase(&lt;span class="string"&gt;"A + B + C"&lt;/span&gt;, &lt;span class="string"&gt;""&lt;/span&gt;, ExpectedException = &lt;span class="keyword"&gt;typeof&lt;/span&gt;(IncompatibleDataTypeFormulaException))]&lt;br /&gt;        [TestCase(&lt;span class="string"&gt;"HelloWorld(2,3,2)"&lt;/span&gt;, &lt;span class="string"&gt;""&lt;/span&gt;, ExpectedException = &lt;span class="keyword"&gt;typeof&lt;/span&gt;(UnexpectedCalculationException))]&lt;br /&gt;        [TestCase(&lt;span class="string"&gt;"2 3 2"&lt;/span&gt;, &lt;span class="string"&gt;""&lt;/span&gt;, ExpectedException = &lt;span class="keyword"&gt;typeof&lt;/span&gt;(UnexpectedCalculationException))]&lt;br /&gt;        &lt;span class="keyword"&gt;public&lt;/span&gt; &lt;span class="keyword"&gt;void&lt;/span&gt; EvaluationTest(&lt;span class="keyword"&gt;string&lt;/span&gt; formula, &lt;span class="keyword"&gt;string&lt;/span&gt; expected)&lt;br /&gt;        {&lt;br /&gt;            Assert.AreEqual(expected, _calculator.Calculate(formula));&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;Above, I have also added a few additional test cases where necessary. Now lets us compile and test run them. As expected, they are still failed.&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://2.bp.blogspot.com/_DSopvqyYd9M/TKDahM3PgnI/AAAAAAAAABA/SPq3Wu5gVBo/s1600/Calculator.Tests.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img style="cursor: pointer; width: 320px; height: 173px;" border="0" src="http://2.bp.blogspot.com/_DSopvqyYd9M/TKDahM3PgnI/AAAAAAAAABA/SPq3Wu5gVBo/s1600/Calculator.Tests.jpg" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://2.bp.blogspot.com/_DSopvqyYd9M/TKDak_L8BNI/AAAAAAAAABE/8Gv4LzM5-5c/s1600/Calculator.Core.Tests.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img style="cursor: pointer; width: 320px; height: 173px;" border="0" src="http://2.bp.blogspot.com/_DSopvqyYd9M/TKDak_L8BNI/AAAAAAAAABE/8Gv4LzM5-5c/s1600/Calculator.Core.Tests.jpg" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;Before we proceed, to correct all these tests, let us revisit what have we done so far?&lt;br /&gt;1. We created solution based on some (small) fundamental architecture design.&lt;br /&gt;2. We created a wire frame demonstrated how this look like conceptually.&lt;br /&gt;3. We then created some unit tests focuses on "how we think the public API would be useful and clean". (API Usability Concern from consumer perspective.)&lt;br /&gt;4. We introduce new projects (core) to ensure we provide better separation of business core logic. (Separation of Concern and Single Responsibility)&lt;br /&gt;5. We then decide again how is the public API of the new project just added would look like. (API Usability again)&lt;br /&gt;6. We implemented the presenter logic, wire up the UI wire frame, and the Core logic classes. (some UI design patterns were introduced for unit tests and better code separation).&lt;br /&gt;7. We refactor the some API within its implementation and its corresponding unit testings in Calculator.Tests and Calculator.Core.Tests. (Refactoring based on needs).&lt;br /&gt;&lt;br /&gt;Now, all the above just came naturally as we do our development in TDD fashion.&lt;br /&gt;&lt;br /&gt;So, the next workshop, we will be aiming to clear all these unit tests.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6458135603295822938-3489018474771619173?l=synersov.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://synersov.blogspot.com/feeds/3489018474771619173/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://synersov.blogspot.com/2010/09/test-driven-approach-positive-impact_1367.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6458135603295822938/posts/default/3489018474771619173'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6458135603295822938/posts/default/3489018474771619173'/><link rel='alternate' type='text/html' href='http://synersov.blogspot.com/2010/09/test-driven-approach-positive-impact_1367.html' title='Test Driven Approach - Positive Impact for Developers - Workshop III (Part  B)'/><author><name>aahkam</name><uri>http://www.blogger.com/profile/11579245596035586334</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/_DSopvqyYd9M/TKDahM3PgnI/AAAAAAAAABA/SPq3Wu5gVBo/s72-c/Calculator.Tests.jpg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6458135603295822938.post-6891974654050649417</id><published>2010-09-27T10:44:00.000-07:00</published><updated>2010-09-27T10:44:34.357-07:00</updated><title type='text'>Test Driven Approach - Positive Impact for Developers - Workshop III (Part A)</title><content type='html'>Quickly, we are now at 3rd session. Before we start, I would like to cover a bit on the missing architecture detail. This small application will be (hopefully) tailored into 3 layers design. UI, Core Logic, Data Access (if any). It is not that the requirements asking for so, it is simply some thought to have clear separation such that each component can be more tidy up with better cut of responsibility. Also, I hope I will have an opportunity in the future to bring this example into some further discussion on Scaling Out and Services Oriented fashion.&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/_DSopvqyYd9M/TKDUftBwzyI/AAAAAAAAAA8/v9-_cG_Tb7U/s1600/Solution+Explorer.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://2.bp.blogspot.com/_DSopvqyYd9M/TKDUftBwzyI/AAAAAAAAAA8/v9-_cG_Tb7U/s1600/Solution+Explorer.jpg" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;We have not create any data access layer assembly, but because we created a new assembly, "Core", hence a new Unit Test project for Core project is needed.&lt;br /&gt;&lt;br /&gt;Enough said, now lets focus on the assignment. In reality, the calculator will be very unlikely to perform the calculation of such formula at once, "5 + 5% * 50 / 2 + pow(2,3)". Soon as you type in "5 + 5%", the calculator has already responded with the result. (Please verify with Windows Calculator). So, we will probably not cover this within this series of workshop.&lt;br /&gt;&lt;br /&gt;Question: Where do we start coding to pass the test?&lt;br /&gt;Answer: Let's start with the UI.&lt;br /&gt;&lt;br /&gt;Question: How do we test the code in the UI?&lt;br /&gt;Answer: We need a presenter or controller logic.&lt;br /&gt;&lt;br /&gt;Calculator Presenter class develop as such: -&lt;br /&gt;&lt;pre&gt;&lt;code class="cs"&gt;&lt;span class="keyword"&gt;using&lt;/span&gt; System;&lt;br /&gt;&lt;span class="keyword"&gt;using&lt;/span&gt; System.Text;&lt;br /&gt;&lt;br /&gt;&lt;span class="keyword"&gt;namespace&lt;/span&gt; Calculator.Presenter&lt;br /&gt;{&lt;br /&gt;    &lt;span class="keyword"&gt;public&lt;/span&gt; &lt;span class="keyword"&gt;class&lt;/span&gt; Calculator&lt;br /&gt;    {&lt;br /&gt;        &lt;span class="keyword"&gt;private&lt;/span&gt; &lt;span class="keyword"&gt;readonly&lt;/span&gt; ICalculatorView _view;&lt;br /&gt;        &lt;span class="keyword"&gt;private&lt;/span&gt; &lt;span class="keyword"&gt;readonly&lt;/span&gt; Core.Calculator _calculatorCore;&lt;br /&gt;&lt;br /&gt;        &lt;span class="keyword"&gt;public&lt;/span&gt; Calculator(ICalculatorView view)&lt;br /&gt;        {&lt;br /&gt;            _view = view;&lt;br /&gt;            _calculatorCore = &lt;span class="keyword"&gt;new&lt;/span&gt; Core.Calculator();&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        &lt;span class="keyword"&gt;public&lt;/span&gt; &lt;span class="keyword"&gt;void&lt;/span&gt; Evaluate()&lt;br /&gt;        {&lt;br /&gt;            _view.Result = _calculatorCore.Calculate(_view.Formula);&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    &lt;span class="keyword"&gt;public&lt;/span&gt; &lt;span class="keyword"&gt;interface&lt;/span&gt; ICalculatorView&lt;br /&gt;    {&lt;br /&gt;        &lt;span class="keyword"&gt;string&lt;/span&gt; Result { &lt;span class="keyword"&gt;get&lt;/span&gt;; &lt;span class="keyword"&gt;set&lt;/span&gt;; }&lt;br /&gt;        &lt;span class="keyword"&gt;string&lt;/span&gt; Formula { &lt;span class="keyword"&gt;get&lt;/span&gt;; &lt;span class="keyword"&gt;set&lt;/span&gt;; }&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;This will need an additional Calculator class within the Core assembly as such: -&lt;br /&gt;&lt;pre&gt;&lt;code class="cs"&gt;    &lt;span class="keyword"&gt;public&lt;/span&gt; &lt;span class="keyword"&gt;class&lt;/span&gt; Calculator&lt;br /&gt;    {&lt;br /&gt;        &lt;span class="keyword"&gt;public&lt;/span&gt; &lt;span class="keyword"&gt;string&lt;/span&gt; Calculate(&lt;span class="keyword"&gt;string&lt;/span&gt; formula)&lt;br /&gt;        {&lt;br /&gt;            &lt;span class="keyword"&gt;throw&lt;/span&gt; &lt;span class="keyword"&gt;new&lt;/span&gt; NotImplementedException();&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;Now we sort of have everything (API) within this application that needs public access modifier done. We need to ensure the new public API sits under the Core project is unit tested as well. In this case, it is very similar to the earlier unit test created in Workshop II.&lt;br /&gt;&lt;br /&gt;Next, we focus on how to wire up the UI into the presenter logic. This is what generated by VS 2010.&lt;br /&gt;&lt;pre&gt;&lt;code class="cs"&gt;&lt;span class="keyword"&gt;namespace&lt;/span&gt; Calculator&lt;br /&gt;{&lt;br /&gt;    &lt;span class="keyword"&gt;static&lt;/span&gt; &lt;span class="keyword"&gt;class&lt;/span&gt; Program&lt;br /&gt;    {&lt;br /&gt;        &lt;span class="comment"&gt;&lt;span class="xmlDocTag"&gt;///&lt;/span&gt; &lt;span class="xmlDocTag"&gt;&amp;lt;summary&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;        &lt;span class="comment"&gt;&lt;span class="xmlDocTag"&gt;///&lt;/span&gt; The main entry point for the application.&lt;/span&gt;&lt;br /&gt;        &lt;span class="comment"&gt;&lt;span class="xmlDocTag"&gt;///&lt;/span&gt; &lt;span class="xmlDocTag"&gt;&amp;lt;/summary&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;        [STAThread]&lt;br /&gt;        &lt;span class="keyword"&gt;static&lt;/span&gt; &lt;span class="keyword"&gt;void&lt;/span&gt; Main()&lt;br /&gt;        {&lt;br /&gt;            Application.EnableVisualStyles();&lt;br /&gt;            Application.SetCompatibleTextRenderingDefault(&lt;span class="keyword"&gt;false&lt;/span&gt;);&lt;br /&gt;&lt;br /&gt;            Application.Run(&lt;span class="keyword"&gt;new&lt;/span&gt; CalculatorForm());&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;And here, we improve the sample WinForm class created during prototyping to utilize the presenter coded, as such: -&lt;br /&gt;&lt;pre&gt;&lt;code class="cs"&gt;&lt;span class="keyword"&gt;using&lt;/span&gt; System.Windows.Forms;&lt;br /&gt;&lt;span class="keyword"&gt;using&lt;/span&gt; Calculator.Presenter;&lt;br /&gt;&lt;br /&gt;&lt;span class="keyword"&gt;namespace&lt;/span&gt; Calculator&lt;br /&gt;{&lt;br /&gt;    &lt;span class="keyword"&gt;public&lt;/span&gt; &lt;span class="keyword"&gt;partial&lt;/span&gt; &lt;span class="keyword"&gt;class&lt;/span&gt; CalculatorForm : Form, ICalculatorView&lt;br /&gt;    {&lt;br /&gt;        &lt;span class="keyword"&gt;private&lt;/span&gt; Presenter.Calculator _calculator;&lt;br /&gt;&lt;br /&gt;        &lt;span class="keyword"&gt;public&lt;/span&gt; CalculatorForm()&lt;br /&gt;        {&lt;br /&gt;            InitializeComponent();&lt;br /&gt;            _calculator = &lt;span class="keyword"&gt;new&lt;/span&gt; Presenter.Calculator(&lt;span class="keyword"&gt;this&lt;/span&gt;);&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        &lt;span class="keyword"&gt;public&lt;/span&gt; &lt;span class="keyword"&gt;string&lt;/span&gt; Result&lt;br /&gt;        {&lt;br /&gt;            &lt;span class="keyword"&gt;get&lt;/span&gt; { &lt;span class="keyword"&gt;return&lt;/span&gt; textBoxDisplay.Text; }&lt;br /&gt;            &lt;span class="keyword"&gt;set&lt;/span&gt; { textBoxDisplay.Text = &lt;span class="keyword"&gt;value&lt;/span&gt;; }&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        &lt;span class="keyword"&gt;public&lt;/span&gt; &lt;span class="keyword"&gt;string&lt;/span&gt; Formula&lt;br /&gt;        {&lt;br /&gt;            &lt;span class="keyword"&gt;get&lt;/span&gt; { &lt;span class="keyword"&gt;return&lt;/span&gt; textBoxDisplay.Text; }&lt;br /&gt;            &lt;span class="keyword"&gt;set&lt;/span&gt;&lt;br /&gt;            {&lt;br /&gt;                textBoxDisplay.Text = &lt;span class="keyword"&gt;value&lt;/span&gt;;&lt;br /&gt;                textBoxDisplay.Refresh();&lt;br /&gt;            }&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;}&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;Till this stage, we already have wire up most of the API needed within this application.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6458135603295822938-6891974654050649417?l=synersov.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://synersov.blogspot.com/feeds/6891974654050649417/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://synersov.blogspot.com/2010/09/test-driven-approach-positive-impact_27.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6458135603295822938/posts/default/6891974654050649417'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6458135603295822938/posts/default/6891974654050649417'/><link rel='alternate' type='text/html' href='http://synersov.blogspot.com/2010/09/test-driven-approach-positive-impact_27.html' title='Test Driven Approach - Positive Impact for Developers - Workshop III (Part A)'/><author><name>aahkam</name><uri>http://www.blogger.com/profile/11579245596035586334</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/_DSopvqyYd9M/TKDUftBwzyI/AAAAAAAAAA8/v9-_cG_Tb7U/s72-c/Solution+Explorer.jpg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6458135603295822938.post-2257566824189569636</id><published>2010-09-26T08:26:00.000-07:00</published><updated>2010-09-26T20:53:39.995-07:00</updated><title type='text'>Test Driven Approach - Positive Impact for Developers - Workshop II</title><content type='html'>First of all, there were couple of useful tools for Test Driven within Visual Studio .NET 2008 or 2010.&lt;br /&gt;&lt;br /&gt;These are the tools the I usually use: -&lt;br /&gt;1. &lt;a href="http://www.nunit.org/"&gt;NUnit&lt;/a&gt;&lt;br /&gt;2. &lt;a href="http://www.testdriven.net/"&gt;TestDriven.NET&lt;/a&gt;&lt;br /&gt;3. &lt;a href="http://www.jetbrains.com/resharper/download/index.html"&gt;JetBrains ReSharper&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Note: JetBrains resharper is not free though.&lt;br /&gt;&lt;br /&gt;So, after all, how should we start the development based on the requirements?&lt;br /&gt;&lt;br /&gt;I usually create a new Test Project first, named Calculator.Tests.&lt;br /&gt;&lt;br /&gt;For any TDD development, we should always attempt to write the tests from highest level possible with the simplest code. To achieve this, we should always attempt with the simplest API that we are going to deal with.&lt;br /&gt;&lt;br /&gt;So, I would imagine the calculator class to work like this: -&lt;br /&gt;&lt;pre&gt;&lt;code class=cs&gt;Calculator cal = &lt;span class=keyword&gt;new&lt;/SPAN&gt; Calculator();&lt;br /&gt;&lt;span class=keyword&gt;var&lt;/SPAN&gt; result = cal.Evaluate(formula);&lt;/CODE&gt;&lt;/PRE&gt;Hence, I created a class within the Calculator.Tests as such: -&lt;br /&gt;&lt;pre&gt;&lt;code class=cs&gt;&lt;span class=keyword&gt;using&lt;/SPAN&gt; NUnit.Framework;&lt;br /&gt;&lt;br /&gt;&lt;span class=keyword&gt;namespace&lt;/SPAN&gt; Calculator.Tests&lt;br /&gt;{&lt;br /&gt;    [TestFixture]&lt;br /&gt;    &lt;span class=keyword&gt;public&lt;/SPAN&gt; &lt;span class=keyword&gt;class&lt;/SPAN&gt; CalculatorTester&lt;br /&gt;    {&lt;br /&gt;        &lt;span class=keyword&gt;private&lt;/SPAN&gt; Calculator _calculator;&lt;br /&gt;&lt;br /&gt;        [SetUp]&lt;br /&gt;        &lt;span class=keyword&gt;public&lt;/SPAN&gt; &lt;span class=keyword&gt;void&lt;/SPAN&gt; SetUp()&lt;br /&gt;        {&lt;br /&gt;            _calculator = &lt;span class=keyword&gt;new&lt;/SPAN&gt; Calculator(); &lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        [TestCase(&lt;span class=string&gt;"5 + 6"&lt;/SPAN&gt;, &lt;span class=string&gt;"11"&lt;/SPAN&gt;)]&lt;br /&gt;        [TestCase(&lt;span class=string&gt;"3 - 2"&lt;/SPAN&gt;, &lt;span class=string&gt;"1"&lt;/SPAN&gt;)]&lt;br /&gt;        [TestCase(&lt;span class=string&gt;"5 * 6"&lt;/SPAN&gt;, &lt;span class=string&gt;"30"&lt;/SPAN&gt;)]&lt;br /&gt;        [TestCase(&lt;span class=string&gt;"12 / 6"&lt;/SPAN&gt;, &lt;span class=string&gt;"2"&lt;/SPAN&gt;)]&lt;br /&gt;        [TestCase(&lt;span class=string&gt;"2 * 3 - 4 / 5 + 6"&lt;/SPAN&gt;, &lt;span class=string&gt;"11.2"&lt;/SPAN&gt;)]&lt;br /&gt;        [TestCase(&lt;span class=string&gt;"5 + 6%"&lt;/SPAN&gt;, &lt;span class=string&gt;"5.3"&lt;/SPAN&gt;)]&lt;br /&gt;        [TestCase(&lt;span class=string&gt;"reciproc(2)"&lt;/SPAN&gt;, &lt;span class=string&gt;"0.5"&lt;/SPAN&gt;)]&lt;br /&gt;        [TestCase(&lt;span class=string&gt;"pow(2,3)"&lt;/SPAN&gt;, &lt;span class=string&gt;"8"&lt;/SPAN&gt;)]&lt;br /&gt;        [TestCase(&lt;span class=keyword&gt;new&lt;/SPAN&gt; [] {&lt;span class=string&gt;"A + B + C"&lt;/SPAN&gt;, &lt;span class=keyword&gt;string&lt;/SPAN&gt;.Empty},&lt;br /&gt;                    &lt;span class=string&gt;"Incompatible data type evaluation test."&lt;/SPAN&gt;,&lt;br /&gt;                    &lt;span class=keyword&gt;typeof&lt;/SPAN&gt;(IncompatibleDataTypeFormulaException))]&lt;br /&gt;        &lt;span class=keyword&gt;public&lt;/SPAN&gt; &lt;span class=keyword&gt;void&lt;/SPAN&gt; EvaluationTest(&lt;span class=keyword&gt;string&lt;/SPAN&gt; formula, &lt;span class=keyword&gt;string&lt;/SPAN&gt; expected)&lt;br /&gt;        {&lt;br /&gt;            &lt;span class=keyword&gt;var&lt;/SPAN&gt; result = _calculator.Evaluate(formula);&lt;br /&gt;            Assert.AreEqual(result.ToString(), expected);&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;/CODE&gt;&lt;/PRE&gt;Now with have almost demonstrated most of the features needed using various test cases based on TestCaseAttribute of NUnit 2.5.&lt;br /&gt;&lt;br /&gt;You may be asking, so, this is the business logic, where is the UI testing? Isn't it we must start from the UI?&lt;br /&gt;&lt;br /&gt;Yes, you got it half spots on. We must start from the UI (highest level), however are you sure this calculator class is just a business logic class? We shall see then.&lt;br /&gt;&lt;br /&gt;Now, lets try to fix all the compilation error by creating some fundamental skeleton for it to compile.&lt;br /&gt;&lt;pre&gt;&lt;code class=cs&gt;&lt;span class=keyword&gt;public&lt;/SPAN&gt; &lt;span class=keyword&gt;class&lt;/SPAN&gt; Calculator&lt;br /&gt;{&lt;br /&gt;    &lt;span class=keyword&gt;public&lt;/SPAN&gt; &lt;span class=keyword&gt;double&lt;/SPAN&gt; Evaluate(&lt;span class=keyword&gt;string&lt;/SPAN&gt; formula)&lt;br /&gt;    {&lt;br /&gt;        &lt;span class=keyword&gt;throw&lt;/SPAN&gt; &lt;span class=keyword&gt;new&lt;/SPAN&gt; NotImplementedException();&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;span class=keyword&gt;public&lt;/SPAN&gt; &lt;span class=keyword&gt;class&lt;/SPAN&gt; IncompatibleDataTypeFormulaException:Exception&lt;br /&gt;{&lt;br /&gt;}&lt;/CODE&gt;&lt;/PRE&gt;Now that we have written the unit tests and the compilation is done. We should test run it and see all of them failed.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_DSopvqyYd9M/TJ9t09x8HKI/AAAAAAAAAA0/OHMorHpPWOc/s1600/UnitTests+-+First+Time+-+All+Fail.jpg"&gt;&lt;img style="cursor: pointer; width: 320px; height: 173px;" src="http://1.bp.blogspot.com/_DSopvqyYd9M/TJ9t09x8HKI/AAAAAAAAAA0/OHMorHpPWOc/s320/UnitTests+-+First+Time+-+All+Fail.jpg" alt="" id="BLOGGER_PHOTO_ID_5521252424884165794" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;As expected, all test cases failed. I would be extremely surprised if any of this passed. :)&lt;br /&gt;&lt;br /&gt;So, the next assignment is to get them green.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6458135603295822938-2257566824189569636?l=synersov.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://synersov.blogspot.com/feeds/2257566824189569636/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://synersov.blogspot.com/2010/09/test-driven-approach-positive-impact_26.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6458135603295822938/posts/default/2257566824189569636'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6458135603295822938/posts/default/2257566824189569636'/><link rel='alternate' type='text/html' href='http://synersov.blogspot.com/2010/09/test-driven-approach-positive-impact_26.html' title='Test Driven Approach - Positive Impact for Developers - Workshop II'/><author><name>aahkam</name><uri>http://www.blogger.com/profile/11579245596035586334</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/_DSopvqyYd9M/TJ9t09x8HKI/AAAAAAAAAA0/OHMorHpPWOc/s72-c/UnitTests+-+First+Time+-+All+Fail.jpg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6458135603295822938.post-8269702519650682341</id><published>2010-09-24T04:02:00.001-07:00</published><updated>2010-09-26T02:11:29.250-07:00</updated><title type='text'>Test Driven Approach - Positive Impact for Developers - Workshop I</title><content type='html'>Start from this post and over the next few posts, I will be covering the Test Driven Approach - Positive Impacts for Developers.&lt;br /&gt;&lt;br /&gt;Impacts: -&lt;br /&gt;1. Think like a user&lt;br /&gt;2. Clean APIs Design&lt;br /&gt;3. Improves Abstractions&lt;br /&gt;4. Better Used of Patterns&lt;br /&gt;5. Improves Separation of Concerns.&lt;br /&gt;&lt;br /&gt;Let starts with some fundamental user requirements on a calculator.&lt;br /&gt;&lt;br /&gt;I can do fundamental calculation, +, -, *, /, sqrt, %, pow and 1/x.&lt;br /&gt;I can use whole numbers or rational numbers as the input.&lt;br /&gt;I can defined the result format within the format of whole number or rational number.&lt;br /&gt;I can specify the number of decimal places for the results.&lt;br /&gt;I can define a formula and save it.&lt;br /&gt;I can load a formula and calculate using the loaded formula.&lt;br /&gt;I can only specify the values for variables within the formula.&lt;br /&gt;&lt;br /&gt;There is all we have for the requirements.&lt;br /&gt;&lt;br /&gt;So, if we're to start right away, we should have start writing the unit tests first.&lt;br /&gt;&lt;br /&gt;A quick glance into the requirements, it seems quite straight forward to accomplish.&lt;br /&gt;&lt;br /&gt;Questions: -&lt;br /&gt;1. How many of you already start thinking of classes for logic separation, like Adder, Subtractor, Divisor and Multiplicator etc.?&lt;br /&gt;&lt;br /&gt;2. How many of you already start writing unit tests right away based on the requirement defined?&lt;br /&gt;&lt;br /&gt;"If there is anyone falling into those traps, you're wrong!" The requirement wasn't quite defined into a stage where this can be started.&lt;br /&gt;&lt;br /&gt;Based on the requirements given, we should have at least asking how would it be deployed? Web Services, Windows Services, Web Apps or Windows Forms Apps for instance.&lt;br /&gt;&lt;br /&gt;So, to make it more simple, this is a Win Form application, just like the calculator in Windows.&lt;br /&gt;&lt;br /&gt;New User Requirements: -&lt;br /&gt;"I can use it like many windows desktop application."&lt;br /&gt;&lt;br /&gt;So now, we are good to start, however, not unit testing yet. It is the UI wireframe (prototyping for GUI, i.e. Forms.) Here it is: -&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_DSopvqyYd9M/TJ8NMqULOKI/AAAAAAAAAAs/OSzdS_Kzxhc/s1600/Calculator+UI.jpg"&gt;&lt;img style="cursor: pointer; width: 301px; height: 301px;" src="http://3.bp.blogspot.com/_DSopvqyYd9M/TJ8NMqULOKI/AAAAAAAAAAs/OSzdS_Kzxhc/s320/Calculator+UI.jpg" alt="" id="BLOGGER_PHOTO_ID_5521146179348019362" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Now, we can start writing some tests, that will be in workshop II.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6458135603295822938-8269702519650682341?l=synersov.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://synersov.blogspot.com/feeds/8269702519650682341/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://synersov.blogspot.com/2010/09/test-driven-approach-positive-impact.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6458135603295822938/posts/default/8269702519650682341'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6458135603295822938/posts/default/8269702519650682341'/><link rel='alternate' type='text/html' href='http://synersov.blogspot.com/2010/09/test-driven-approach-positive-impact.html' title='Test Driven Approach - Positive Impact for Developers - Workshop I'/><author><name>aahkam</name><uri>http://www.blogger.com/profile/11579245596035586334</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/_DSopvqyYd9M/TJ8NMqULOKI/AAAAAAAAAAs/OSzdS_Kzxhc/s72-c/Calculator+UI.jpg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6458135603295822938.post-2410131722482395349</id><published>2010-09-08T09:51:00.001-07:00</published><updated>2010-09-08T11:14:50.414-07:00</updated><title type='text'>ETL Sorting or SQL Sorting (ORDER BY)</title><content type='html'>&lt;h1 align="center"&gt;ETL Magic&lt;/h1&gt;&lt;br /&gt;&lt;hr/&gt;&lt;br /&gt;Often hear about ETL (Extract, Transform, Load) solution for better data integration between applications, systems or solution within an enterprise. What are the major consideration before choosing an appropriate ETL solution?&lt;br /&gt;&lt;br /&gt;Sorting, Merging, Unification, Transformation and Loading are quite commonly happen within Data Integration stage. Often, we heard of &lt;a href="http://www.ordinal.com/"&gt;NSort&lt;/a&gt;, &lt;a href="http://www.cosort.com/"&gt;CoSort (IRI)&lt;/a&gt;, &lt;a href="http://www.syncsort.com/"&gt;SyncSort&lt;/a&gt; and others famous 3rd party ETL solution and tools. Each of these offers some great performance if not exceptional in their respective technical strength with many data integration efficiency (Terabytes of data size) bar being set higher and higher.&lt;br /&gt;&lt;br /&gt;&lt;h1 align="center"&gt;&lt;u&gt;E&lt;/u&gt;n&lt;u&gt;T&lt;/u&gt;erprise solution missing &lt;u&gt;L&lt;/u&gt;ink? &lt;/h1&gt;&lt;br /&gt;&lt;hr/&gt;&lt;br /&gt;Quite honestly, many solution architects would think of the use in these ready made ETL solution to glue data movement processes within the sub-solutions altogether to not just making data extraction, transformation and loading much faster (conceptually), but also act as a missing link to gel many independent components within the enterprise solution to ensure they get the right data in timely fashion before going live.&lt;br /&gt;&lt;br /&gt;&lt;h1 align="center"&gt;Question of the day&lt;/h1&gt;&lt;br /&gt;&lt;hr/&gt;&lt;br /&gt;What would be the topic of discussion today is rather, will those 3rd parties solution offers the best performance value to the enterprise solution and often considered as the missing link in the solutions integration?&lt;br /&gt;&lt;br /&gt;&lt;h1 align="center"&gt;ETL Rules of thumb: -&lt;/h1&gt;&lt;br /&gt;&lt;hr/&gt;&lt;br /&gt;If data is already in the database and you would want to extract all these data into another database, consider doing the sorting and filtering related tasks within your database server itself. Ordering, filtering and unification tasks within the database server is always consider as "as good" when compared to the other ETL solution.&lt;br /&gt;&lt;br /&gt;If the data has to be somewhat inserted into tables within database, consider doing sorting, unification, merging (joins), filtering, data enrichment (meta tagging) and etc. altogether within the database server. Again, the same principles applied here. Database server can handle all those as good as the third parties ETL.&lt;br /&gt;&lt;br /&gt;If the batch data integration process can be avoided by putting it into an incremental data integration approach, by all means doing it in an incremental fashion with proper application/data partitioning.&lt;br /&gt;&lt;br /&gt;If the data is migrating from one database platform into another, try to look for some out of the box integration solutions. For example, SSIS for Microsoft SQL Server. (&lt;a href="http://msdn.microsoft.com/en-us/library/dd537533%28SQL.100%29.aspx"&gt;SSIS is free and has also recently breaking some integration records&lt;/a&gt;.)&lt;br /&gt;&lt;br /&gt;Never ever thinking of re-inventing your own ETL solution, from ground up, if you are not intending to step into the red ocean, ETL business.&lt;br /&gt;&lt;br /&gt;Consider 3rd parties ETL solutions when the data source is originated from a non-database model and the data target is another non-database model.&lt;br /&gt;&lt;br /&gt;Consider 3rd parties ETL solutions when majority of the data transformation, extraction, unification, merging, filtering and sorting involves many different types of data sources.&lt;br /&gt;&lt;br /&gt;Consider 3rd parties ETL solutions when it has more than one intended data target that are of different platforms.&lt;br /&gt;&lt;br /&gt;&lt;h1 align="center"&gt;Take Away&lt;/h1&gt;&lt;br /&gt;&lt;hr/&gt;&lt;br /&gt;SQL ordering, filtering, conditional relationship/merging (joins) are almost equally as fast as the 3rd parties ETL tools.&lt;br /&gt;&lt;br /&gt;No real magics with ready made ETL solutions, it is the solution integration architecture that counts.&lt;br /&gt;&lt;br /&gt;Fancy solutions will cost more in terms of investment capital, learning curve, maintenance efforts, business opportunity, end product selling prices (to your customers).&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6458135603295822938-2410131722482395349?l=synersov.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://synersov.blogspot.com/feeds/2410131722482395349/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://synersov.blogspot.com/2010/09/etl-sorting-or-sql-sorting-order-by.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6458135603295822938/posts/default/2410131722482395349'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6458135603295822938/posts/default/2410131722482395349'/><link rel='alternate' type='text/html' href='http://synersov.blogspot.com/2010/09/etl-sorting-or-sql-sorting-order-by.html' title='ETL Sorting or SQL Sorting (ORDER BY)'/><author><name>aahkam</name><uri>http://www.blogger.com/profile/11579245596035586334</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6458135603295822938.post-746882600420886501</id><published>2010-08-19T19:15:00.000-07:00</published><updated>2010-09-24T00:48:31.565-07:00</updated><title type='text'>Side Effects of Linq Select Statements due to Deferred Execution</title><content type='html'>I have a function to read data from a delimited text that is splitted into a string array. To the caller didn’t specifies the columns to extract, it extract all columns, and only extracts the specified one otherwise.&lt;br /&gt;&lt;br /&gt;Assumed that I have a delimited text that contains 2 columns only: -&lt;br /&gt;&lt;br /&gt;&lt;PRE&gt;&lt;CODE class=cs&gt;&lt;SPAN class=keyword&gt;public&lt;/SPAN&gt; DataField[] Read()&lt;br /&gt;{&lt;br /&gt;    &lt;SPAN class=comment&gt;// splits the text according to the defined delimiters.&lt;/SPAN&gt;&lt;br /&gt;    &lt;SPAN class=keyword&gt;var&lt;/SPAN&gt; data = _reader.Read();&lt;br /&gt;    &lt;SPAN class=comment&gt;// when no columns specified, take all column from data.&lt;/SPAN&gt;&lt;br /&gt;    &lt;SPAN class=keyword&gt;if&lt;/SPAN&gt; (_columns == &lt;SPAN class=keyword&gt;null&lt;/SPAN&gt;)&lt;br /&gt;    {&lt;br /&gt;        &lt;SPAN class=keyword&gt;var&lt;/SPAN&gt; counter = &lt;SPAN class=number&gt;0&lt;/SPAN&gt;;&lt;br /&gt;        &lt;SPAN class=comment&gt;// save as the instance fields to avoid recompilation.&lt;/SPAN&gt;&lt;br /&gt;        _columns = data.Select(item =&amp;gt; &lt;SPAN class=keyword&gt;new&lt;/SPAN&gt; ColumnInfo&lt;br /&gt;                                        {&lt;br /&gt;                                            Index = counter++&lt;br /&gt;                                        });&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    &lt;SPAN class=keyword&gt;return&lt;/SPAN&gt; data == &lt;SPAN class=keyword&gt;null&lt;/SPAN&gt;&lt;br /&gt;    ? &lt;SPAN class=keyword&gt;null&lt;/SPAN&gt;&lt;br /&gt;    : _columns.Select(item =&amp;gt; &lt;SPAN class=keyword&gt;new&lt;/SPAN&gt; DataField&lt;br /&gt;                                {&lt;br /&gt;                                    Column = item,&lt;br /&gt;                                    Data = data[item.Index]&lt;br /&gt;                                }).ToArray();&lt;br /&gt;}&lt;/CODE&gt;&lt;/PRE&gt;&lt;br /&gt;&lt;br /&gt;To my surprise that this Read method keeps throwing ArrayOutOfBoundException after the first attempt. Can anyone guess what’s wrong? :) (Answer: scroll down please)&lt;br /&gt;&lt;br /&gt;After the first call, the enumerator is wellover (at its end element). However, IEnumerable created (which I thought it was) from a Linq statement is not a real creation of IEnumerable instance.&lt;br /&gt;&lt;br /&gt;&lt;PRE&gt;&lt;CODE class=cs&gt;_columns = data.Select(item =&amp;gt; &lt;SPAN class=keyword&gt;new&lt;/SPAN&gt; ColumnInfo&lt;br /&gt;                                {&lt;br /&gt;                                    Index = counter++&lt;br /&gt;                                });&lt;/CODE&gt;&lt;/PRE&gt;&lt;br /&gt;&lt;br /&gt;This statement is rather associating _columns field to the Linq statement (like a callback, I think). The subsequent Read() call would continue to invoke the lambda expression within the linq statement for next element, which created column with Index=3. (This also explains why linq’s performance is good without much overhead).&lt;br /&gt;&lt;br /&gt;To workaround this side effets, one need to really tell the Linq function to create a real array or list for caching and the side effect will be gone.&lt;br /&gt;Solution as such: -&lt;br /&gt;&lt;br /&gt;&lt;PRE&gt;&lt;CODE class=cs&gt;&lt;SPAN class=keyword&gt;public&lt;/SPAN&gt; DataField[] Read()&lt;br /&gt;{&lt;br /&gt;    &lt;SPAN class=keyword&gt;var&lt;/SPAN&gt; data = _reader.Read();&lt;br /&gt;&lt;br /&gt;    &lt;SPAN class=keyword&gt;if&lt;/SPAN&gt; (_columns == &lt;SPAN class=keyword&gt;null&lt;/SPAN&gt;)&lt;br /&gt;    {&lt;br /&gt;        &lt;SPAN class=keyword&gt;var&lt;/SPAN&gt; counter = &lt;SPAN class=number&gt;0&lt;/SPAN&gt;;&lt;br /&gt;        &lt;SPAN class=comment&gt;// ToArray() will tear off the callback by caching a real array, not callback.&lt;/SPAN&gt;&lt;br /&gt;        _columns = data.Select(item =&amp;gt; &lt;SPAN class=keyword&gt;new&lt;/SPAN&gt; ColumnInfo&lt;br /&gt;                                        {&lt;br /&gt;                                            Index = counter++&lt;br /&gt;                                        }).ToArray();&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    &lt;SPAN class=keyword&gt;return&lt;/SPAN&gt; data == &lt;SPAN class=keyword&gt;null&lt;/SPAN&gt;&lt;br /&gt;        ? &lt;SPAN class=keyword&gt;null&lt;/SPAN&gt;&lt;br /&gt;        : _columns.Select(item =&amp;gt; &lt;SPAN class=keyword&gt;new&lt;/SPAN&gt; DataField&lt;br /&gt;        {&lt;br /&gt;            Column = item,&lt;br /&gt;            Data = data[item.Index]&lt;br /&gt;        }).ToArray();&lt;br /&gt;}&lt;/CODE&gt;&lt;/PRE&gt;&lt;br /&gt;&lt;br /&gt;&lt;a href="http://msmvps.com/blogs/jon_skeet/archive/2008/02/14/human-linq.aspx"&gt;Read Jon Skeet article on Human Linq&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;a href="http://www.eggheadcafe.com/software/aspnet/33966517/-linq-select.aspx"&gt;Also here about side effects with select&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6458135603295822938-746882600420886501?l=synersov.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://synersov.blogspot.com/feeds/746882600420886501/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://synersov.blogspot.com/2010/08/i-have-function-to-read-data-from.html#comment-form' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6458135603295822938/posts/default/746882600420886501'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6458135603295822938/posts/default/746882600420886501'/><link rel='alternate' type='text/html' href='http://synersov.blogspot.com/2010/08/i-have-function-to-read-data-from.html' title='Side Effects of Linq Select Statements due to Deferred Execution'/><author><name>aahkam</name><uri>http://www.blogger.com/profile/11579245596035586334</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6458135603295822938.post-8818194200799835512</id><published>2010-08-05T00:33:00.000-07:00</published><updated>2010-09-08T11:23:49.788-07:00</updated><title type='text'>TDD: Only Unit Testing Public</title><content type='html'>Many times when I spoke to people about TDD and Unit Testing, quite surprisingly I will be trapped into a debate of "Unit Test Public only?".&lt;br /&gt;&lt;br /&gt;My quick answer is "Yes".&lt;br /&gt;&lt;br /&gt;Reason?&lt;br /&gt;Internal, Protected, Private "properties" of an Assembly or Class are the abstraction for each of them respectively. Unit tests should never cross the border to break the abstraction intend of a design.&lt;br /&gt;&lt;br /&gt;DISCLAIMER: "properties" I used here refers to methods, subtypes, property (fields) etc.&lt;br /&gt;&lt;br /&gt;Come to think of this topic again, why would one asked the question of such like? (unit test public?)&lt;br /&gt;My only view is that, these may be the people who are writing real implementation first before writing the tests. They knew the design and implementation before even writing unit test and they knew the importance of the internal implementation and they would like to secure it (secure logic implementation intend). Are these suggesting TDD practice? (Refer to my earlier TDD post &lt;a href="http://synersov.blogspot.com/2010/07/test-driven-development.html"&gt;HERE&lt;/a&gt;).&lt;br /&gt;&lt;br /&gt;If one started to think of the application (usage) of code to be developed first before thinking how to develop it (or design it), one should start with the accessible content. (Which is public content). Get the usage right is the prime criteria for TDD and also many software quality assurance measure. From the righteous usage of the public "properties" corresponded with right expectation and that makes the "right" deliverable.&lt;br /&gt;&lt;br /&gt;So, spend more time thinking of what may be "right" for the time of writing, and ensure unit tested the "right" intend that you would want to enforced. Internal implementation are abstraction that meant for future re-development or refactoring or enhancement that usually and very likely to change from time to time without prior noticed.&lt;br /&gt;&lt;br /&gt;This way, you have done your team and yourself a favor by created some maintainable unit tests.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6458135603295822938-8818194200799835512?l=synersov.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://synersov.blogspot.com/feeds/8818194200799835512/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://synersov.blogspot.com/2010/08/tdd-only-unit-testing-public.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6458135603295822938/posts/default/8818194200799835512'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6458135603295822938/posts/default/8818194200799835512'/><link rel='alternate' type='text/html' href='http://synersov.blogspot.com/2010/08/tdd-only-unit-testing-public.html' title='TDD: Only Unit Testing Public'/><author><name>aahkam</name><uri>http://www.blogger.com/profile/11579245596035586334</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6458135603295822938.post-307240199514428443</id><published>2010-08-03T03:55:00.000-07:00</published><updated>2010-09-24T03:49:29.880-07:00</updated><title type='text'>MSSQL Common Table Expression (CTE)</title><content type='html'>&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_DSopvqyYd9M/TFf-hXCqmVI/AAAAAAAAAAU/RaWzz1cwjew/s1600/DB+Design+Diagram.jpg"&gt;&lt;img style="display: block; margin: 0px auto 10px; text-align: center; cursor: pointer; width: 320px; height: 232px;" src="http://1.bp.blogspot.com/_DSopvqyYd9M/TFf-hXCqmVI/AAAAAAAAAAU/RaWzz1cwjew/s320/DB+Design+Diagram.jpg" alt="" id="BLOGGER_PHOTO_ID_5501145318930684242" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;What is Common Table Expression?&lt;/span&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Can be thought as a temporally result set that is defined within the SQL execution scope.&lt;/li&gt;&lt;li&gt;Usage: -&lt;/li&gt;&lt;/ul&gt;&lt;ol&gt;&lt;li&gt;Create Recursive Query&lt;/li&gt;&lt;li&gt;Substitute for a view&lt;/li&gt;&lt;li&gt;Enable Grouping by column that is derived from a scalar sub select.&lt;/li&gt;&lt;li&gt;Referencing the resulting table multiple times.&lt;/li&gt;&lt;li&gt;Available since SQL Server 2005&lt;/li&gt;&lt;/ol&gt;&lt;br /&gt;&lt;br /&gt;Syntax: -&lt;br /&gt;&lt;br /&gt;WITH &lt;expression&gt; [(coloumn name [, column name...n])]&lt;br /&gt;AS&lt;br /&gt;(&lt;br /&gt;  /* anchor member definition */&lt;br /&gt;  UNION ALL | UNION | EXCEPT | INTERCECT&lt;br /&gt;  /* recursion member definition*/&lt;br /&gt;)&lt;br /&gt;&lt;statement&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Statement to use with CTE include INSERT, UPDATE, DELETE, CREATE VIEW.&lt;br /&gt;&lt;br /&gt;CTE can be used without recursion member and that will serve very well as the temporally result set for further joining.&lt;br /&gt;&lt;br /&gt;Example: -&lt;br /&gt;&lt;PRE&gt;&lt;CODE class=sql&gt;/*************** BEGIN OF QUERY **********************/&lt;br /&gt;USE NRule&lt;br /&gt;GO&lt;br /&gt;&lt;br /&gt;WITH DocumentReport&lt;br /&gt;AS&lt;br /&gt;(&lt;br /&gt;SELECT a.id, a.[Description], a.Name AS [DocumentName], c.Name AS [AttributeName], d.value&lt;br /&gt;FROM Documents AS a&lt;br /&gt;INNER JOIN DocumentMetaAttributePathIndex AS b&lt;br /&gt;ON a.id = b.documentId&lt;br /&gt;INNER JOIN MetaAttributes AS c&lt;br /&gt;ON b.attributeId = c.id&lt;br /&gt;INNER JOIN AttributeValues AS d&lt;br /&gt;ON b.valueId = d.id&lt;br /&gt;)&lt;br /&gt;SELECT *&lt;br /&gt;FROM DocumentReport ORDER BY id&lt;br /&gt;GO&lt;br /&gt;/*************** END OF QUERY **********************/&lt;/CODE&gt;&lt;/PRE&gt;&lt;br /&gt;CTE would be best use to query of outcome that is expanding dynamically. Typical example is to trace the tree or graph data structure represented under adjancent list table design pattern within relational model of a database.&lt;br /&gt;&lt;br /&gt;Example: -&lt;br /&gt;&lt;PRE&gt;&lt;CODE class=sql&gt;/*************** BEGIN OF QUERY **********************/&lt;br /&gt;USE NRule&lt;br /&gt;GO&lt;br /&gt;&lt;br /&gt;DECLARE @documentId bigint&lt;br /&gt;DECLARE @ancestorId bigint&lt;br /&gt;SET @documentId = 1&lt;br /&gt;SET @ancestorId = NULL;&lt;br /&gt;WITH AttributeHierarchyReport(AncestorId, AttributeId, DocumentId, ValueId, LEVEL)&lt;br /&gt;AS&lt;br /&gt;(&lt;br /&gt;-- Anchor member definition&lt;br /&gt;SELECT meta.AncestorId, meta.attributeId, meta.[DocumentId], meta.[ValueId], 0 AS LEVEL&lt;br /&gt;FROM dbo.DocumentMetaAttributePathIndex AS meta&lt;br /&gt;WHERE (@ancestorId is NULL or meta.AncestorId = @ancestorId) AND&lt;br /&gt;(@documentId is NULL or meta.DocumentId = @documentId)&lt;br /&gt;UNION ALL&lt;br /&gt;-- Recursive member definition&lt;br /&gt;SELECT meta.ancestorId, meta.attributeId, meta.[documentId], meta.[valueId], LEVEL + 1&lt;br /&gt;FROM dbo.DocumentMetaAttributePathIndex AS meta&lt;br /&gt;INNER JOIN AttributeHierarchyReport rpt ON meta.ancestorId = rpt.AttributeId&lt;br /&gt;WHERE (@ancestorId is NULL or meta.AncestorId = @ancestorId) AND&lt;br /&gt;(@documentId is NULL or meta.DocumentId = @documentId)&lt;br /&gt;)&lt;br /&gt;SELECT AncestorId, AttributeId, DocumentId, ValueId, Level&lt;br /&gt;FROM AttributeHierarchyReport ORDER BY Level;&lt;br /&gt;GO&lt;br /&gt;/*************** END OF QUERY **********************/&lt;/CODE&gt;&lt;/PRE&gt;&lt;br /&gt;However, watch out for the data redundancy that is appearing in the query result set. Redundant query result set within the recursive CTE proven to be a killer to your database application using it. It grows the result set sometimes exponentially until it kills the application by running out of memory.&lt;br /&gt;&lt;br /&gt;Tweak is needed to CTE when redundant row sets happened and if you care about your application, never live with redundant row sets by either further tuning your CTE or improve your Database/Table design to help better/efficient use with your CTE.&lt;br /&gt;&lt;br /&gt;Example: -&lt;br /&gt;&lt;PRE&gt;&lt;CODE class=sql&gt;/*************** BEGIN OF QUERY **********************/&lt;br /&gt;/* this version is using additional column ParentDescendantId to enforce root node validation at anchor member */&lt;br /&gt;USE NRule&lt;br /&gt;GO&lt;br /&gt;&lt;br /&gt;DECLARE @documentId bigint&lt;br /&gt;DECLARE @ancestorId bigint&lt;br /&gt;/* @documentId = NULL would mean to get all attributes for all documents regardlessly */&lt;br /&gt;/* alternatively we can use the @documentId to narrow down to a specific document attribute tree for retrieval */&lt;br /&gt;SET @documentId = 1&lt;br /&gt;/* @ancestorId = NULL would mean to get all attributes regardlessly */&lt;br /&gt;/* alternatively we can use the ancestorId to narrow down the attribute tree for retrieval */&lt;br /&gt;SET @ancestorId = NULL;&lt;br /&gt;WITH AttributeHierarchyReport(AncestorId, DescendantId, DocumentId, ValueId, ParentDescendantId, LEVEL)&lt;br /&gt;AS&lt;br /&gt;(&lt;br /&gt;-- Anchor member definition&lt;br /&gt;SELECT meta.AncestorId, meta.attributeId, meta.[DocumentId], meta.[ValueId], parent.attributeId, 1 AS LEVEL&lt;br /&gt;FROM dbo.DocumentMetaAttributePathIndex AS meta&lt;br /&gt;LEFT JOIN dbo.DocumentMetaAttributePathIndex AS parent ON meta.AncestorId = parent.attributeId&lt;br /&gt;WHERE (@ancestorId is NULL or meta.AncestorId = @ancestorId) AND /* Ensure the ancestor id is matched */&lt;br /&gt;    (@documentId is NULL or meta.DocumentId = @documentId) AND /* Ensure the document id is matched */&lt;br /&gt;    (parent.attributeId IS NULL) /* Ensure there is no ancestor, Root node only */&lt;br /&gt;UNION ALL&lt;br /&gt;-- Recursive member definition&lt;br /&gt;SELECT meta.ancestorId, meta.attributeId, meta.[documentId], meta.[valueId], parent.DescendantId, LEVEL + 1&lt;br /&gt;FROM dbo.DocumentMetaAttributePathIndex AS meta&lt;br /&gt;INNER JOIN AttributeHierarchyReport parent ON meta.ancestorId = parent.DescendantId /* Ensure all is child is recursively joined */&lt;br /&gt;)&lt;br /&gt;SELECT AncestorId, DescendantId, DocumentId, ValueId, ParentDescendantId, Level&lt;br /&gt;FROM AttributeHierarchyReport;&lt;br /&gt;GO&lt;br /&gt;/*************** END OF QUERY **********************/&lt;/CODE&gt;&lt;/PRE&gt;&lt;br /&gt;&lt;/statement&gt;&lt;/expression&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6458135603295822938-307240199514428443?l=synersov.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://synersov.blogspot.com/feeds/307240199514428443/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://synersov.blogspot.com/2010/08/mssql-common-table-expression-cte.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6458135603295822938/posts/default/307240199514428443'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6458135603295822938/posts/default/307240199514428443'/><link rel='alternate' type='text/html' href='http://synersov.blogspot.com/2010/08/mssql-common-table-expression-cte.html' title='MSSQL Common Table Expression (CTE)'/><author><name>aahkam</name><uri>http://www.blogger.com/profile/11579245596035586334</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/_DSopvqyYd9M/TFf-hXCqmVI/AAAAAAAAAAU/RaWzz1cwjew/s72-c/DB+Design+Diagram.jpg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6458135603295822938.post-4935563358243655340</id><published>2010-08-01T21:41:00.000-07:00</published><updated>2011-03-18T18:48:19.396-07:00</updated><title type='text'>Don't Limiting Yourself Much Than Your Users or Clients Do.</title><content type='html'>Many times, before planning on a new software release you often hear the voice of backward compatibility, upgrade costs, additional component dependencies, operating platforms upgrades and etc. from the team. Are these important? Yes they do. Are these debates necessary before the plan of a release? Absolutely not. We need to look at it and aware of it, but lets not debating it now.&lt;br /&gt;&lt;br /&gt;A new software release is to ensure it maintains attractiveness and sounds of improve workability, usability, flexibility, integrativity, scalability, security, martketability and many more.&lt;br /&gt;&lt;br /&gt;Before one starting to look at the release plan or product backlog, and if you have already be the first to attack on your own team, you are not doing your team a favor, but holding them back to be closer with FAILURE and not able to deliver.&lt;br /&gt;&lt;br /&gt;One phrase that I often hear and it is always true is that "Many times, we often limiting ourselves much more than the customers or users do."&lt;br /&gt;&lt;br /&gt;Wake up guys! Be wild and creative when innovating of what you want to do to your software during visioning stage, and only come to be more focus and cautious for not over committing when you are planning and delivering it.&lt;br /&gt;&lt;br /&gt;Overly conservative does no help of bringing innovations. Bottom line, don't limiting yourself much than your users or customers do would always be a golden phrase to follow.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6458135603295822938-4935563358243655340?l=synersov.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://synersov.blogspot.com/feeds/4935563358243655340/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://synersov.blogspot.com/2010/08/dont-limiting-yourself-much-than-your.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6458135603295822938/posts/default/4935563358243655340'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6458135603295822938/posts/default/4935563358243655340'/><link rel='alternate' type='text/html' href='http://synersov.blogspot.com/2010/08/dont-limiting-yourself-much-than-your.html' title='Don&apos;t Limiting Yourself Much Than Your Users or Clients Do.'/><author><name>aahkam</name><uri>http://www.blogger.com/profile/11579245596035586334</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6458135603295822938.post-6733283223872277288</id><published>2010-07-22T04:35:00.000-07:00</published><updated>2010-07-22T04:53:09.158-07:00</updated><title type='text'>Test Driven Development</title><content type='html'>&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_DSopvqyYd9M/TEgwoQeeD8I/AAAAAAAAAAM/ePJCtEke_Dc/s1600/TDD.jpg"&gt;&lt;img style="display: block; margin: 0px auto 10px; text-align: center; cursor: pointer; width: 233px; height: 320px;" src="http://2.bp.blogspot.com/_DSopvqyYd9M/TEgwoQeeD8I/AAAAAAAAAAM/ePJCtEke_Dc/s320/TDD.jpg" alt="" id="BLOGGER_PHOTO_ID_5496696813381357506" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;Five key principle questions must be asked all time:&lt;br /&gt;&lt;ol&gt;&lt;li&gt;What Do I Want to Accomplish?&lt;/li&gt;&lt;li&gt;Does It Do What I Want?&lt;/li&gt;&lt;li&gt;Does It Do What I Want All of the Time?&lt;/li&gt;&lt;li&gt;Can I Depend On It?&lt;/li&gt;&lt;li&gt;Does It Document My Intent?&lt;/li&gt;&lt;/ol&gt;TDD Process Itinerary&lt;br /&gt;&lt;ol&gt;&lt;li&gt;Obtains Project Specification Documents to identify specification needs, usually the action from the UML CASE diagram. (What needs to be done?)&lt;/li&gt;&lt;li&gt;Write the test procedures and test methods (Unit Test) to enforce it achieve the specification needs as how it was documented in Project Specification Document. (Does it do what I want?)&lt;/li&gt;&lt;li&gt;Write the code just to pass the test.&lt;/li&gt;&lt;li&gt;Ensure and maintain the tests from never fail at all times. (Does it do what I want at all time and Can I depend on it?)&lt;/li&gt;&lt;li&gt;Re-factor the code for readability and maintainability, while ensure the tests remain intact to the specification. (Does it document my intent?)&lt;/li&gt;&lt;/ol&gt;&lt;br /&gt;Few ways to achieve unit testing: -&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Dummy&lt;/li&gt;&lt;li&gt;Fakes&lt;/li&gt;&lt;li&gt;Mocks&lt;/li&gt;&lt;li&gt;Stubs&lt;/li&gt;&lt;/ul&gt;To be continue...&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6458135603295822938-6733283223872277288?l=synersov.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://synersov.blogspot.com/feeds/6733283223872277288/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://synersov.blogspot.com/2010/07/test-driven-development.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6458135603295822938/posts/default/6733283223872277288'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6458135603295822938/posts/default/6733283223872277288'/><link rel='alternate' type='text/html' href='http://synersov.blogspot.com/2010/07/test-driven-development.html' title='Test Driven Development'/><author><name>aahkam</name><uri>http://www.blogger.com/profile/11579245596035586334</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/_DSopvqyYd9M/TEgwoQeeD8I/AAAAAAAAAAM/ePJCtEke_Dc/s72-c/TDD.jpg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6458135603295822938.post-6755907879201555187</id><published>2010-07-22T03:30:00.000-07:00</published><updated>2010-08-05T00:22:05.410-07:00</updated><title type='text'>Top 10 Unwanted Characteristic of a Developer</title><content type='html'>1. Egoness&lt;br /&gt;Example: -&lt;br /&gt;We are senior and we have many years of exposure and we know what we need to do, please keep your explanation to yourself.&lt;br /&gt;Outcome: -&lt;br /&gt;Fail to grow as a team, fail to deliver or deliver with ULTRA high defects. Copying design ideas from others but not bothering to ask and resulting in sub-standard code, but proclaiming that is the beauty of it when challenged.&lt;br /&gt;&lt;br /&gt;2. Year-istic Mathematician&lt;br /&gt;Example: -&lt;br /&gt;I want a lead role because of my many years of exposure. I work with many big profound companies and I derserved the lead role.&lt;br /&gt;Outcome: -&lt;br /&gt;Not able to justify the pros and cons and delivering sub standard work or not delivering at all.&lt;br /&gt;&lt;br /&gt;3. Favor Quick Wins over Quality&lt;br /&gt;Example: -&lt;br /&gt;Deliver the max within the shortest time is the primary concern of the company to make money. Patterns and design are purism and that often complicates the development.&lt;br /&gt;Outcome: -&lt;br /&gt;Fails to grow as a team or individually. Produced sub standard codes that needs major rework whenever enhancement needs imposed.&lt;br /&gt;&lt;br /&gt;4. Never Admit Own Mistakes&lt;br /&gt;Example: -&lt;br /&gt;The bugs had happened because the calling function never do a parameter validation and error checking.&lt;br /&gt;The late delivery was largely due to inconsistent and or incomplete requirements.&lt;br /&gt;Outcome: -&lt;br /&gt;Never learn from mistakes and similar problems reoccuring over and over again. It is quite clear that if it is not your problem but it somewhat impact your work delivery or team goals, it is everyone's problem and deal with it if you can, escalates otherwise.&lt;br /&gt;To be continue....&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6458135603295822938-6755907879201555187?l=synersov.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://synersov.blogspot.com/feeds/6755907879201555187/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://synersov.blogspot.com/2010/07/top-10-unwanted-characteristic-of.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6458135603295822938/posts/default/6755907879201555187'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6458135603295822938/posts/default/6755907879201555187'/><link rel='alternate' type='text/html' href='http://synersov.blogspot.com/2010/07/top-10-unwanted-characteristic-of.html' title='Top 10 Unwanted Characteristic of a Developer'/><author><name>aahkam</name><uri>http://www.blogger.com/profile/11579245596035586334</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6458135603295822938.post-1549452506749106241</id><published>2010-07-22T03:00:00.000-07:00</published><updated>2010-07-22T03:10:31.945-07:00</updated><title type='text'>.NET Application Slow?</title><content type='html'>Many people complained about .NET application being slow. First question first, do you know how .NET work internally?&lt;br /&gt;&lt;br /&gt;Pickup a good book like CLR via C# (Jeffrey Ricther) or Framework Design Guideline (Cwalina, Abrams) would help.&lt;br /&gt;&lt;br /&gt;If you don't understand how GC (Garbage Collector) works, please do yourself a favor.&lt;br /&gt;&lt;br /&gt;If you find yourself writing lots of codes (and redundant codes), do yourself a favor reading Design Patterns.&lt;br /&gt;&lt;br /&gt;If you find yourself adding lots of project/assembly references into a project, do yourself a favor reading books about SoC (Separation of Concern or Single Responsibility or Architectural Consideration).&lt;br /&gt;&lt;br /&gt;If you find yourself fixing lots of bugs that subsequently introduce more and more bugs (defects), change your development engineering process but adopting TDD (Test Driven Development) approach. (Unit Testing)&lt;br /&gt;&lt;br /&gt;I'm hoping to have touch more indepth details of these topics in the coming post.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6458135603295822938-1549452506749106241?l=synersov.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://synersov.blogspot.com/feeds/1549452506749106241/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://synersov.blogspot.com/2010/07/net-application-slow.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6458135603295822938/posts/default/1549452506749106241'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6458135603295822938/posts/default/1549452506749106241'/><link rel='alternate' type='text/html' href='http://synersov.blogspot.com/2010/07/net-application-slow.html' title='.NET Application Slow?'/><author><name>aahkam</name><uri>http://www.blogger.com/profile/11579245596035586334</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry></feed>
