<?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-36645098</id><updated>2012-01-05T10:25:54.652-08:00</updated><category term='NSTextField'/><category term='debugging'/><category term='Covariance'/><category term='XP'/><category term='Biases'/><category term='bounds'/><category term='Fallacies'/><category term='Generics'/><category term='delegates'/><category term='NSButton'/><category term='Objective C'/><category term='Extreme Programming'/><category term='Generic Delegates'/><category term='XCode'/><category term='properties'/><category term='C#'/><category term='SCRUM'/><category term='Agile'/><category term='contravariance'/><category term='Cocoa'/><category term='Classes Tab'/><category term='UIView'/><category term='frame'/><category term='NSView'/><category term='UILabel'/><category term='Interface Builder'/><category term='convariance'/><category term='Rotate'/><category term='.NET'/><title type='text'>Digerati Illuminatus</title><subtitle type='html'>In this blog I will share insights and information concerning software development. The target audience includes Software Engineers, Software Project personnel, Software Product personnel, Management, and Executives.</subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://digerati-illuminatus.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/36645098/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://digerati-illuminatus.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>Geoff Slinker</name><uri>http://www.blogger.com/profile/12365501393247949005</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>76</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-36645098.post-9021739994940094988</id><published>2012-01-05T10:16:00.000-08:00</published><updated>2012-01-05T10:25:54.681-08:00</updated><title type='text'>Null Object, Whole  Value, Exceptional Value, and Meaningless Behavior Patterns</title><content type='html'>v1.1 March 22, 2006&lt;br /&gt;&lt;br /&gt;v1.0 December 6, 2005&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size: large;"&gt;Introduction&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Recently I have been involved with some discussions concerned with signaling errors. Since I work in C++ style languages I was aware of two major camps, one being exception handling and the other being error return values. I discovered there was another popular camp that seems to have come from Smalltalk users called the NullObject.&lt;br /&gt;&lt;br /&gt;Basically the NullObject was described as an object with no behavior. The premise is thus: When a method is supposed to return an object with which the caller will collaborate and the generation of the collaborator resulted in an error, instead of throwing an exception or returning an error value, return a NullObject. The NullObject will have the same interface as a non-NullObject and each method will have no behavior and no side effects.&lt;br /&gt;&lt;br /&gt;My research leads me to understand that the NullObject Pattern is one of the Meaningless Behavior Patterns. The paper&lt;i&gt; "The CHECKS Pattern Language of Information Integrity, 1994"&lt;/i&gt; by &lt;b&gt;Ward Cunningham&lt;/b&gt; describes the Meaningless Behavior Pattern and two other related patterns, the Whole Value and Exceptional Value Patterns. &lt;u&gt;This paper draws heavily from and often paraphrases Cunningham's work.&lt;/u&gt; I suggest reading Cunningham's paper. Briefly stated Cunningham is concerned with user inputs and separating good input from bad in a way that doesn't result in complicated code.&lt;br /&gt;&lt;br /&gt;My paper does not introduce new concepts but instead is a report of existing concepts from my current perspective.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size: large;"&gt;Null Object Pattern&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;The Null Object Pattern is not a replacement for exception handling or returning error values from functions. As with any object the NullObject is concerned with a particular set of behaviors. If you are modeling something that has various run-time behaviors then the Strategy Pattern is often used. If one of the valid behaviors for the object is "do nothing" then the do nothing strategy for this object has a special name, the NullObject. There is no rule that says you have to use the strategy pattern to arrive at the NullObject. You could implement an interface in two ways, one way being the "do nothing" or NullObject and the other way being the "do something" behavior.&lt;br /&gt;&lt;br /&gt;When considering the run-time behavior of an object you should include this question: "Is doing nothing a valid behavior?". By asking yourself this question during design you are identifying correct behavior and exceptional conditions. By identifying more fully all of the run-time behaviors of an object you can properly identify the set of exceptional conditions. This can result in fewer errors to be signaled but it is not a replacement for an error signaling mechanism.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size: large;"&gt;Whole Value&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;The C++ like programming languages (C++, Java, C#) provide the ability to use literal values, value types, types defined in a standard library, and the ability to create your own types that are meaningful in the domain you are working. When deciding the type of object you will use to hold your domain data you should use a type that will be complete and have the whole/entire set of information and operations needed and have a name that is meaningful.&lt;br /&gt;&lt;br /&gt;Remember, Cunningham is concerned with capturing data at the user interface and taking that data into the domain logic (business logic) of the system. By acquiring data that is correct at the UI the business logic can be simpler, easier to read, and more intent revealing if it is not cluttered with checks for bad data.&lt;br /&gt;&lt;br /&gt;During the design of the business logic Cunningham points out that it is tempting to select the object types from the simplest or most fundamental types available. If my business logic uses customer names it is tempting to represent the name with a String. If my business logic uses current balance it is tempting to represent this value with a float or a decimal multiplied by the literal value 10. The value is the business information but don't forget the type of the value is business information as well. If, while reading some code, you come across a variable of type String can you say what the value is other than a string? If you define a domain type of UserName then you know if you come across a variable of type UserName that it is a user's name in the context of the system.&lt;br /&gt;&lt;br /&gt;I recently worked with a system that had two database tables for storing user information. Both of these tables used a unique key field. The older table used a long value, the newer table a string value. While studying the code I became confused when I saw a method that like this:&lt;br /&gt;&lt;br /&gt;void DoSomethingForUser(string id)&lt;br /&gt;&lt;br /&gt;I assumed that the method worked with the newer table. The assumption came from the input parameter being a string. Down in the implementation of the method the string was converted a long value and was used with the older table.&lt;br /&gt;&lt;br /&gt;Consider these two methods:&lt;br /&gt;&lt;br /&gt;int GetUserId(string customerName)&lt;br /&gt;&lt;br /&gt;string GetUserId(int userId )&lt;br /&gt;&lt;br /&gt;The return value doesn't express what type of user Id it is returning. It could be an 'old' Id or a 'new' Id for either method. A Whole Value would be this:&lt;br /&gt;&lt;br /&gt;DurangoUserId GetUserId(CustomerName)&lt;br /&gt;&lt;br /&gt;WarpUserId GetUserId(DurangoUserId&amp;nbsp; )&lt;br /&gt;&lt;br /&gt;Using Whole Values I can read the methods and understand what they do. The old system is code named Durango. The new system is code named Warp. One method takes a customer name and returns a Durango user Id. The other method converts a Durango user Id into a Warp user Id.&lt;br /&gt;&lt;br /&gt;Cunningham warns that you should not extend your Whole Values to include or accept unexpected or exceptional values.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size: large;"&gt;Exceptional Value&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Trying to anticipate all of the values a user might enter into an input field in a UI is not feasible. The designer must come up with the set of acceptable values or valid domain values that are the Whole Values. Also the designer must plan for the unexpected. Cunningham suggests specifying one or more types to represent the exceptional values.&lt;br /&gt;&lt;br /&gt;These types either return another exceptional value type or reject any method invocation. Cunningham states that it should not be necessary to explicitly test for exceptional values in methods because they will either absorb messages or produce Meaningless Behavior.&lt;br /&gt;&lt;br /&gt;Recall that this pattern is concerned with user input. A user can input any data they want into a UI. Dealing with unexpected input is what the Exceptional Value pattern is about.&amp;nbsp; Exceptional value handling is done extremely close to the UI.&lt;br /&gt;&lt;br /&gt;When working with a UI the pattern of development is something like this:&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; Get user input value from UI widget&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; Generate domain or business object from value&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; Echo the domain object's value back by putting it back into the UI widget&lt;br /&gt;&lt;br /&gt;Imagine these steps if the UI widget is to collect a date. Let's go through the steps to see how this works with an expected value and then an exceptional value.&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; User enters 10/7/2005&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; Domain object for Date is generated.&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; The Date object normalizes dates to be October 7, 2005. So the input widget is immediately updated with the normalized date representation upon the echo.&lt;br /&gt;&lt;br /&gt;And now for an exceptional value:&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; User enters 120 Cherry Street, Lexington, Kentucky&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; Domain object is generated, but since this is not a date the object returned from the generator/factory is an Exceptional Value object for Dates.&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; The Date Exceptional Value object echoes its value back to the UI, which is nothing, so the UI date field ends up being blank.&lt;br /&gt;&lt;br /&gt;The key to this is that the same three steps work for the valid and the invalid input. The code is clean and intent revealing. Remember, these patterns are about user input and cleaner code, and really nothing more.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size: large;"&gt;Meaningless Behavior&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Business rules change. If you have ever worked on an ECommerce system I ask you, "How many times have the pricing rules or product definitions changed?" Since business rules are constantly changing the developer should adhere to the advice of "writing the simplest thing that works". Trying to anticipate future changes will just create code that will forever be maintained regardless of whether or not the future changes actually followed that path. Design the business logic without concerns for possible failure and expect the UI that initiated the execution to handle possible failures. At the UI layer if there is a failure output should remain blank because any other output is an attempt to attach meaning to meaningless behavior. The user will learn that blank output is caused by invalid inputs (paraphrasing Cunningham).&lt;br /&gt;&lt;br /&gt;Meaningless Behavior can be viewed as an alternate implementation of Exceptional Value. Use Meaningless Value if you cannot anticipate the condition as meaningful in your business domain.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size: large;"&gt;Conclusion&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;NullObject, Exceptional Value, or Meaningless Behavior is not a replacement for signaling errors, whether the error signaling mechanism is Exceptions or Return Values.&lt;br /&gt;&lt;br /&gt;When designing the objects in your system ask yourself if the object has a valid "does nothing" state. If so, then consider the NullObject pattern to handle that state.&lt;br /&gt;&lt;br /&gt;When designing domain/business objects make Whole Value types to represent the data and the domain concept. Do not be overly tempted to use the most fundamental type (such as int or string) to represent domain data.&lt;br /&gt;&lt;br /&gt;At the transition layer of user input data and domain data consider generating Exceptional Value and Meaningless Behavior types when the user's input is not expected, exceptional, or out of bounds.&lt;br /&gt;&lt;br /&gt;Refer to Cunningham's original work on these topics.&lt;br /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/36645098-9021739994940094988?l=digerati-illuminatus.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://digerati-illuminatus.blogspot.com/feeds/9021739994940094988/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=36645098&amp;postID=9021739994940094988' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/36645098/posts/default/9021739994940094988'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/36645098/posts/default/9021739994940094988'/><link rel='alternate' type='text/html' href='http://digerati-illuminatus.blogspot.com/2012/01/null-object-whole-value-exceptional.html' title='Null Object, Whole  Value, Exceptional Value, and Meaningless Behavior Patterns'/><author><name>Geoff Slinker</name><uri>http://www.blogger.com/profile/12365501393247949005</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-36645098.post-5497905088646763</id><published>2011-02-14T09:47:00.000-08:00</published><updated>2011-02-14T09:51:28.411-08:00</updated><title type='text'>work = duty + character</title><content type='html'>I have often spoken about work, especially during the discussions of Maverick Software Development.&lt;br /&gt;&lt;br /&gt;In physics I learned:&lt;br /&gt;&lt;br /&gt;work = force X distance   (w = f*d)&lt;br /&gt;&lt;br /&gt;However, what about work when we are talking about a career?&lt;br /&gt;&lt;br /&gt;work = duty + character&lt;br /&gt;&lt;br /&gt;The work one has done at the end of the day, the quality of the work, the results of the work, and the market for which the work is done is reflected by the worker's understanding of duty and their individual character.&lt;br /&gt;&lt;br /&gt;Think about that.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/36645098-5497905088646763?l=digerati-illuminatus.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://digerati-illuminatus.blogspot.com/feeds/5497905088646763/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=36645098&amp;postID=5497905088646763' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/36645098/posts/default/5497905088646763'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/36645098/posts/default/5497905088646763'/><link rel='alternate' type='text/html' href='http://digerati-illuminatus.blogspot.com/2011/02/work-duty-character.html' title='work = duty + character'/><author><name>Geoff Slinker</name><uri>http://www.blogger.com/profile/12365501393247949005</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-36645098.post-2439808562265815228</id><published>2011-01-03T11:05:00.000-08:00</published><updated>2011-01-03T11:22:00.944-08:00</updated><title type='text'>Performance Optimizations Harden Code</title><content type='html'>Performance optimizations harden code for specific situations. Once the code is running then optimization is considered. The code is profiled for very specific situations. Inefficiencies are identified and if these inefficiencies are addressed with true refactoring then the code base isn't necessarily hardened. However if the inefficiencies require rearchitecturing, either at the micro level or the macro, the code is hardened.&lt;br /&gt;&lt;br /&gt;For instance, if the inefficiency is simply changing a for loop, either by removing nested loops or moving invariants outside of the loop then this is simple refactoring.&lt;br /&gt;&lt;br /&gt;If the inefficiency has to be addressed with caching and object lifespan management then every new feature will experience additional cost of development in order to work in this more complex system. This type of optimization is done through architectural changes. Other optimizations that require rearchitecture include the introduction of threading, asynchronous calls, lazy loading, etc.&lt;br /&gt;&lt;br /&gt;Sometimes new features will conflict so much with the optimized architecture that either the new feature is not added or the optimization code has to be unwound, untangled, and removed. From my experience trying to remove an optimization is too expensive. By their nature the optimization is highly coupled.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/36645098-2439808562265815228?l=digerati-illuminatus.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://digerati-illuminatus.blogspot.com/feeds/2439808562265815228/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=36645098&amp;postID=2439808562265815228' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/36645098/posts/default/2439808562265815228'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/36645098/posts/default/2439808562265815228'/><link rel='alternate' type='text/html' href='http://digerati-illuminatus.blogspot.com/2011/01/performance-optimizations-harden-code.html' title='Performance Optimizations Harden Code'/><author><name>Geoff Slinker</name><uri>http://www.blogger.com/profile/12365501393247949005</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-36645098.post-7994027057732423570</id><published>2010-12-29T08:58:00.000-08:00</published><updated>2010-12-29T12:06:01.989-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Extreme Programming'/><category scheme='http://www.blogger.com/atom/ns#' term='Biases'/><category scheme='http://www.blogger.com/atom/ns#' term='Fallacies'/><category scheme='http://www.blogger.com/atom/ns#' term='XP'/><category scheme='http://www.blogger.com/atom/ns#' term='Agile'/><category scheme='http://www.blogger.com/atom/ns#' term='SCRUM'/><title type='text'>Cognitive Biases in Agile Process, Agile Leaders, Agile Practitioners, and Agile User Group Participants</title><content type='html'>Recently I have been studying cognitive biases. I soon began to think that, "If a person or group of persons value certain biases and they compose some method or process are these biases passed on to the process and are they evident in the process?"&lt;br /&gt;&lt;br /&gt;For reference I will use Wikipedia's entry for a list of &lt;a href="http://en.wikipedia.org/wiki/List_of_cognitive_biases"&gt;Cognitive Biases&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;Also, I will use Wikipedia's entry for &lt;a href="http://en.wikipedia.org/wiki/Agile_software_development"&gt;Agile Software Development&lt;/a&gt; and the&lt;a href="http://en.wikipedia.org/wiki/Agile_software_development#Agile_Manifesto"&gt; Agile Manifesto&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;Of course anything I report will be affected by my own personal biases, as with any report, but this should not cause one to avoid the task but instead to recognize the reality that human bias manifests itself.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Anchoring &lt;/span&gt;– the common human tendency to rely too heavily, or "anchor," on one trait or piece of information when making decisions.&lt;br /&gt;&lt;br /&gt;Agile Leaders state their opinion that software development had become heavily anchored to processes, tools, comprehensive documentation, contract negotiation, and following a plan.&lt;br /&gt;&lt;br /&gt;Agile Leaders recognized the value of these "anchors" but proposed that such biases may actually have adverse affects in software development.&lt;br /&gt;&lt;br /&gt;Agile processes reflect the belief of the agile leaders manifesting a shift from these traditional anchors by placing individuals, working software, customer collaboration, and response to change on one side of the balance and the traditional anchors on the other, with the scale tipping in favored weight for the new agile values.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Bandwagon effect&lt;/span&gt; – the tendency to do (or believe) things because many other people do (or believe) the same. Related to groupthink and herd behavior.&lt;br /&gt;&lt;br /&gt;In my opinion the majority of participants in any software process, traditional or agile, are those on the bandwagon. Bandwagon participation may be justified by an authority bias in that one will say, "Most everyone in the industry is following this process and the process has been defined and recommended by several industry leaders." This opinion coincides with my experience in following company efforts in adopting agile processes.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Bias blind spot&lt;/span&gt; – the tendency to see oneself as less biased than other people.&lt;br /&gt;&lt;br /&gt;I believe that many agile practitioners and agile user group participants suffer from the blind spot bias. &lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Confirmation bias&lt;/span&gt; – the tendency to search for or interpret information in a way that confirms one's preconceptions.&lt;br /&gt;&lt;br /&gt;Many arguments, contentions, and heated debates between different schools of thought concerning software development have their premise based upon building blocks gathered specifically to confirm one's preconceptions. If someone finds a success story from a group that executed a waterfall approach to software development does that make that success transferable? That same goes for an agile shop.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Distinction bias&lt;/span&gt; – the tendency to view two options as more dissimilar when evaluating them simultaneously than when evaluating them separately.&lt;br /&gt;&lt;br /&gt;During the early years of the agile reformation many tried to contrast the new agile methods with traditional methods by showing them to be very dissimilar. In my opinion the similarities of all software processes are greater than their dissimilarities.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Hyperbolic discounting&lt;/span&gt; – the tendency for people to have a stronger preference for more immediate payoffs relative to later payoffs, where the tendency increases the closer to the present both payoffs are.&lt;br /&gt;&lt;br /&gt;This bias is particularly interesting in the Agile community. This one bias deserves in-depth treatment on its own. Briefly though I notice agile practitioners weigh immediate "everything" as preferred. For those that recognize such behavior as a bias it can cause conflict during planning meetings and discussions.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Illusion of control&lt;/span&gt; – the tendency to overestimate one's degree of influence over other external events.&lt;br /&gt;&lt;br /&gt;Traditional software process seemed to suffer greatly from the illusion of control. For me, the recognition of this bias, was one of the main motivators for me to try and figure out a better way to develop software. Big Upfront Design wasn't working on large projects. Therefore I had began to lay ground work for alternative approaches and to identify methods and practices that seemed to contribute to the issues. I remember the CCB, the Change Control Board, where all changes had to go through committee. When I started reading about Extreme Programming I recognized some common concerns and therefore was further intrigued. (Initially I didn't see how XP worked together and started to write a paper against the process, but as I gave real effort in creating real examples of how XP principles didn't apply I soon found that they did.)&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Irrational escalation&lt;/span&gt; – the phenomenon where people justify increased investment in a decision, based on the cumulative prior investment, despite new evidence suggesting that the decision was probably wrong.&lt;br /&gt;&lt;br /&gt;With heavy processes I have experienced this irrational escalation bias many times. "We have hundreds of pages of documentation and we just can't throw out all of that valuable work!"&lt;br /&gt;&lt;br /&gt;I see the same with code. We have tens of thousands of lines of code and we can not afford any kind of change to that base.&lt;br /&gt;&lt;br /&gt;Agile processes have offered many approaches to the avoidance of this bias. Refactoring, Test First, Continuous Builds, and many other.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Neglect of probability&lt;/span&gt; – the tendency to completely disregard probability when making a decision under uncertainty.&lt;br /&gt;&lt;br /&gt;Agile processes speak directly to uncertainty and probability. "You Aint Going To Need It" (YAGNI) is an excellent example of this.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Normalcy bias&lt;/span&gt; – the refusal to plan for, or react to, a disaster which has never happened before.&lt;br /&gt;&lt;br /&gt;Sometimes agile practitioners are accused of the normalcy bias. Through the use of the mantra "Do the simplest thing that works" leads people to believe that there is no planning for disaster. Some people may chose to not plan for disaster but I do not know of any software process that says not to be concerned with the potential of disaster.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Outcome bias&lt;/span&gt; – the tendency to judge a decision by its eventual outcome instead of based on the quality of the decision at the time it was made.&lt;br /&gt;&lt;br /&gt;I believe that agile processes are outcome bias and that the agile leaders recognized this bias and therefore recommend short delivery cycles.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Semmelweis reflex&lt;/span&gt; – the tendency to reject new evidence that contradicts an established paradigm.&lt;br /&gt;&lt;br /&gt;I believe that the adoption of any process may be effected by the Semmelweis reflex. Just as groups that practice traditional software processes have had difficulty accepting agile processes, groups that practice agile processes will have difficulty accepting some other process.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Status quo bias&lt;/span&gt; – the tendency to like things to stay relatively the same (see also loss aversion, endowment effect, and system justification).&lt;br /&gt;&lt;br /&gt;Any individual or group of people may have the status quo bias. Sometimes persons dealing with others that are rejecting some proposed change immediately label the others as suffering with status quo bias. I don't know the name of the bias of labeling others with the most commonly known biases is called, but it definitely exists. This labeling may close communication paths and make it more difficult for change. (I have found it: the fundamental attribution error,  correspondence bias or attribution effect.)&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Forward Bias&lt;/span&gt; - the tendency to create models based on past data which are validated only against that past data.&lt;br /&gt;&lt;br /&gt;This bias is tied to estimation. Someday I will have to give thought to "yesterday's weather" as compared to forward bias and the gambler's fallacy.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Primacy effect&lt;/span&gt; – the tendency to weigh initial events more than subsequent events.&lt;br /&gt;&lt;br /&gt;Traditional processes often suffer from the  primacy effect. Agile processes are not immune from the primacy effect either.&lt;br /&gt;&lt;br /&gt;In the context of source code, the primacy effect is very real. The abstract idea of code mass may be a result of the primacy effect.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Disregard of regression toward the mean&lt;/span&gt; – the tendency to expect extreme performance to continue.&lt;br /&gt;&lt;br /&gt;I feel that some advocates of new processes intentionally disregard the regression toward the mean. I have particularly noticed this in various implementations of SCRUM, where the idea is that performance increases should be expected over several months as the practitioner improves in their application of SCRUM.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Stereotyping &lt;/span&gt;– expecting a member of a group to have certain characteristics without having actual information about that individual.&lt;br /&gt;&lt;br /&gt;I feel that this happens too often in the areas of "swarming" and "cross functional team".&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Conclusion&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;I believe that biases are in full effect in the Leadership of any group and that those biases will be reflected in their proposed methods and processes.&lt;br /&gt;&lt;br /&gt;Agile Leadership recognized various biases reflected in traditional processes and addressed some of those biases.&lt;br /&gt;&lt;br /&gt;Agile practitioners and Agile user group participants manifest their particular biases as individuals and other biases associated with groups.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/36645098-7994027057732423570?l=digerati-illuminatus.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://digerati-illuminatus.blogspot.com/feeds/7994027057732423570/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=36645098&amp;postID=7994027057732423570' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/36645098/posts/default/7994027057732423570'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/36645098/posts/default/7994027057732423570'/><link rel='alternate' type='text/html' href='http://digerati-illuminatus.blogspot.com/2010/12/cognitive-biases-in-agile-process-agile.html' title='Cognitive Biases in Agile Process, Agile Leaders, Agile Practitioners, and Agile User Group Participants'/><author><name>Geoff Slinker</name><uri>http://www.blogger.com/profile/12365501393247949005</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-36645098.post-6099471634648721324</id><published>2010-09-29T14:20:00.000-07:00</published><updated>2010-09-29T16:54:49.110-07:00</updated><title type='text'>What is "Software Seasoning"?</title><content type='html'>I have been reading an interview with the late Hiromu Naruse entitled "&lt;a href="http://gazoo.com/racing/english/grmn/meister/vol_01/index.asp"&gt;What is 'Automotive Seasoning'?&lt;/a&gt;".&lt;br /&gt;&lt;br /&gt;Naruse was known as a "meister of automobile manufacturing".&lt;br /&gt;&lt;br /&gt;Naruse compares the inception, creation, and completion of an automobile to that of preparing a culinary dish. For me the analogy is clear and meaningful. I love automobiles and I drive as many different types as possible. It doesn't matter if the automobile is a Honda Civic or a BMW 3 series, I enjoy "tasting" each vehicle and judging if the automobile was satisfying in its role.&lt;br /&gt;&lt;br /&gt;Is there flavor to software products? I believe so. I will follow the flow of Naruse's interview and compare it to software.&lt;br /&gt;&lt;br /&gt;The performance of the software, the minimum system requirements, the list of features, and other "specs" of the software are simply the ingredients. Having all of the "right" features does not determine the quality of the software or whether it will impress the users.&lt;br /&gt;&lt;br /&gt;The goal of "software seasoning" is to provide the customer with the optimal product. Just as there are many different types of cars made for many different purposes and many different dishes there are many different types of software, from text editors, to games, from shell's to windowing environments. The flavor of the software should be adjusted to its specific characteristics.&lt;br /&gt;&lt;br /&gt;What are software characteristics? Two important ones are "flow" and "use". The software will have a purpose for which it is used and the work will progress with a certain flow. Complex software will have "inner" activities that will have their own flow. In that sense software can be similar to an entire meal instead of just a single dish. Each "inner" activity would be like a course of the meal.&lt;br /&gt;&lt;br /&gt;Refactoring software is not "seasoning" software. The seasoning of software is centered around how the user feels about the product. The fine tuning or seasoning of software results in true user satisfaction.&lt;br /&gt;&lt;br /&gt;A software user's experience can be changed greatly by moving an item in the "flow" or positioning a control in a different location.&lt;br /&gt;&lt;br /&gt;Naruse describes the quality of the ride of an automobile is related to the "logitudinal G-force". The quality of the software user's experience can be enhanced by such well known things as uses multiple threads to complete the initialization of the software thus giving the user the ability to interact with portions of the software sooner while other portions are still loading. I relate this to how the courses of a meal are delivered. While you are eating the soup the salad is being prepared. If you ordered your meal and then had to wait until all the courses where prepared before any course was delivered the overall experience would be tainted by the initial long wait.&lt;br /&gt;&lt;br /&gt;Everyone knows about using multiple threads for initialization, but since we all know about that practice it makes it an excellent example. When the technique first came into practice those that used it had a more seasoned product than those that did not. Now that practice is common to all and therefore not interesting anymore. It is up to you to find new ways to season your software.&lt;br /&gt;&lt;br /&gt;Naruse makes an interesting observation, "most people cannot really tell the difference between high-end brand clothes and relatively inexpensive clothes simply by looking at them, but when worn, the differences become apparent."&lt;br /&gt;&lt;br /&gt;Looking at feature lists and screen shots is not sufficient to determine the flavor of a software product. Usage allow the difference to become apparent.&lt;br /&gt;&lt;br /&gt;Naruse also points out that we get tired of food that tastes too good. That is interesting. Do people get tired of software that is too good? I can think of examples where this is the case. I will leave that as an exercise for you to see if you agree.&lt;br /&gt;&lt;br /&gt;True flavor comes out after years of use. This is an interesting point. Software changes quickly and often very drastically. Naruse says, "It has been commonly said that people get tired of a beauty after three days. With a car, as in the case of my dear wife, the true flavor comes out after years of being together, through thick and thin. As with one’s spouse, it is the odd imperfection that gives a car its unique character and appeal."&lt;br /&gt;&lt;br /&gt;If you have ever participated in a major change of a well established software product there is often a quick and vocal expression of dissatisfaction with the new flavor of the software.&lt;br /&gt;&lt;br /&gt;Removing all imperfections does not create quality. I like McDonald's fries because of their particular "over" saltiness. I can not sit down and eat McDonald's fries all day long because they are too salty for that. But they are "just right too salty" for certain occasions! I also like the fries from "Five Guys" and from "In N Out" but if you combined all three of these fries to make the perfect french fry do you think you will succeed? In other words, there are times when I like the salty quality of McDonald's fries.&lt;br /&gt;&lt;br /&gt;Naruse, again, makes another very interesting observation:&lt;br /&gt;"When adding seasoning, it is necessary to determine one’s own flavor. Even if you were to conduct a survey and ask customers what kinds of flavor they want, you wouldn’t find the answer there. Rather, there are two possible questions that you could ask customers. Does it taste good or bad? Or, do you want to eat it again or not? This is because customers are not professionals, and if you increase or decrease the salt according to customer requests, the flavor will gradually become peculiar. There is no sense in seeking a middle of the road taste that practically no-one would dislike."&lt;br /&gt;&lt;br /&gt;This is interesting because many software processes feel that continuous customer input is the only way to arrive at a quality product. This is very interesting. I have studied the development of the iPod and found that the product was kept secret and did not use continuous customer involvement. Are there lessons here?&lt;br /&gt;&lt;br /&gt;Can a software process be developed that will produce software that has qualities that appeal to users, such quality that the user will spend their money to own the product? It is arguable that all software processes try to lay some claim in that area.&lt;br /&gt;&lt;br /&gt;Naruse states in the interview, "At one point, there was an attempt to quantify my know-how and create a manual. In the end, however, it didn’t turn out well. This is because know-how is not the same as knowledge. Results such as 'in this type of situation, I used this kind of countermeasure' are no more than solutions for specific problems. What is important is asking how the solution was reached, or why something was done the way it was. This is what we call technique or craftsmanship. Craftsmanship is not handed down through education. Things that are learnt from others passively will never be useful. What is necessary is 'nurturing.' In other words, you will not learn unless you feel that you must do something and want to do something and have the desire to learn and to take from others. Craftsmanship is handed down in implicit knowledge."&lt;br /&gt;&lt;br /&gt;This too is very interesting when considering software process, the teaching of a particular software process, and the expectation of a particular quality result from the process. Is your method of instructing developers on how to write quality software more like a manual of knowledge or more like a nurturing system of sharing know-how?&lt;br /&gt;&lt;br /&gt;Naruse states that the racetrack creates the flavor of cars. "Races are the best forum for handing down craftsmanship and nurturing human resources. Unexpected things happen all the time and things that must be done out of necessity occur constantly. It is necessary to skillfully and accurately solve problems with limited time and tools. These types of things do not happen within a computer, but happen right before our eyes. It is under these extreme conditions that we focus entirely on winning the race and work as hard as we possibly can. The word “can’t” does not exist at the racetrack. This type of experience builds our character, and builds cars. Both the drivers and engineers focus their five senses to engage in a dialogue with the car under the extreme conditions of the race. It is through this dialogue that the perfect flavor becomes visible" - Naruse.&lt;br /&gt;&lt;br /&gt;Do you develop software at the racetrack or in the shop? Did you notice that dialog is the key? Dialog between professionals, between craftsmen, that bring skill to the situation. The approach is based on "go and see". See it in use. Push it in use. Break it in use. Go and see, don't imagine it, don't talk about it, don't have meetings to talk about it, but go and see.&lt;br /&gt;&lt;br /&gt;Finally there has to be someone that is responsible for the "flavor" of the software. Until that one person gives the okay the software cannot be sold. This statement might not be readily accepted or understood by most. Some might quickly argue that Naruse is Japanese and "they" are different. Maybe Japanese are different than Americans, and Americans different than Europeans, and maybe they are not. I feel that we are more alike than different. At least those of us that have come to recognize the difference is a worker and a craftsman, a stone cutter versus a cathedral builder.&lt;br /&gt;&lt;br /&gt;There can be democracy in a software development team. The freedom to fine-tune your work area, your work process, and the things for which you have responsibility. But ultimately the flavor being expressed will be that of one chef. If you are a cook but want to act like a chef you might become frustrated. If you want to be a chef then be one. Do not complain if you are a cook and treated as one.&lt;br /&gt;&lt;br /&gt;The software that many work on will have no particular taste, and will require no particular seasoning. But for those lucky developers that work on software that is valued and sought after, that brings some modicum of satisfaction to the user, those developers should be aware of the need for "flavor" and work together like the racing team through dialog to hand down craftsmanship and through "going" and "seeing" that the correct flavor will be made manifest.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/36645098-6099471634648721324?l=digerati-illuminatus.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://digerati-illuminatus.blogspot.com/feeds/6099471634648721324/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=36645098&amp;postID=6099471634648721324' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/36645098/posts/default/6099471634648721324'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/36645098/posts/default/6099471634648721324'/><link rel='alternate' type='text/html' href='http://digerati-illuminatus.blogspot.com/2010/09/what-is-software-seasoning.html' title='What is &quot;Software Seasoning&quot;?'/><author><name>Geoff Slinker</name><uri>http://www.blogger.com/profile/12365501393247949005</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-36645098.post-8809298207374147958</id><published>2010-08-10T11:38:00.000-07:00</published><updated>2010-08-10T12:46:35.785-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='.NET'/><category scheme='http://www.blogger.com/atom/ns#' term='Covariance'/><category scheme='http://www.blogger.com/atom/ns#' term='C#'/><category scheme='http://www.blogger.com/atom/ns#' term='Generic Delegates'/><category scheme='http://www.blogger.com/atom/ns#' term='contravariance'/><title type='text'>Covariance and Contravariance and Generic Delegates</title><content type='html'>Generic Delegates now use the modifiers "in" and "out" with .NET 4.&lt;br /&gt;&lt;br /&gt;"Out" is associated with return values and covariance.&lt;br /&gt;"In" is associated with input parameters(method arguments) and contravariance.&lt;br /&gt;&lt;br /&gt;I use the following classes and relationships throughout this blog post.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;class A { }&lt;br /&gt;class B : A { }&lt;br /&gt;class C : B { }&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Object "is a" Object =&gt; true.&lt;br /&gt;Object "is a" A =&gt; false.&lt;br /&gt;Object "is a" B =&gt; false.&lt;br /&gt;Object "is a"  C =&gt; false.&lt;br /&gt;&lt;br /&gt;A "is a" Object =&gt; true.&lt;br /&gt;A "is a" A =&gt; true.&lt;br /&gt;A "is a" B =&gt; false.&lt;br /&gt;A "is a" C =&gt; false.&lt;br /&gt;&lt;br /&gt;B "is a" Object =&gt; true.&lt;br /&gt;B "is a" A =&gt; true.&lt;br /&gt;B "is a" B =&gt; true.&lt;br /&gt;B "is a" C =&gt; false.&lt;br /&gt;&lt;br /&gt;C "is a" Object =&gt; true.&lt;br /&gt;C "is a" A =&gt; true.&lt;br /&gt;C "is a" B =&gt; true.&lt;br /&gt;C "is a" C =&gt; true.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Covariance&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;  //-----------------------------------------------&lt;br /&gt;  public delegate R DCovariant&amp;lt;out R&amp;gt;( );&lt;br /&gt;&lt;br /&gt;  //-----------------------------------------------&lt;br /&gt;  //Methods that match the Covariant Signature&lt;br /&gt;&lt;br /&gt;  public static object CovariantObjectMethod( )&lt;br /&gt;  {&lt;br /&gt;      return new object( );&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;  public static A CovariantAMethod( )&lt;br /&gt;  {&lt;br /&gt;      return new A( );&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;  public static B CovariantBMethod( )&lt;br /&gt;  {&lt;br /&gt;      return new B( );&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;  public static C CovariantCMethod( )&lt;br /&gt;  {&lt;br /&gt;      return new C( );&lt;br /&gt;  }&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Delegate "DCovariant" is an example of using "out" to specify a covariant delegate. Covariance is concerned with the return type of the delegate.&lt;br /&gt;&lt;br /&gt;Any covariant delegate can be assigned any method that matches the signature of the delegate and the return type of the method satisfies the "is a" relationship with the return type of the delegate.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;       DCovariant&amp;lt;object&amp;gt; dCovObj = CovariantObjectMethod;&lt;br /&gt;       DCovariant&amp;lt;A&amp;gt; dCovA = CovariantAMethod;&lt;br /&gt;       DCovariant&amp;lt;B&amp;gt; dCovB = CovariantBMethod;&lt;br /&gt;       DCovariant&amp;lt;C&amp;gt; dCovC = CovariantCMethod;&lt;br /&gt;&lt;br /&gt;       dCovObj = CovariantAMethod;&lt;br /&gt;       dCovObj = CovariantBMethod;&lt;br /&gt;       dCovObj = CovariantCMethod;&lt;br /&gt;&lt;br /&gt;       //dCovA = CovarianteObjectMethod; //wrong return type.&lt;br /&gt;       dCovA = CovariantBMethod;&lt;br /&gt;       dCovA = CovariantCMethod;&lt;br /&gt;&lt;br /&gt;       //dCovB = CovarianteObjectMethod; //wrong return type.&lt;br /&gt;       //dCovB = CovarianteAMethod; //wrong return type.&lt;br /&gt;       dCovB = CovariantCMethod;&lt;br /&gt;&lt;br /&gt;       //dCovC = CovarianteObjectMethod; //wrong return type.&lt;br /&gt;       //dCovC = CovarianteAMethod; //wrong return type.&lt;br /&gt;       //dCovC = CovarianteBMethod; //wrong return type.&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Consider the declaration:&lt;br /&gt;DCovariant&amp;lt;object&amp;gt; dCovObj&lt;br /&gt;&lt;br /&gt;This delegate's return type is Object, so therefore any method that matches the delegate signature and returns something that is an object may be assigned to dConObj.&lt;br /&gt;&lt;br /&gt;DCovariant&amp;lt;A&amp;gt; dCovA can be assigned any method that matches the delegate signature and returns something that "is a" A.&lt;br /&gt;&lt;br /&gt;DCovariant&amp;lt;B&amp;gt; dCovB can be assigned any method that matches the delegate signature and returns something that "is a" B.&lt;br /&gt;&lt;br /&gt;DCovariant&amp;lt;C&amp;gt; dCovC can be assigned any method that matches the delegate signature and returns something that "is a" C.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Contravariance&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;      //-----------------------------------------------&lt;br /&gt;      public delegate void DContravariant&amp;lt;in T&amp;gt;( T t );&lt;br /&gt;&lt;br /&gt;      //-----------------------------------------------&lt;br /&gt;      //Methods that match the Contravariant Signature&lt;br /&gt;&lt;br /&gt;      public static void ContravariantObjectMethod( Object o )&lt;br /&gt;      {&lt;br /&gt;      }&lt;br /&gt;&lt;br /&gt;      public static void ContravariantAMethod( A a )&lt;br /&gt;      {&lt;br /&gt;      }&lt;br /&gt;&lt;br /&gt;      public static void ContravariantBMethod( B b )&lt;br /&gt;      {&lt;br /&gt;      }&lt;br /&gt;&lt;br /&gt;      public static void ContravariantCMethod( C c )&lt;br /&gt;      {&lt;br /&gt;      }&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Above are declared a contravariant delegate using the "in" modifier and four methods that match the signature of the contravariant delegate.&lt;br /&gt;&lt;br /&gt;Below I have declared and assigned four DContravariant delegates. The types used are Object, A, B, and C.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;          //Contravariant&lt;br /&gt;          DContravariant&amp;lt;object&amp;gt; dContravarObj = ContravariantObjectMethod;&lt;br /&gt;          DContravariant&amp;lt;A&amp;gt; dContravarA = ContravariantAMethod;&lt;br /&gt;          DContravariant&amp;lt;B&amp;gt; dContravarB = ContravariantBMethod;&lt;br /&gt;          DContravariant&amp;lt;C&amp;gt; dContravarC = ContravariantCMethod;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Below I have declared and instantiated an object of each type and then invoke each delegate with each type.&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;          Object o = new Object( );&lt;br /&gt;          A a = new A( );&lt;br /&gt;          B b = new B( );&lt;br /&gt;          C c = new C( );&lt;br /&gt;&lt;br /&gt;          dContravarObj( o );&lt;br /&gt;          dContravarObj( a );&lt;br /&gt;          dContravarObj( b );&lt;br /&gt;          dContravarObj( c );&lt;br /&gt;&lt;br /&gt;          //dContravarA( o );   //Argument 1: cannot convert from...&lt;br /&gt;          dContravarA( a );&lt;br /&gt;          dContravarA( b );&lt;br /&gt;          dContravarA( c );&lt;br /&gt;&lt;br /&gt;          //dContravarB( o );   //Argument 1: cannot convert from...&lt;br /&gt;          //dContravarB( a );   //Argument 1: cannot convert from...&lt;br /&gt;          dContravarB( b );&lt;br /&gt;          dContravarB( c );&lt;br /&gt;&lt;br /&gt;          //dContravarC( o );   //Argument 1: cannot convert from...&lt;br /&gt;          //dContravarC( a );   //Argument 1: cannot convert from...&lt;br /&gt;          //dContravarC( b );   //Argument 1: cannot convert from...&lt;br /&gt;          dContravarC( c );&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Notice that there are compile time errors where the input argument could not be converted to the proper type.&lt;br /&gt;&lt;br /&gt;dContravarObj can accept all of the variables as arguments because they all satisfy the "is a" relationship with Object.&lt;br /&gt;&lt;br /&gt;dContravarA can accept variables of type Object and A.&lt;br /&gt;dContravarB can accept variables of type Object, A, and B.&lt;br /&gt;dContravarC can accept variables of type Object, A, B, and C.&lt;br /&gt;&lt;br /&gt;The contraviance and the use of "in" plays its role when assigning methods with different signatures to the delegate. Below are the results.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;          //dContravarObj = ContravariantAMethod;   //no overload matches delegate...&lt;br /&gt;          //dContravarObj = ContravariantBMethod;   //no overload matches delegate...&lt;br /&gt;          //dContravarObj = ContravariantCMethod;   //no overload matches delegate...&lt;br /&gt;&lt;br /&gt;          dContravarA = ContravariantObjectMethod;&lt;br /&gt;          //dContravarA = ContravariantBMethod;   //no overload matches delegate...&lt;br /&gt;          //dContravarA = ContravariantCMethod;   //no overload matches delegate...&lt;br /&gt;&lt;br /&gt;          dContravarB = ContravariantObjectMethod;&lt;br /&gt;          dContravarB = ContravariantAMethod;&lt;br /&gt;          //dContravarB = ContravariantCMethod;   //no overload matches delegate...&lt;br /&gt;&lt;br /&gt;          dContravarC = ContravariantObjectMethod;&lt;br /&gt;          dContravarC = ContravariantAMethod;&lt;br /&gt;          dContravarC = ContravariantBMethod;&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Notice that any method may be assigned to any delegate if:&lt;br /&gt;The &lt;span style="font-weight: bold;"&gt;delegate&lt;/span&gt;'s input argument satisfies the &lt;span style="font-weight: bold;"&gt;"is a"&lt;/span&gt; relationship with the &lt;span style="font-weight: bold;"&gt;method&lt;/span&gt;'s input argument.&lt;br /&gt;&lt;br /&gt;Finally to tie this all together I will use the most derived class "C" and the corresponding delegate and assign it the method with the lease derived class "Object".&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;            //Invocations&lt;br /&gt;            dContravarC = ContravariantObjectMethod;&lt;br /&gt;            //dContravarC( o );   //Argument 1: cannot convert from...&lt;br /&gt;            //dContravarC( a );   //Argument 1: cannot convert from...&lt;br /&gt;            //dContravarC( b );   //Argument 1: cannot convert from...&lt;br /&gt;            dContravarC( c );&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Eventhough the ContravarianteObjectMethod can take any of our classes as input the delegate signature for dContravarC is DContravariant&amp;lt;C&amp;gt; and therefore the method invocation can only accept objects that "is a" C.&lt;br /&gt;&lt;br /&gt;To help illustrate this I will assign dContravarB since class B is in the "middle" of the derivation.&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;            dContravarB = ContravariantObjectMethod;&lt;br /&gt;            //dContravarB( o );   //Argument 1: cannot convert from...&lt;br /&gt;            //dContravarB( a );   //Argument 1: cannot convert from...&lt;br /&gt;            dContravarB( b );&lt;br /&gt;            dContravarB( c );&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Notice that the delegate invocation will only accept things that satisfy the "is a" relationship with class B, which is class B and class C.&lt;br /&gt;&lt;br /&gt;Following is the complete listing of the example code:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;using System;&lt;br /&gt;using System.Collections.Generic;&lt;br /&gt;using System.Linq;&lt;br /&gt;using System.Text;&lt;br /&gt;&lt;br /&gt;namespace GenericDelegateModifiers&lt;br /&gt;{&lt;br /&gt;    class A { }&lt;br /&gt;    class B : A { }&lt;br /&gt;    class C : B { }&lt;br /&gt;&lt;br /&gt;    class Program&lt;br /&gt;    {&lt;br /&gt;        //-----------------------------------------------&lt;br /&gt;        public delegate R DCovariant&amp;lt;out R&amp;gt;( );&lt;br /&gt;&lt;br /&gt;        //-----------------------------------------------&lt;br /&gt;        //Methods that match the Covariant Signature&lt;br /&gt;&lt;br /&gt;        public static object CovariantObjectMethod( )&lt;br /&gt;        {&lt;br /&gt;            return new object( );&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        public static A CovariantAMethod( )&lt;br /&gt;        {&lt;br /&gt;            return new A( );&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        public static B CovariantBMethod( )&lt;br /&gt;        {&lt;br /&gt;            return new B( );&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        public static C CovariantCMethod( )&lt;br /&gt;        {&lt;br /&gt;            return new C( );&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        //-----------------------------------------------&lt;br /&gt;        public delegate void DContravariant&amp;lt;in T&amp;gt;( T t );&lt;br /&gt;&lt;br /&gt;        //-----------------------------------------------&lt;br /&gt;        //Methods that match the Contravariant Signature&lt;br /&gt;&lt;br /&gt;        public static void ContravariantObjectMethod( Object o )&lt;br /&gt;        {&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        public static void ContravariantAMethod( A a )&lt;br /&gt;        {&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        public static void ContravariantBMethod( B b )&lt;br /&gt;        {&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        public static void ContravariantCMethod( C c )&lt;br /&gt;        {&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        //-----------------------------------------------&lt;br /&gt;&lt;br /&gt;        static void Main( string[] args )&lt;br /&gt;        {&lt;br /&gt;            //-----------------------------------------------&lt;br /&gt;            //Covariant&lt;br /&gt;            DCovariant&amp;lt;object&amp;gt; dCovObj = CovariantObjectMethod;&lt;br /&gt;            DCovariant&amp;lt;A&amp;gt; dCovA = CovariantAMethod;&lt;br /&gt;            DCovariant&amp;lt;B&amp;gt; dCovB = CovariantBMethod;&lt;br /&gt;            DCovariant&amp;lt;C&amp;gt; dCovC = CovariantCMethod;&lt;br /&gt;&lt;br /&gt;            dCovObj = CovariantAMethod;&lt;br /&gt;            dCovObj = CovariantBMethod;&lt;br /&gt;            dCovObj = CovariantCMethod;&lt;br /&gt;&lt;br /&gt;            //dCovA = CovarianteObjectMethod; //wrong return type.&lt;br /&gt;            dCovA = CovariantBMethod;&lt;br /&gt;            dCovA = CovariantCMethod;&lt;br /&gt;&lt;br /&gt;            //dCovB = CovarianteObjectMethod; //wrong return type.&lt;br /&gt;            //dCovB = CovarianteAMethod; //wrong return type.&lt;br /&gt;            dCovB = CovariantCMethod;&lt;br /&gt;&lt;br /&gt;            //dCovC = CovarianteObjectMethod; //wrong return type.&lt;br /&gt;            //dCovC = CovarianteAMethod; //wrong return type.&lt;br /&gt;            //dCovC = CovarianteBMethod; //wrong return type.&lt;br /&gt;&lt;br /&gt;            //-----------------------------------------------&lt;br /&gt;            //Contravariant&lt;br /&gt;            DContravariant&amp;lt;object&amp;gt; dContravarObj = ContravariantObjectMethod;&lt;br /&gt;            DContravariant&amp;lt;A&amp;gt; dContravarA = ContravariantAMethod;&lt;br /&gt;            DContravariant&amp;lt;B&amp;gt; dContravarB = ContravariantBMethod;&lt;br /&gt;            DContravariant&amp;lt;C&amp;gt; dContravarC = ContravariantCMethod;&lt;br /&gt;&lt;br /&gt;            Object o = new Object( );&lt;br /&gt;            A a = new A( );&lt;br /&gt;            B b = new B( );&lt;br /&gt;            C c = new C( );&lt;br /&gt;&lt;br /&gt;            dContravarObj( o );&lt;br /&gt;            dContravarObj( a );&lt;br /&gt;            dContravarObj( b );&lt;br /&gt;            dContravarObj( c );&lt;br /&gt;&lt;br /&gt;            //dContravarA( o );   //Argument 1: cannot convert from...&lt;br /&gt;            dContravarA( a );&lt;br /&gt;            dContravarA( b );&lt;br /&gt;            dContravarA( c );&lt;br /&gt;&lt;br /&gt;            //dContravarB( o );   //Argument 1: cannot convert from...&lt;br /&gt;            //dContravarB( a );   //Argument 1: cannot convert from...&lt;br /&gt;            dContravarB( b );&lt;br /&gt;            dContravarB( c );&lt;br /&gt;&lt;br /&gt;            //dContravarC( o );   //Argument 1: cannot convert from...&lt;br /&gt;            //dContravarC( a );   //Argument 1: cannot convert from...&lt;br /&gt;            //dContravarC( b );   //Argument 1: cannot convert from...&lt;br /&gt;            dContravarC( c );&lt;br /&gt;&lt;br /&gt;            //dContravarObj = ContravariantAMethod;   //no overload matches delegate...&lt;br /&gt;            //dContravarObj = ContravariantBMethod;   //no overload matches delegate...&lt;br /&gt;            //dContravarObj = ContravariantCMethod;   //no overload matches delegate...&lt;br /&gt;&lt;br /&gt;            dContravarA = ContravariantObjectMethod;&lt;br /&gt;            //dContravarA = ContravariantBMethod;   //no overload matches delegate...&lt;br /&gt;            //dContravarA = ContravariantCMethod;   //no overload matches delegate...&lt;br /&gt;&lt;br /&gt;            dContravarB = ContravariantObjectMethod;&lt;br /&gt;            dContravarB = ContravariantAMethod;&lt;br /&gt;            //dContravarB = ContravariantCMethod;   //no overload matches delegate...&lt;br /&gt;&lt;br /&gt;            dContravarC = ContravariantObjectMethod;&lt;br /&gt;            dContravarC = ContravariantAMethod;&lt;br /&gt;            dContravarC = ContravariantBMethod;&lt;br /&gt;&lt;br /&gt;            //Invocations&lt;br /&gt;            dContravarC = ContravariantObjectMethod;&lt;br /&gt;            //dContravarC( o );   //Argument 1: cannot convert from...&lt;br /&gt;            //dContravarC( a );   //Argument 1: cannot convert from...&lt;br /&gt;            //dContravarC( b );   //Argument 1: cannot convert from...&lt;br /&gt;            dContravarC( c );&lt;br /&gt;&lt;br /&gt;            dContravarB = ContravariantObjectMethod;&lt;br /&gt;            //dContravarB( o );   //Argument 1: cannot convert from...&lt;br /&gt;            //dContravarB( a );   //Argument 1: cannot convert from...&lt;br /&gt;            dContravarB( b );&lt;br /&gt;            dContravarB( c );&lt;br /&gt;&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/36645098-8809298207374147958?l=digerati-illuminatus.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://digerati-illuminatus.blogspot.com/feeds/8809298207374147958/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=36645098&amp;postID=8809298207374147958' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/36645098/posts/default/8809298207374147958'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/36645098/posts/default/8809298207374147958'/><link rel='alternate' type='text/html' href='http://digerati-illuminatus.blogspot.com/2010/08/covariance-and-contravariance-and_10.html' title='Covariance and Contravariance and Generic Delegates'/><author><name>Geoff Slinker</name><uri>http://www.blogger.com/profile/12365501393247949005</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-36645098.post-8599665021970908868</id><published>2010-08-09T17:02:00.000-07:00</published><updated>2010-08-10T11:40:22.919-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='.NET'/><category scheme='http://www.blogger.com/atom/ns#' term='Generics'/><category scheme='http://www.blogger.com/atom/ns#' term='Covariance'/><category scheme='http://www.blogger.com/atom/ns#' term='C#'/><category scheme='http://www.blogger.com/atom/ns#' term='contravariance'/><title type='text'>Covariance and Contravariance and Generic Interfaces</title><content type='html'>Generic Interfaces now use the modifiers "in" and "out" with .NET 4.&lt;br /&gt;&lt;br /&gt;"Out" is associated with return values and covariance.&lt;br /&gt;"In" is associated with input parameters (method arguments) and contravariance.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Covariance&lt;/span&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;// Covariant interface.&lt;br /&gt;interface ICovariant&amp;lt;out R&amp;gt; { }&lt;br /&gt;&lt;br /&gt;// Extending covariant interface.&lt;br /&gt;interface IExtCovariant&amp;lt;out R&amp;gt; : ICovariant&amp;lt;R&amp;gt; { }&lt;br /&gt;&lt;br /&gt;// Implementing covariant interface.&lt;br /&gt;class SampleCovariant&amp;lt;R&amp;gt; : ICovariant&amp;lt;R&amp;gt; { }&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;The generic type parameter has "out" as a modifier. The "out" declaration can be used if the type parameter is used only as a return type of interface methods and not used as a type of method arguments.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;&lt;br /&gt;ICovariant&amp;lt;Object&amp;gt; covObj = new SampleCovariant&amp;lt;Object&amp;gt;( );&lt;br /&gt;ICovariant&amp;lt;String&amp;gt; covStr = new SampleCovariant&amp;lt;String&amp;gt;( );&lt;br /&gt;&lt;br /&gt;//covStr = covObj; //Cannot implicitly convert type ICovariant&amp;lt;object&amp;gt; to ICovariante&amp;lt;string&amp;gt;. An explicit conversion exists (are you mssing a cast?)&lt;br /&gt;&lt;br /&gt;// You can assign covStr to covObj because the ICovariant interface is covariant.&lt;br /&gt;covObj = covStr;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;String "is a" Object =&gt; true&lt;br /&gt;Object "is a" String =&gt; false&lt;br /&gt;&lt;br /&gt;(see : &lt;a href="http://digerati-illuminatus.blogspot.com/2010/08/covariance-and-contravariance-for.html"&gt;Covariance and Contravariance for Delegates in C#&lt;/a&gt;)&lt;br /&gt;&lt;br /&gt;Since string is an object then the instance of SampleConvariant&lt;string&gt; can be assigned to the interface ICovariant&amp;lt;out R&amp;gt;.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Contravariance&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;// Contravariant interface.&lt;br /&gt;interface IContravariant&amp;lt;in A&amp;gt; { }&lt;br /&gt;&lt;br /&gt;// Extending contravariant interface.&lt;br /&gt;interface IExtContravariant&amp;lt;in A&amp;gt; : IContravariant&amp;lt;A&amp;gt; { }&lt;br /&gt;&lt;br /&gt;// Implementing contravariant interface.&lt;br /&gt;class SampleContravariant&amp;lt;A&amp;gt; : IContravariant&amp;lt;A&amp;gt; { }&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;The generic type parameter has "in" as a modifier. The "in" declaration can be used if the type parameter is used only as a type of method arguments and not used as a return type of interface methods.&lt;br /&gt;&lt;br /&gt;&lt;/string&gt;String "is a" Object =&gt; true&lt;br /&gt;Object "is a" String =&gt; false&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;     IContravariant&amp;lt;Object&amp;gt; contraObj = new SampleContravariant&amp;lt;Object&amp;gt;( );&lt;br /&gt;     IContravariant&amp;lt;String&amp;gt; contraStr = new SampleContravariant&amp;lt;String&amp;gt;( );&lt;br /&gt;&lt;br /&gt;     //contraObj = contraStr; //Cannot implicitly convert IContravariant&amp;lt;string&amp;gt; to IContravariant&amp;lt;object&amp;gt;. An explicit conversion exists (are you missing a cast?)&lt;br /&gt;&lt;br /&gt;     // You can assign contraObj to contraStr because the IContravariant interface is contravariant.&lt;br /&gt;     contraStr = contraObj;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Since we are dealing with arguments (input parameters) and a string is an object you can assign an instance of IContravariant &amp;lt;Object&amp;gt; to  IContravariant&amp;lt;String&amp;gt;.&lt;br /&gt;&lt;br /&gt;As I am writing this I recognize that the above statement is not clear, even to me. That is because the example code is insufficient. I based the example code on MSDN code. So, let us continue now with a better example.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;interface IBetterContravariant&amp;lt;in T&amp;gt;&lt;br /&gt;{&lt;br /&gt;  void MyMethod( T t );&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;class BetterContravariant&amp;lt;T&amp;gt; : IBetterContravariant&amp;lt;T&amp;gt;&lt;br /&gt;{&lt;br /&gt;  #region IBetterContravariant&amp;lt;T&amp;gt; Members&lt;br /&gt;&lt;br /&gt;  public void MyMethod( T t )&lt;br /&gt;  {&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;  #endregion&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;This better example now has a method with a generic input parameter of type &amp;lt;in T&amp;gt; because the interface is contravariant.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;           IBetterContravariant&amp;lt;Object&amp;gt; betterContraObj = new BetterContravariant&amp;lt;Object&amp;gt;( );&lt;br /&gt;           IBetterContravariant&amp;lt;String&amp;gt; betterContraString = new BetterContravariant&amp;lt;String&amp;gt;( );&lt;br /&gt;&lt;br /&gt;           String s = "text";&lt;br /&gt;           Object o = new object( );&lt;br /&gt;&lt;br /&gt;           betterContraObj.MyMethod( s );&lt;br /&gt;           betterContraObj.MyMethod( o );&lt;br /&gt;&lt;br /&gt;           betterContraString.MyMethod( s );&lt;br /&gt;           //betterContraString.MyMethod( o ); //Error: Arugment 1: cannot convert 'object' to 'string'&lt;br /&gt;&lt;br /&gt;           //betterContraObj = betterContraString; //Cannot implicitly convert... error&lt;br /&gt;&lt;br /&gt;           // You can assign betterContraObj to betterContraString because IBetterContravariant interface is contravariant&lt;br /&gt;           betterContraString = betterContraObj;&lt;br /&gt;&lt;br /&gt;           betterContraString.MyMethod( s );&lt;br /&gt;           //betterContraString.MyMethod( o ); //Error: Arugment 1: cannot convert 'object' to 'string'&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Notice that I have instantiated a String and an Object. Before betterContraString is assigned betterContraObj I invoke the "MyMethod" method on each instance of IBetterContravariant twice, once passing a String and then passing an Object.&lt;br /&gt;&lt;br /&gt;Notice that betterContraObject.MyMethod accepts a String or an Object and there are no compile time errors. This is because a String "is a" Object.&lt;br /&gt;&lt;br /&gt;Notice that betterContraString.MyMethod accepts a String however it does not accept an Object. This is because an Object is NOT a String.&lt;br /&gt;&lt;br /&gt;Since betterContraObject accepts Strings (as well as Objects) it can be assigned to betterContraString.&lt;br /&gt;&lt;br /&gt;Notice in the example code that after betterContraString is assigned betterContraObject that betterContraString still only accepts Strings as input to MyMethod. This is because betterContrString is still an interface to IBetterContravariant&amp;lt;String&amp;gt;. The interface did not change because of the assignment.&lt;br /&gt;&lt;br /&gt;Here is all of the example source code.&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;using System;&lt;br /&gt;using System.Collections.Generic;&lt;br /&gt;using System.Linq;&lt;br /&gt;using System.Text;&lt;br /&gt;&lt;br /&gt;namespace GenericModifiers&lt;br /&gt;{&lt;br /&gt;    interface IDefault&amp;lt;R&amp;gt; { }&lt;br /&gt;    class SampleDefault&amp;lt;R&amp;gt; : IDefault&amp;lt;R&amp;gt; { }&lt;br /&gt;&lt;br /&gt;    //---------------------------------------------------------&lt;br /&gt;&lt;br /&gt;    // Covariant interface.&lt;br /&gt;    interface ICovariant&amp;lt;out R&amp;gt; { }&lt;br /&gt;&lt;br /&gt;    // Extending covariant interface.&lt;br /&gt;    interface IExtCovariant&amp;lt;out R&amp;gt; : ICovariant&amp;lt;R&amp;gt; { }&lt;br /&gt;&lt;br /&gt;    // Implementing covariant interface.&lt;br /&gt;    class SampleCovariant&amp;lt;R&amp;gt; : ICovariant&amp;lt;R&amp;gt; { }&lt;br /&gt;&lt;br /&gt;    //---------------------------------------------------------&lt;br /&gt;&lt;br /&gt;    // Contravariant interface.&lt;br /&gt;    interface IContravariant&amp;lt;in A&amp;gt; { }&lt;br /&gt;&lt;br /&gt;    // Extending contravariant interface.&lt;br /&gt;    interface IExtContravariant&amp;lt;in A&amp;gt; : IContravariant&amp;lt;A&amp;gt; { }&lt;br /&gt;&lt;br /&gt;    // Implementing contravariant interface.&lt;br /&gt;    class SampleContravariant&amp;lt;A&amp;gt; : IContravariant&amp;lt;A&amp;gt; { }&lt;br /&gt;&lt;br /&gt;    //---------------------------------------------------------&lt;br /&gt;&lt;br /&gt;    //Better Contravariant interface example&lt;br /&gt;&lt;br /&gt;    interface IBetterContravariant&amp;lt;in T&amp;gt;&lt;br /&gt;    {&lt;br /&gt;        void MyMethod( T t );&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    class BetterContravariant&amp;lt;T&amp;gt; : IBetterContravariant&amp;lt;T&amp;gt;&lt;br /&gt;    {&lt;br /&gt;        #region IBetterContravariant&amp;lt;T&amp;gt; Members&lt;br /&gt;&lt;br /&gt;        public void MyMethod( T t )&lt;br /&gt;        {&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        #endregion&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    //---------------------------------------------------------&lt;br /&gt;&lt;br /&gt;    class Program&lt;br /&gt;    {&lt;br /&gt;        static void Main( string[] args )&lt;br /&gt;        {&lt;br /&gt;            IDefault&amp;lt;Object&amp;gt; dobj = new SampleDefault&amp;lt;Object&amp;gt;( );&lt;br /&gt;            IDefault&amp;lt;String&amp;gt; dstr = new SampleDefault&amp;lt;String&amp;gt;( );&lt;br /&gt;&lt;br /&gt;            //dstr = dobj; //Cannot implicitly convert type IDefault&amp;lt;object&amp;gt; to IDefault&amp;lt;string&amp;gt;. An explicit conversion exists (are you mssing a cast?)&lt;br /&gt;            //dobj = dstr; //Cannot implicitly convert type IDefault&amp;lt;string&amp;gt; to IDefault&amp;lt;object&amp;gt;. An explicit conversion exists (are you mssing a cast?)&lt;br /&gt;&lt;br /&gt;            //---------------------------------------------------------&lt;br /&gt;&lt;br /&gt;            ICovariant&amp;lt;Object&amp;gt; covObj = new SampleCovariant&amp;lt;Object&amp;gt;( );&lt;br /&gt;            ICovariant&amp;lt;String&amp;gt; covStr = new SampleCovariant&amp;lt;String&amp;gt;( );&lt;br /&gt;&lt;br /&gt;            //covStr = covObj; //Cannot implicitly convert type ICovariant&amp;lt;object&amp;gt; to ICovariante&amp;lt;string&amp;gt;. An explicit conversion exists (are you mssing a cast?)&lt;br /&gt;&lt;br /&gt;            // You can assign covStr to covObj because the ICovariant interface is covariant.&lt;br /&gt;            covObj = covStr;&lt;br /&gt;&lt;br /&gt;            //---------------------------------------------------------&lt;br /&gt;            IContravariant&amp;lt;Object&amp;gt; contraObj = new SampleContravariant&amp;lt;Object&amp;gt;( );&lt;br /&gt;            IContravariant&amp;lt;String&amp;gt; contraStr = new SampleContravariant&amp;lt;String&amp;gt;( );&lt;br /&gt;&lt;br /&gt;            //contraObj = contraStr; //Cannot implicitly convert IContravariant&amp;lt;string&amp;gt; to IContravariant&amp;lt;object&amp;gt;. An explicit conversion exists (are you missing a cast?)&lt;br /&gt;&lt;br /&gt;            // You can assign contraObj to contraStr because the IContravariant interface is contravariant.&lt;br /&gt;            contraStr = contraObj;&lt;br /&gt;&lt;br /&gt;            //---------------------------------------------------------&lt;br /&gt;            IBetterContravariant&amp;lt;Object&amp;gt; betterContraObj = new BetterContravariant&amp;lt;Object&amp;gt;( );&lt;br /&gt;            IBetterContravariant&amp;lt;String&amp;gt; betterContraString = new BetterContravariant&amp;lt;String&amp;gt;( );&lt;br /&gt;&lt;br /&gt;            String s = &amp;quot;text&amp;quot;;&lt;br /&gt;            Object o = new object( );&lt;br /&gt;&lt;br /&gt;            betterContraObj.MyMethod( s );&lt;br /&gt;            betterContraObj.MyMethod( o );&lt;br /&gt;&lt;br /&gt;            betterContraString.MyMethod( s );&lt;br /&gt;            //betterContraString.MyMethod( o ); //Error: Arugment 1: cannot convert &amp;apos;object&amp;apos; to &amp;apos;string&amp;apos;&lt;br /&gt;&lt;br /&gt;            //betterContraObj = betterContraString; //Cannot implicitly convert... error&lt;br /&gt;&lt;br /&gt;            // You can assign betterContraObj to betterContraString because IBetterContravariant interface is contravariant&lt;br /&gt;            betterContraString = betterContraObj;&lt;br /&gt;&lt;br /&gt;            betterContraString.MyMethod( s );&lt;br /&gt;            //betterContraString.MyMethod( o ); //Error: Arugment 1: cannot convert &amp;apos;object&amp;apos; to &amp;apos;string&amp;apos;&lt;br /&gt;&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/36645098-8599665021970908868?l=digerati-illuminatus.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://digerati-illuminatus.blogspot.com/feeds/8599665021970908868/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=36645098&amp;postID=8599665021970908868' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/36645098/posts/default/8599665021970908868'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/36645098/posts/default/8599665021970908868'/><link rel='alternate' type='text/html' href='http://digerati-illuminatus.blogspot.com/2010/08/covariance-and-contravariance-and.html' title='Covariance and Contravariance and Generic Interfaces'/><author><name>Geoff Slinker</name><uri>http://www.blogger.com/profile/12365501393247949005</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-36645098.post-5789601677966736765</id><published>2010-08-09T08:56:00.000-07:00</published><updated>2010-08-10T11:41:10.422-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='delegates'/><category scheme='http://www.blogger.com/atom/ns#' term='.NET'/><category scheme='http://www.blogger.com/atom/ns#' term='convariance'/><category scheme='http://www.blogger.com/atom/ns#' term='C#'/><category scheme='http://www.blogger.com/atom/ns#' term='contravariance'/><title type='text'>Covariance and Contravariance for Delegates in C#</title><content type='html'>.NET 4 introduces new usages for covariance and contravariance.&lt;br /&gt;&lt;br /&gt;From MSDN:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style: italic; font-weight: bold;"&gt;Covariance &lt;/span&gt;and &lt;span style="font-style: italic; font-weight: bold;"&gt;contravariance &lt;/span&gt;provide a degree of flexibility when matching method signatures with &lt;span style="font-weight: bold;"&gt;delegate &lt;/span&gt;types. Covariance permits a method to have a more derived return type than what is defined in the delegate. Contravariance permits a method with parameter types that are less derived than in the delegate type.&lt;br /&gt;&lt;br /&gt;What helps me understand this variance stuff is to base it around the "is a" relationship.&lt;br /&gt;&lt;br /&gt;class A {}&lt;br /&gt;class B : A{}&lt;br /&gt;class C: B{}&lt;br /&gt;&lt;br /&gt;A "is a" B =&gt; false&lt;br /&gt;A "is a" C =&gt; false&lt;br /&gt;&lt;br /&gt;B "is a" A =&gt; true&lt;br /&gt;B "is a "C =&gt; false&lt;br /&gt;&lt;br /&gt;C "is a" A =&gt; true&lt;br /&gt;C "is a" B =&gt; true&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Return type of delegate signatures&lt;/span&gt; &lt;span style="font-weight: bold;"&gt;(Covariance)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;public delegate A HandlerMethodA();&lt;br /&gt;&lt;br /&gt;The return type of the delegate is "A".&lt;br /&gt;&lt;br /&gt;Speaking solely about the return type in this example, any method that returns something that "is a" A can be used as the delegate method.&lt;br /&gt;&lt;br /&gt;public static A FirstHandler() { return null; }&lt;br /&gt;public static B SecondHandler(){return null;}&lt;br /&gt;public static C ThirdHandler(){return null;}&lt;br /&gt;&lt;br /&gt;All three of these methods can be used as a delegate method for delegate HandlerMethodA.&lt;br /&gt;&lt;br /&gt;public delegate B HandlerMethodB();&lt;br /&gt;&lt;br /&gt;HandlerMethodB signature has the return type of B. Therefore only SecondHandler and ThirdHandler can be used as methods for the delegate HandlerMethodB.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Parameter types of delegate signatures (Contravariance)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Using the same classes above, A, B, and C, we define a new delegates:&lt;br /&gt;&lt;br /&gt;public delegate void HandlerMethodC(C c);&lt;br /&gt;&lt;br /&gt;public static void FirstHandler(A a) { }&lt;br /&gt;public static void SecondHandler(B b){}&lt;br /&gt;public static void ThirdHandler(C c){}&lt;br /&gt;&lt;br /&gt;All three of these methods can be used as a delegate method for delegate HandlerMethodC.&lt;br /&gt;&lt;br /&gt;The reason is that a variable of type C can be passed to any of these handlers.&lt;br /&gt;The delegate signature parameter "is a" delegate method parameter.&lt;br /&gt;C "is a" A is true.&lt;br /&gt;B "is a" A is true.&lt;br /&gt;A "is a" A is true.&lt;br /&gt;&lt;br /&gt;Consider another delegate:&lt;br /&gt;public delegate void HandlerMethodB(B b);&lt;br /&gt;&lt;br /&gt;Only methods that can accept B as the parameter type can be assigned to the delegate HandlerMethodB.&lt;br /&gt;&lt;br /&gt;FirstHandler and SecondHandler methods  may be assigned to the delegate HandlerMethodB.&lt;br /&gt;FirstHandler method can accept B types as well as A and C.&lt;br /&gt;SecondHandler method can accept B types as well as C.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;ThirdHandler cannot be assigned to delegate HandlerMethodB because there is no overload for ThirdHandler that matches the delegate.&lt;br /&gt;ThirdHandler method can only accept C types.&lt;br /&gt;Since the delegate signature is of type B, third handler cannot be used.&lt;br /&gt;&lt;br /&gt;Regardless of which methods may be assigned to HandlerMethodC or HandlerMethodB the delegate will only accept variables that "are" of the type defined by the delegate's signature.&lt;br /&gt;&lt;br /&gt;HandlerMethodC may only be invoked with a parameter of type C.&lt;br /&gt;HanlderMethodB may be invoked with a parameter of type C or B.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;I recommend reading:&lt;br /&gt;&lt;a href="http://blogs.msdn.com/b/ericlippert/archive/2009/11/30/what-s-the-difference-between-covariance-and-assignment-compatibility.aspx"&gt;http://blogs.msdn.com/b/ericlippert/archive/2009/11/30/what-s-the-difference-between-covariance-and-assignment-compatibility.aspx&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;a href="http://geekswithblogs.net/Martinez/articles/covariance-contravariance-and-invariance-in-c-language.aspx"&gt;http://geekswithblogs.net/Martinez/articles/covariance-contravariance-and-invariance-in-c-language.aspx&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Here is my code I used to better understand Convariance and Contravariance for Delegates in C#.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;using System;&lt;br /&gt;using System.Collections.Generic;&lt;br /&gt;using System.Linq;&lt;br /&gt;using System.Text;&lt;br /&gt;&lt;br /&gt;namespace VarianceExperiments&lt;br /&gt;{&lt;br /&gt;    class A&lt;br /&gt;    {&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    class B : A&lt;br /&gt;    {&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    class C : B&lt;br /&gt;    {&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    class Program&lt;br /&gt;    {&lt;br /&gt;        public delegate A CovarianceHandlerA( );&lt;br /&gt;        public delegate B CovarianceHandlerB( );&lt;br /&gt;        public delegate C CovarianceHandlerC( );&lt;br /&gt;&lt;br /&gt;        public delegate void ContravarianceHandlerA( A a );&lt;br /&gt;        public delegate void ContravarianceHandlerB( B b );&lt;br /&gt;        public delegate void ContravarianceHandlerC( C c );&lt;br /&gt;&lt;br /&gt;        public static A CoHandlerA( ) { return new A( ); }&lt;br /&gt;        public static B CoHandlerB( ) { return new B( ); }&lt;br /&gt;        public static C CoHandlerC( ) { return new C( ); }&lt;br /&gt;&lt;br /&gt;        public static void ContraHandlerA( A a ) { }&lt;br /&gt;        public static void ContraHandlerB( B b ) { }&lt;br /&gt;        public static void ContraHandlerC( C c ) { }&lt;br /&gt;&lt;br /&gt;        static void Main( string[] args )&lt;br /&gt;        {&lt;br /&gt;            A a = new A();&lt;br /&gt;            B b = new B();&lt;br /&gt;            C c = new C();&lt;br /&gt;&lt;br /&gt;            Console.WriteLine( &amp;quot;A is a B =&amp;gt; {0}&amp;quot;, ( a is B ) );&lt;br /&gt;            Console.WriteLine( &amp;quot;A is a C =&amp;gt; {0}&amp;quot;, ( a is C ) );&lt;br /&gt;&lt;br /&gt;            Console.WriteLine( &amp;quot;B is a A =&amp;gt; {0}&amp;quot;, ( b is A ) );&lt;br /&gt;            Console.WriteLine( &amp;quot;B is a C =&amp;gt; {0}&amp;quot;, ( b is C ) );&lt;br /&gt;&lt;br /&gt;            Console.WriteLine( &amp;quot;C is a A =&amp;gt; {0}&amp;quot;, ( c is A ) );&lt;br /&gt;            Console.WriteLine( &amp;quot;C is a B =&amp;gt; {0}&amp;quot;, ( c is B ) );&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;            CovarianceHandlerA coHandler = CoHandlerA;&lt;br /&gt;            A coResult = coHandler( );&lt;br /&gt;            Console.WriteLine( &amp;quot;coResults is a A =&amp;gt; {0}, is a B =&amp;gt; {1},&lt;br /&gt;                               is a C =&amp;gt; {2}&amp;quot;, ( coResult is A ), &lt;br /&gt;                               ( coResult is B ), ( coResult is C ) );&lt;br /&gt;&lt;br /&gt;            coHandler = CoHandlerB;&lt;br /&gt;            coResult = coHandler( );&lt;br /&gt;            Console.WriteLine( &amp;quot;coResults is a A =&amp;gt; {0}, is a B =&amp;gt; {1},&lt;br /&gt;                               is a C =&amp;gt; {2}&amp;quot;, ( coResult is A ), &lt;br /&gt;                               ( coResult is B ), ( coResult is C ) );&lt;br /&gt;&lt;br /&gt;            coHandler = CoHandlerC;&lt;br /&gt;            coResult = coHandler( );&lt;br /&gt;            Console.WriteLine( &amp;quot;coResults is a A =&amp;gt; {0}, is a B =&amp;gt; {1},&lt;br /&gt;                               is a C =&amp;gt; {2}&amp;quot;, ( coResult is A ), &lt;br /&gt;                               ( coResult is B ), ( coResult is C ) );&lt;br /&gt;&lt;br /&gt;            //---------------------------------------------------------------&lt;br /&gt;&lt;br /&gt;            ContravarianceHandlerC contraHandlerC = ContraHandlerA;&lt;br /&gt;            //contraHandlerC( a ); //Error: Argument 1: cannot convert A to C&lt;br /&gt;            //contraHandlerC( b ); //Error: Argument 1: cannot convert B to C&lt;br /&gt;            contraHandlerC( c );&lt;br /&gt;&lt;br /&gt;            contraHandlerC = ContraHandlerB;&lt;br /&gt;            //contraHandlerC( a ); //Error: Argument 1: cannot convert A to C&lt;br /&gt;            //contraHandlerC( b ); //Error: Argument 1: cannot convert B to C&lt;br /&gt;            contraHandlerC( c );&lt;br /&gt;&lt;br /&gt;            contraHandlerC = ContraHandlerC;&lt;br /&gt;            //contraHandlerC( a ); //Error: Argument 1: cannot convert A to C&lt;br /&gt;            //contraHandlerC( b ); //Error: Argument 1: cannot convert B to C&lt;br /&gt;            contraHandlerC( c );&lt;br /&gt;&lt;br /&gt;            //---------------------------------------------------------------&lt;br /&gt;&lt;br /&gt;            ContravarianceHandlerB contraHandlerB = ContraHandlerA;&lt;br /&gt;            //contraHandlerB( a ); //Error: Argument 1: cannot convert A to B&lt;br /&gt;            contraHandlerB( b );&lt;br /&gt;            contraHandlerB( c );&lt;br /&gt;&lt;br /&gt;            contraHandlerB = ContraHandlerB;&lt;br /&gt;            //contraHandlerB( a ); //Error: Argument 1: cannot convert A to B&lt;br /&gt;            contraHandlerB( b );&lt;br /&gt;            contraHandlerB( c );&lt;br /&gt;&lt;br /&gt;            //contraHandlerB = ContraHandlerC; //No overload for ContrHandlerC matches delegate ContravarianceHandlerB&lt;br /&gt;&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/36645098-5789601677966736765?l=digerati-illuminatus.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://digerati-illuminatus.blogspot.com/feeds/5789601677966736765/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=36645098&amp;postID=5789601677966736765' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/36645098/posts/default/5789601677966736765'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/36645098/posts/default/5789601677966736765'/><link rel='alternate' type='text/html' href='http://digerati-illuminatus.blogspot.com/2010/08/covariance-and-contravariance-for.html' title='Covariance and Contravariance for Delegates in C#'/><author><name>Geoff Slinker</name><uri>http://www.blogger.com/profile/12365501393247949005</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-36645098.post-2082766264140499703</id><published>2010-07-30T09:10:00.000-07:00</published><updated>2010-07-30T12:30:55.661-07:00</updated><title type='text'>WIP and the Developer</title><content type='html'>Work in Progress (WIP) at the individual developer's level is the point of view for this blog post.&lt;br /&gt;&lt;br /&gt;WIP for an individual developer (for this blog) is defined as any prioritized item in the backlog/work queue for the developer. The backlog works as any simple priority queue, take the next item with the highest priority. (Starvation of items is acceptable!)&lt;br /&gt;&lt;br /&gt;First, a manufacturing analogy.&lt;br /&gt;&lt;br /&gt;Suppose you are on an assembly line where you attach three widgets to a gadget. You take the gadget from a bin (your backlog) and line up "widget 1", insert screw, and tighten, then line up "widget 2", insert screw, and tighten, and finally line up "widget 3", insert screw, and tighten, and then place the widgetfied gadget into a completion bin (inventory).&lt;br /&gt;&lt;br /&gt;Could you gain performance if the process was changed to this:&lt;br /&gt;Take gadget from bin, line up "widget 1", insert screw, and tighten, place in bin. Do this for all gadgets with widget 1. Then take gadget with widget 1 from bin, line up "widget 2", insert screw, and tighten, and place in bin. Do this for each gadget until all of widget 2 attached and then do this for widget 3 and place results in inventory bin.&lt;br /&gt;&lt;br /&gt;Of course the answer depends. It depends on many things.&lt;br /&gt;&lt;br /&gt;If all three widgets use the same screw, and thus the same screw driver, then it might be faster to  stay with the original approach.&lt;br /&gt;&lt;br /&gt;If all three widgets use different screws then the following should be measured:&lt;br /&gt;- How long does it take to switch screw drivers and select proper screw?&lt;br /&gt;- How long does it take to reach into the bin and extract a gadget plus how long does it take to place a gadget into a completion bin?&lt;br /&gt;- How long does it take to switch position to work with different screw driver, screws, and bin (backlog)?&lt;br /&gt;&lt;br /&gt;With these measurement one can decide which approach is faster.&lt;br /&gt;&lt;br /&gt;Back to software development.&lt;br /&gt;&lt;br /&gt;If the developer's backlog contains work that is related then the developer doesn't need to retool. For instance, if the developer works on a specific feature set,  the domain is well defined, and the developer works with a small number of tools.&lt;br /&gt;&lt;br /&gt;If the developer has many areas of responsibility, front end, middle tier, database layer, web services, etc., the developer has to mentally retool to work in these different areas.&lt;br /&gt;&lt;br /&gt;In this situation the I suggest the consideration of a multiple queues for the single developer. The prioritization process is more complex, but the waste of retooling could be addressed. It may not be possible, but it should be considered. I wouldn't go too crazy with this. The reason is that if the code is being developed like a spike then the domain knowledge and flow from top to bottom is continuous and is good.&lt;br /&gt;&lt;br /&gt;Switching context on features is expensive as well. I personally find it more expensive than switch context for tools.&lt;br /&gt;&lt;br /&gt;If the developer's queue is made up of features (that are not subdivided so finely that it says, make UI change, make middle tier change, and make database change) then the developer can work on the feature from start to finish, keeping the domain context fresh and active in his mind. I prefer this approach.&lt;br /&gt;&lt;br /&gt;If two features are related, like making a horizontal hourglass chart and a vertical hourglass chart, then the only difference is layout. The developer should look at the items in his queue and take "make horizontal hourglass chart" and "make vertical hourglass chart" and change it to "make hourglass chart", "vertical layout for hourglass chart" and "horizontal layout for hourglass chart".&lt;br /&gt;&lt;br /&gt;I have been studying the idea that limiting the number of items in the work queue (the WIP) can increase throughput. This is known as Limiting WIP. It is suggested that the time to manage items in the queue is costly and therefore if the items are limited then the cost to manage them is limited.&lt;br /&gt;&lt;br /&gt;The cost to get something in the queue for a developer consists of:&lt;br /&gt;- Identifying a customer need&lt;br /&gt;- Describing it as a feature&lt;br /&gt;- Estimating its cost of deliver (time, effort, etc)&lt;br /&gt;- Prioritizing it for a release&lt;br /&gt;- Placing it into the developer's queue.&lt;br /&gt;&lt;br /&gt;Once it is in the developer's queue I do not know of any significant cost for the developer to manage the queue. So, limiting WIP for a developer seems unnecessary to me. However, if items are thrown into a developers queue that have not been through the above steps and the burden falls on the developer to define, prioritize, or other tasks then there is cost to the developer.&lt;br /&gt;&lt;br /&gt;If the developer's queue is in constant flux there could be reason to limit WIP. If product can't make up their mind on direction and one day feature A is priority one and the next feature B, and the next a whole new and never heard of feature C and then back to A then there is cost for the developer. (Are process constraints the right way to address indecisiveness?) In this case a developer's queue could be limited to five items, or one iteration's worth of tasks, and once the iteration has started the queue cannot be altered. But this is process trying to mitigate a more serious problem of indecisiveness. Granted it should be mitigated for a short term help but it is not the solution. Maybe the limited WIP could help gather metrics of cost to show to managers how expensive it is to jump from one high priority task to another, back and forth.&lt;br /&gt;&lt;br /&gt;But in a stable system limiting WIP at the developer doesn't seem advantageous to me yet. Maybe there are those that have thousands of items in the backlog. That would be a pain to manage.&lt;br /&gt;&lt;br /&gt;Limiting WIP and the product level does seem reasonable to me. Image you have thought up enough features for three product releases for a desktop application that is released annually.&lt;br /&gt;&lt;br /&gt;If all of those features are placed in a product queue and defined as follows:&lt;br /&gt;- Identifying a customer need&lt;br /&gt;- Describing it as a feature&lt;br /&gt;- Estimating its cost of deliver (time, effort, etc)&lt;br /&gt;- Prioritizing it for a release&lt;br /&gt;&lt;br /&gt;Features that do not make it in the current release need not nor should they be well defined because things will change and when it is time to place it in release queue much of the work will have been wasted. That is why "Agile" methods recommend using a high level description, one sentence, something to capture the thought and cause the proper conversation to happen at a future date.&lt;br /&gt;&lt;br /&gt;Therefore limiting WIP at the release queue seems very reasonable to me. The limit is this, only fully prepare an item for release if it is in the current release.&lt;br /&gt;&lt;br /&gt;Software features are perishable goods. Image a software feature as an apple. If you worked at an apple pealing station and your bin of apples had enough in there to keep you busy all year, I wouldn't want any of your apples after two or three works of work!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/36645098-2082766264140499703?l=digerati-illuminatus.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://digerati-illuminatus.blogspot.com/feeds/2082766264140499703/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=36645098&amp;postID=2082766264140499703' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/36645098/posts/default/2082766264140499703'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/36645098/posts/default/2082766264140499703'/><link rel='alternate' type='text/html' href='http://digerati-illuminatus.blogspot.com/2010/07/wip-and-developer.html' title='WIP and the Developer'/><author><name>Geoff Slinker</name><uri>http://www.blogger.com/profile/12365501393247949005</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-36645098.post-7662061372757989552</id><published>2010-07-29T09:37:00.000-07:00</published><updated>2010-07-29T11:20:03.583-07:00</updated><title type='text'>Work In Progress (WIP) and Little's Law</title><content type='html'>I recently made a small writeup concerning Work In Progress (WIP). I described that throughput is the results of the amount of work to be done divided by the time it takes to do the work. I threw the writeup out yesterday when I was pointed to Little's law, which is exactly what I was defining.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://www.factoryphysics.com/Principle/LittlesLaw.htm"&gt;www.factoryphysics.com/Principle/LittlesLaw.htm&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;(Note that I have had experience with line based work since a child. I grew up on a dairy farm and we went from a simple stanchion barn to what is called a double herringbone with 4 stalls on each side. This was useful for two workers but when there was only one it was too much and we removed 1 stall from each side so that it was a double 3)&lt;br /&gt;&lt;br /&gt;I am still reading about Little's law, but this much I have noticed:&lt;br /&gt;&lt;br /&gt;The key to the Inventory = Throughput X Flow Time is consistency and lack of variability in units of measure.&lt;br /&gt;&lt;br /&gt;Note that even using "cost" as the common unit it is still difficult to use in software development.&lt;br /&gt;&lt;br /&gt;Cost is unknown or varies.&lt;br /&gt;Time is unknown or varies.&lt;br /&gt;Complexity is unknown or varies.&lt;br /&gt;Congestion is unknown or varies.&lt;br /&gt;Bottlenecks are unknown or vary.&lt;br /&gt;&lt;br /&gt;All of the above issues have been concerns of every software process and software estimation technique. But note that even the best techniques still give estimations.&lt;br /&gt;&lt;br /&gt;Predictability is becoming (or maybe already is) the main selling point for software process. This is because if I were going to attempt to use Little's Law for software development I would have to bring software development into the realm of manufacturing and to do this I need predictability. In other words, I can do things to the software process to make it seem to fit better and then jump to the conclusion that if it fits well enough then Little's law still must hold.&lt;br /&gt;&lt;br /&gt;If I could get every developer on my team to divide any task into equal chunks of work then I could apply Little's law. If any task no matter the size or difficulty can be divided, redivided, and re-redivided until it is a small and consistent chunk then I can apply Little's law. If the cost of subdividing large features is to much then I can argue that there should be no large features. I could argue no large features really means that all features can be delivered incrementally and therefore there is no need for any large features.&lt;br /&gt;&lt;br /&gt;All of that arguing takes you down, not only a very narrow path, but one that is not necessarily true.&lt;br /&gt;&lt;br /&gt;For instance, releasing a product into a market that is well established requires large feature development. If I were going to break into the word processing market my first release of the software could only have plain text, no wrapping, etc., and then I would incrementally release wrapping, fonts, until finally the product has a feature set that is comparable to the competition.&lt;br /&gt;&lt;br /&gt;The "total incremental" delivery approach implies that all features can be evolved. (I would like to see that proof.)&lt;br /&gt;&lt;br /&gt;Now, can there be things learned from Little's law? Certainly. Maybe we could have a discussion about that and find ways to use it to improve software development.&lt;br /&gt;&lt;br /&gt;For instance, if you find you are enhancing exist software and roll-out is done regularly and consistently then you may be in a situation where you should subdivide large features and get your development down to the smallest reasonable "chunk size" as possible.&lt;br /&gt;&lt;br /&gt;I am doing further investigation based on this:&lt;br /&gt;"Reducing WIP in a line without making any other changes will also reduce throughput."&lt;br /&gt;&lt;br /&gt;Geoff&lt;br /&gt;&lt;br /&gt;p.s.&lt;br /&gt;(Additional Research)&lt;br /&gt;&lt;a href="http://www.shmula.com/2407/lean-and-theory-of-constraints-either-or"&gt;www.shmula.com/2407/lean-and-theory-of-constraints-either-or&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/36645098-7662061372757989552?l=digerati-illuminatus.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://digerati-illuminatus.blogspot.com/feeds/7662061372757989552/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=36645098&amp;postID=7662061372757989552' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/36645098/posts/default/7662061372757989552'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/36645098/posts/default/7662061372757989552'/><link rel='alternate' type='text/html' href='http://digerati-illuminatus.blogspot.com/2010/07/work-in-progress-wip-and-littles-law.html' title='Work In Progress (WIP) and Little&apos;s Law'/><author><name>Geoff Slinker</name><uri>http://www.blogger.com/profile/12365501393247949005</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-36645098.post-2381034132545583085</id><published>2010-07-22T16:43:00.000-07:00</published><updated>2010-07-22T17:00:00.869-07:00</updated><title type='text'>Agile and "People before Process"</title><content type='html'>As I have watched this thing called "Agile" develop I have always been looking for things to creep in that may be in violation of foundational aspects of Agile process.&lt;br /&gt;&lt;br /&gt;Okay, I do more than watch, I try to direct where I feel direction is needed. It might not be wanted but it is what I "feel" is needed. One thing that took me a while to learn is that my opinion and observation is just as good as anyone's. I tended to defer too much because I didn't understand that some people are just "word" factories continuously spewing forth informational pollution. Maybe I have become a polluter.&lt;br /&gt;&lt;br /&gt;Agile has been described and re-described and defended over an over. This is a refinement type process. It is natural.&lt;br /&gt;&lt;br /&gt;A recent description of an Agile team is "a team who's members have all of the skills necessary to complete the task." If the team doesn't have the exactly right members then it has failed this Agile qualification and therefore is not Agile and any failures cannot be attributed to Agile.&lt;br /&gt;&lt;br /&gt;Well, I am going to make up a new software process right here and right now. It is called "Superior Software Development Process" or SSDP.&lt;br /&gt;&lt;br /&gt;Superior Software Development Process requires omnipotent and omniscient members. SSDP guarantees success. If you have mere mortals on your team you cannot use SSDP.&lt;br /&gt;&lt;br /&gt;People before process. I think that is important. I recognize that people are imperfect. Sometimes imperfect people luck up and do better than expected and sometimes they chose incorrectly due to lack of experience and really mess things up.&lt;br /&gt;&lt;br /&gt;An Agile team is made up of imperfect people with limited skill sets who are willing to learn and with new information and experience continuously refine estimates and improve code quality, product quality, and user satisfaction.&lt;br /&gt;&lt;br /&gt;Agile recognizes this is a journey, that this is a growth process, that the end cannot be seen but we can guess what is coming and accept what actually comes.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/36645098-2381034132545583085?l=digerati-illuminatus.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://digerati-illuminatus.blogspot.com/feeds/2381034132545583085/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=36645098&amp;postID=2381034132545583085' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/36645098/posts/default/2381034132545583085'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/36645098/posts/default/2381034132545583085'/><link rel='alternate' type='text/html' href='http://digerati-illuminatus.blogspot.com/2010/07/agile-and-people-before-process.html' title='Agile and &quot;People before Process&quot;'/><author><name>Geoff Slinker</name><uri>http://www.blogger.com/profile/12365501393247949005</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-36645098.post-3214976331743876546</id><published>2010-07-22T16:13:00.000-07:00</published><updated>2010-07-22T16:28:29.090-07:00</updated><title type='text'>End of Iteration is not the "final exam"</title><content type='html'>The end of a development iteration should not be considered the final exam.&lt;br /&gt;&lt;br /&gt;During a semester at college for a given class there were many assignments to be turned in, there were quizzes, mid-term exams, more assignments and quizzes, and the final exam.&lt;br /&gt;&lt;br /&gt;When software development organizations adopt an iterative development process I have observed that the developers tend to over react to the iteration aspects of iterative development and forget about the full Product Plan.&lt;br /&gt;&lt;br /&gt;New iterative teams seem to overreact to anything that might interfere with their "well-define" iteration. If you get to the end of your iteration (and I am thinking about one to two week iterations) and you got less done or you got more done it is okay. The end of an iteration should not be viewed as a "final exam" and should not carry that type of weight.&lt;br /&gt;&lt;br /&gt;I believe that developers are afraid they will be judged on the results of the end of an iteration in the same manner they would be judged on the results of a product release. This should not be the case.&lt;br /&gt;&lt;br /&gt;I believe that managers are afraid as well and some how feel they need to show that they can accurately predict software delivery after ten or fewer iterations of release schedule that is made up of fifty or more iterations.&lt;br /&gt;&lt;br /&gt;I know of "agile" managers that refuse to add something to an iteration even if the developer got all of the other tasks done and there are two more days left. Is velocity really that precious? Is the manager's ability to sell up the idea that this manager can accurately predict and estimate software to such a fine degree really what is important?&lt;br /&gt;&lt;br /&gt;There is an entire Project/Product plan. Features and enhancement are gathered. These are divided into releases that could cover several versions of the product over several years. Releases are divided into iterations. Iterations are quizzes.&lt;br /&gt;&lt;br /&gt;Maybe there should be some type of "mid-term" exam where the current set of functionality is deployed to a test environment or a test installer just to see where things are at and that we are not forgetting something (like securing licenses to redistribute 3rd part components).&lt;br /&gt;&lt;br /&gt;Lighten up on the end of iteration stress that is artificial and not needed.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/36645098-3214976331743876546?l=digerati-illuminatus.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://digerati-illuminatus.blogspot.com/feeds/3214976331743876546/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=36645098&amp;postID=3214976331743876546' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/36645098/posts/default/3214976331743876546'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/36645098/posts/default/3214976331743876546'/><link rel='alternate' type='text/html' href='http://digerati-illuminatus.blogspot.com/2010/07/end-of-iteration-is-not-final-exam.html' title='End of Iteration is not the &quot;final exam&quot;'/><author><name>Geoff Slinker</name><uri>http://www.blogger.com/profile/12365501393247949005</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-36645098.post-2718591049465797938</id><published>2010-07-22T13:34:00.000-07:00</published><updated>2010-07-22T15:35:35.212-07:00</updated><title type='text'>Resources versus Teams</title><content type='html'>&lt;span style="font-weight: bold;"&gt;Scenario&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Suppose you find yourself at a software company that has 80 or more developers. The developers are assigned to teams which in turn are aligned to specific products, features, and business needs. Over the past ten years so so the company has hired and fired and people have moved around and found a team or product area that they like.&lt;br /&gt;&lt;br /&gt;The company is at a stage where it wants to deliver several initiatives that it feels will excite customers and frustrate competition. Some of the new products are defined to pull together data and functionality across teams because it is obvious to unify product functionality and leverage established value.&lt;br /&gt;&lt;br /&gt;The release schedule and product descriptions are presented to development. Teams will be required to integrate their systems. Development raises concerns because of the cost of integrating systems, team communication, scheduling, dependencies, and work that must be done on the existing systems in order to implement specific enhancements.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Response&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Product Management is alarmed by the concerns of Development.&lt;br /&gt;&lt;br /&gt;Why is it that the software doesn't readily integrate? "We" have been working together for ten years. Are the Architects doing there job?&lt;br /&gt;&lt;br /&gt;Why is communication going to be costly? Where is the professionalism that is needed at this time? Why are we silo'ed?&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Possible Reaction by Product Personnel&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Product Management looks at the developers and recognizes them as highly skilled employees that are concerned with the big picture and with company wide goals.&lt;br /&gt;&lt;br /&gt;We must break down these walls and tear down these silos. "What if we move developers around as needed, you know, if product 'X' needs integration  with product 'Y' we move the people we need to get the job done and align the reporting chain accordingly." That is being agile.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;My Remarks&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Be very careful when viewing developers, which are people, as resources. Be very careful when discounting the usefulness of teams, which are groups of people. Be very careful thinking that all you have to do is get the right skill sets/resources together and that will almost guarantee the likelihood of success.&lt;br /&gt;&lt;br /&gt;If you have development which seems silo'ed did you ever stop to think that maybe that is just a negative adjective "silo'ed" and what you really have is development divided along products that run efficiently and almost autonomously?&lt;br /&gt;&lt;br /&gt;I argue that every team has some aspects of self organization. Through the hiring, the firing, and the team transfers, teams settle into a state that is acceptable both to the team members and well as to management. Even if your team is ran by a dictator you can still quit so anyone that remains on the team does so by choice.&lt;br /&gt;&lt;br /&gt;I argue that any outward examination of a development organization may describe the organization as silo'ed. A well defined organization will always have well defined attributes that may be described as walls. Any skilled debater knows to use adjectives that are commonly viewed as a negativity to advocate their agenda. Possibly this silo'ed and walled development organization is really a self organized team aligned specifically to product needs and technological needs.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Possible Solution&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Listen to development's concerns and then give them a week to propose solutions. If development's concerns are not about implementation and delivery but are about the products and features themselves then management may need to take the time to explain why these are the "right" products and features. This can be done with information from real customers. If you are thinking, "Developers don't need to know why we want these products and features they just need to do the job they were hired to do which is write software and implement the things we demand", then you should reconsider what a developer really is. A developer is more than a coder. Developers use software all day, every day, and have valuable experience in recognizing good software.&lt;br /&gt;&lt;br /&gt;Developers understand that when deciding a product schedule that costs are to be considered and some ideas will not make it to the table because of some unacceptable attribute. They know that some ideas for a product can be described easily and with few words but just because everyone can understand an idea because of common experience which gives way for simple descriptions doesn't mean the software will be simple, short, or easy to develop.&lt;br /&gt;&lt;br /&gt;Listen to the concerns of the developers and then give them a week to come up with solutions. Developers are problem solvers. Let them solve the problem. If development comes back and says the product cannot be developed then you have to ask why? It can't be developed because it will take longer than acceptable? It can't be developed because the existing list of things to do are higher priority or have been overlooked to often and these things have to be done before anyone can even guess what additional functionality might cost in time and effort. It can't be done because the technologies you want to integrate will not integrate because of data mapping issues.&lt;br /&gt;&lt;br /&gt;There are many reasons why things cannot be done now. An interesting question is, "If it can't be done now what does it take to get things so that we can do it in the future and when will that be?"&lt;br /&gt;&lt;br /&gt;Listen and ask for solutions and give time to come up with solutions.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Pet Peeve&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;I really cannot stand it when product people think up "cool" features and products and sell them up before selling them down.&lt;br /&gt;&lt;br /&gt;As a developer I have said, "Wouldn't it be a sweet job for me to dream up really cool stuff that someone else has to develop." Work together.&lt;br /&gt;&lt;br /&gt;Don't sell your boss on something and then find development saying it can't be done. Do you really want to go to your boss now and say that your team can't deliver what you sold him? Do you really want to press your developers just to save your face with the boss? Don't get yourself into that situation.&lt;br /&gt;&lt;br /&gt;Maybe the silo and the wall is with the product people and the development teams. Maybe "Product" has silo'ed all of the activities of product and feature definition. Ah, I am glad you noticed that I used the term silo'ed with all of its negative connotations. Maybe I am becoming a skilled debater.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/36645098-2718591049465797938?l=digerati-illuminatus.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://digerati-illuminatus.blogspot.com/feeds/2718591049465797938/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=36645098&amp;postID=2718591049465797938' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/36645098/posts/default/2718591049465797938'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/36645098/posts/default/2718591049465797938'/><link rel='alternate' type='text/html' href='http://digerati-illuminatus.blogspot.com/2010/07/resources-versus-teams.html' title='Resources versus Teams'/><author><name>Geoff Slinker</name><uri>http://www.blogger.com/profile/12365501393247949005</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-36645098.post-1972810474424625667</id><published>2010-06-30T09:16:00.001-07:00</published><updated>2010-06-30T09:17:32.813-07:00</updated><title type='text'>Broaden your horizons</title><content type='html'>I think everyone should  be well rounded.&lt;br /&gt;Thus said, I will now share my latest poem.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;Tree growing&lt;br /&gt;Leaves green&lt;br /&gt;Cow grazing&lt;br /&gt;leaves green&lt;br /&gt;&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/36645098-1972810474424625667?l=digerati-illuminatus.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://digerati-illuminatus.blogspot.com/feeds/1972810474424625667/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=36645098&amp;postID=1972810474424625667' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/36645098/posts/default/1972810474424625667'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/36645098/posts/default/1972810474424625667'/><link rel='alternate' type='text/html' href='http://digerati-illuminatus.blogspot.com/2010/06/broaden-your-horizons.html' title='Broaden your horizons'/><author><name>Geoff Slinker</name><uri>http://www.blogger.com/profile/12365501393247949005</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-36645098.post-5123493752419134041</id><published>2010-06-04T10:11:00.000-07:00</published><updated>2010-06-04T10:13:47.662-07:00</updated><title type='text'>Meetings about work is not work...</title><content type='html'>"Work can not be replaced. Talking about work is not work. Planning to do work is not work. Meetings about work is not work."&lt;br /&gt;-Maverick Software Development&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/36645098-5123493752419134041?l=digerati-illuminatus.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://digerati-illuminatus.blogspot.com/feeds/5123493752419134041/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=36645098&amp;postID=5123493752419134041' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/36645098/posts/default/5123493752419134041'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/36645098/posts/default/5123493752419134041'/><link rel='alternate' type='text/html' href='http://digerati-illuminatus.blogspot.com/2010/06/meetings-about-work-is-not-work.html' title='Meetings about work is not work...'/><author><name>Geoff Slinker</name><uri>http://www.blogger.com/profile/12365501393247949005</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-36645098.post-3974168280486197318</id><published>2010-05-16T16:52:00.000-07:00</published><updated>2010-05-16T16:55:40.966-07:00</updated><title type='text'></title><content type='html'>Call me Wolfgang.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;a href="http://www.blogger.com/%3Ca%20href=" com="" strips="" comic="" 16="" title="Dilbert.com"&gt;&lt;img src="http://dilbert.com/dyn/str_strip/000000000/00000000/0000000/000000/80000/9000/500/89598/89598.strip.sunday.gif" alt="Dilbert.com" border="0" /&gt;&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/36645098-3974168280486197318?l=digerati-illuminatus.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://digerati-illuminatus.blogspot.com/feeds/3974168280486197318/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=36645098&amp;postID=3974168280486197318' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/36645098/posts/default/3974168280486197318'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/36645098/posts/default/3974168280486197318'/><link rel='alternate' type='text/html' href='http://digerati-illuminatus.blogspot.com/2010/05/call-me-wolfgang.html' title=''/><author><name>Geoff Slinker</name><uri>http://www.blogger.com/profile/12365501393247949005</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-36645098.post-1650716575420132556</id><published>2010-04-19T18:11:00.000-07:00</published><updated>2010-04-20T08:37:48.667-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Objective C'/><category scheme='http://www.blogger.com/atom/ns#' term='bounds'/><category scheme='http://www.blogger.com/atom/ns#' term='frame'/><category scheme='http://www.blogger.com/atom/ns#' term='UIView'/><category scheme='http://www.blogger.com/atom/ns#' term='XCode'/><category scheme='http://www.blogger.com/atom/ns#' term='UILabel'/><category scheme='http://www.blogger.com/atom/ns#' term='properties'/><category scheme='http://www.blogger.com/atom/ns#' term='debugging'/><title type='text'>UIView frame and bounds in GDB</title><content type='html'>I was trying to examine the frame property of a UILabel in the XCode debugger (GDB). Since I only do iPhone app development on occasion I tend to forget common tasks. I tried many different commands and none worked. I searched for posts on how to do this and found nothing specific.&lt;br /&gt;&lt;br /&gt;So, here is how you do it:&lt;br /&gt;(gdb) print (CGRect)[self.label frame]&lt;br /&gt;$1 = {&lt;br /&gt;           origin = {&lt;br /&gt;                x = 20,&lt;br /&gt;                y = 20&lt;br /&gt;           },&lt;br /&gt;           size = {&lt;br /&gt;              width = 280,&lt;br /&gt;              height = 21&lt;br /&gt;           }&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;I have a View Controller that has an UILabel *label.&lt;br /&gt;&lt;br /&gt;@interface TextViewController : UIViewController {&lt;br /&gt;IBOutlet UILabel *label;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;@property (nonatomic, retain) UILabel *label;&lt;br /&gt;&lt;br /&gt;@end&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/36645098-1650716575420132556?l=digerati-illuminatus.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://digerati-illuminatus.blogspot.com/feeds/1650716575420132556/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=36645098&amp;postID=1650716575420132556' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/36645098/posts/default/1650716575420132556'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/36645098/posts/default/1650716575420132556'/><link rel='alternate' type='text/html' href='http://digerati-illuminatus.blogspot.com/2010/04/debugging-uilabel-frame-and-bounds-in.html' title='UIView frame and bounds in GDB'/><author><name>Geoff Slinker</name><uri>http://www.blogger.com/profile/12365501393247949005</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-36645098.post-6313771330817240188</id><published>2010-01-26T07:56:00.000-08:00</published><updated>2010-01-26T08:12:42.695-08:00</updated><title type='text'>Warning to those about to re-invent the wheel</title><content type='html'>I have to warn those of you (or us) that find them self re-inventing the wheel.&lt;br /&gt;&lt;br /&gt;First, and we all know this, that you should not re-invent the wheel unless it is absolutely necessary. Often there is a performance criteria that causes the wheel to be remade.&lt;br /&gt;&lt;br /&gt;I have dealt with four major "new" wheels that I vividly recall.&lt;br /&gt;&lt;br /&gt;1) Memory Manager&lt;br /&gt;2) WinMac - a port of the Win32 API to the Macintosh&lt;br /&gt;3) XML parser&lt;br /&gt;4) The Gadget Library, a replacement for WinForms controls, layout, and UI containment&lt;br /&gt;&lt;br /&gt;All of these have commonalities.&lt;br /&gt;1) Performance was the driving reason&lt;br /&gt;2) Replacing well known and highly used functionality&lt;br /&gt;3) Complex code to give the performance increase&lt;br /&gt;4) One or two developers owning the code&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;The Memory Manager&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;The new memory manager allowed a product who's core was indexing and retrieval to be extremely fast on even Intel 386 based machines. Without such speed the product could not have gained the user base that it ultimately maintained.&lt;br /&gt;&lt;br /&gt;The growth of the company and the spreading use of the product allowed for the development of a Unix version. That is where I came into the picture. Since I was a Mac programmer I also did some Unix development, or another way to read this was I was a Win'tel hater. Youthful convictions run deeper than reason.&lt;br /&gt;&lt;br /&gt;I looked at porting the memory manager to Unix and found that the memory management on Unix was faster, so there was no need for the port. However I had to port the interface of the new memory manager so that I could reuse the "C" code of the product. So a bit of warning, performance issues and the resulting optimizations may not, most likely will not, be of value to cross platform code.&lt;br /&gt;&lt;br /&gt;Finally the memory manager itself was the bottleneck. It was so in two ways. First, as new versions of Windows came out and new compilers came out the native memory manager became faster than the custom one. Second, since the memory manager was developed by one person he could not keep his custom memory manager up to date, he was a bottleneck.&lt;br /&gt;&lt;br /&gt;Eventually the memory manager was removed. Was it necessary? Yes, it was. The company would not have grown to the point where the memory manager became obsolete if it hadn't have sold well allowing the company to stay in business and grow.&lt;br /&gt;&lt;br /&gt;The memory manager should have been architected differently. The issue was it had its own procedure calls completely different than "Stdlib". If the interface would have been the same as the standard memory manager then it would have been a simple swap out. So, when replacing something like the memory manager, stick to the interfaces so that it is a compile time or link time switch that uses the desired memory manager.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;WinMac - a port of the Win32 API to the Macintosh&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;A good friend of mine took the task of porting a Win32 application to the Macintosh. He is an excellent programmer and therefore there is no coding task that he will not consider as the correct solution to the problem. (I on the otherhand will say, 'Yes it can be coded, but should it be coded?')&lt;br /&gt;&lt;br /&gt;To make a long story short he decided to get the Windows code to compile on the Mac without any modification to the code. Sounds good to management, one code base, all new Windows functionality is immediately available on the Mac. In those days no one even considered if it was legal, those types of legal issues had never been spoken of.&lt;br /&gt;&lt;br /&gt;Well, he got behind, had no one to bounce ideas off of, and so they decided to hire someone to help. That is where I come in. The pay raise was around 15%, who could say no.&lt;br /&gt;&lt;br /&gt;There were some big problems.&lt;br /&gt;&lt;br /&gt;1) The WinMac library was a subset of Win32. It only contained a port of the Win32 calls that were made by the Windows product.&lt;br /&gt;&lt;br /&gt;2) Macintosh OS 7 (8 and 9, and those before) is an event based model with one main event loop and cooperative multitasking. (I have dealt with crazy Mac programmers that coded up multiple event loops! Shame on them. SHAME.) Windows is a message based UI with crazy message pumps and all of those message id's, etc.&lt;br /&gt;&lt;br /&gt;3) No specification of Win32. Just run it, use the event spy, and figure it out. There was documentation on how to developer for WIn32, but not a specification on how Win32 was developed.&lt;br /&gt;&lt;br /&gt;4) Bugs in Windows.&lt;br /&gt;&lt;br /&gt;As we developed on the single code base we quickly found ourselve's downstream of the changes made to the Windows product. We would get the code compiling and then a few days later get code again to find that some developer called some new Windows API that we hadn't ported yet. We ended up porting the vast majority of the entire Windows API.&lt;br /&gt;&lt;br /&gt;Also, we found many bugs in Windows and the order of messages. The documentation would state a certain series of messages but the event spy showed at runtime that Windows did not do it that way. So, we had to mimic even the bugs.&lt;br /&gt;&lt;br /&gt;Finally my friend got into a workplace polictical conflict with management and left me all alone.&lt;br /&gt;&lt;br /&gt;Lesson learned, it is better to port ideas than it is code!&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;The XML parser&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Once again performance was the issue. I do admit the developers I work with have a good vision for the future and when XML was very young the idea of using it for making calls to servers through http was leading edge. So, as SOAP is coming into existence the company has moved far ahead. Standard emerge and the team keeps the code up to date as best as they can. However, the XML that was used to test the custom XML parser was unique in that all attributes where in double quotes. No one, by habbit or dumb luck, ever passed xml that had attributes in single quotes. Well, that is where I come in. I had started using XML later and had used the libraries that came with the IDE. I spent several days trying to debug code that was an http call passing xml to a server and I kept getting exceptions. My XML was valid, I had checked in many times, had others look at it, etc. One of the "old timers" noticed the single quotes and said, "There's the problem".&lt;br /&gt;&lt;br /&gt;As the company grew rapidly the new/younger developers started writing SOAP implementations and now there were both worlds in existense at the same time. At first SOAP was slower and those that used it got chastized by the old timers for not stepping up and learning the proprietary solution. But, eventually SOAP gets the performance it needs.&lt;br /&gt;&lt;br /&gt;Lesson learned here is that if you are have a replacement for something in which there are standards then you have to keep up with the standard. The personel working of the code is the bottleneck. Typically an update in a standard is significant and you get it dumped upon you all at once. Therefore you find yourself picking and chosing and therefore you are now noncompliant.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;The Gadget Library, a replacement for WinForms controls, layout, and UI containment&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;This is my most recent experience. Performance was the issue, that and the inability to create thousands of Controls dynamically, to draw all of these controls to offscreen bitmaps, or to visuall scale/zoom all of the controls.&lt;br /&gt;&lt;br /&gt;Because I have replaced WinForm's controls, completely replaced them I find myself the bottleneck to getting in new functionality. Imagine just one guy owning the WinForms classes for Microsoft. Each bug, each new feature, each change is huge. The amount of code to keep in one's head is tremendous as well.&lt;br /&gt;&lt;br /&gt;The issue is that UI components and their abilities are a commodity now. When I developed a gadget it was coded to do just what was needed and nothing extra. YAGNI was the driving mantra. Users are unaware that the Gadget library exists, it all looks like Windows to them. So, they say, "We would like it do X". "X" would be easy enough if I was using WinForm's controls. The users expect it and management doesn't necessarily see the difficulty in asking for it. But it is starting to wear me out. Too much code, too much responsibility, to much complexity, just too dang much.&lt;br /&gt;&lt;br /&gt;The lesson learned here is when replacing a UI commodity, you should fully replace it in most cases. Fully means, full functionality implemented, all of the behavior of the original.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Final Thoughts&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;There are some items of interest as well, based upon my experience. When I was an undergrad at BYU I took several upper level classes. One of which was a GUI class by Dr. Olsen. I don't think that man ever liked me. In that class I wrote a GUI system on my little Mac SE. We were constrained and could only use the basic draw functions, like draw rect, draw string, etc. I made windows, controls, scroll bars, drop down menus, and other GUI components from scratch.&lt;br /&gt;&lt;br /&gt;I would go home for the summers and work on my Father's dairy farm (which also included about 200 acres of alfalfa). I would purchase the computer science text books for the classes I would take in the fall and read them and work through the end of chapter items. During one summer I wrote a new Macintosh GUI system where I developed a language for describing a UI. I wrote a parser and code generator for that language. This was around 1986 or so.&lt;br /&gt;&lt;br /&gt;Then I helped write that WinMac monstrosity. With these experiences in developing GUI environments I was at least able to write the Gadget library I use with WinForms development. The point is the path I had taken, or better yet been herded down, gave me the knowledge to be able to make the Gadget library which is extremely fast and meets the performance requirements. The hard road, the big tasks, the complex assignments, all have helped make me what I am capable of doing today.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Geoff&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/36645098-6313771330817240188?l=digerati-illuminatus.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://digerati-illuminatus.blogspot.com/feeds/6313771330817240188/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=36645098&amp;postID=6313771330817240188' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/36645098/posts/default/6313771330817240188'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/36645098/posts/default/6313771330817240188'/><link rel='alternate' type='text/html' href='http://digerati-illuminatus.blogspot.com/2010/01/warning-to-those-about-to-re-invent.html' title='Warning to those about to re-invent the wheel'/><author><name>Geoff Slinker</name><uri>http://www.blogger.com/profile/12365501393247949005</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-36645098.post-1132554963913467450</id><published>2009-11-09T07:45:00.000-08:00</published><updated>2010-04-20T08:39:09.463-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='XCode'/><title type='text'>XCode Quick Keys or Key Short Cuts</title><content type='html'>When learning any new programming environment there will be lots of experimentation. Often being unfamiliar with the IDE becomes a frustration while trying to learn a new language like Objective C or learn new classes and libraries found in Cocoa.&lt;br /&gt;&lt;br /&gt;Frustration with the IDE may cause you to give up. I know my impatience is the culprit!&lt;br /&gt;&lt;br /&gt;So, here are three Quick Keys that were not obvious to me, and I was too impatient to drop down all of the menus or read the key stroke preferences to discover.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Switching between the source file and header file:&lt;/span&gt;&lt;br /&gt;⌥⌘↑&lt;br /&gt;Option Command Up Arrow (Opt Command UpArrow)&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Commenting code "in" or "out":&lt;/span&gt;&lt;br /&gt;⌘/&lt;br /&gt;Command Forward Slash (Cmd /)&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Move to the next argument in the auto-completion list:&lt;/span&gt;&lt;br /&gt;^/&lt;br /&gt;Control Forward Slash (Control /)&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;⌘  Command key&lt;br /&gt;⌃  Control Key&lt;br /&gt;⌥  Option Key (aka Alt Key)&lt;br /&gt;⇧ Shift Key&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/36645098-1132554963913467450?l=digerati-illuminatus.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://digerati-illuminatus.blogspot.com/feeds/1132554963913467450/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=36645098&amp;postID=1132554963913467450' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/36645098/posts/default/1132554963913467450'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/36645098/posts/default/1132554963913467450'/><link rel='alternate' type='text/html' href='http://digerati-illuminatus.blogspot.com/2009/11/xcode-quick-keys-or-key-short-cuts.html' title='XCode Quick Keys or Key Short Cuts'/><author><name>Geoff Slinker</name><uri>http://www.blogger.com/profile/12365501393247949005</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-36645098.post-8492458814112312180</id><published>2009-11-08T10:46:00.000-08:00</published><updated>2010-04-20T08:39:35.482-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Objective C'/><category scheme='http://www.blogger.com/atom/ns#' term='XCode'/><title type='text'>Objective C Method Signatures and Method Keywords</title><content type='html'>Objective C "looks" a bit different than the object oriented languages I have used previously. Object C and Pascal (Remember Lightspeed C and Pascal, single inheritance languages), C++, Java, and C#. I have not taken the time to learn Small Talk and so I do not know if Object C takes after Small talk or not.&lt;br /&gt;&lt;br /&gt;I noticed that method signatures in Objective C have multiple "method keywords".&lt;br /&gt;&lt;br /&gt;What is a method keyword? It is a word that proceeds the parameter type.&lt;br /&gt;&lt;br /&gt;Here is a method from NSMutableDictionary:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;-(void)setObject:(id)anObject forKey:(id)aKey&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;The method keywords are "setObject" and "forKey".&lt;br /&gt;&lt;br /&gt;Because of many years developing in languages other than Objective C I find myself in the habit of decorating the method name. For example,  if I have a method that inserts an object into some container and the object is stored by name then the method name would be like this:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;void InsertObjectWithName (object i&lt;/span&gt;&lt;span style="font-family:courier new;"&gt;nsert, string name)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;This habit shows up in my Objective C code.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;@interface Foo : NSObject&lt;br /&gt;{&lt;/span&gt;  &lt;span style="font-family:courier new;"&gt;&lt;br /&gt;}&lt;/span&gt;  &lt;span style="font-family:courier new;"&gt;&lt;br /&gt;-(void) insertValueWithName:(id) value : (NSString *)name;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;@end&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;However, in Objective C you can have more than one method keyword.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;@interface Foo : NSObject&lt;br /&gt;{&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;-(void) insertValueWithName:(id)value :(NSString *)name;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-weight: bold;font-family:courier new;" &gt;-(void) insertValue:(id) value withName :(NSString *)name;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;@end&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:85%;"&gt;&lt;br /&gt;(I intend the two methods to do exactly the same thing. Both are valid Objective C methods.)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;This additional method uses two method keywords:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;-(void) &lt;span style="font-weight: bold; font-style: italic;"&gt;insertValue&lt;/span&gt;:(id) value &lt;span style="font-weight: bold; font-style: italic;"&gt;withName&lt;/span&gt; :(NSString *)name;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;At first I thought I liked either style the same. The more I use XCode the more I like the method with two method keywords because of how auto-completion reads.&lt;br /&gt;&lt;br /&gt;Here is the single keyword style in XCode with auto-complete:&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_W3ZUYKgeEpk/Svccqxc8t-I/AAAAAAAAADc/j9a75ZYnbZE/s1600-h/s2.jpg"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 400px; height: 52px;" src="http://1.bp.blogspot.com/_W3ZUYKgeEpk/Svccqxc8t-I/AAAAAAAAADc/j9a75ZYnbZE/s400/s2.jpg" alt="" id="BLOGGER_PHOTO_ID_5401817799209039842" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Here is the multiple keyword style in XCode with auto-complete:&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_W3ZUYKgeEpk/SvcdN-q9iMI/AAAAAAAAADs/RXqW-Mavagk/s1600-h/s2.jpg"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 400px; height: 38px;" src="http://2.bp.blogspot.com/_W3ZUYKgeEpk/SvcdN-q9iMI/AAAAAAAAADs/RXqW-Mavagk/s400/s2.jpg" alt="" id="BLOGGER_PHOTO_ID_5401818404052895938" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;For me I find that the method with two keywords reads clearer. Also I like the way the separation and highlighting of the auto-complete looks when multiple method keywords are used.&lt;br /&gt;&lt;br /&gt;So, I am going to use multiple keywords in Objective C and avoid techniques that I use in other programming languages.&lt;br /&gt;&lt;br /&gt;Slightly Off Topic&lt;br /&gt;&lt;br /&gt;Syntax is just syntax and it doesn't take long to figure out the need to use brackets to invoke a method, or better said, to send a message to an object. For me it is still a bit painful to anticipate how many open brackets that I will need and I have to go back and forth in the source code inserting them as necessary.&lt;br /&gt;&lt;br /&gt;It goes something like this:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;Foo *myFoo = [Foo alloc]&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Oh yeah, I better call the init...&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;Foo *myFoo = [Foo alloc] init]&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Oh yea, I have to have another bracket at the front...&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;Foo *myFoo = [[Foo alloc] init]&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;And on and on I go back and forth inserting brackets where I need them.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/36645098-8492458814112312180?l=digerati-illuminatus.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://digerati-illuminatus.blogspot.com/feeds/8492458814112312180/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=36645098&amp;postID=8492458814112312180' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/36645098/posts/default/8492458814112312180'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/36645098/posts/default/8492458814112312180'/><link rel='alternate' type='text/html' href='http://digerati-illuminatus.blogspot.com/2009/11/objective-c-method-signatures-and.html' title='Objective C Method Signatures and Method Keywords'/><author><name>Geoff Slinker</name><uri>http://www.blogger.com/profile/12365501393247949005</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/_W3ZUYKgeEpk/Svccqxc8t-I/AAAAAAAAADc/j9a75ZYnbZE/s72-c/s2.jpg' height='72' width='72'/><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-36645098.post-2740573827570227161</id><published>2009-09-15T06:05:00.000-07:00</published><updated>2009-09-17T07:49:40.332-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='NSView'/><category scheme='http://www.blogger.com/atom/ns#' term='XCode'/><category scheme='http://www.blogger.com/atom/ns#' term='NSTextField'/><category scheme='http://www.blogger.com/atom/ns#' term='NSButton'/><category scheme='http://www.blogger.com/atom/ns#' term='Cocoa'/><category scheme='http://www.blogger.com/atom/ns#' term='Rotate'/><title type='text'>How do you rotate an NSButton, NSTextField, or NSView?</title><content type='html'>How do you rotate an NSButton, NSTextField, or NSView?&lt;br /&gt;&lt;br /&gt;First, you can do it and it is fairly easy to do! Here is what it will look like!&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_W3ZUYKgeEpk/Sq-gPAkor2I/AAAAAAAAADM/TjlHjvP0rj0/s1600-h/results.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 314px; height: 172px;" src="http://2.bp.blogspot.com/_W3ZUYKgeEpk/Sq-gPAkor2I/AAAAAAAAADM/TjlHjvP0rj0/s400/results.png" alt="" id="BLOGGER_PHOTO_ID_5381696259443175266" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;There are two NSView methods available to do this.&lt;br /&gt;&lt;br /&gt;In OS 10.0 you have:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;- (void)setFrameRotation:(CGFloat)&lt;span style="font-style: italic;"&gt;angle&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;And in OS 10.5 you have:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;- (void)setFrameCenterRotation:(CGFloat)&lt;span style="font-style: italic;"&gt;angle&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;For some the above information will be sufficient. For those desiring more information please continue to read this posting.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_W3ZUYKgeEpk/Sq-U_ToPh-I/AAAAAAAAACs/chFUFpmYU8g/s1600-h/newproj.png"&gt;&lt;img style="margin: 0pt 10px 10px 0pt; float: left; cursor: pointer; width: 400px; height: 349px;" src="http://2.bp.blogspot.com/_W3ZUYKgeEpk/Sq-U_ToPh-I/AAAAAAAAACs/chFUFpmYU8g/s400/newproj.png" alt="" id="BLOGGER_PHOTO_ID_5381683895052765154" border="0" /&gt;&lt;/a&gt;Create a new "Cocoa Application". From the File menu choose "New Project" and then select "Cocoa Application".&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Name and save the project whatever you want. I named my project "RotatedControl".&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_W3ZUYKgeEpk/Sq-W-spKzlI/AAAAAAAAAC0/yiMeRXLWx14/s1600-h/newnsobj.png"&gt;&lt;img style="margin: 0pt 10px 10px 0pt; float: left; cursor: pointer; width: 400px; height: 349px;" src="http://2.bp.blogspot.com/_W3ZUYKgeEpk/Sq-W-spKzlI/AAAAAAAAAC0/yiMeRXLWx14/s400/newnsobj.png" alt="" id="BLOGGER_PHOTO_ID_5381686083610922578" border="0" /&gt;&lt;/a&gt;In XCode add to the "Classes" folder a "New File". Choose "Objective-C class".&lt;br /&gt;&lt;br /&gt;I named my class "Controller"&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Add your IBOutlets to your new class. Here is my code:&lt;br /&gt;&lt;br /&gt;&lt;img src="file:///Users/General/Library/Caches/TemporaryItems/moz-screenshot.png" alt="" /&gt;&lt;span style="font-family:courier new;"&gt;//&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;//  Controller.h&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;//  RotatedControl&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;//&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;//  Created by Geoffrey_Slinker on 9/13/09.&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;//  Copyright 2009 Area 51. All rights reserved.&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;//&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;#import &lt;foundation h=""&gt;&lt;/foundation&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;@interface Controller : NSObject {&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;    IBOutlet NSTextField *textField;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;    IBOutlet NSButton *button;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;@property (retain) NSTextField *textField;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;@property (retain) NSButton *button;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;- (void) awakeFromNib;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;@end&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;//&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;//  Controller.m&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;//  RotatedControl&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;//&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;//  Created by Geoffrey_Slinker on 9/13/09.&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;//  Copyright 2009 Area 51. All rights reserved.&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;//&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;#import "Controller.h"&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;@implementation Controller&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;@synthesize textField;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;@synthesize button;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;- (void) awakeFromNib&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;{&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;    //[textField setFrameRotation:45.0];&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;    //[button setFrameRotation:30.0];&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;    &lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;    [textField setFrameCenterRotation:45.0];&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;    [button setFrameCenterRotation:-45.0];&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;    &lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;@end&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Now open the NIB file. In XCode double click "MainMenu.xib" found in the folder "NIB Files". This should launch Interface Builder (IB).&lt;br /&gt;&lt;br /&gt;Add an "Object Controller" and set its class to be the class type you created above. In my case I set it to "Controller". See "&lt;a href="http://digerati-illuminatus.blogspot.com/2009/09/where-is-classes-tab-in-interface.html"&gt;Where is the Classes Tab&lt;/a&gt;" for detailed information.&lt;br /&gt;&lt;br /&gt;Still in IB add a Button and a Text Field to your Window. Just select them from the Library of Objects and drag them onto the Window.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_W3ZUYKgeEpk/Sq-bFPxkv5I/AAAAAAAAAC8/emT4ebRKXSU/s1600-h/ib_fullShot.png"&gt;&lt;img style="cursor: pointer; width: 400px; height: 250px;" src="http://2.bp.blogspot.com/_W3ZUYKgeEpk/Sq-bFPxkv5I/AAAAAAAAAC8/emT4ebRKXSU/s400/ib_fullShot.png" alt="" id="BLOGGER_PHOTO_ID_5381690594167144338" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Now "hook up" the IBOutlets of the Controller to the controls on the window.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_W3ZUYKgeEpk/Sq-dInnSyUI/AAAAAAAAADE/H6fRoUjzrM4/s1600-h/wiring.png"&gt;&lt;img style="margin: 0pt 10px 10px 0pt; float: left; cursor: pointer; width: 400px; height: 217px;" src="http://2.bp.blogspot.com/_W3ZUYKgeEpk/Sq-dInnSyUI/AAAAAAAAADE/H6fRoUjzrM4/s400/wiring.png" alt="" id="BLOGGER_PHOTO_ID_5381692851129338178" border="0" /&gt;&lt;/a&gt;You can see I have "wired" or "connected" the button outlet to the button on the window. The same was done for the text field.&lt;br /&gt;&lt;br /&gt;Also wire the the "Referencing Outlets" delegate to the "Application". The "Application is above the "Controller" in the MainMenu.xib view.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;If I haven't missed any steps then from XCode just build and run the application.&lt;br /&gt;&lt;br /&gt;&lt;!-- Start Bravenet.com Service Code --&gt;&lt;br /&gt;&lt;script language="JavaScript" type="text/javascript" src="http://pub35.bravenet.com/counter/code.php?id=406982&amp;usernum=2924324409&amp;cpv=2"&gt;&lt;br /&gt;&lt;/script&gt;&lt;br /&gt;&lt;!-- END DO NOT MODIFY --&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/36645098-2740573827570227161?l=digerati-illuminatus.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://digerati-illuminatus.blogspot.com/feeds/2740573827570227161/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=36645098&amp;postID=2740573827570227161' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/36645098/posts/default/2740573827570227161'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/36645098/posts/default/2740573827570227161'/><link rel='alternate' type='text/html' href='http://digerati-illuminatus.blogspot.com/2009/09/how-do-you-rotate-nsbutton-nstextfield.html' title='How do you rotate an NSButton, NSTextField, or NSView?'/><author><name>Geoff Slinker</name><uri>http://www.blogger.com/profile/12365501393247949005</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/_W3ZUYKgeEpk/Sq-gPAkor2I/AAAAAAAAADM/TjlHjvP0rj0/s72-c/results.png' height='72' width='72'/><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-36645098.post-8753893313143640037</id><published>2009-09-14T07:04:00.001-07:00</published><updated>2009-09-14T07:34:09.229-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Interface Builder'/><category scheme='http://www.blogger.com/atom/ns#' term='XCode'/><category scheme='http://www.blogger.com/atom/ns#' term='Classes Tab'/><title type='text'>Where is the Classes Tab in Interface Builder? It has been removed.</title><content type='html'>Where is the Classes Tab in Interface Builder?  It has been removed.&lt;br /&gt;&lt;br /&gt;Interface Builder 3.1.2 does not have it. I do not know which version was the first to "not have it" but I know my version doesn't.&lt;br /&gt;&lt;br /&gt;This can cause some confusion with tutorials, texts, books, etc., that refer to the Classes Tab.&lt;br /&gt;&lt;br /&gt;Many examples refer you to a screen shot of IB's UI like this one:&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_W3ZUYKgeEpk/Sq5OqVcGZAI/AAAAAAAAACM/QLFeBhsWkJU/s1600-h/InterfaceBuilderClasses.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 366px; height: 250px;" src="http://4.bp.blogspot.com/_W3ZUYKgeEpk/Sq5OqVcGZAI/AAAAAAAAACM/QLFeBhsWkJU/s400/InterfaceBuilderClasses.png" alt="" id="BLOGGER_PHOTO_ID_5381325093970797570" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;Well, stop looking for it because it is gone.&lt;br /&gt;&lt;br /&gt;Interface Builder 3 looks like this:&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_W3ZUYKgeEpk/Sq5QJDANSwI/AAAAAAAAACU/7CmPiKg_Wzc/s1600-h/IB3_clip.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 400px; height: 111px;" src="http://2.bp.blogspot.com/_W3ZUYKgeEpk/Sq5QJDANSwI/AAAAAAAAACU/7CmPiKg_Wzc/s400/IB3_clip.png" alt="" id="BLOGGER_PHOTO_ID_5381326721109543682" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;For instance, if you are creating a class that has some IBOutlet's then create that class in XCode, add the IBOutlet's that you desire. Launch Interface builder by doubling clicking your NIB file in XCode.&lt;br /&gt;&lt;br /&gt;Select an Object from this panel:&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_W3ZUYKgeEpk/Sq5RzwYCn1I/AAAAAAAAACc/ZOIOOY-pWQg/s1600-h/ObjectController.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 208px; height: 400px;" src="http://2.bp.blogspot.com/_W3ZUYKgeEpk/Sq5RzwYCn1I/AAAAAAAAACc/ZOIOOY-pWQg/s400/ObjectController.png" alt="" id="BLOGGER_PHOTO_ID_5381328554355236690" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Drag the "Object" to "Main***.xib" window, the window that has "File's Owner, First Responder, etc".&lt;br /&gt;&lt;br /&gt;Make sure this new object is selected and from the Tools Menu open the Identity Inspector. There is a menu at the top labeled "Class". Click this and select the class that you created in XCode. The one I created I named "Controller", so I select "Controller" from the Class drop down menu.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_W3ZUYKgeEpk/Sq5TreLL25I/AAAAAAAAACk/CEEoehlTLbs/s1600-h/IdentityInspector_clip.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 285px; height: 400px;" src="http://1.bp.blogspot.com/_W3ZUYKgeEpk/Sq5TreLL25I/AAAAAAAAACk/CEEoehlTLbs/s400/IdentityInspector_clip.png" alt="" id="BLOGGER_PHOTO_ID_5381330611053779858" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;I hope that helps clear up things for some.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/36645098-8753893313143640037?l=digerati-illuminatus.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://digerati-illuminatus.blogspot.com/feeds/8753893313143640037/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=36645098&amp;postID=8753893313143640037' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/36645098/posts/default/8753893313143640037'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/36645098/posts/default/8753893313143640037'/><link rel='alternate' type='text/html' href='http://digerati-illuminatus.blogspot.com/2009/09/where-is-classes-tab-in-interface.html' title='Where is the Classes Tab in Interface Builder? It has been removed.'/><author><name>Geoff Slinker</name><uri>http://www.blogger.com/profile/12365501393247949005</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://4.bp.blogspot.com/_W3ZUYKgeEpk/Sq5OqVcGZAI/AAAAAAAAACM/QLFeBhsWkJU/s72-c/InterfaceBuilderClasses.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-36645098.post-6309956242351585699</id><published>2009-08-14T13:11:00.000-07:00</published><updated>2009-08-14T14:13:47.889-07:00</updated><title type='text'>Out of Browser and Desktop Applications</title><content type='html'>I have been researching the use of Silverlight and Adobe Air for creating a cross platform desktop application.&lt;br /&gt;&lt;br /&gt;Michael Wolf blogged on this topic: &lt;a href="http://www.cynergysystems.com/blogs/page/michaelwolf?entry=silverlight_out_of_browser_deep"&gt;Silverlight Out of Browser deep dive.&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;My research has discovered that there are many that want a development platform that will run on different Operating Systems. For my interest those systems are Mac OS X and Windows.&lt;br /&gt;&lt;br /&gt;Not only is it desirable to run on different OS's but also to run in a browser.&lt;br /&gt;&lt;br /&gt;This desire is based on code reuse and development effort. If the same code can run "in browser" and "out of browser (OOB)" businesses view this as a significant win.&lt;br /&gt;&lt;br /&gt;The limitations of OOB solutions are justified and at the same time make it unrealistic to use the solution as a desktop application that has high system resource utilization. Don't misunderstand, I think the demand is great and will cause solutions to be developed. Certain companies/products can justify the "glue code" that is necessary to get to system resources but many can not.&lt;br /&gt;&lt;br /&gt;For now, those companies that have desktop applications that need to run on various operating systems, don't forget Java. Microsoft and Adobe have no reason to mention Java for cross platform solutions.&lt;br /&gt;&lt;br /&gt;For later let us watch the direction of Silverlight and Air, and at the same time watch for new solutions in the Platform as a Service (PaaS) arena.&lt;br /&gt;&lt;br /&gt;PaaS technologies and Web Application technologies that I am watching include:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Cappuccino, Objective-J, Cocotron&lt;/li&gt;&lt;li&gt;SproutCore&lt;/li&gt;&lt;li&gt;Windows Azure&lt;/li&gt;&lt;/ul&gt;Silverlight and Adobe Air do what they were designed to do well enough. Using either to make desktop applications is "living on the edge".&lt;br /&gt;&lt;br /&gt;Geoff&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/36645098-6309956242351585699?l=digerati-illuminatus.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://digerati-illuminatus.blogspot.com/feeds/6309956242351585699/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=36645098&amp;postID=6309956242351585699' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/36645098/posts/default/6309956242351585699'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/36645098/posts/default/6309956242351585699'/><link rel='alternate' type='text/html' href='http://digerati-illuminatus.blogspot.com/2009/08/out-of-browser-and-desktop-applications.html' title='Out of Browser and Desktop Applications'/><author><name>Geoff Slinker</name><uri>http://www.blogger.com/profile/12365501393247949005</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-36645098.post-2027588564995681192</id><published>2009-07-20T16:10:00.000-07:00</published><updated>2009-07-20T16:47:42.329-07:00</updated><title type='text'>There is no Agility without timely Acceptance</title><content type='html'>There is no agility without timely acceptance of features or changes. Need I say more?&lt;br /&gt;&lt;br /&gt;If you answered no then don't waste your precious time reading any further.&lt;br /&gt;&lt;br /&gt;For the rest of you I will continue.&lt;br /&gt;&lt;br /&gt;Lack of timely acceptance of features/changes requires detailed requirements, which in turn leads to traditional waterfall development. "What?" you say. "Yes!" I say, "Big Up Front Requirements gathering which necessitates flow charts, prototypes, etc..., and other such activities will become necessary."&lt;br /&gt;&lt;br /&gt;When a feature/change is completed and the users of the product run the features on real data and on real hardware and finds issues the developer will still  remember the changes needed for the implementation. Therefore the developer is more likely to correct the issues in the right places.&lt;br /&gt;&lt;br /&gt;When a feature/change is completed and the users do not exercise the new code for days, weeks, or months the developer may have difficulty correcting any issues found. Why? The most common cause of difficulty is that the developer doesn't remember the ramifications of the changes. The developer will have to find the changes in the revision control system and review the check-in comments and maybe even walk through the code in the debugger just to get their mind wrapped around the code again. Even worse (and yet very common) is that the changes were built upon and used by other aspects of the product. Now the developer or developers have to figure out all of the possible side effects of working on this code because it is coupled to other features!&lt;br /&gt;&lt;br /&gt;At this point the developer will say, "Enough is enough. Next time you tell me exactly what you want in great detail. You spend your time and effort instead of you spending mine."&lt;br /&gt;&lt;br /&gt;Why will the developer say such a thing? Continuing with the above scenario (based on real world experience) the developer knows that since the acceptance test of this feature has taken so long that the odds are that the related features have not been used either. It is possible that the related features work correctly, and in that case the code has to remain the same for those features and all new code has to be developed for the feature in question. It is possible that none of the related features built  are correct and that some should be one way and some another. Do you get the picture now?&lt;br /&gt;&lt;br /&gt;Such work is very costly. It costs time, money, and morale.&lt;br /&gt;&lt;br /&gt;Maybe I will blog about Morale Debt some day (previous posts have been made on Code Debt, Market Debt, Product Debt, etc).&lt;br /&gt;&lt;br /&gt;Without timely acceptance of features/changes the costs of corrections increase. In an attempt to avoid issues caused by untimely acceptance  the natural tendency is to require more detailed specifications, requirements, and designs. When this happens you can officially kiss Agility good bye.&lt;br /&gt;&lt;br /&gt;Acceptance of features/changes by users is more important to me that having unit tests! If you made me choose between users giving timely feedback on acceptance or having unit tests I would take the users timely feedback.&lt;br /&gt;&lt;br /&gt;Timely acceptance, in my opinion, is less than three days.&lt;br /&gt;&lt;br /&gt;If you do not have timely acceptance of features/changes then you can be sure your development process is not Agile. Being Agile shouldn't be the goal, but being efficient should be the goal. Maybe I should rename this post to: &lt;span style="font-weight: bold;"&gt;"There is Waste without timely Acceptance"&lt;/span&gt;. Yes, I like that title better!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/36645098-2027588564995681192?l=digerati-illuminatus.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://digerati-illuminatus.blogspot.com/feeds/2027588564995681192/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=36645098&amp;postID=2027588564995681192' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/36645098/posts/default/2027588564995681192'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/36645098/posts/default/2027588564995681192'/><link rel='alternate' type='text/html' href='http://digerati-illuminatus.blogspot.com/2009/07/there-is-no-agility-without-timely.html' title='There is no Agility without timely Acceptance'/><author><name>Geoff Slinker</name><uri>http://www.blogger.com/profile/12365501393247949005</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-36645098.post-3629045670790361683</id><published>2009-06-23T10:19:00.000-07:00</published><updated>2009-06-23T10:31:17.033-07:00</updated><title type='text'>What can I do to help us succeed?</title><content type='html'>Have you ever been working on some difficult issue and have someone come up and say "What can I do to help us succeed?"&lt;br /&gt;&lt;br /&gt;I am not going to talk about the "peace and love" version of this story where everyone magically finds synergy because caring people have joined together.&lt;br /&gt;&lt;br /&gt;"What can I do to help us succeed?" Some of the possible responses are :&lt;br /&gt;&lt;ol&gt;&lt;li&gt;"Us, where did this 'Us' come from?"&lt;/li&gt;&lt;li&gt;"Nothing, shut up and quit bugging me!"&lt;/li&gt;&lt;li&gt;"You caused this mess I am fixing, get out of my face!"&lt;/li&gt;&lt;li&gt;"You could find a new job!"&lt;/li&gt;&lt;li&gt;"Do you know of any companies hiring?"&lt;/li&gt;&lt;li&gt;"You could learn to mind your own business."&lt;/li&gt;&lt;li&gt;"Instead of talking about how we might work around here, why don't you just let me work like I know how!"&lt;/li&gt;&lt;/ol&gt;Sometimes the above responses may be the correct response. However it might not be wise to say these things out loud.&lt;br /&gt;&lt;br /&gt;When someone is under stress trying to get something done that is urgent a well intending person might interrupt with the question "what can I do to help us succeed". This well intending person needs to realize that a response like one of those listed above may be accurate and the best thing to do to help is to stop asking or looking for ways to inject themselves into the solution and allow the situation to run its course.&lt;br /&gt;&lt;br /&gt;Does that make sense?&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/36645098-3629045670790361683?l=digerati-illuminatus.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://digerati-illuminatus.blogspot.com/feeds/3629045670790361683/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=36645098&amp;postID=3629045670790361683' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/36645098/posts/default/3629045670790361683'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/36645098/posts/default/3629045670790361683'/><link rel='alternate' type='text/html' href='http://digerati-illuminatus.blogspot.com/2009/06/what-can-i-do-to-help-us-succeed.html' title='What can I do to help us succeed?'/><author><name>Geoff Slinker</name><uri>http://www.blogger.com/profile/12365501393247949005</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-36645098.post-3502835579201758806</id><published>2009-04-17T08:28:00.000-07:00</published><updated>2009-04-17T08:29:57.426-07:00</updated><title type='text'>People CHOOSE Process</title><content type='html'>To me it is not people versus process or even process versus people. People choose the process they will follow and choose how closely they will follow it.&lt;br /&gt;&lt;br /&gt;The choice of process should be based on issues, problems, and concerns that need to be confronted. This is a basic thought of all of the Maverick papers I wrote years ago.&lt;br /&gt;&lt;br /&gt;[Label: 1]&lt;br /&gt;As the choices are implemented, the implementers (the people), watch to see if the issues are being corrected. If so, they continue forward, if not they re-evaluate and re-implement.&lt;br /&gt;&lt;br /&gt;These implementers are the founders and early adopters.&lt;br /&gt;&lt;br /&gt;From this point there are many paths that can be taken, one path of evolution is that there are those that come after the founders and early adopters and these people are the ignorant believers.&lt;br /&gt;&lt;br /&gt;These ignorant believers become dogmatic and assume they are the guardians and defenders of this newly founded ministry. This is an opportunity to roust those that have held the power, those with which many feel were the cause of some problem. Any failure of the previous regime will be used as a reason to oust them and adopt the new methodology with it's new set of leaders.&lt;br /&gt;&lt;br /&gt;Once the new authorities have taken charge they must institute a means of policing actions and judging conformity. Here is were Process versus People begin.&lt;br /&gt;&lt;br /&gt;Now the rules have been established and the means of judging conformity in place the next thing is to rank people according to their compliance. Decisions are made on actions to be taken if someone poorly complies. These are known as the consequences.&lt;br /&gt;&lt;br /&gt;Now the authorities have the power to fire, with-hold rewards, reward, and promote.&lt;br /&gt;&lt;br /&gt;There are those that come in even later. They do not understand why the process is the way it is. They do not understand why the people who are in charge where chosen to be in charge or how they got to be in charge. Others of these new-comers seem to fit in and thrive, while some fit in and perform with mediocrity.&lt;br /&gt;&lt;br /&gt;If an employee refuses to follow the process then the machinery that has become the process will act upon that employee.&lt;br /&gt;&lt;br /&gt;Most likely there will exist some employees who seem to have an almost magical ability to fight the process but never seem to reap the consequences. I have seen this many times. Usually two or three people can project the reasons why they do not conform in such a manner that they are not punished.&lt;br /&gt;&lt;br /&gt;At some point a group of individuals will sit down and analyze the current situation and list a set of problems, issues, and concerns. They will use their experiences to devise a plan to address the issues and they will create an opportunity to put those plans into play.&lt;br /&gt;[GoTo: Label: 1]&lt;br /&gt;&lt;br /&gt;If you are not the creator of a new process then you should study the processes that are in practice. As you study them you should try to "fit" the process to the ways you choose to do things and they ways you imagine things should be done. Then you should try to work somewhere that uses that process. This will allow you to fit in, to understand, and most importantly to imagine the next step in the evolution of that process. This notion of the gathering of people based on some common ground has often been attacked. It has been said that this idea limits diversity. That is a statement that has not been proven true. Once you gain experience and seek understanding in the underlying goals of a process and the problems, issues, and concerns being addressed then you can build on a solid foundation.&lt;br /&gt;&lt;br /&gt;If you choose to be a mediocre participant then be prepared for the process to "grind you up and spit you out". If you choose to halfheartedly do your job, put in your eight hours, do as little as you can to avoid work and to avoid consequence you will eventually find yourself facing situations of poor performance rankings and you may not even know why and did not even see it coming. If you assume that your co-workers are not studying and experimenting on their own time you are mistaken. There are those that seek to gain knowledge and experience on their on time and dime.&lt;br /&gt;&lt;br /&gt;As you study on your own do not become another breed of the dog-matic (get it, dog breed). Do not bring the latest thing you have read about into the work place and shout, "We should do this now!" First experiment with it, use it, and understand the problems, issues, and concerns it addresses. Then do a gentle analysis of your work and see if these problems, concerns, and issues exist. THEN see if the current process has methods to address these issues. Often there exists a way to address the issue and no-one is doing it. If there is no current way of addressing the issue then look at the current system and figure out how to create an interface to use to plug this new method into place. Do not be a bull in a glass/china shop.&lt;br /&gt;&lt;br /&gt;Some say that people are never the problem. My level of enlightenment is not sufficient to see things that way. Maybe some day I will see it that way, or maybe not. Maybe I am ahead of them already. The problem is there is no way to know for sure!&lt;br /&gt;&lt;br /&gt;At this time I believe this: People make the choices, and people enforce the consequences. (I am not talking about people choosing to break physical laws but people choosing to break impositions.) People choose their response to the consequences. People choose how to judge and they do so inconsistently and imperfectly and therefore the results vary.&lt;br /&gt;&lt;br /&gt;(This was originally posted to the &lt;a href="http://tech.groups.yahoo.com/group/extremeprogramming/"&gt;Extreme Programming Users Group&lt;/a&gt;)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/36645098-3502835579201758806?l=digerati-illuminatus.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://digerati-illuminatus.blogspot.com/feeds/3502835579201758806/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=36645098&amp;postID=3502835579201758806' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/36645098/posts/default/3502835579201758806'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/36645098/posts/default/3502835579201758806'/><link rel='alternate' type='text/html' href='http://digerati-illuminatus.blogspot.com/2009/04/people-choose-process.html' title='People CHOOSE Process'/><author><name>Geoff Slinker</name><uri>http://www.blogger.com/profile/12365501393247949005</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-36645098.post-7427988079246017296</id><published>2009-03-26T09:36:00.000-07:00</published><updated>2009-03-26T09:50:48.886-07:00</updated><title type='text'>Runtime Adaptation</title><content type='html'>Runtime Adaptation is the ability for an object to increase and grow into another type of object at runtime.&lt;br /&gt;&lt;br /&gt;In most Object Oriented languages an object is "born" with a set of abilities. Typically this is done through inheritance or interfaces.&lt;br /&gt;&lt;br /&gt;class JackOfAllTrades : IPerson, IHandyMan, IPlumber, IBrainSurgeon, IAutoMechanic&lt;br /&gt;{&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;JackOfAllTrades can be used in any method where an IPerson, IHandyMan, IPlumber, IBrainSurgeon, or IAutoMechanic is needed.&lt;br /&gt;&lt;br /&gt;At runtime JackOfAllTrades can not become IDentist. JackOfAllTrades can not learn to be a dentist and cannot act in the role of a dentist.&lt;br /&gt;&lt;br /&gt;Runtime Adaptation allows JackOfAllTrades to become a full fledged dentist at runtime and retain this ability carrying forward. JackOfAllTrades does not have to use another object that implements IDentist and then have that object do work in his behalf.&lt;br /&gt;&lt;br /&gt;Just as JackOfAllTrades wants to increase in ability JackOfAllTrades may want to loose abilities as well and give up plumbing.&lt;br /&gt;&lt;br /&gt;The acquisition of new abilities could be considered "Behavior as a Service" and I could vend the IDentist capabilities to your JackOfAllTrades.&lt;br /&gt;&lt;br /&gt;Just a small glimpse of the sandbox in which my mind plays.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/36645098-7427988079246017296?l=digerati-illuminatus.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://digerati-illuminatus.blogspot.com/feeds/7427988079246017296/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=36645098&amp;postID=7427988079246017296' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/36645098/posts/default/7427988079246017296'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/36645098/posts/default/7427988079246017296'/><link rel='alternate' type='text/html' href='http://digerati-illuminatus.blogspot.com/2009/03/runtime-adaptation.html' title='Runtime Adaptation'/><author><name>Geoff Slinker</name><uri>http://www.blogger.com/profile/12365501393247949005</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-36645098.post-2166651571932220214</id><published>2009-03-17T07:18:00.000-07:00</published><updated>2009-03-17T07:26:52.146-07:00</updated><title type='text'>Design by Use to the rescue... AGAIN</title><content type='html'>Just a quick note. Yesterday I was bogged down in a serious piece of code re-work. It was the changing of part of a framework. Since it is a framework, everything built on it is affected by change.&lt;br /&gt;&lt;br /&gt;I was changing from an Event based model to what I term a "usage" based model. Remembering the advice of Stroustrup that resource acquisition is allocation I used this knowledge to begin to make the changes. I became stuck very quickly. Stuck in the overwhelming amount of code and all of the many classes that had overridden these framework interfaces.&lt;br /&gt;&lt;br /&gt;Once again I remembered, Design by Use. When I did this the paralysis ended and the solution began flowing. I started at the level from which the new model/framework would be called and I wrote the code as if the new framework already existed. Often the old code was harvested into the new methods where appropriate. Everything flowed and it was more like writing new code with no dependencies than re-working code. Why? Because that is what it became, new code!&lt;br /&gt;&lt;br /&gt;All of you must try Design by Use! It has really made a difference for me. When ever you are stuck try it out!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/36645098-2166651571932220214?l=digerati-illuminatus.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://digerati-illuminatus.blogspot.com/feeds/2166651571932220214/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=36645098&amp;postID=2166651571932220214' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/36645098/posts/default/2166651571932220214'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/36645098/posts/default/2166651571932220214'/><link rel='alternate' type='text/html' href='http://digerati-illuminatus.blogspot.com/2009/03/design-by-use-to-rescue-again.html' title='Design by Use to the rescue... AGAIN'/><author><name>Geoff Slinker</name><uri>http://www.blogger.com/profile/12365501393247949005</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-36645098.post-8525037540172462008</id><published>2009-03-16T10:24:00.000-07:00</published><updated>2009-03-16T11:16:06.949-07:00</updated><title type='text'>Solutions and Opinions</title><content type='html'>Applying my knowledge of Computer Science and recalling experiences from years of application I find myself contemplating "solutions" and "opinions".&lt;br /&gt;&lt;br /&gt;When I am writing code, when I am actually typing in the code, I am working towards a solution to a problem.&lt;br /&gt;&lt;br /&gt;These problems are constrained to be solved in the environment in which they exist. For instance the code has to be in C#, it has to work in Windows Forms, etc. There are other constraints such as memory usage, and performance. And still there are constraints in how the code will present itself to the user through the User Interface. The User Interface is constrained by accepted and common interactions defined by the domain of the product. What I mean is a Word Processor has a certain set of UI expectations and constraints placed on it by the user community just because it is a word processor.&lt;br /&gt;&lt;br /&gt;Solving problems as a developer is a difficult task. The breadth and depth of knowledge and experience must be large and ever increasing. I have seen many people never gain enough knowledge and experience necessary to continue to advance as a software developer. Some of these people were aware of their situation and made appropriate career choices. Others were oblivious to their position and found themselves locked into dead end tasks or even fired.&lt;br /&gt;&lt;br /&gt;Currently I find myself re-working some code. The code came into existence because of a short coming in the design. The code was the results of considering what would be the simplest thing to do while fitting into the current design. As with all code once it is wrote it becomes part of the environment in which any new code will exist and has influence over how the new code will be implemented.&lt;br /&gt;&lt;br /&gt;Honestly my head seems to hurt at the thought of re-working the code so that current needs for improved resource usage can be realized.&lt;br /&gt;&lt;br /&gt;The burden of the solution rests upon me. The idea of sharing the problem with others and getting their opinion on how to develop the solution is interesting and maybe even therapeutic but ultimately shallow. In all of my years of experience I have never seen anything more than a superficial "pre-flight" check from having others review a design that is based upon a large set of code that the reviewers have no real knowledge of the inner workings, couplings, code-arounds, and all the other things that make up that piece of working code. If the code had a boundary with  some other system then it would be beneficial to talk to the owners of the other systems. This current problem is completely encapsulated in "my" code.&lt;br /&gt;&lt;br /&gt;As I sit here focused on the problem at hand a tinge of jealousy seems to rise up. Jealousy of what you ask? Jealousy of those around me working on things where opinion is sufficient and no further effort is required.&lt;br /&gt;&lt;br /&gt;The solution I have to invent has to meet those many constraints  I mentioned before. It will be domonstrable that I have met the requirements through running the profilers and passing the programmer's tests. I literaly sit at this desk for hours without end and yes it is hard.&lt;br /&gt;&lt;br /&gt;So, I am a bit jealous today of the buzz I hear going on around me where people are making decisions based on opinions and where people can declare "It must be done like this" on one day and then the next day say "It now must be done differently" and those that actually have to "do the doing" are different people. Do they feel more important? Do they feel more job satisfaction? Do they feel less pressure? Do they have the burden of constantly improving? Do they have the burden of constantly replacing the core tools of their trade with new and shiny tools that are completely incompatible with the old tools and basically no better (i.e. Fortan -&gt; Pascal -&gt; Modula 2 -&gt; Ada -&gt; C -&gt; C++ -&gt; Java -&gt; C#). I am absolutely sure I could have created the current product that I am working on using Structured Analysis and C and it would be just as good as the one we have now that uses Object Oriented Design and C#.&lt;br /&gt;&lt;br /&gt;So, I sit here, improving the resource utilitization of the product and I wonder what difference does it all make. Someone else in the product could be making a choice right now that uses all of the RAM I am trying to save. Somewhere someone is making yet another GUI toolkit to which I will have to eventually port the current system.&lt;br /&gt;&lt;br /&gt;Oh yeah, I remember my motivation. A pay check. Yep that must be it. Because it surely is not all of the opinions I hear every day and change with the current weather.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/36645098-8525037540172462008?l=digerati-illuminatus.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://digerati-illuminatus.blogspot.com/feeds/8525037540172462008/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=36645098&amp;postID=8525037540172462008' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/36645098/posts/default/8525037540172462008'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/36645098/posts/default/8525037540172462008'/><link rel='alternate' type='text/html' href='http://digerati-illuminatus.blogspot.com/2009/03/solutions-and-opinions.html' title='Solutions and Opinions'/><author><name>Geoff Slinker</name><uri>http://www.blogger.com/profile/12365501393247949005</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-36645098.post-7952890971845786893</id><published>2009-02-25T09:39:00.000-08:00</published><updated>2009-02-25T10:25:55.412-08:00</updated><title type='text'>Always "Releasable"</title><content type='html'>Recently I was trying to describe code that is always releasable.&lt;br /&gt;&lt;br /&gt;One simple criteria is if someone came to a developer and said "We are going to doing a build this afternoon and release  it to the public" the developer would not say "Well you need to wait because I need to go back in and change _____".&lt;br /&gt;&lt;br /&gt;Can code be inter-iteration releasable? That is, right in the middle of the iteration can a build be made to release? It can be. I have found because of troublesome code merging issues caused by source control  I often check in things that are not complete or done. These things compile and even pass their tests but the task is not finished. I check in often because I have had significant "fights" with source control not recognizing "new items" because the project file was modified by another developer, etc. If the "sand box" or "shelf set" were better I would not be inclined to check in to the main line of the code until the task was complete.&lt;br /&gt;&lt;br /&gt;So, code can be always releasable if only completed tasks are checked-in. Incomplete tasks are safely backed up and stored in a sand box or shelf set or jump drive or something.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/36645098-7952890971845786893?l=digerati-illuminatus.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://digerati-illuminatus.blogspot.com/feeds/7952890971845786893/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=36645098&amp;postID=7952890971845786893' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/36645098/posts/default/7952890971845786893'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/36645098/posts/default/7952890971845786893'/><link rel='alternate' type='text/html' href='http://digerati-illuminatus.blogspot.com/2009/02/always-releasable.html' title='Always &quot;Releasable&quot;'/><author><name>Geoff Slinker</name><uri>http://www.blogger.com/profile/12365501393247949005</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-36645098.post-5562529230234680135</id><published>2009-02-12T16:07:00.000-08:00</published><updated>2009-02-12T17:12:46.793-08:00</updated><title type='text'>Software Quality: Customer Facing -vs- Developer Facing</title><content type='html'>There are, at least, two different types of quality to software. Customer facing and Developer facing.&lt;br /&gt;&lt;br /&gt;Customer facing quality is defined by the customer and has to do with any aspect that the customer finds important. If there is some aspect of a software product that the customer dislikes for any reason the customer can deem the product to be low quality. For instance, if the software takes too long to load at startup the customer may complain about the quality of the software. If a button in a GUI interface is not where the user expects it then the customer may complain about the quality of the software. In these two examples often the user will say, "Did anyone test this before it went out the door." This line of questioning also leads many to think that enough testing will find all quality issues.&lt;br /&gt;&lt;br /&gt;Developer facing quality is defined by the developer when making judgments about the code or the systems upon which the code is developed. Code quality is often discussed in terms of such things as no duplication, no go-to's, no global variables, etc. Code quality also encompasses such things as which database was used, which OS is the target, etc. Yet another aspect of code quality has to do with the architecture, design, and metaphors used to compose the software.&lt;br /&gt;&lt;br /&gt;Let me be clear, the customer does not care about the code quality. (Now if you are developing software libraries, tool kits, frameworks, etc., and provide the code to your customers then this is obviously different.)  To the customer it is all product quality. If a customer finds problems with their software and the customer actually has the opportunity to talk to the developer of the software and the software developer says, "Well the problem is we have way too much duplication in the code and there is this static class filled with values that get changed all over the place, yadda yadda yadda" all the customer hears are EXCUSES.&lt;br /&gt;&lt;br /&gt;Does this mean that the developer's concerns and efforts to have a level of quality in the code are ultimately worthless? Well, if you think that then I suggest you are trying to convince yourself of something other than reality, whether you are denying the fact that you don't really have enough money or skill to be in the business or some other reason you want to blame development. Developer's have compelling reasons to address code quality issues.&lt;br /&gt;&lt;br /&gt;Does the customer care if the software was developed by the greatest programmers? The first answer is "NO", they do not care. One reason is they don't care because they do not understand how software is made and how the making of the software is tied to the customer facing quality.&lt;br /&gt;&lt;br /&gt;Should developers try to get customers to care about code level quality? No because I feel it is not possible to communicate such things.&lt;br /&gt;&lt;br /&gt;So, if I am correct that customers do not care about code quality and it is difficult to imagine that the majority of customers could be enlightened. So then, what is the purpose of this posting?&lt;br /&gt;&lt;br /&gt;There are at least two types of quality spoken of when talking about software. Often one person is talking about customer facing quality and the other is talking about developer facing quality. It causes endless discussion which get no where!&lt;br /&gt;&lt;br /&gt;In my opinion these items are realities of software:&lt;br /&gt;&lt;ol&gt;&lt;li&gt;The customer cares about product quality.&lt;/li&gt;&lt;li&gt;The customer DOES NOT care about code quality.&lt;/li&gt;&lt;li&gt;The customer believes product quality is the results of testing.&lt;/li&gt;&lt;li&gt;A product can have minimum "product quality" issues and be filled with "code quality" issues.&lt;/li&gt;&lt;li&gt;A product with poor code quality will not be able to keep up with competing products in an agressive market space.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;A product with poor code quality will not be able to attract or retain the talented software developers needed to move the product forward&lt;/li&gt;&lt;li&gt;A product with great code quality may receive a low quality product rating by the customers.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;The customer will leave a product that lags behind the competition.&lt;/li&gt;&lt;li&gt;The customer will spend their money how they see fit.&lt;/li&gt;&lt;li&gt;A company with more money can produce more low quality code and be able to afford the incurred costs in order to push a company with less capital out of the sector.&lt;/li&gt;&lt;li&gt;A company with more money can address customer facing quality issues through the use of customer service activities such as phone support, books, tutorials, managed users groups, etc., thus the company's wealth is sufficient to afford the costs of issues with product quality.&lt;/li&gt;&lt;/ol&gt;This list could go on and on.&lt;br /&gt;&lt;br /&gt;In the developer community can we at least be clear when we are talking about customer facing quality versus developer facing quality? Call it out when it is not clear which type of quality is being discussed or maybe it is yet another facet of quality still.&lt;br /&gt;&lt;br /&gt;Is it obvious that this is a complex system with many inputs and feedbacks. Cash is king, up to a point. Product quality is king, up to a point. Code quality is king, up to a point.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/36645098-5562529230234680135?l=digerati-illuminatus.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://digerati-illuminatus.blogspot.com/feeds/5562529230234680135/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=36645098&amp;postID=5562529230234680135' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/36645098/posts/default/5562529230234680135'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/36645098/posts/default/5562529230234680135'/><link rel='alternate' type='text/html' href='http://digerati-illuminatus.blogspot.com/2009/02/software-quality-customer-facing-vs.html' title='Software Quality: Customer Facing -vs- Developer Facing'/><author><name>Geoff Slinker</name><uri>http://www.blogger.com/profile/12365501393247949005</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-36645098.post-8581521906573653007</id><published>2009-02-02T09:54:00.000-08:00</published><updated>2009-02-02T11:04:35.016-08:00</updated><title type='text'>Where does Quality Code come from?</title><content type='html'>I have commented and blogged about code quality many times. A recent discussion has influenced me to review my old posts.&lt;br /&gt;&lt;br /&gt;A current blog entry entitled "&lt;a href="http://xprogramming.com/blog/2009/02/01/quality-speed-tradeoff-youre-kidding-yourself/"&gt;Quality-Speed Tradeoff - You're kidding yourself&lt;/a&gt;" asserts that quality is a primary factor in obtaining and sustaining a high speed of software development.&lt;br /&gt;&lt;br /&gt;The Maverick Software Development blog contains an archive of the most interesting posts from the old Maverick Software Development group. On that blog can be found "&lt;a href="http://mavericksoftwaredevelopment.blogspot.com/2008/01/quality-code.html"&gt;Quality Code&lt;/a&gt;" where an analogy is presented to show some of the various definitions of a quality automobile.&lt;br /&gt;&lt;br /&gt;So, where does quality code come from? Another question could be where does poor/low quality code come from?&lt;br /&gt;&lt;br /&gt;If those questions can be answered could we arrive at the "cause" of poor/low quality code and the "cause" of high quality code?&lt;br /&gt;&lt;br /&gt;Another question that comes to mind is this, "Can a high quality software product be made of low quality code?" This question causes one to suppose that the quality of the software product and the quality of the code may be independent. Is this true?&lt;br /&gt;&lt;br /&gt;Consider read-ability to be an aspect of quality code. Readable code is another term for code that conveys an accurate message of what the code is actually doing. It is beyond "intent revealing". Intent revealing code is supposed to convey the intent of the programmer. What if the programmer did not meet their intentions? Readable code makes it apparent to what is actually taking place.&lt;br /&gt;&lt;br /&gt;Can a quality software product be developed with code that is not easily read?&lt;br /&gt;&lt;br /&gt;Here is a consideration for you. Assembly languages are not easily read by the human programmer. There have been quality software products developed in assembly language. Therefore quality software products can be developed with code that has poor readability and therefore a quality software product can be developed with poor/low quality code.&lt;br /&gt;&lt;br /&gt;Can poor/low quality code be modified correctly as fast as high quality code?&lt;br /&gt;&lt;br /&gt;Consider the development of what is termed "high level languages". One of many reasons that languages such as AGOL, Pascal, COBOL, C, Ada, ...., C# and Java have been developed was to decrease the burden and cost of understanding existing code that needed modification. Simply stated it is that high level languages are more readable. Given this known aspect of programming it can be stated that readable code can be modified correctly faster than less-readable code. Therefore quality code allows for increased speed when maintaining code, or stated another way, quality code takes less time to modify than poor/low quality code. Can this be said for all facets of quality for code?&lt;br /&gt;&lt;br /&gt;Consider another attribute of quality code. Quality code has little or no duplicated code. Let's go back to some of the previous questions. Can a quality software product be developed with low quality code? Can a quality software product be developed with duplicated code? I propose that the answer is again YES.&lt;br /&gt;&lt;br /&gt;Can code with duplication be correctly modified as fast or faster than code with little or no duplication? The answer is NO. The time to locate the duplicate code plus the time to insert the modification in each location are just two of the factors of the increased time needed to deal with duplicate code. Once again code quality is related to the speed in which correct modifications can be made to the code.&lt;br /&gt;&lt;br /&gt;Does it take longer to initially develop high quality code? In the case of readable code I propose that in the worst case it takes no longer to develop readable code than non-readable code and that in most cases it takes less time. In the example of assembly code versus a high level language I propose that most modern software applications can always be developed faster in a high level language. In the case of duplicate code I propose that it takes less time to create the appropriate non-duplicate containing solution than it does to duplicate the code. Let us step back a few short years before refactoring functionality in modern IDE's. Many times I had developed code that I had "inlined" what was conceptually a function. After I had developed it and stepped through it with the debugger until I was satisfied I would then copy the code and make a function and paste it in. It was easy and didn't take any longer than it would to have duplicated it else where. I have now given two examples where quality code takes less time to develop than poor/low quality code.&lt;br /&gt;&lt;br /&gt;Finally, where does quality code come from? Well the obvious answer is from people that understand code quality. So, where do people come from that have that understanding? I dare say they are the result of much work and effort on their part to gain experience, knowledge, techniques, and tools which allow them to excel in their profession.&lt;br /&gt;&lt;br /&gt;I propose that the level of quality of code is directly related to the level of experience, expertise, and professionalism of the one writing the code. If you want to experience the benefits of quality code then you must first find experienced professionals or allow your developers the opportunity to become those desired professionals.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/36645098-8581521906573653007?l=digerati-illuminatus.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://digerati-illuminatus.blogspot.com/feeds/8581521906573653007/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=36645098&amp;postID=8581521906573653007' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/36645098/posts/default/8581521906573653007'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/36645098/posts/default/8581521906573653007'/><link rel='alternate' type='text/html' href='http://digerati-illuminatus.blogspot.com/2009/02/where-does-quality-code-come-from.html' title='Where does Quality Code come from?'/><author><name>Geoff Slinker</name><uri>http://www.blogger.com/profile/12365501393247949005</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-36645098.post-4518478158401864453</id><published>2009-01-27T10:28:00.000-08:00</published><updated>2009-01-27T10:29:55.562-08:00</updated><title type='text'>Birds and Stones</title><content type='html'>If you kill too many birds with one stone there will be no birds left.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/36645098-4518478158401864453?l=digerati-illuminatus.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://digerati-illuminatus.blogspot.com/feeds/4518478158401864453/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=36645098&amp;postID=4518478158401864453' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/36645098/posts/default/4518478158401864453'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/36645098/posts/default/4518478158401864453'/><link rel='alternate' type='text/html' href='http://digerati-illuminatus.blogspot.com/2009/01/birds-and-stones.html' title='Birds and Stones'/><author><name>Geoff Slinker</name><uri>http://www.blogger.com/profile/12365501393247949005</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-36645098.post-5495371276840634225</id><published>2009-01-12T10:08:00.000-08:00</published><updated>2009-01-12T10:09:39.888-08:00</updated><title type='text'>Leadership, Wisdom, and Experience</title><content type='html'>A leader has enough wisdom to allow others to gain experience.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/36645098-5495371276840634225?l=digerati-illuminatus.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://digerati-illuminatus.blogspot.com/feeds/5495371276840634225/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=36645098&amp;postID=5495371276840634225' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/36645098/posts/default/5495371276840634225'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/36645098/posts/default/5495371276840634225'/><link rel='alternate' type='text/html' href='http://digerati-illuminatus.blogspot.com/2009/01/leadership-wisdom-and-experience.html' title='Leadership, Wisdom, and Experience'/><author><name>Geoff Slinker</name><uri>http://www.blogger.com/profile/12365501393247949005</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-36645098.post-7971109181601425293</id><published>2009-01-01T12:24:00.000-08:00</published><updated>2009-01-01T13:44:02.071-08:00</updated><title type='text'>One Year...</title><content type='html'>One year ago I canceled all of my subscriptions to software development groups. One year ago I stopped attending any local users groups. One year ago I went back to being nothing more than a programmer.&lt;br /&gt;&lt;br /&gt;I did that for a few reasons.&lt;br /&gt;&lt;br /&gt;One reason was that I decided the posting opinions and comments to all of those groups seemed to exhibit attributes of an addiction. It became too important to be heard on a forum where there is no human interaction and that is filled with miscommunication, misinterpretation, and seemingly endless rehashing.&lt;br /&gt;&lt;br /&gt;I canceled my subscriptions so that I would not be able to post. I have lurked on the groups that have rights that anyone may read without being a member. Because of not being able to post I did not feel the need to read the group several times a day. I probably checked the groups twice a month and then I quickly scanned the topics to see if anything new or interesting was being discussed or if any particular posters that I like to monitor had any comments.&lt;br /&gt;&lt;br /&gt;Wow, if you have read to this point I am amazed. I mean really, who cares what one software developer rambles on about.&lt;br /&gt;&lt;br /&gt;I have focused on software development. At work I am just another programmer. During the last year I have written tens of thousands of lines of code. Yes, that much. I have thrown out about the same amount as well. I have developed some of the most sophisticated code that is highly optimized for the specific platform in which it runs. I have invented two new visualization techniques for specific types of data. I have invented new "widgets" for manipulating data.&lt;br /&gt;&lt;br /&gt;All of the code has been developed using the "Design by Use" approach.&lt;br /&gt;&lt;br /&gt;I have complex objects that have tests to exercise them. I have thousands of lines of code without a single test (in the current way of thinking of tests).&lt;br /&gt;&lt;br /&gt;I have not encouraged any process what-so-ever, in the traditional sense of process. I don't remind anyone to have a stand-up meeting. I haven't moved a single card on the white board from one category to the next.&lt;br /&gt;&lt;br /&gt;During this time I have became "online" friends with a few of our key customers. Yes, a lowly developer talking directly to customers! Surely the end is nigh.&lt;br /&gt;&lt;br /&gt;During this year I have been quite satisfied with work. And for me work has been writing software. Not talking about writing large systems, but actually writing them. This system is multi-threaded and difficult to manage because it needs lots of system resources. It runs on a database and has complex data structures. Just the other day I had to refresh my memory on the shortest path problem for graphs.&lt;br /&gt;&lt;br /&gt;Here is an interesting observation. The code seems to be just as solid, reliable, and efficient as code where I used some software process and lauded the processes' use and talked of its advantages. "Heresy! Surely he has strayed because of his absence!" cries the dogmatic process evangelist!&lt;br /&gt;&lt;br /&gt;During this time I have been carefully observing every aspect of the team I work on and other teams in the company. What have I learned? A lot.&lt;br /&gt;&lt;br /&gt;I have learned "selective publication of favorable results" seems to dominate discussion in the field of software development. The "causal" argument is predominant in software process.&lt;br /&gt;&lt;br /&gt;I have learned that skill in programming is the most important aspect of all. A skilled programmer can seemingly ignore process and still produce quality code. Another thing I have observed is that software process does not seem to improve the core skills of the software developer.&lt;br /&gt;&lt;br /&gt;For example the core skills of a software developer would be such things as understanding the order of an algorithm, when to use a hash table, etc.&lt;br /&gt;&lt;br /&gt;I have noticed some "younger" developers have the idea that you can just find something on "Code Project" and it will do. I ask them, "Can you maintain what you download?" By that I mean do you understand how it works because you are responsible for that code and no excuses will be sufficient to relieve you have the responsibility that the code works correctly.&lt;br /&gt;&lt;br /&gt;A programmer with a sound understanding of algorithms, data-structures (or containers), threading, and other essentials is more capable of writing solid code than one who does not have good coding skills that follows some software processes religiously.&lt;br /&gt;&lt;br /&gt;I recommend the reading of &lt;a href="http://www.apa.org/journals/features/psp7761121.pdf"&gt;"Unskilled and Unaware of It: How Difficulties in Recognizing One's Own Incompetence Lead to Inflated Self-Assessments"&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;In my opinion the greatest thing that can be done to improve software development is to improve the fundamental skills of the software developer.&lt;br /&gt;&lt;br /&gt;This year of observation has me currently of the opinion that I would rather have a team of solid programmers that follow some informal process than a team of average programmers that adhere to every tenant of some software process.&lt;br /&gt;&lt;br /&gt;Those that have followed my posts and ideas know that I am not talking about a bunch of cowboy programmers and empire builders. So, If you are imagining that I am justifying such behavior you are incorrect and I have not been clear and for that I apologize.&lt;br /&gt;&lt;br /&gt;I advocate improved education, processes that promote the gaining of experience, and improved reasoning skills.&lt;br /&gt;&lt;br /&gt;&lt;i&gt;"&lt;span style="font-family:Verdana, Arial, Helvetica, sans-serif;font-size:85%;"&gt;The haphazard approach to training in reasoning from evidence in our society is, in its way, astounding — and merits a call to action. Better reasoning from evidence is substantially teachable but seldom directly taught, much less required. It should be central to curriculum requirements, at both graduate (advanced) and undergraduate (basic) levels — if not sooner.&lt;/span&gt;"&lt;/i&gt;&lt;br /&gt;&lt;br /&gt;&lt;i&gt;"&lt;span style="font-family:Verdana, Arial, Helvetica, sans-serif;font-size:85%;"&gt;After all, sound reasoning from evidence is (or ought to be) fundamental for persons in each arena in which decisions should be rendered, or inferences drawn, on evidence: not just doctors and scientists, but journalists, policy makers — and indeed citizens, whose determinations affect not solely their own lives but others', each time they parent, serve on juries, and vote.&lt;/span&gt;"&lt;br /&gt;&lt;/i&gt;&lt;span style="font-size:78%;"&gt;Reasoning from Evidence: A Call for Education, Beatrice Golomb, MD, PhD&lt;/span&gt;&lt;i&gt;&lt;br /&gt;&lt;/i&gt;&lt;br /&gt;This year I am going to become involved again in Software Process. Not in the way I used to be involved. Times have changed and so have I.&lt;br /&gt;&lt;br /&gt;What have you learned in the past year? What did you do to learn it?&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/36645098-7971109181601425293?l=digerati-illuminatus.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://digerati-illuminatus.blogspot.com/feeds/7971109181601425293/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=36645098&amp;postID=7971109181601425293' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/36645098/posts/default/7971109181601425293'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/36645098/posts/default/7971109181601425293'/><link rel='alternate' type='text/html' href='http://digerati-illuminatus.blogspot.com/2009/01/one-year.html' title='One Year...'/><author><name>Geoff Slinker</name><uri>http://www.blogger.com/profile/12365501393247949005</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-36645098.post-4146012196699219745</id><published>2008-09-15T16:00:00.000-07:00</published><updated>2008-09-15T17:34:38.166-07:00</updated><title type='text'>Time Tables versus Mile Stones</title><content type='html'>It's Saturday morning and you are going fishing. You need to catch  twenty blue gill because you have invited friends over for dinner for some fresh fish, home fries, coleslaw, and hush puppies.&lt;br /&gt;&lt;br /&gt;You need to have the fish caught by 4:30 p.m. and cleaned by 5:00 p.m. in order to have them hot out of the skillet for when the guests arrive.&lt;br /&gt;&lt;br /&gt;What time should you go to the lake and start fishing?&lt;br /&gt;What time is the latest that you could possibly go and start fishing?&lt;br /&gt;&lt;br /&gt;Those questions are just to get you to thinking.&lt;br /&gt;&lt;br /&gt;I live in the United States of America. Currently my country is involved in what is commonly referred to as a war against terror on two fronts. The fronts are Iraq and Afghanistan. I am not giving my opinion on any aspect of these military actions other than the issue of time tables.&lt;br /&gt;&lt;br /&gt;Currently there are those who desire a time table for when military action will be completed in Iraq.&lt;br /&gt;&lt;br /&gt;Too often time tables are the results of "pure management". What I mean is that those that are not actually doing the action but have some relationship with the outcome try to manage by arbitrary dictate of schedule. Managers may try to time-box everything into a neat package. Managers like neat.&lt;br /&gt;&lt;br /&gt;(This will be tied to Software Development. I hope you can wait.)&lt;br /&gt;&lt;br /&gt;Let's go back to the fishing analogy.&lt;br /&gt;&lt;br /&gt;Let's suppose you allow thirty minutes to catch the twenty blue gill. I personally have caught that many fish in that time, for real. And there have been days when I have caught one or two in thirty minutes.&lt;br /&gt;&lt;br /&gt;Let's suppose you have been fishing for fifteen minutes and you only have four fish. You may inform the fish that you are on a time table if you like, but I think it will not entice them to bite.&lt;br /&gt;&lt;br /&gt;Obviously you can't make fish bite and you can't predict how long it will take to catch twenty fish. Fish have a mind of their own and are motivated to take bait by many factors which you can not control.&lt;br /&gt;&lt;br /&gt;My advice to you is to go fishing as early as you possibly can and have a couple of ponds or lakes you can visit. Also, invite your friends over for some fresh fish or for brats, depending on the outcome of the fishing trip.&lt;br /&gt;&lt;br /&gt;Now I will draw this closer to programming by returning to the Iraq time table. It is closer to programming because people are involved, not fish.&lt;br /&gt;&lt;br /&gt;When dealing with people, time tables are used to focus the people on the tasks at hand. It is supposed that people may not work as hard as possible unless there is a tight schedule and management pressure. Often rewards for early delivery or punishment for late delivery are used as an added motivator.&lt;br /&gt;&lt;br /&gt;It could be argued that in Iraq there are those that would prefer a U.S. military presence for a very long time. Maybe the Iraqi government prefers having the U.S. risk military personnel instead of risking Iraqi citizens. Maybe the Iraqi government prefers having the U.S. military infrastructure at their disposal because it is cheaper than developing their own. Maybe there are military contractors that want to continue involvement because it is lucrative for them. Which ever reasons exist it seems to show that there are conflicting interests and no common goal.&lt;br /&gt;&lt;br /&gt;Just as you can not clean a fish until it is caught and you can not fry the fish until it is cleaned you can not expect Iraqi security forces to take control until there are sufficient members of the Iraqi security force. At least with the fish story if you don't catch the fish in the time allotted you have told your guests they may have to eat brats instead. I do not know of any alternatives in the Iraq situation. Mile stones have to be reached before the next step can be taken.&lt;br /&gt;&lt;br /&gt;Another aspect of management setting aggressive time tables is that it can be inferred that management considers the work force lazy and not working as hard as it can all of the time. In the situation with Iraq it may be inferred that the military personnel are not doing their best job. This inference can be very upsetting because military personnel are putting their life on the line and it is insulting to think that the managers feel they are not doing their best job.&lt;br /&gt;&lt;br /&gt;For some it is considered failure to move on to the next time boxed item before the previous is finished. Continuing to move forward without finishing items is building failure upon failure. That is why you will hear it said that "failure is not an option". A series of failures or incomplete objectives create instability and invite opportunities for disaster. For military actions such behavior would seem total foolishness and would risk further loss of life and possible defeat. That may be why time tables are associated to defeat.&lt;br /&gt;&lt;br /&gt;If you are building a house and you do not complete the foundation just because the time for completing the foundation has passed an you move on to installing the walls it would seem foolish to most everyone. If you are fishing you do not go to the cutting board and get out your filleting knife just because it is time to start cleaning fish if you don't have any fish to clean.&lt;br /&gt;&lt;br /&gt;Software development, fortunately, is not as rigid as building a house or managing a war. A software product may have many features. However, not all of those features are needed for a first release of the product. In software it is actually preferred to release enough features to place the product into the market such that the product can gain traction, build a user base, and start a revenue stream. After the first release feed back is used to select a few more features and a new version of the product is released. This continues over and over again for as long as the product is marketable and viable.&lt;br /&gt;&lt;br /&gt;Software can combine time tables with mile stones.&lt;br /&gt;&lt;br /&gt;Suppose we have product with many features defined. The market seems to indicate that a release in twelve months would be optimal. The features are prioritized and an estimate on the time to deliver each feature is made. Features are organized by dependency so that if feature D is wanted in the product release it is understood that features A, B, and C must be developed first. (Notice that to get to D, you must pass milestones A, B, and C.)&lt;br /&gt;&lt;br /&gt;After the dependencies and estimates are in place a sub set of the total feature set is selected and this will be the goal for  the twelve month time table. (I just realized that I am imagining a desktop application so delivery of the product is more complex than a Web app that could be rolled out incrementally.)&lt;br /&gt;&lt;br /&gt;The product now has a feature set definition. At this point each feature, in order of dependency, can be time boxed (a time box is a start date and and end date) and the features can be organized and assigned. This is effectively serializing the feature set.&lt;br /&gt;&lt;br /&gt;As each feature is delivered (this implies that it really does work) the product's release schedule can be monitored to give an idea if the product will ship on the desired date.&lt;br /&gt;&lt;br /&gt;If the feature set of the product is a bare minimum and can not be reduced further then the product can not ship until every feature is completed. If features take longer than expected then the ship date will have to slip. There is no alternative. You can not alter time. Therefore mile stones actually trump time tables. Delivery is an end, time tables are a means of estimation. Do not confuse the means with the ends.&lt;br /&gt;&lt;br /&gt;Now, let's imagine managers, pure managers, trying to shorten the development time for the product OR trying to include more features in the twelve month period. When I say "pure manager" I mean they can not develop code so in other words they can not do anything to help get the code finished any sooner. They can't lend a hand.&lt;br /&gt;&lt;br /&gt;If the managers will not increase the number of developers and re-assign existing tasks amongst the work force then it seems impossible to get more done in less amount of time.&lt;br /&gt;&lt;br /&gt;For management to change the dates because they feel the work force is not working at full capacity can infer that management feels the workers are lazy. That is insulting to the work force. Maybe management feels the workers have padded the time estimates. The workers will recognize this and infer that management feels that they are dishonest and lazy. The workers morale may drop and if that happens then there will be side effects.&lt;br /&gt;&lt;br /&gt;Here is something I want you to consider.&lt;br /&gt;&lt;br /&gt;If you have hired the brightest and best developers, and if they are completely honest and ethical, and if they never get sick or have any personal issues or crisis, and if they are the very best at software architecture, then how ever long it takes them to develop a software product is the shortest amount of time that it could possibly be done in and no manner of process management would have decreased the time to delivery.&lt;br /&gt;&lt;br /&gt;Now, given those brilliant developers described above, if there are other tasks besides just the development tasks that need to be organized then it is prudent to add another task to the developers (which will take time and thus push the finish time out further) to estimate feature set release dates so that marketing can queue their tasks, documentation can queue their tasks, etc. By organizing other tasks to be performed in parallel you can shorten the overall time for the complete release and delivery of the product.&lt;br /&gt;&lt;br /&gt;As each milestone is reach (each feature is finished) the time tables can be readjusted and parallel tasks can be rescheduled.&lt;br /&gt;&lt;br /&gt;The software will not be done until the last feature is delivered and it will take how ever long it takes. Mile stones have power over time tables. They always will, if you expect to finish something.&lt;br /&gt;&lt;br /&gt;I hope you understand my analogy with fishing, with the very difficult situation of the Iraq war, and with house building.&lt;br /&gt;&lt;br /&gt;Your comments are welcome.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/36645098-4146012196699219745?l=digerati-illuminatus.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://digerati-illuminatus.blogspot.com/feeds/4146012196699219745/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=36645098&amp;postID=4146012196699219745' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/36645098/posts/default/4146012196699219745'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/36645098/posts/default/4146012196699219745'/><link rel='alternate' type='text/html' href='http://digerati-illuminatus.blogspot.com/2008/09/time-tables-versus-mile-stones.html' title='Time Tables versus Mile Stones'/><author><name>Geoff Slinker</name><uri>http://www.blogger.com/profile/12365501393247949005</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-36645098.post-8344363093835017910</id><published>2008-07-27T18:38:00.000-07:00</published><updated>2008-07-29T07:34:24.749-07:00</updated><title type='text'>The Allure of Code Reuse</title><content type='html'>The desire to reuse is well ingrained into the software development process.&lt;br /&gt;&lt;br /&gt;The idea of code reuse suffers from a poor choice in wording. I have not seen great success with code reuse. I have seen significant productivity gains from using object files, libraries, services, and frameworks.&lt;br /&gt;&lt;br /&gt;The bad kind of code reuse often involves what is known to programmers as ifdefs, custom environment variables, shims, wrappers, and most commonly the copying and pasting of code. Code reuse is inside the box or white box. Libraries are black boxes.&lt;br /&gt;&lt;br /&gt;The "ifdef" type changes have an insidious nature. Firstly those involved work under the assumption that just a few little changes will ultimately be harmless to the code base. Secondly the thought of reusing a large amount of code seems enticing but the very thought beguiles the user with the thought that reuse is always cheaper than rewriting software.&lt;br /&gt;&lt;br /&gt;The trickery is the idea that your only two choices are reuse or rewrite the code.&lt;br /&gt;&lt;br /&gt;"We can take Kim's code and just tweak it a bit to handle our needs!"&lt;br /&gt;&lt;br /&gt;This thought is as if it came inside of a vacuum or in absolute defiance of how code takes the shape that it takes.&lt;br /&gt;&lt;br /&gt;I have designed many clean domain models, object models, and system architectures in the pure and clean world of theoretical idea. Sometimes these designs have been based on well understood programming paradigms and the resulting code was very much the embodiment of the design. Sometimes. More often the development runs into issues and these issues cause the design to be changed.&lt;br /&gt;&lt;br /&gt;I recently developed a 2D graphing/charting package. This is nothing new to me because I have done a few. What was new to me was the system that it had to be built upon. Fortunately developing 2D graphics in a GUI based OS has not changed much since the early days of Macintosh, Amiga, OS/2, and Windows development. Fundamental rules still apply. For instance, if you want to cause something to be drawn or refreshed you call Invalidate on the window or control.&lt;br /&gt;&lt;br /&gt;Because the fundamental rules apply my design for this system was "mostly" correct. As I coded I soon discovered that the OS had limitations that I did not expect. These limitations caused me to make "in place" design changes to get around the weakness of the OS. These in place changes mutate the design of the overall system making it difficult to remember or explain what the code does and why it does it that way. Obviously one uses all of the tricks of the trade to capture the intent of the code but I often hear people reading such code and saying, "That looks weird. Why did they do it that way when all you have to do is blah blah blah".&lt;br /&gt;&lt;br /&gt;I myself have even forgotten why I did something one way and I put in the more obvious solution only to remember, "Oh yeah, that doesn't work. That is why I had to do it that way."&lt;br /&gt;&lt;br /&gt;One of the most common short comings is performance. There may be some call you can make in a provided library that does what you need, but does it too slow. Performance is a requirement and it must be met. Another issue may be memory usage. Any of these issues cause the code to deviate from the theoretical design in order to meet the demands of reality.&lt;br /&gt;&lt;br /&gt;Forgetting or ignoring that code is filled with such special case code is one of the traps of code reuse.&lt;br /&gt;&lt;br /&gt;Code often takes the path of least resistance. I have seen developers change their code because of a deficiency in their own code. Sometimes it is expedient to just fix a problem where it is  encountered instead of drilling in and finding the real problem in their own code. Some developers do this because they do not consider that their code is flawed and others do it knowing the flaws of their code but justify that this is the most expedient solution to the problem.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Regardless of the reasons code is filled with little "bypasses" around bad or clogged veins of code.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;No back to the topic, code reuse.&lt;br /&gt;&lt;br /&gt;As an argument if favor of code reuse you will hear it said, "This code does almost all we need already."&lt;br /&gt;&lt;br /&gt;If I may I would like to say that 80% is almost. I pick that value not as an absolute but as a common variable used by programmers when describing code. It does not really mean exactly 80% but it means "mostly".&lt;br /&gt;&lt;br /&gt;I have heard and witnessed that 80% of the code can be developed in about 20% of the time to complete a software feature. It is the last 20% that is difficult. Again, 20% doesn't mean exactly 20% but it means "the devil is in the details".&lt;br /&gt;&lt;br /&gt;Please remember that code has bypasses all through it to avoid deficiencies. With that in mind take into consideration that the last 20% of the code takes 80% of the time to develop. This 20% of the code is the very same code that will cause the code to be difficult to reuse.&lt;br /&gt;&lt;br /&gt;So, if you can write the theoretical ideal of the code (the first 80%) easily then why exclude that when considering code reuse. Remember that the two factors of code reuse often are reuse or rewrite.&lt;br /&gt;&lt;br /&gt;I have ported code from Macintosh OS 7, 8, and 9 to Unix and Windows. I know from years of experience on large systems that it is better to first port the design, the theoretical model, the ideal, than to reuse code filled with bypasses. (Well our code is not filled with bypasses. Yeah, right.)&lt;br /&gt;&lt;br /&gt;Instead of taking code that is almost correct and filling it with ifdefs and conditions and bypasses around the new problem I suggest to develop the model from the experience gained from the previous solution.&lt;br /&gt;&lt;br /&gt;With this design reuse then let the code take its natural path of bypasses and conditions to handle the deficiencies of the new problem space.&lt;br /&gt;&lt;br /&gt;Even if the old 80/20 axiom is pure myth, I still recommend to rewrite based on a clean design.&lt;br /&gt;&lt;br /&gt;Now many will hear rewrite and equate that to expense. From my experience the reuse situation causes the code to reach a state of confusion such that it is not maintainable or extensible and thus it goes from satisfying one task sufficiently to failing to satisfy two tasks sufficiently and thus forces a rewrite. A forced rewrite due to code collapse is considered expensive in that the collapse usually happens at an inopportune moment when the system is under new loads and stresses.&lt;br /&gt;&lt;br /&gt;I once worked on some code that was reused by another team. I encountered a performance flaw that needed to be addressed. To do so meant changing the parameters to several methods. Making these changes would break the other team. The other team did not have time to change their code to provide these new parameters. I was stuck. The code began to do two tasks poorly. It only compounds from that day forward.&lt;br /&gt;&lt;br /&gt;Now there is another topic that is not considered here. That is the development of frameworks and code units that are meant to be used by many teams. I have developed such systems before and their reuse has been beneficial. Such reuse is really at a higher level than code reuse. These are libraries and services that are reused and the internal code is a black box to the users.&lt;br /&gt;&lt;br /&gt;In summary, don't limit yourself to the two choices of reuse or rewrite. There is more, there are designs to be reused and there are experiences to build upon. Code is filled with bypasses around environment deficiencies and thus makes reusing code difficult filled with pitfalls.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/36645098-8344363093835017910?l=digerati-illuminatus.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://digerati-illuminatus.blogspot.com/feeds/8344363093835017910/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=36645098&amp;postID=8344363093835017910' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/36645098/posts/default/8344363093835017910'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/36645098/posts/default/8344363093835017910'/><link rel='alternate' type='text/html' href='http://digerati-illuminatus.blogspot.com/2008/07/allure-of-code-reuse.html' title='The Allure of Code Reuse'/><author><name>Geoff Slinker</name><uri>http://www.blogger.com/profile/12365501393247949005</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>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-36645098.post-3144768291098298865</id><published>2008-05-23T10:16:00.000-07:00</published><updated>2008-05-23T11:23:31.712-07:00</updated><title type='text'>Approximating a Semicircle with a Cubic Nonrational Bezier Curve</title><content type='html'>&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://bp3.blogger.com/_W3ZUYKgeEpk/SDcFgbq1xpI/AAAAAAAAABE/Ml3Qv0TZUAk/s1600-h/VisualTestImage.jpg"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" src="http://bp3.blogger.com/_W3ZUYKgeEpk/SDcFgbq1xpI/AAAAAAAAABE/Ml3Qv0TZUAk/s400/VisualTestImage.jpg" alt="" id="BLOGGER_PHOTO_ID_5203633949191292562" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;div style="text-align: center;"&gt;&lt;br /&gt;&lt;/div&gt;At times I have had the need to approximate a semicircle with two quadratic Bezier curves.&lt;br /&gt;&lt;br /&gt;Recently I wanted to approximate a semicircle with one Bezier curve. I decided to do this with a non-rational cubic Bezier curve.&lt;br /&gt;&lt;br /&gt;&lt;div style="text-align: right;"&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://bp0.blogger.com/_W3ZUYKgeEpk/SDb9I7q1xiI/AAAAAAAAAAM/jAb8qkmT3hA/s1600-h/UnitSquare.jpg"&gt;&lt;img style="margin: 0pt 10px 10px 0pt; float: left; cursor: pointer;" src="http://bp0.blogger.com/_W3ZUYKgeEpk/SDb9I7q1xiI/AAAAAAAAAAM/jAb8qkmT3hA/s320/UnitSquare.jpg" alt="" id="BLOGGER_PHOTO_ID_5203624749371344418" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;First I made a cubic Bezier curve with a control polygon whose points correspond to a unit square.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://bp2.blogger.com/_W3ZUYKgeEpk/SDb-Pbq1xjI/AAAAAAAAAAU/zoXGTu2NjwU/s1600-h/UnitCircleAgainstBezier.jpg"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" src="http://bp2.blogger.com/_W3ZUYKgeEpk/SDb-Pbq1xjI/AAAAAAAAAAU/zoXGTu2NjwU/s400/UnitCircleAgainstBezier.jpg" alt="" id="BLOGGER_PHOTO_ID_5203625960552121906" border="0" /&gt;&lt;/a&gt;Then I plotted a circle against the Bezier curve to see how close the Bezier curve was to a semicircle. It wasn't very close. So I knew I needed to adjust the Y values of P1 and P2 to bring down the curve. But how much? I evaluated the Bezier curve parametrically at t = 0.5 and determined that the y value at t = 0.5 was 0.75 or 3/4.&lt;br /&gt;&lt;br /&gt;The radius of the semicircle is 0.5. I needed to move the Bezier curve down from 0.75 to 0.5. To do this I adjust the Y value of points P1 and P2 by:&lt;br /&gt;&lt;br /&gt;yValueOffset = radius * 4.0 / 3.0&lt;br /&gt;&lt;br /&gt;The resulting Bezier control polygon and curve is shown in the following image.&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://bp0.blogger.com/_W3ZUYKgeEpk/SDcAerq1xkI/AAAAAAAAAAc/W9OnovkzgPI/s1600-h/RectanglularControlPoly.jpg"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" src="http://bp0.blogger.com/_W3ZUYKgeEpk/SDcAerq1xkI/AAAAAAAAAAc/W9OnovkzgPI/s400/RectanglularControlPoly.jpg" alt="" id="BLOGGER_PHOTO_ID_5203628421568382530" border="0" /&gt;&lt;/a&gt;That looks more like a semicircle. Following is the same image with the semicircle plotted against it for reference.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://bp0.blogger.com/_W3ZUYKgeEpk/SDcAzrq1xlI/AAAAAAAAAAk/yIiuVqzAe_U/s1600-h/UnitCircleAgainstFirstAdjustment.jpg"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" src="http://bp0.blogger.com/_W3ZUYKgeEpk/SDcAzrq1xlI/AAAAAAAAAAk/yIiuVqzAe_U/s400/UnitCircleAgainstFirstAdjustment.jpg" alt="" id="BLOGGER_PHOTO_ID_5203628782345635410" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;For most situations this approximation will suffice.  However, I decided to try and get it a bit closer! The next change was done by some calculations which yielded a value that was very close but to tell the truth my math and the complexity of the blending functions where such that I am not sure at this time if my conclusions are correct. (Note: Don't let your math skills get too rusty!)&lt;br /&gt;&lt;br /&gt;While I endeavor to get the correct solution to the problem I will at this time share with you an easy value to remember that tightens up the Bezier curve close to the circle. The magic number is 0.05.&lt;br /&gt;&lt;br /&gt;By insetting points P1 and P2 in the X value only the resulting Bezier control polygon and curve are shown in the following image.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://bp3.blogger.com/_W3ZUYKgeEpk/SDcCTbq1xmI/AAAAAAAAAAs/Iq9Z02_6E1g/s1600-h/Approximation05.jpg"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" src="http://bp3.blogger.com/_W3ZUYKgeEpk/SDcCTbq1xmI/AAAAAAAAAAs/Iq9Z02_6E1g/s400/Approximation05.jpg" alt="" id="BLOGGER_PHOTO_ID_5203630427318109794" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;Notice how nicely this cubic non-rational Bezier curve approximates a semicircle.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://bp0.blogger.com/_W3ZUYKgeEpk/SDcCvrq1xnI/AAAAAAAAAA0/PXHD2kTKTgs/s1600-h/FitOfFullyAdjusted.jpg"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" src="http://bp0.blogger.com/_W3ZUYKgeEpk/SDcCvrq1xnI/AAAAAAAAAA0/PXHD2kTKTgs/s400/FitOfFullyAdjusted.jpg" alt="" id="BLOGGER_PHOTO_ID_5203630912649414258" border="0" /&gt;&lt;/a&gt;Here is an enlarged image so that you can see how nicely the curve fits the semicircle. (Click Image to see larger view.)&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://bp2.blogger.com/_W3ZUYKgeEpk/SDcC_Lq1xoI/AAAAAAAAAA8/3XmK3Rf6zT4/s1600-h/ZoomOfResults.jpg"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 593px; height: 404px;" src="http://bp2.blogger.com/_W3ZUYKgeEpk/SDcC_Lq1xoI/AAAAAAAAAA8/3XmK3Rf6zT4/s400/ZoomOfResults.jpg" alt="" id="BLOGGER_PHOTO_ID_5203631178937386626" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;So, in summary:&lt;br /&gt;&lt;br /&gt;xValueInset = Diameter * 0.05&lt;br /&gt;yValueOffset = radius * 4.0 / 3.0&lt;br /&gt;&lt;br /&gt;P0 = (0,0)&lt;br /&gt;P1 = (xValueInset, yValueOffset)&lt;br /&gt;P2 = (Diameter - xValueInset, yValueOffset)&lt;br /&gt;P3 = (Diameter, 0)&lt;br /&gt;&lt;br /&gt;This gives a pretty good approximation to a semicircle using only one Bezier curve.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://bp3.blogger.com/_W3ZUYKgeEpk/SDcFgbq1xpI/AAAAAAAAABE/Ml3Qv0TZUAk/s1600-h/VisualTestImage.jpg"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" src="http://bp3.blogger.com/_W3ZUYKgeEpk/SDcFgbq1xpI/AAAAAAAAABE/Ml3Qv0TZUAk/s400/VisualTestImage.jpg" alt="" id="BLOGGER_PHOTO_ID_5203633949191292562" border="0" /&gt;&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/36645098-3144768291098298865?l=digerati-illuminatus.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://digerati-illuminatus.blogspot.com/feeds/3144768291098298865/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=36645098&amp;postID=3144768291098298865' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/36645098/posts/default/3144768291098298865'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/36645098/posts/default/3144768291098298865'/><link rel='alternate' type='text/html' href='http://digerati-illuminatus.blogspot.com/2008/05/approximating-semicircle-with-cubic.html' title='Approximating a Semicircle with a Cubic Nonrational Bezier Curve'/><author><name>Geoff Slinker</name><uri>http://www.blogger.com/profile/12365501393247949005</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://bp3.blogger.com/_W3ZUYKgeEpk/SDcFgbq1xpI/AAAAAAAAABE/Ml3Qv0TZUAk/s72-c/VisualTestImage.jpg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-36645098.post-8321048801509974992</id><published>2008-05-07T07:35:00.000-07:00</published><updated>2008-05-07T07:37:30.852-07:00</updated><title type='text'>Dilbert Mashups are fun!</title><content type='html'>Many of us enjoy the Dilbert comic strip. The new site allows for mashups where you can change the comments of the last cell of the strip.&lt;br /&gt;&lt;br /&gt;Please check out mine! I enjoy trying to think of a new punch line.&lt;br /&gt;&lt;br /&gt;http://dilbert.com/users/geoffrey_slinker/&lt;br /&gt;&lt;br /&gt;You may have to create an account.&lt;br /&gt;&lt;br /&gt;Please make comments or share links to your own mashups.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/36645098-8321048801509974992?l=digerati-illuminatus.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://digerati-illuminatus.blogspot.com/feeds/8321048801509974992/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=36645098&amp;postID=8321048801509974992' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/36645098/posts/default/8321048801509974992'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/36645098/posts/default/8321048801509974992'/><link rel='alternate' type='text/html' href='http://digerati-illuminatus.blogspot.com/2008/05/dilbert-mashups-are-fun.html' title='Dilbert Mashups are fun!'/><author><name>Geoff Slinker</name><uri>http://www.blogger.com/profile/12365501393247949005</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-36645098.post-8249664989344244641</id><published>2008-05-06T07:23:00.000-07:00</published><updated>2008-05-06T08:05:04.313-07:00</updated><title type='text'>Measure or Listen?</title><content type='html'>Following are thoughts directed at Managers. This could be a Team Lead, a Technical Manager, a Product Manager, and especially a Process Manager.&lt;br /&gt;&lt;br /&gt;Why "especially a process manager"? Because in my experience they often want to measure   stuff!&lt;br /&gt;&lt;br /&gt;Measuring isn't good or bad. Measuring isn't the only thing to do either and it may not be the first thing to do. In my opinion it is never the first thing to do.&lt;br /&gt;&lt;br /&gt;If you are working on a software development team and it is experiencing some difficulty what do you do to get "control" of the situation?&lt;br /&gt;&lt;br /&gt;Suppose the code is in a state of thrashing in that one bug fix seems to create new bugs.&lt;br /&gt;&lt;br /&gt;What would you do?&lt;br /&gt;&lt;br /&gt;Maybe you would do this:&lt;br /&gt;1) Are they doing code reviews? How many of you are doing code reviews before check-in?&lt;br /&gt;2) Are there regression tests? How much code coverage do we have with our tests?&lt;br /&gt;(I will stop here for brevity)&lt;br /&gt;&lt;br /&gt;For a process manager does everything have a process solution? If the perfect process is in place and there are failures does it mean that the people are wrong? Just a couple of thought questions.&lt;br /&gt;&lt;br /&gt;Now to the point.&lt;br /&gt;&lt;br /&gt;If there are problems then ask those that are experiencing the problems what they think the problems are and how they think the problems can be addressed. Listen carefully to their responses.&lt;br /&gt;&lt;br /&gt;I have worked on many products where the software's design had reached its limit of usability. This includes software that I myself designed. There comes a time where weaknesses and inefficiencies become grossly apparent and it is time to address the core issues. While working on these products (with very large code bases) I have seen the fixes create new bugs and the code stability thrashes about. In each of these instances I have been asked what is wrong and I have said, "We need time to build a new foundation, the code has become a mess of add-ons and kludges and it is only going to get worse." Most every time the response is, "We do not have time for that. We will do code reviews and have someone start on writing tests to get better coverage." And most every time the thrashing problem does not go away. The thrashing seems to lessen but I propose that it lessens only because less code is being written due to the fact that more time is spent in code reviews and writing regression tests.&lt;br /&gt;&lt;br /&gt;Do you have an example where you felt you knew how to address the "real" problem but was never asked? Is it always a matter of improving the process that will make the bugs go away?&lt;br /&gt;&lt;br /&gt;Well, some of you are probably saying, "He wants cowboy programming. He never has liked Process Managers and gives them grief whenever he can. He never has worked on a large project with many developers or he would know that process is what holds it all together." Well, say what you may, that is your prerogative and that is what I am doing here!&lt;br /&gt;&lt;br /&gt;I still say this, "Listen first." What does listen mean? It means hearing and understanding. Understanding is the key. This key makes it difficult for managers that do not have technical backgrounds for if they do not understand the problem or the proposed solution. How do such know if the suggestion is good or bad? If the manager doesn't understand the technical issues and only understands process then how can the manager do anything but suggest process changes to address every problem?&lt;br /&gt;&lt;br /&gt;Listen first. Measure later.&lt;br /&gt;&lt;br /&gt;Geoff&lt;br /&gt;&lt;br /&gt;p.s. Maybe you have heard, Measure twice and cut once. It is a saying used by carpenters. It doesn't apply to software. Sorry.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/36645098-8249664989344244641?l=digerati-illuminatus.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://digerati-illuminatus.blogspot.com/feeds/8249664989344244641/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=36645098&amp;postID=8249664989344244641' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/36645098/posts/default/8249664989344244641'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/36645098/posts/default/8249664989344244641'/><link rel='alternate' type='text/html' href='http://digerati-illuminatus.blogspot.com/2008/05/measure-or-listen.html' title='Measure or Listen?'/><author><name>Geoff Slinker</name><uri>http://www.blogger.com/profile/12365501393247949005</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-36645098.post-5270166435427340775</id><published>2008-05-04T05:49:00.000-07:00</published><updated>2008-05-04T06:16:29.041-07:00</updated><title type='text'>Delivering Software Faster...</title><content type='html'>Delivering software faster than what or who?&lt;br /&gt;&lt;br /&gt;I know the following statement is not generally accepted, but for me it has been a constant my entire career.&lt;br /&gt;&lt;br /&gt;"Software is done when it is done. It takes as long as it is going to take."&lt;br /&gt;&lt;br /&gt;I have noticed in current discussion that the idea of incremental delivery is some how being changed exclusively into the idea of faster delivery. This incremental delivery is delivery to the customer and not solely to a QA team.&lt;br /&gt;&lt;br /&gt;I prefer incremental development of software. I believe in enough planning to divide the software into some type of conceptual model with vocabulary and metaphors to describe the abstract notion. Then I believe in enough planning to organize these abstractions in such a way that the pieces can be developed in a manner to utilize as many working in parallel as possible. Finally I believe that each piece is developed completely following the adage of finishing what you start before you start something else.&lt;br /&gt;&lt;br /&gt;For me the above paragraph is enough to be the basis for a good software development process. With all of the books, articles, and methods available I feel that the above statement in contrast is concise and sufficient.&lt;br /&gt;&lt;br /&gt;As for "delivering faster", well faster than what?&lt;br /&gt;&lt;br /&gt;What can delay software delivery?&lt;br /&gt;Poor programming skills.&lt;br /&gt;Lazy people.&lt;br /&gt;Burdensome I.T. policies.&lt;br /&gt;Buggy hardware.&lt;br /&gt;Low morale.&lt;br /&gt;...&lt;br /&gt;...&lt;br /&gt;...&lt;br /&gt;&lt;br /&gt;You add to the list anything you want that you have experienced that slows down development and thus delays software delivery. When you encounter one of these "things" that slows down development then address it in context and in a timely manner. That's the best that anyone can do. After you have addressed it then you can develop policies and practices to avoid it in the future.&lt;br /&gt;&lt;br /&gt;For instance, coupling slows down software development. One way it does so it that the human developer can not recall all of the places a piece of code is used and thus may not understand all of the side effects of a change. Problem identified. One solution is to develop the software with regression tests so that when a change is made any issues from coupling may surface. Policy and procedure to avoid unidentified coupling issues is to use a development practice like Design by Use, Test First Programming, Test Driven Development, or some other approach that facilitates the creation of a code base with "built-in" regression tests.&lt;br /&gt;&lt;br /&gt;The code will be done when it is done and not a day before. It may ship before it is done, that happens all the time!&lt;br /&gt;&lt;br /&gt;Geoff&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/36645098-5270166435427340775?l=digerati-illuminatus.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://digerati-illuminatus.blogspot.com/feeds/5270166435427340775/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=36645098&amp;postID=5270166435427340775' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/36645098/posts/default/5270166435427340775'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/36645098/posts/default/5270166435427340775'/><link rel='alternate' type='text/html' href='http://digerati-illuminatus.blogspot.com/2008/05/delivering-software-faster.html' title='Delivering Software Faster...'/><author><name>Geoff Slinker</name><uri>http://www.blogger.com/profile/12365501393247949005</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-36645098.post-6470965246808005251</id><published>2008-04-22T07:22:00.000-07:00</published><updated>2008-04-22T08:02:11.302-07:00</updated><title type='text'>YAGNI IMO</title><content type='html'>You aint going to need it = YAGNI&lt;br /&gt;&lt;br /&gt;When I first learned about YAGNI I was learning about it while I was in the context of doing code level design. &lt;br /&gt;&lt;br /&gt;I learned object oriented programming at the same time as structured programming. I didn't realize that I entered the field during a time of transition. Object oriented programming has what is known as polymorphism. Polymorphism allows a procedure of function to be declared with one name and have many versions taking different types and numbers of parameters. In this context of designing object oriented code and specifically polymorphic methods is where I learned and applied the "mantra" of YAGNI.&lt;br /&gt;&lt;br /&gt;Often I would feel "pressure" to write a method with many different sets of parameters. Here is a contrived example (without much thought put into it)&lt;br /&gt;&lt;br /&gt;public string GetName(PersonID pid){...}&lt;br /&gt;public string GetName(Person person){...}&lt;br /&gt;public string GetName(string personXML){...}&lt;br /&gt;&lt;br /&gt;The reason these three methods were coded would be because the Person class has these methods:&lt;br /&gt;&lt;br /&gt;public class Person&lt;br /&gt;{&lt;br /&gt; public PersonID GetPersonID(){...}&lt;br /&gt; public string SerializeToXML(){...}&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;So the rationale was that you didn't know how someone might want to call your methods and it is clear that they may have a Person, a PersonID, or some XML representing a person so therefore robust code will handle all three types.&lt;br /&gt;&lt;br /&gt;I was young and didn't know better and hadn't really thought it out.&lt;br /&gt;&lt;br /&gt;I would write all of these polymorphic methods and then guess what, I would have to maintain all of them as well.&lt;br /&gt;&lt;br /&gt;As I learned not to develop polymorphic methods just for the sake of someone who MIGHT want it that way I learned of YAGNI and I said, "That's it. YAGNI describes a way to avoid a maintenance problem I am experiencing in a way that I can now describe to those that are still arguing for many polymorphic methods using the term ROBUSTNESS for their defense."&lt;br /&gt;&lt;br /&gt;So, for me ROBUSTNESS and YAGNI collided! I liked it.&lt;br /&gt;&lt;br /&gt;Over the years I have seen YAGNI applied to other things instead of code level design. Now maybe it was originally envisioned for something other than code level design and I had applied it to the wrong problem. If I have done this, then I say it worked well for me and has been a sound approach for avoiding duplicate code!&lt;br /&gt;&lt;br /&gt;I have seen YAGNI applied to extra features that developers want to add to a product. I have heard this called "gold plating" as well. Most developers get ideas as they work on a product. In this case the idea is that the PRODUCT aint going to need it. (Should we call this PAGNI? Which implies the customer aint going to need it. CAGNI? James CAGNI?)&lt;br /&gt;&lt;br /&gt;The application of YAGNI to gold plating seems to hold well enough with me. But it is fairly distant from YAGNI in code level design.&lt;br /&gt;&lt;br /&gt;More recently I have heard of YAGNI being used during release planning of a product. This is where the application of YAGNI gets fuzzy for me. If there is a list of product requirements and these requirements are being sliced up into releases then all of the requirements are needed by definition of being a requirement. (Do not jump on the BIG UPFRONT WHATEVER BAND WAGON. I am not on that wagon and it is not my point.) So using YAGNI based arguments at release planning seems really far from code level design and is very very fuzzy to me. &lt;br /&gt;&lt;br /&gt;Release planning may have statements like "we can't do B before A" or "we can't do C,D, and E with the resources we have" or "H, I, and K are so far out we are not sure the technology won't change before we get there", stuff like that.&lt;br /&gt;&lt;br /&gt;Here is an interesting correlation. Methods are interfaces into the code. Polymorphism may be thought of as multiple ways of doing the same thing. Correlate this to User Interface design. There may be more than one UI control that could be used for some particular interaction with the user. Is it necessary to provide the user with three different ways to enter their user name? It is natural for me to apply YAGNI at this level.&lt;br /&gt;&lt;br /&gt;So, I use YAGNI during arguments of code level design and user interface design. In other phases of development I may be arguing what some would call YAGNI but to me it is different. I like to keep things simple. YAGNI for code level design and YAGNI for UI design.&lt;br /&gt;&lt;br /&gt;Geoff&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/36645098-6470965246808005251?l=digerati-illuminatus.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://digerati-illuminatus.blogspot.com/feeds/6470965246808005251/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=36645098&amp;postID=6470965246808005251' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/36645098/posts/default/6470965246808005251'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/36645098/posts/default/6470965246808005251'/><link rel='alternate' type='text/html' href='http://digerati-illuminatus.blogspot.com/2008/04/yagni-imo.html' title='YAGNI IMO'/><author><name>Geoff Slinker</name><uri>http://www.blogger.com/profile/12365501393247949005</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-36645098.post-3039433041143597473</id><published>2008-04-12T20:27:00.000-07:00</published><updated>2008-04-12T20:49:59.089-07:00</updated><title type='text'>Frequent Delivery of Developed Features in Software</title><content type='html'>In the "Agile" community you will hear the cry for frequent delivery of features to the customer so that the customer can know that the product is progressing.&lt;br /&gt;&lt;br /&gt;In the old days these were called "demos" or demonstrations of the product.&lt;br /&gt;&lt;br /&gt;Why are the developers trying to "sell" frequent delivery of developed features? Isn't this backwards? Shouldn't the Product Managers or the customers be the ones that are saying, "Hey, we really want to see what you have developed thus far. Can you show it to us?" How did this get twisted around such that it is the Developers trying to sell the idea of frequent demonstrations of the ever increasing functionality to the Product managers, the Process managers, and the customer! &lt;br /&gt;&lt;br /&gt;Dr. Peter Venkman: This city is headed for a disaster of biblical proportions.&lt;br /&gt;Mayor: What do you mean, "biblical"?&lt;br /&gt;Dr Ray Stantz: What he means is Old Testament, Mr. Mayor, real wrath of God type stuff.&lt;br /&gt;Dr. Peter Venkman: Exactly.&lt;br /&gt;Dr Ray Stantz: Fire and brimstone coming down from the skies! Rivers and seas boiling!&lt;br /&gt;Dr. Egon Spengler: Forty years of darkness! Earthquakes, volcanoes...&lt;br /&gt;Winston Zeddemore: The dead rising from the grave!&lt;br /&gt;Dr. Peter Venkman: Human sacrifice, dogs and cats living together... mass hysteria! &lt;br /&gt;&lt;br /&gt;Well here we are in mass hysteria. The Developers are the ones crying out to have frequent demonstrations of the current state of development.&lt;br /&gt;&lt;br /&gt;In my opinion the main point of frequent releases or demonstrations (depending on your deployment model) are primarily for showing where we are at in the development of the product. Once we know where we are at we can then say things like "Six months ago we had those features and now we have those features plus these features. We are making progress." Knowing where we are and where we have been and how long it took us to get here are facts used to progressively refine estimates of how much longer it will take and at what cost. This is a part of honesty in reporting.&lt;br /&gt;&lt;br /&gt;On a side note, somehow along the way various Anti-Agilists have distorted the weight of reporting with that of getting feedback from the customer. These Anti's have created a straw man to tear apart. The claim is that incremental development (yes, that is what every Agile process I understand uses) is some lazy, shady, and shoddy approach to software requirements. The straw man goes like this, "Agile development does not try to understand the task at hand and do their due diligence in understanding what the customer really needs. Instead they hack out some code and show it to the customer and say 'Is this what your wanted?'" Maybe some idiotic process out there does that and if so I will stand by my description of it being idiotic.&lt;br /&gt;&lt;br /&gt;The key to frequent delivery is to show where we are in the development of the product. Once you have shown this to someone it is natural for them to want to give feedback. But the intent was to deliver exactly what the customer wanted the first time. It was NOT the intent to deliver some overly simplified hack of some half known requirements and then refine the requirements because you knew you had developed a piece of junk.&lt;br /&gt;&lt;br /&gt;I have delivered many features in an incremental fashion that were 100% correct when the user saw them. There was no need to make any changes what so ever. That is the goal. Showing the progress as the product comes together allows for everyone to know the REAL status of development and to fine tune other events and tasks that will need to be performed in order to have a successful and thoughtful product launch.&lt;br /&gt;&lt;br /&gt;Isn't this stuff just common sense? Maybe cats and dogs are living together and I missed the memo.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/36645098-3039433041143597473?l=digerati-illuminatus.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://digerati-illuminatus.blogspot.com/feeds/3039433041143597473/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=36645098&amp;postID=3039433041143597473' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/36645098/posts/default/3039433041143597473'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/36645098/posts/default/3039433041143597473'/><link rel='alternate' type='text/html' href='http://digerati-illuminatus.blogspot.com/2008/04/frequent-delivery-of-developed-features.html' title='Frequent Delivery of Developed Features in Software'/><author><name>Geoff Slinker</name><uri>http://www.blogger.com/profile/12365501393247949005</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-36645098.post-3605934641625217471</id><published>2008-04-12T20:08:00.000-07:00</published><updated>2008-04-12T20:25:03.318-07:00</updated><title type='text'>Responsibility in Software Estimation</title><content type='html'>This blog post will be short for me. I will be blunt and to the point with my following opinions.&lt;br /&gt;&lt;br /&gt;Estimating the cost and time to develop software is just that, an ESTIMATION. &lt;br /&gt;&lt;br /&gt;1) It is foolish on the part of those hearing an estimate and then later representing it as a promise.&lt;br /&gt;&lt;br /&gt;2) It is unethical and dishonest for the development team to hide the discovery that an estimated delivery date and cost is now known to be in error.&lt;br /&gt;&lt;br /&gt;Why do clients and product management still to this day take software estimates and turn them into hardened dates and commitments? I understand that estimated dates are used to coordinate many parallel events and used to queue up related tasks so that everyone can rendezvous at a product delivery date. Why does product management still try to work in a fantasy software development world that simply does not exist? I can not speak for them because I am not one of them.&lt;br /&gt;&lt;br /&gt;I am a developer and I will speak from my experience on why development teams hide the knowledge that dates are slipping. They do it because it is in their best interest. They sell themselves a lie that they can catch up, do more, bend time, or some other activity which history has shown does not happen.&lt;br /&gt;&lt;br /&gt;Why is it in their best interest to hide the truth? You can answer this yourself. Just examine your company or clients and reflect on how they responded to the truth when it was given them.&lt;br /&gt;&lt;br /&gt;For you developers out there, it is my opinion that you should tell the truth on the current state of the product and the outstanding features and give corrected and updated estimates as soon as they are known. If the client or customer doesn't respond favorably to this behavior you should decide on if this is a job you want to keep instead of waiting to see if they are going to fire you for being late. Just my opinion.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/36645098-3605934641625217471?l=digerati-illuminatus.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://digerati-illuminatus.blogspot.com/feeds/3605934641625217471/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=36645098&amp;postID=3605934641625217471' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/36645098/posts/default/3605934641625217471'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/36645098/posts/default/3605934641625217471'/><link rel='alternate' type='text/html' href='http://digerati-illuminatus.blogspot.com/2008/04/responsibility-in-software-estimation.html' title='Responsibility in Software Estimation'/><author><name>Geoff Slinker</name><uri>http://www.blogger.com/profile/12365501393247949005</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-36645098.post-4594696804977941316</id><published>2008-03-20T16:57:00.000-07:00</published><updated>2008-03-24T12:39:37.064-07:00</updated><title type='text'>Windows Vista SP1 and "Unable to load DLL 'VistaDb20.dll': Invalid access to memory location."</title><content type='html'>I recently updated my "Vista box" to SP1. I ran my current project without recompiling and everything was fine. Then I checked out a file, made some changes, and recompiled my project and found that my application would no longer run.&lt;br /&gt;&lt;br /&gt;The error message I got was this:&lt;br /&gt;Unable to load DLL 'VistaDb20.dll': Invalid access to memory location.&lt;br /&gt;&lt;br /&gt;What an untimely error. We are trying to release our latest patch of our product and this takes the wind right out of our sails!&lt;br /&gt;&lt;br /&gt;After some vigorous exploration we figure out that this has something to do with the DEP. The DEP is &lt;a href="http://en.wikipedia.org/wiki/Data_Execution_Prevention"&gt;Data Excecution Prevention&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;We figured out how to completely disable the DEP and sure enough the product could now run.&lt;br /&gt;&lt;br /&gt;So now we had to figure out how to disable it pro grammatically (or at least we thought).&lt;br /&gt;&lt;br /&gt;We are doing C# development. So I wrapped up a call into the Kernel32.dll to call SetProcessDEPPolicy. This had no effect. While I was doing this Jerry (one of the members of the team) was looking into  why the recompile caused things to break.&lt;br /&gt;&lt;br /&gt;I did a build on my "XP box" and copied it to my "Vista box" and sure enough it would run just fine. So we knew it had to be something with the compile.&lt;br /&gt;&lt;br /&gt;Some Googling reveals some interesting information:&lt;br /&gt;&lt;a href="http://blogs.msdn.com/ed_maurer/archive/2007/12/14/nxcompat-and-the-c-compiler.aspx"&gt;I'm Just Saying&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Ed Maurer nails it right down. Thanks Ed.&lt;br /&gt;&lt;br /&gt;Jerry added the following to our Post-build event command line:&lt;br /&gt;&lt;br /&gt;call "$(DevEnvDir)..\tools\vsvars32.bat"&lt;br /&gt;editbin.exe /NXCOMPAT:NO "$(TargetPath)"&lt;br /&gt;mt.exe -manifest "$(ProjectDir)$(TargetName).exe.manifest" -outputresource:"$(TargetPath);#1"&lt;br /&gt;&lt;br /&gt;I just wanted to share this with those that may be having the same problems.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/36645098-4594696804977941316?l=digerati-illuminatus.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://digerati-illuminatus.blogspot.com/feeds/4594696804977941316/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=36645098&amp;postID=4594696804977941316' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/36645098/posts/default/4594696804977941316'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/36645098/posts/default/4594696804977941316'/><link rel='alternate' type='text/html' href='http://digerati-illuminatus.blogspot.com/2008/03/windows-vista-sp1-and-unable-to-load.html' title='Windows Vista SP1 and &quot;Unable to load DLL &apos;VistaDb20.dll&apos;: Invalid access to memory location.&quot;'/><author><name>Geoff Slinker</name><uri>http://www.blogger.com/profile/12365501393247949005</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>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-36645098.post-7869274445919246085</id><published>2008-03-09T07:47:00.000-07:00</published><updated>2008-03-09T09:17:06.643-07:00</updated><title type='text'>More on Code Debt</title><content type='html'>I have blogged before on &lt;a href="http://digerati-illuminatus.blogspot.com/2007/11/code-debt-product-market-debt-and.html"&gt;code debt&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;I would like to say a bit more about it.&lt;br /&gt;&lt;br /&gt;Code is like an onion. Onions have layers.&lt;br /&gt;&lt;br /&gt;The outer most layer of the code onion are the public interfaces or the exported functions. This is the layer that external code may hook up to the code.&lt;br /&gt;&lt;br /&gt;The inner layers are often made up of the classes and structures imagined and created by the developers to organize their abstraction of the problem. In this inner layer the classes will have methods visible to all of the other classes in the same layer and may have methods that only subclasses can see and finally they may have methods that only themself can see and are private.&lt;br /&gt;&lt;br /&gt;Each layer may have its own level of code debt. If the outer layer is well defined and no one ever has to peel into the onion the code debt will never be recognized.&lt;br /&gt;&lt;br /&gt;Code debt is not recognized until some activity causes its recognition.&lt;br /&gt;&lt;br /&gt;If the code is never modified or extended then no one will ever know that the code was poorly written or poorly designed and will never have to pay the costs for the poor code. I have developed code that has been running for years and never revisited. I do not accept the myth that all code is actively changing. I do feel that all code is actively becoming obsolete or decaying, but the rate of decay varies and his tied to Product Debt and Customer Debt.&lt;br /&gt;&lt;br /&gt;Another example that code debt does not exist until someone tries to modify the code is this, code may have a very accurate and understandable model of the domain, with classes and methods that are intuitive and make sense. If the activity is to add new methods and functionality to such a code base it doesn't matter if the code internal to each method is poorly written. If you don't enter that layer of the code you will never know it is poorly written. Each of the existing methods may be filled with duplicate code, multiple returns and go-to statements, use of global variables, poorly named local variables, and a myriad of other things, but the external view of the class may be very accurate and correct. If the class is added upon and the existing methods are not modified then no one will know of the code debt that lives inside the method layer. This is an example of "inner code debt" or "deep layer code debt".&lt;br /&gt;&lt;br /&gt;One of the most expensive types of code debt I have seen is where all of the code is not extend-able, modifiable, or maintainable. I have seen this often. It is when the code has to be ported to a new language. The existing system may be the best code ever developed with regression tests galore. But it doesn't matter. The choice to develop the code in a language that did not meet the future needs of the product is costly.&lt;br /&gt;&lt;br /&gt;Code debt is subjective. Often I have seen a developer take ownership of existing code and upon examination of the code find it unsavory. Such things as, "This should be an interface instead of an abstract base class". The new owner of the code starts to re-write the code to suit their idea of clean code.&lt;br /&gt;&lt;br /&gt;Code debt is relative. Often I have seen a developer take ownership of existing code and upon examination of the code find it too complex for their skill level. An easy example of this is C++ code. I have seen programmers that couldn't read parameterized types (templates). It was so foreign to them they just couldn't read the code.&lt;br /&gt;&lt;br /&gt;At the inner most layers of the code onion the code may be written very very well but the users of the objects have used them poorly and now you have a coupling mess. Tightly coupled code is a form of code debt. Often no one recognizes how tightly code is coupled until they try to remove a class from the code and replace it with a new one.&lt;br /&gt;&lt;br /&gt;Is there a relationship to source lines of code (SLOC) and code debt? If you have zero lines of code one might argue that you have no code debt. I will argue that zero lines of code is adding to the Product Debt!&lt;br /&gt;&lt;br /&gt;Code debt is not recognized until some activity exposes it by entering into its layer of existence. Any layer may be rotten but if that layer doesn't need change it will not matter. Poorly designed and architected code does not mean it has to be buggy code.&lt;br /&gt;&lt;br /&gt;Suppose there is a function of a C++ class that has 200 lines of code in it. Suppose it has to be fixed because somewhere in it there is a bug. How much code debt is there? Can you give me a cost to pay this debt?&lt;br /&gt;&lt;br /&gt;Let's take two specific scenarios.&lt;br /&gt;&lt;br /&gt;First, the 200 lines of code was written by a novice programmer. The programmer assigned to fix the bug is an expert in C++ and all of the C++ libraries. The programmer recognizes that 80% of the functionality of this buggy routine is string manipulation and replaces that code with three calls into the C++ string routines. The programmer runs a test and the bug is fixed and everything is done. Time to fix, let's say it took him two hours. Not very expensive at all.&lt;br /&gt;&lt;br /&gt;Second, the 200 lines of code was written by an expert programmer. The programmer assigned to fix the bug is a junior programmer relegated to maintenance because it is felt this is the best way for him to get to know the system. (Yes, I know about pair programming, but I am talking about code debt and how it is relative and subjective).  The junior programmer doesn't understand that any operator can be overloaded in C++ and in this particular code the indirection operator has been overloaded. The junior programmer makes changes to the code hoping to fix the bug but the changes doesn't seem to make any difference. (Why? Because the bug is somewhere else, in the overloaded operators code.) The junior developer spends days working on this. At first he thinks he has found a compiler bug! The junior programmer adds a variable to the class for tracking some state he hopes is relative and inserts the saving of this state into the code and does some conditional logic with this new state variable. The bug is fixed! He checks it in. Two weeks of work. What was the cost of paying this code debt? The sad thing is that he did not fix the bug. By adding the variable to the class he changed it's size and thus hid the real bug where part of the memory of the class was being corrupted in the code for the overloaded operator. So, in reality, nothing was fixed and everything was a waste of time and money.&lt;br /&gt;&lt;br /&gt;Because of these two examples and my previous statements I do not believe that a large number of SLOC means there is significant code debt.&lt;br /&gt;&lt;br /&gt;Some may argue that the number of features has to do with code debt. I ask, "Features at what level?" The external layer of a system may be viewed as its feature set. Thus I refer you back to my statements above about layers. Also, I remind the reader that features that have to be ported to a new programming language have a high code debt regardless of the quality of the existing code.&lt;br /&gt;&lt;br /&gt;A large system with millions of lines of code may be maintained inexpensively. One factor that keeps the expense down is that the original developers stay on with the system. They know why and how things were done. Thus code debt is affected by the members of the team. Suppose the team becomes insulted in some manner and all quit. Suddenly the code debt changed from low to extremely high!&lt;br /&gt;&lt;br /&gt;Just some of my thoughts on code debt. I hope it causes you to think about code debt in new ways as well. As a final thought I think the best way to address code debt is with the right people. Programmers (which usually are people) are the ones to address the issues with the code and their skill can make a job quick and simple.&lt;br /&gt;&lt;br /&gt;Drop me a line. I have no idea if anyone ever reads my blog posts!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/36645098-7869274445919246085?l=digerati-illuminatus.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://digerati-illuminatus.blogspot.com/feeds/7869274445919246085/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=36645098&amp;postID=7869274445919246085' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/36645098/posts/default/7869274445919246085'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/36645098/posts/default/7869274445919246085'/><link rel='alternate' type='text/html' href='http://digerati-illuminatus.blogspot.com/2008/03/more-on-code-debt.html' title='More on Code Debt'/><author><name>Geoff Slinker</name><uri>http://www.blogger.com/profile/12365501393247949005</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-36645098.post-7943262599931817520</id><published>2008-03-07T10:13:00.000-08:00</published><updated>2009-03-04T13:34:03.645-08:00</updated><title type='text'>Design by Use, Object Oriented Design, Design by Contract, and Test Driven Development</title><content type='html'>&lt;span style="font-weight: bold;font-size:130%;" &gt;Design by Use (DBU) &lt;/span&gt;&lt;br /&gt;&lt;br /&gt;DBU is a set of software design and development techniques which I have found very useful during my career. I recognize that the parts that make up DBU are not new to everyone.&lt;br /&gt;&lt;br /&gt;Before I go into a general description of DBU and compare it to OOD, DbC, and TDD I want to point out some unique aspects of DBU.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;font-size:130%;" &gt;Unique Aspects of DBU&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;DBU considers large software development issues and specifically multiple teams working simultaneously to build components and subcomponents which ultimately will work together as a software system.&lt;br /&gt;&lt;br /&gt;DBU describes what is termed "immediate integration". For me this was a new concept. For you it may not be, or maybe I have not communicated clearly what I mean.&lt;br /&gt;&lt;br /&gt;Suppose there are two teams, Team A and Team B.&lt;br /&gt;&lt;br /&gt;Suppose that Team A is writing Component A which depends on Component B which will be developed by Team B.&lt;br /&gt;&lt;br /&gt;Team A writes inside of Component A the call to Component B before Component B is developed. Team B takes the code from Component A and uses that to define the method signature or interface into Component B. Team A decides how they want to use Component B. Team A codes the preferred usage and gives that to Team B.&lt;br /&gt;&lt;br /&gt;Team A writes this "preferred usage" code very early in the development of Component A. This is done early so that Team B can start as soon as possible so that all teams are working on their components in parallel as much as possible. When I say "very early" I mean at first for most situations.&lt;br /&gt;&lt;br /&gt;Notice that Team A specifies the first version of the interfaces for Component B which are of interest to Team A. As with most software, changes to the interfaces occur before finishing the product. I shouldn't even have to say that, but so many read a description and then say, "You don't allow for future changes." All I can say is that people who think like that need to take the blinders off. If I don't describe some particular issue that you think is important I say to you can you imagine a way to address your issue and if so then everything is still good.&lt;br /&gt;&lt;br /&gt;So, Team A writes inside of Component A the "preferred usage" code for the call to Component B, and then creates a stub for Component B. Team B takes ownership of this stub and brings it into Component B and Component A no longer calls the stub but calls Component B. Thus we have &lt;span style="font-weight: bold;"&gt;immediate integration&lt;/span&gt; between Component A and Component B.  This new call into Component B had the pre-conditions, post-conditions, and invariants that are concerns for Team A specified by Team A. These concerns can be used in the definition of automated tests.&lt;br /&gt;&lt;br /&gt;Team B does not have to wait and wait for Team A to finally decide to call their system. Team A does not have to worry about Component B's interface and how to match up the classes, structures, parameters, exceptions, or return values. There will be no useless code and design based on the common tactic of "We will go ahead and design and implement Component B and when you finally figure out how you want to call us we can implement a mapping layer between the systems." What a poor way to do parallel component development.&lt;br /&gt;&lt;br /&gt;Notice that Team B did not declare to Team A that Component B will have these interfaces and Team A will have to figure out how to create the data necessary to make the call. In the development of "NEW" software the "user" has priority over the "used". Some may say, "This doesn't work for integrating software to existing systems." That's right, it doesn't have anything to do with integrating to existing systems such as third party libraries, unless you are designing a transformation layer between your system and the third party system. If you are designing a transformation layer then I would do it in the DBU fashion.&lt;br /&gt;&lt;br /&gt;Component B should only do what its users need it to do and nothing more, and obviously nothing less. Any extra code is just a waste. Mapping layers sometimes are the sign of poor design or poor utilization of teams and are just unnecessary and extra code.&lt;br /&gt;&lt;br /&gt;Team A knows critical constraints that Team B will not know. For instance, there may be a performance constraint. Suppose Component A must return results in 1 second. That means Component B must return its results in less than 1 second. Team A knows this requirement and passes it down to Team B by means of the "preferred usage" which is stubbed out and called by Team A with the appropriate error code if the call into Component B takes too long. When Team B takes ownership the stubbed code and moves it into Component B then Team B will have reference to the timing constraints and proceed accordingly.&lt;br /&gt;&lt;span style="font-size:130%;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="font-weight: bold;font-size:130%;" &gt;DBU in its Simplest Form&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;In its simplest form DBU is similar to Test First Programming. The developer, on an individual basis, must start writing code somewhere and in some direction. After appropriate domain consideration the developer will start building classes, structures, or even data flows. It doesn't matter if you are Object Oriented, Structured, or Procedural, there is an architecture that corresponds to your development method.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;The direction choice is made by writing calls as if they already exist.&lt;/span&gt; Thus you are designing the method on how you are going to use it. The parameters to the call will be of the type that you have available. The results of the call will be of a type that you want to handle. This is by its very nature low level code design. DBU does not require you to have a high level design nor does it exclude the use of a high level design. DBU does not need a detailed low level design before coding because&lt;span style="font-weight: bold;"&gt; DBU creates the low level designed as needed, in context, on time, in place, and correct for the situation.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;That is how you get started designing and writing new code. It is a very powerful way to do so.&lt;br /&gt;&lt;br /&gt;DBU is applicable to modifying existing code. Often I find myself adding to existing code. I struggle to organize new code with existing code. I find myself trying to use what already exists instead of trying to use the code the way I would prefer. As I group calls to existing code I often feel that I am ruining the architecture or that this really doesn't fit. I often get stuck and can't figure out how I am going to get the data from all of the places I need and transform it to how it is needed. Then I remember, "Hey dummy, write the new code how you would prefer it to be, even if it doesn't exist." When I do this the code flows, the architecture is maintained or extended but it is not violated or hacked. Every time I have done this I have been pleased with the results. Yes, every time.&lt;br /&gt;&lt;br /&gt;I have previously blogged concerning &lt;a href="http://digerati-illuminatus.blogspot.com/2007/10/database-design-by-use.html"&gt;DBU and database design&lt;/a&gt; and how it has helped me with SQL queries and such.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;font-size:130%;" &gt;DBU and Object Oriented Design&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;DBU is applied at low level / code level design. Therefore DBU works well with Object Oriented Design (OOD). Sometimes I design my domain objects using UML. I feel it is very important to gain as much understanding of the domain as possible before the low level code design begins. I define the objects and then I usually go right to sequence diagramming in order to imagine or simulate interactions. I do not "flesh out" the method calls to any great extent in UML. But that is me. You do what works for you. I do not use UML to generate my code. I use it to define meta data, organize thoughts on the domain, and get me pointed in the right direction. On small tasks where the domain is simple or in areas where I have lots of domain knowledge I do not even do UML.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;font-size:130%;" &gt;DBU and Design By Contract&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;DBU uses aspects of Design By Contract (DbC). There are three questions associated with DbC.&lt;br /&gt;1) What does it expect?&lt;br /&gt;2) What does it guarantee?&lt;br /&gt;3) What does it maintain?&lt;br /&gt;&lt;br /&gt;DbC is based on the metaphor of a "client" and a "supplier". In DBU the user  is the "client". In DBU the user of the "to be developed" method defines the preconditions, postconditions, and invariants on externally visible state. DBU follows the same rules of DbC for extending the contract down into lower level methods and procedures, such as a subclass may weaken a precondition, a subclass my strengthen a postcondition, and a subclass may strengthen invariants.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;font-size:130%;" &gt;Design by Use and Test Driven Development&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;DBU and Test Driven Development (TDD) have similarities but are different. Both are design activities. In my opinion both are low level code design activities.&lt;br /&gt;&lt;br /&gt;Some definitions of TDD require you to write a failing test (which is similar to a usage example of DBU) and then run your testing framework and see the indication that the test fails. You may do that in DBU but it is not a requirement of DBU. I want to point out that many will say you are not doing TDD unless you write a failing test and then watch it fail. DBU is not thusly constrained.&lt;br /&gt;&lt;br /&gt;DBU is defined for new development and for modifying existing code. In DBU if you are modifying existing code and you are developing new functionality you do it in place, in context, in state, where it is needed. You write the new code as if it already exists. Of course the new code isn't going to compile and you don't have to compile it to see it fail. Now if you want, and this is something I personally do, you take this new code and you put it into a "programmer's test" so that it will benefit from automated regression testing. &lt;span style="font-weight: bold;"&gt;You can put the new code into the tests before you actually develop the underlying functionality if you want and drive the development underlying functionality from the test, or in other words at this point you can use TDD.&lt;/span&gt; Or, you can continue in the existing code and use your IDE to generate the method and then fill in the functionality whilst considering DbC and then place calls to the new code in the "programmer's tests".&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;DBU is concerned with designing the call to the new code in context with the data that is on hand or accessible.&lt;/span&gt; DBU does not get stuck on such things has what needs to be public or private or if everything has to be public so that I can fully unit test the code. &lt;span style="font-weight: bold;"&gt;DBU designs code as needed and needed code is code that is called and code that is called is exercised and code that is exercised is tested.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Am I saying that all possible states are exercised. No. I don't think that TDD promises that either. Why, because in TDD the unit tests are still written by humans who have a finite amount of knowledge, time, and attention.&lt;br /&gt;&lt;br /&gt;If the method you have just defined is visible to other classes or callers then I refer you back to DbC to state what is expected.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;font-size:130%;" &gt;Summary&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Design By Use defines "Immediate Integration"&lt;/span&gt; where the user specifies the inputs, outputs, and method name (or in other words the method signature). Once the user of the new method has defined the preferred method signature and constraints the team that will develop the new method works from the users definition to build the actual functionality. These component boundaries or interfaces are defined early so that all teams may work in parallel and so that the components are linked together immediately at definition time and not at some far off date.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;DBU avoids the unnecessary code of mapping layers&lt;/span&gt; that result from poor communication, downstream waiting, or teams going off in their own direction.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;DBU is a low level code design activity.&lt;/span&gt; It works well with OOD, DbC, and TDD.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;DBU applies the user's preference on how things should be called to existing code as well as new code.&lt;/span&gt; When modifying existing code DBU says to write the modifications in the way that seems best even if the code doesn't exist. By doing this the overall structure and architecture of the system is extended and not just hacked and coupled. I do not know of any other low level code design methodology that follows that principle. There could be many. I just don't know them or maybe they don't have a cool name like Design by Use!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/36645098-7943262599931817520?l=digerati-illuminatus.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://digerati-illuminatus.blogspot.com/feeds/7943262599931817520/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=36645098&amp;postID=7943262599931817520' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/36645098/posts/default/7943262599931817520'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/36645098/posts/default/7943262599931817520'/><link rel='alternate' type='text/html' href='http://digerati-illuminatus.blogspot.com/2008/03/design-by-use-object-oriented-design.html' title='Design by Use, Object Oriented Design, Design by Contract, and Test Driven Development'/><author><name>Geoff Slinker</name><uri>http://www.blogger.com/profile/12365501393247949005</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-36645098.post-837420591067977481</id><published>2008-02-29T11:16:00.000-08:00</published><updated>2008-02-29T12:15:48.336-08:00</updated><title type='text'>What is Necessary to Develop Software?</title><content type='html'>I will work from these definitions.&lt;br /&gt;&lt;br /&gt;Software is a general term for the various kinds of programs used to operate computers and related devices.&lt;br /&gt;&lt;br /&gt;A Program is a specific set of ordered operations for a computer to perform.&lt;br /&gt;&lt;br /&gt;A Computer is a device that accepts information and operation instructions.&lt;br /&gt;&lt;br /&gt;So, to rephrase the initial question, What is necessary to develop specific sets of ordered instructions for a computer to perform?&lt;br /&gt;&lt;br /&gt;You will need:&lt;br /&gt;&lt;br /&gt;- A computer&lt;br /&gt;- A specification of the instructions the computer accepts&lt;br /&gt;- Something to generate sequences of instructions&lt;br /&gt;&lt;br /&gt;Something to generate sequences of instructions! Another computer could do this. A person could do this if the person has knowledge of the computer's instruction set.&lt;br /&gt;&lt;br /&gt;A Programmer is a person that specifies a sequence of instructions for a computer.&lt;br /&gt;&lt;br /&gt;I will not go into the roles of low level languages, high level languages, compilers, interpreters, and other methods of specifying computer instructions.&lt;br /&gt;&lt;br /&gt;So, that is all that is necessary to develop computer programs.&lt;br /&gt;&lt;br /&gt;What? You feel that there is more necessary? I don't think so.&lt;br /&gt;&lt;br /&gt;Oh, you want to develop a specific program to solve a specific problem. Well then, it is necessary for you to describe the problem in terms such that the programmer can order the correct sequence of instructions for the computer to solve the problem.&lt;br /&gt;&lt;br /&gt;Does the specification of the problem have to be done in a certain format? No. The only thing necessary is that you communicate to the programmer accurately the problem to be solved.&lt;br /&gt;&lt;br /&gt;So, if you want a specific problem solved then you must define the requirements.&lt;br /&gt;&lt;br /&gt;Now we are up to:&lt;br /&gt;- A computer&lt;br /&gt;- A specification of the instructions the computer accepts&lt;br /&gt;- Something to generate sequences of instructions&lt;br /&gt;- Specification of the problem requirements&lt;br /&gt;&lt;br /&gt;Wait, does the problem specification include a description or specification of the solution? No, it does not. The expected results of a software program may be termed the solution set. For instance if the specification for the program says, "Enter two numbers and compute the multiplication of those two number and display them." If you enter the numbers 6 and 2 and the results where "To be or not to be? That is the question." clearly that result is not in the expected set of solutions for multiplication.&lt;br /&gt;&lt;br /&gt;The specification of the solution set or correct set of results for a program are necessary if you only accept specific results.&lt;br /&gt;&lt;br /&gt;Now we are up to:&lt;br /&gt;- A computer&lt;br /&gt;- A specification of the instructions the computer accepts&lt;br /&gt;- Something to generate sequences of instructions&lt;br /&gt;- Specification of the problem requirements&lt;br /&gt;- Specification of acceptable results&lt;br /&gt;&lt;br /&gt;Some might say the last to specifications go together into one specification. It doesn't matter to me.  The point is, if you want specific problems to be solved and receive results in a specific set of possible results then it is necessary for those to be specified and communicated to the programmer.&lt;br /&gt;&lt;br /&gt;So, that's all you need.&lt;br /&gt;&lt;br /&gt;But you are thinking there is so much more to software development. There are books and books on how to write good solid code. There are books and books on how to organize teams. There are books and books on how to layout the User Interface.&lt;br /&gt;&lt;br /&gt;Ultimately it all depends on what you want and what you value and the things you are willing to do to get the things you want.&lt;br /&gt;&lt;br /&gt;Here are some related questions to the topic:&lt;br /&gt;- What is necessary to develop software quickly?&lt;br /&gt;- What is necessary to develop software with few defects?&lt;br /&gt;- What is necessary to develop software that runs on many different computers?&lt;br /&gt;- What is necessary to develop software inexpensively?&lt;br /&gt;- What is necessary to stop developers from quitting?&lt;br /&gt;- What is necessary to protect intellectual property?&lt;br /&gt;- What is necessary to attract talented programmers?&lt;br /&gt;- What is necessary to get incremental results from the development effort?&lt;br /&gt;- What is necessary to build software for life critical systems?&lt;br /&gt;- What is necessary to make code that is reusable?&lt;br /&gt;- What is necessary to make code backwards compatible?&lt;br /&gt;- What is necessary to develop software for moving/shifting requirements?&lt;br /&gt;&lt;br /&gt;The list goes on and on and on.&lt;br /&gt;&lt;br /&gt;Geoff&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/36645098-837420591067977481?l=digerati-illuminatus.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://digerati-illuminatus.blogspot.com/feeds/837420591067977481/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=36645098&amp;postID=837420591067977481' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/36645098/posts/default/837420591067977481'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/36645098/posts/default/837420591067977481'/><link rel='alternate' type='text/html' href='http://digerati-illuminatus.blogspot.com/2008/02/what-is-necessary-to-develop-software.html' title='What is Necessary to Develop Software?'/><author><name>Geoff Slinker</name><uri>http://www.blogger.com/profile/12365501393247949005</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-36645098.post-6577791343964424481</id><published>2008-02-28T16:50:00.001-08:00</published><updated>2008-02-29T11:11:38.216-08:00</updated><title type='text'>Lessons learned from the farm.</title><content type='html'>My Dad has often recounted to me the story of a neighboring farmer. The neighbor ran a dairy where they milked Jersey cows. It was a very profitable operation. Not only was it ran well, it was clean and in good order, meaning that the barns were in good repair and that the fence rows were not grown up with briers, weeds, or trees.&lt;br /&gt;&lt;br /&gt;The neighbor sent his son to a University were the son majored in agriculture. Upon his graduation and return to the farm the son started applying the lessons he learned at the University. The son took the savings from the farm's years of profit and increased the size of the operation. One of the changes was the adding of a Harvestore "big blue" silo. Trust me, these silos are expensive. The son ran the operation and soon was broke and had to sell out.&lt;br /&gt;&lt;br /&gt;Now the son is working at the state government level in the Department of Agriculture.&lt;br /&gt;&lt;br /&gt;My Dad is amazed that someone who took control of a "gem" of a dairy operation and ran it into the ground is qualified to make agriculture decisions at the state level.&lt;br /&gt;&lt;br /&gt;In my opinion the man is not qualified.&lt;br /&gt;&lt;br /&gt;When I remember this story it causes me to think about software development and a couple of similarities I have seen.&lt;br /&gt;&lt;br /&gt;The first is that I have seen directors and executives run companies into the ground and then in mass those "people" go to another company and do it all over again. This scenario is not exclusive to dairy farms and software development. I know that using such derisive terms as "ran into the ground" poison the well and since I do not know all of the reasons for the company failures and thus this is an invalid argument based on an appeal to consequences of belief. Nevertheless I have seen people advance in the same business sector even though previously they were involved in significant failures in that same sector.&lt;br /&gt;&lt;br /&gt;The second thing that the dairy farm story reminds me is that "just because it was taught at the University doesn't mean it will work!". I loved my education at Brigham Young University. The professors there taught me well. However, I knew the dairy farm story before I went to the University and I knew that I would have to carefully apply the lessons from school to my career.&lt;br /&gt;&lt;br /&gt;So, some advice for my friends. When someone else has an idea on how you should run your business figure out if that someone makes a living doing what you do. The University Professor teaching agriculture makes his money through the University and not through farming. The Professor's teachings may be right and applicable and they may not be applicable. The onus or burden of proof falls upon you.&lt;br /&gt;&lt;br /&gt;One might conclude that my Father's farm is not progressive because he doesn't follow the latest suggestions from the Universities, feed salesmen, or machinery salesmen. This is not so. My Dad has often told me of how his father had them using a mule to plow the fields. My Dad and his younger Brother decided that if they were going to run the farm and make any money doing it that they would need a tractor. So the two brothers bought a tractor and some implements to use with that tractor.&lt;br /&gt;&lt;br /&gt;My Father would go to different parts of the U.S.A. and see what farmers where doing there. I remember when we had traveled through the Mid-West and we had seen the hay balers that make a large round bale. My Dad ordered one and our farm was the first in the area to use the new technology by several years.&lt;br /&gt;&lt;br /&gt;My Father also rejected many ideas that he saw adopted. One of which was to place all of the cattle into a confined area to limit the cattle's movement and to put in large silos and conveyor systems. Our neighbors did so. To pay for the silos and such they added more cows to the heard. Even though our neighbors had an operation valued in the millions of dollars my Dad's farm made more profit, was less stressful on the cattle because the cows stilled roamed in their pasture, costs less in operations because the cattle are healthier, etc.&lt;br /&gt;&lt;br /&gt;My Father rejected the recommendation of the Agriculture representatives to give the cows a shot of hormones, known as BST, to the cattle. The cost of the hormones was not the reason he rejected this idea. The idea of giving the cows a shot, and trust me the needle to give a cow a shot is large and it hurts the cow, and making the cows nervous and even mean was not worth it. Also, it was not something he wanted in his milk and so he figured you wouldn't want it in yours (even though they claimed that the hormone can not end up in the milk). The shots, the confinement, and other issues of a large "modern" dairy reduces the life of a cow from over 10 years to less than 7 years. The costs of raising or buying replacement cattle is tremendous.&lt;br /&gt;&lt;br /&gt;My Father values the living conditions of his cattle over making a profit. My Father has learned that having a bigger business does not mean you have a more profitable business. My Father has learned that salesmen are motivated to sell their product and can spin quite the story of reasons why you should use their product. My Father does not define success by short term profits alone.&lt;br /&gt;&lt;br /&gt;For those that have stuck with me on this post you may be asking what does this have to do with software development. To me it has plenty and if it hasn't been clear then please post some comments and I will try to help you understand.&lt;br /&gt;&lt;br /&gt;Remember, you are probably smarter than you think you are and those you think are really smart may not be as smart as you think! Think for yourself. Know what is important to you and if you don't know what is important you will eventually learn what is important.&lt;br /&gt;&lt;br /&gt;When someone is trying to sell you something that will make you money here's a little test for them:&lt;br /&gt;&lt;br /&gt;If someone says that by adopting the new Lissom Software Development Methodology you will increase your productivity by 20%, then ask them to put it into writing and if it doesn't deliver they will give you your money back!&lt;br /&gt;&lt;br /&gt;When they refuse to offer you a money back guarantee ask them to stop with the hype and spin and ask them to work with you so that you can see if their methodology addresses real problems that you are experiencing.&lt;br /&gt;&lt;br /&gt;You know the problems you face even though you might not recognize the root cause of the problems and you might not know all of the possible ways to address the problem. That is where getting help and ideas from others internally or externally can be useful.&lt;br /&gt;&lt;br /&gt;Just some thoughts.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/36645098-6577791343964424481?l=digerati-illuminatus.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://digerati-illuminatus.blogspot.com/feeds/6577791343964424481/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=36645098&amp;postID=6577791343964424481' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/36645098/posts/default/6577791343964424481'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/36645098/posts/default/6577791343964424481'/><link rel='alternate' type='text/html' href='http://digerati-illuminatus.blogspot.com/2008/02/lessons-learned-from-farm.html' title='Lessons learned from the farm.'/><author><name>Geoff Slinker</name><uri>http://www.blogger.com/profile/12365501393247949005</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-36645098.post-7242794980030918660</id><published>2008-02-17T14:40:00.000-08:00</published><updated>2008-02-17T15:48:35.893-08:00</updated><title type='text'>Poor Requirements, Poor Coding, Poor Design, Poor Policies, Poor Management, Poor Leadership</title><content type='html'>The software development industry seems to be completely in love with excuses! (Sadly enough, it seems that many industries are infected with this poor behavior. Pun intended.)&lt;br /&gt;&lt;br /&gt;In software development, when a problem is identified it doesn't take but an instance to pass before someone has an explanation. Maybe drawing rapid conclusions is part of the software development ecosystem. Developing software requires quick decision making. Maybe "quick thinking" has become our primary method of problem solving.&lt;br /&gt;&lt;br /&gt;I have seen many of the different problems encountered from software development. Buggy software or quality problems, performance issues, missing features, extra features, months of overtime, changing requirements and moving targets, threats used to squeeze out a little more work, heroics, power plays, re-organizations, firings, and more.&lt;br /&gt;&lt;br /&gt;If you work for a company who's products are web based have you ever experienced something that brought down "the site"? At least that is what it is referred to in the Utah area, that is "bringing down the site". Has this happened where you work?&lt;br /&gt;&lt;br /&gt;I have seen it happen a few times. The most drastic reactions from bringing down the site have resulting in the CEO calling the developer for an explanation AND the CTO coming down to "see" what the problem really is. It was termed the "blame game". Someone has to be blamed. Maybe the Executives where not looking for someone to blame but instead were offering suggestions from a higher view hoping their perspective could help. Regardless of their unknown intentions the interpretation was that someone had to be blamed. &lt;br /&gt;&lt;br /&gt;The blaming resulted in excuses. Excuses such as, "My change brought the site down because of the ridiculous policy that I can't have access to the live databases. I did not know that the tables on live did not have the exact same schema as those on our staging machines", or, "My change brought down live because the design of the system is so complex that there is no way I can manually test all of the possible states the system may enter", or, "The system that you forced us to build upon is very complex and the company has never trained us on its proper use."&lt;br /&gt;&lt;br /&gt;So, back to the title of this post.&lt;br /&gt;"Poor Requirements, Poor Coding, Poor Design, Poor Policies, Poor Management, Poor Leadership"&lt;br /&gt;&lt;br /&gt;Upon release of a product if it doesn't do what is wanted then the excuse is "poor requirements". It may be true that the requirements were poorly defined. But waiting to the release of the product to discover this is ridiculous. It is ridiculous on the part of management, on part of the customer, and on part of the developer. Historically the suggested solution to this problem has been creating a more formal and controlled requirements process. A more formal process is something management can dictate but apart from large amounts of ceremony have failed to deliver.&lt;br /&gt;&lt;br /&gt;I really don't care how long it takes a company to define the requirements for a software product. There are many that love to play in the undefined space of "Big Upfront Requirements". Well, they can play there all they want. It is a situational trap.&lt;br /&gt;&lt;br /&gt;I do care that the company was foolish enough to wait until the product is finished to start finding fault with it and to start looking for those to blame. Those responsible for the delivery of a software product should be using that product continuously during it's development. There is no excuse for not doing so. If those concerned say, "The software is too new, too buggy, and won't run long enough to really evaluate it. So we will wait until they make their alpha candidate." Hog wash. First there are formal management techniques of functional decomposition which allows for meaningful incremental development and release of working features. If management wants to put something formal in place, then put in incremental development.&lt;br /&gt;&lt;br /&gt;If you think that incremental development is ad hoc, or some type of cowboy approach then you do not understand it. Incremental developer imposes a level of work that waterfall development does it. It requires features to be organized, group by dependency and priority, estimated, and the scheduled by placing them into release queues. What I just described is a lot of work. A lot of work before the first line of code is developed. Notice I did not say the feature was designed at the code level. That is something different that I will talk about at a future date.&lt;br /&gt;&lt;br /&gt;Do you see how these complaints of poor this and poor that are just excuses?&lt;br /&gt;&lt;br /&gt;I have lightly covered poor requirements. I will touch on poor management. I know that many believe that a manager of developers doesn't have to be a developer. I will agree with this if the manager has the ability to know where the development line is drawn.&lt;br /&gt;&lt;br /&gt;I had a manager that had did some programming. Delphi type stuff, some HTML, a few databases designed with a nice GUI DB designer. Those kinds of things. As sophisticated as that is compared to the masses, it is light weight stuff compared to systems level development using multiple processes communicated using shared memory techniques or wiring up a model view controller in such a way as to avoid race conditions. However this manager (director level) assumed that he really understood programming and he would come down and stick his big honking management nose in the developers code. He required developers of 20+ years experience to explain all of their code changes and designs to him for approval. When we faced technical issues he would make design level decisions that were so idiotic that we couldn't believe it. There was a problem with some web servers that were not responding to sent messages. He said to the team, "If the server fails to respond, send the message again. Double pump the message. Triple pump the message. We must be sure the message gets to the server." How utterly ignorant of server side development! Sending more and more messages to a server that is not responding is not the first solution to the problem. Before I go completely insane from remembering these experiences I better get back on topic. We had poor management.&lt;br /&gt;&lt;br /&gt;Poor management was our excuse for our problems. Because we had poor management we felt that we couldn't fix the real problems. Those were excuses and we did not allow excuses to stop us from working to the best of our ability. We did not follow his advice of double pumping the messages and we did not tell him how we fixed the problems. We chose to ignore him and do our job. It is hard to ignore a director when your pay raise goes through his office. But we did anyway. I left the team as did others. Soon there was a new director.&lt;br /&gt;&lt;br /&gt;Ultimately I realize that I will be plagued with excuses and will be guilty of giving excuses. If you do not have the ability to make a change then you will probably make an excuse.&lt;br /&gt;&lt;br /&gt;Surely there are many poor aspects of any software development. They will stay poor until someone realizes how to stop complaining and to start thinking and then doing something about. Just like the example I give of missed requirements. It is not reasonable to have such problems with the knowledge of incremental feature development.&lt;br /&gt;&lt;br /&gt;As for the problem with the poor manager/director, the solution is one of communication and trust. That is a large topic. But to make it short either the manager could have learned to communicate his concern for quality at the same time showing that he trusted the developers to deliver, OR, the VP could have communicated with the developers and could have realized that the manager should be replaced, OR some other solution.&lt;br /&gt;&lt;br /&gt;If your development process is suffering from something that is poor, then drop a line to us on this blog or on the users group, "http://tech.groups.yahoo.com/group/digerati-illuminatus/" and we will be glad to offer suggestions. For FREE! But be prepared to give open and honest details about the entire problem and the organization in which the problem lives.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/36645098-7242794980030918660?l=digerati-illuminatus.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://digerati-illuminatus.blogspot.com/feeds/7242794980030918660/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=36645098&amp;postID=7242794980030918660' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/36645098/posts/default/7242794980030918660'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/36645098/posts/default/7242794980030918660'/><link rel='alternate' type='text/html' href='http://digerati-illuminatus.blogspot.com/2008/02/poor-requirements-poor-coding-poor.html' title='Poor Requirements, Poor Coding, Poor Design, Poor Policies, Poor Management, Poor Leadership'/><author><name>Geoff Slinker</name><uri>http://www.blogger.com/profile/12365501393247949005</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-36645098.post-61372479116614550</id><published>2008-02-05T06:53:00.000-08:00</published><updated>2008-02-05T15:19:30.724-08:00</updated><title type='text'>Agile Fiction and Myth</title><content type='html'>&lt;span style="font-style:italic;"&gt;"Perhaps the sentiments contained in the following pages, are not YET sufficiently fashionable to procure them general favour; a long habit of not thinking a thing WRONG, gives it a superficial appearance of being RIGHT, and raises at first a formidable outcry in defense of custom. But the tumult soon subsides. Time makes more converts than reason."&lt;/span&gt; Common Sense, by Thomas Paine - 1776&lt;br /&gt;&lt;br /&gt;The topic of this posting will be "The Agile Method and Other Fairy Tales", by David Longstreet.&lt;br /&gt;&lt;br /&gt;http://www.softwaremetrics.com/Agfa/Agile%20Paper.pdf&lt;br /&gt;&lt;br /&gt;Mr. Longstreet gives an impressive background of travel and study of software organizations in many varied fields and marketplaces. I declares that he has "&lt;span style="font-style:italic;"&gt;been dedicated to the idea of improving software productivity and quality...consulting and studying software organizations&lt;/span&gt;".&lt;br /&gt;&lt;br /&gt;I have twenty three years experience in software development. I have always been involved with the improvement of software quality and productivity. My level of involvement is "applied", that is, I am a Computer Scientist and Software Engineer. I apply ideas for improvement and I stay around to live with the results. I have a vested interested in improving software development because those improvements directly affect me. I have developed software on the family dairy farm to manage accounts payable and production. I have delivered software for the Department of Energy to visualize magnetic fields, and to render 3D data visualizations from scanning/tunneling microscopes. I have written coding standards and guides which were adopted by the entire Computer Science department at the National Laboratory where I worked. I have delivered software for EMail applications, real-time stock market analysis, record managers for high performance indexing engines, eCommerce systems, new specialized GUI controls, charting packages, and many many other high quality and working systems. I can produce references if someone wants to question the veracity of my statements.&lt;br /&gt;&lt;br /&gt;I have not limited myself to just studying the software industry. I am an award winning Dairy farmer and have been recognized for my techniques in raising dairy calves. I have traveled and performed voluntary service. I have studied Gothic Architecture and Renaissance Art, and I have traveled in Western Europe to see the actual works. I study languages and culture. I have done in-depth research on the Biblical Prophet Abraham and I currently study the Qur'an. I collect HO scale electric trains and I change the oil in my automobiles. I played the Cornet and Saxophone and I have proven myself to be a fairly good artist. Like everyone I have met, I am not a one-dimensional person.&lt;br /&gt;&lt;br /&gt;I have developed software in 68000 and VAX assembly, Pascal, FORTAN 77, Ada, APL, Object C, Object Pascal, C, C++, Java, HyperTalk, C#, various scripting languages, and SQL stored procedures. I have managed teams of developers. I do not limit myself to my department either. Everyone knows that I will speak up in other departments and I am not afraid to go to the CEO or the Board. As a matter of fact, I have been demanding on many organizations and I have had no fear of any position.&lt;br /&gt;&lt;br /&gt;I state all of this because Mr. Longstreet does so at the beginning of his paper and then later in the paper describes Agile users as one dimensional. Even with all of my experience there are many things to learn.&lt;br /&gt;&lt;br /&gt;Like Mr. Longstreet, I was very skeptical of eXtreme Programming (XP) when I first heard of it. I started writing a paper, XP eXposed. As I studied XP and then applied parts of it I started to see what Kent Beck was describing. Soon I abandoned the paper and started applying parts of XP and I found value in XP.&lt;br /&gt;&lt;br /&gt;I will now take some quotes from Longstreet's paper and make some comments:&lt;br /&gt;&lt;br /&gt;"&lt;span style="font-style:italic;"&gt;I have come to the conclusion that software developers cause most of their own problems. The root cause of most of the problems facing software development is actually caused by software developers themselves. They are creating their own complexity and chaos.&lt;/span&gt;"&lt;br /&gt;&lt;br /&gt;This argument is flawed and is known as an appeal to consequences of a belief.&lt;br /&gt;&lt;br /&gt;"&lt;span style="font-style:italic;"&gt;Agile methods want continuation and formal acceptance of the status quo... Up to this point in time software development has been a Wild West endeavor... IT has been sloppy. There is nothing new with Agile, because it only tries to formalize sloppiness.&lt;/span&gt;"&lt;br /&gt;&lt;br /&gt;This argument is flawed and is known as an appeal to ridicule, spite, and ultimately the argument turns to an appeal of tradition.&lt;br /&gt;&lt;br /&gt;"&lt;span style="font-style:italic;"&gt;I am bringing a level of professionalism and rigor to the software industry, and I hope you join me.&lt;/span&gt;"&lt;br /&gt;&lt;br /&gt;This is a setup for the well known fallacy known as an "appeal to authority".&lt;br /&gt;&lt;br /&gt;"&lt;span style="font-style:italic;"&gt;An Agile proponent will argue there is limited value in requirements specifications because the requirements are ever changing.&lt;/span&gt;"&lt;br /&gt;&lt;br /&gt;There may be someone that Mr. Longstreet views as an Agile proponent that has argued this point. That does not make it so. Use Cases and User Stories are the two approaches I am most familiar with and both are taught and used by Agile proponents.  I personally believe that some of the confusion is with the roles of XP and the idea of Agile.&lt;br /&gt;&lt;br /&gt;"&lt;span style="font-style:italic;"&gt;'I think it's fair to say that customer practices are not addressed in Agile methods.' It is clear that understanding what the customer wants or helping the customer figure out what they want is not really part of Agile, and in turn not part of software development&lt;/span&gt;."&lt;br /&gt;&lt;br /&gt;Mr. Longstreet is quoting someone from an online users group. Such methods of fact finding are laughable. This statement is a hasty generalization, and hearsay.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style:italic;"&gt;"It is clear that understanding what the customer wants or helping the customer figure out what they want is not really part of Agile, and in turn not part of software development."&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;I believe this is a fallacy of composition.&lt;br /&gt; &lt;br /&gt;&lt;span style="font-style:italic;"&gt;"Perhaps it is the statistician in me, but I do not believe anything is random. Nothing occurs by random and nothing occurs by chance."&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;This is an appeal to authority.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style:italic;"&gt;"The Agile argument is based upon the idea that systematic study does not work for&lt;br /&gt;software development. They believe 'most software is not predictable.'"&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;This is on the border line of the fallacy of "confusing cause and effect". Also this is a false dilemma.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style:italic;"&gt;"Every single time a development project is done, it is done differently. Documents are not cataloged and organized. There is no consistent usage of terms and symbols between projects, within projects, and even within single requirements&lt;br /&gt;documents."&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;This is a distortion and thus a Straw Man argument.&lt;br /&gt;&lt;br /&gt;Discussing pair programming Mr. Longstreet states, &lt;span style="font-style:italic;"&gt;"The idea is that one programmer writes code and the other programmer stands over his shoulder and watches for mistakes."&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;This is a complete falsehood. He goes on to say, &lt;span style="font-style:italic;"&gt;"I am not sure what problem pair programming is trying to solve. Most of the issues with software development are related to incomplete requirements, not coding."&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;The first part of his statements on pair programming is a Straw Man. Also his statement that most issues are related to incomplete requirements is confusing cause and effect, and is an appeal to consequences of a belief.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style:italic;"&gt;"Incomplete requirements are the biggest issue facing software development. I guess it is clear to the Agile folks that it is only logical to spend more time coding instead of cleaning up requirements or writing concise requirements in the first place."&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;As with many of the statements this one is of questionable cause and confusing cause and effect.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style:italic;"&gt;"They believe trial and error is the best method to gather and communicate requirements."&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;This is an appeal to ridicule, as is this statement:&lt;br /&gt;&lt;span style="font-style:italic;"&gt;"Agile proponents believe discipline is not necessary and inhibits productivity."&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style:italic;"&gt;"Again the basic premise of Agile Methods is there is nothing I can do about my environment. I am a victim of my environment. I am a victim of circumstances. I can’t plan I can only react."&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;This is simply an example of poisoning the well. The fallacy goes like this:&lt;br /&gt;- Unfavorable information (be it true or false) about person A is presented.&lt;br /&gt;- Therefore any claims person A makes will be false. &lt;br /&gt;&lt;br /&gt;I am only half way through this paper. I find it filled with falsehoods based upon poor research. Mr. Longstreet assumes an authoritative position at the beginning of his paper by stating his experience and declares that he specializes in non-biased scrutiny of people, processes, and businesses. He claims that multi-disciplinary study is a key component to his authority. Yet with these statements there is an obvious lack of research done concerning the current body of knowledge on the subjects of Agile and XP.&lt;br /&gt;&lt;br /&gt;For those that are the authors of Agile methodologies I invite you to make concise statements defining your Agile Method. For Mr. Longstreet, I challenge him to clean up his paper and to cite sources and remove the unnecessary fallacies.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/36645098-61372479116614550?l=digerati-illuminatus.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://digerati-illuminatus.blogspot.com/feeds/61372479116614550/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=36645098&amp;postID=61372479116614550' title='8 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/36645098/posts/default/61372479116614550'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/36645098/posts/default/61372479116614550'/><link rel='alternate' type='text/html' href='http://digerati-illuminatus.blogspot.com/2008/02/agile-fiction-and-myth.html' title='Agile Fiction and Myth'/><author><name>Geoff Slinker</name><uri>http://www.blogger.com/profile/12365501393247949005</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>8</thr:total></entry><entry><id>tag:blogger.com,1999:blog-36645098.post-5035807522365953718</id><published>2008-02-02T19:36:00.000-08:00</published><updated>2008-02-02T21:29:05.542-08:00</updated><title type='text'>It's okay to THINK for Yourself</title><content type='html'>I started studying the Sofware Development process in 1985. In about four years I had learned techniques in estimation and learned the name of Halstead. I had learned of something called "COCOMO" and learned the name of Boehm. I learned of Jackson System Development and found out that Michael wasn't just the king of MoTown. I learned of the SW-CMM and learned the name of Humphrey. I learned of Brooks and Parnas, of Booch and many others.&lt;br /&gt;&lt;br /&gt;The biggest thing I did not know at the time was that all of these topics were new. I came from a Dairy farm and I had never used a computer until college. I had seen a TRaSh 80 once before but that was it. As I took my math classes, physics classes, and computer science classes I just assumed that the C.S. stuff was "old" stuff and that everyone in industry used and believed in what I was learning in school. I had no idea that the topics were leading and even bleeding edge. My first programming language was Pascal on a VAX 11-750. I did not know that in industry at that same time many projects were done completely in assembly language and that in industry it is costly and takes time to switch from assembly to Pascal, ADA, or C.&lt;br /&gt;&lt;br /&gt;My ignorance was a blessing in disguise. Since I assumed that everything I was taught was in common use in industry I had no problem analyzing the concepts as if they were "old" and in need of replacement. I was not mesmerized by these new concepts because I didn't know they were new.&lt;br /&gt;&lt;br /&gt;I remember in my CS 327 class I was taught about the Waterfall model. I just went down stairs and got my old text book out. "Software Engineering: A Practitioner's approach. Second Edition" Chapter one of the text taught me the "classic life cycle" of software development. The text clearly states that the waterfall model was under criticism even at that time. It says that projects rarely follow the sequential flow, that customer's had difficulty stating all requirements explicitly, and that the customer had to be very patient because a working version of the software is not available until late in the project time span. The next section introduced Prototyping.&lt;br /&gt;&lt;br /&gt;Well, I better fast forward to the now.&lt;br /&gt;&lt;br /&gt;Now I have years of context. I know when XP and Agile came on the scene and I viewed them in their true position for the time as being new approaches. I have watched as the current set of software development practitioners beg to be told how to develop software. I mean just what I said. BEG TO BE TOLD. I have participated heavily in many online users groups, more lightly with local users groups, and heavily within the companies where I have worked. I have watched my peers look for someone to whom they can abdicate the decision of how to make good software.&lt;br /&gt;&lt;br /&gt;In the late 80's and early 90's the companies I worked for brought in consultants which taught Waterfall, change control boards, and formal inspections. My peers accepted those methods as the way to develop software and seem to have never revisited that problem again. Well, we have moved on in our careers and now many are Managers, Directors, VP's, and even CXO's. Most have not revisited the problem of "how to develop software". I watch the next generation of software developers rage against the old machine. They want to develop software in better ways that work with the advancements in hardware and development tools. But they do what my generation did and  abdicate the decision of how to make good software to the current set of consultants. This isn't totally bad unless they make the second mistake that many of my peers made and never revisit the question again.&lt;br /&gt;&lt;br /&gt;I watch as people look for Agile Methods. Agile recipes is what they want. Secretly I think they are looking for guarantees. They want to say, "When I find myself in situation X I can apply practice Y and that is the best that can be done." Not only that, but they want to recite the authority of the practice as well, "Beck and Jeffries have both said this is how to do it." Well there you go, we could never question Beck or Jeffries now could we! :-)&lt;br /&gt;&lt;br /&gt;It's great to read the latest books and articles, to talk with the authors, and even hire them to teach, clarify, and expound. Ultimately you will find yourself metaphorically alone and having to make decisions. At this point you can either think for yourself or you can blindly follow your method.&lt;br /&gt;&lt;br /&gt;By current definitions of Agile Software development I probably practiced it for about a week. I immediately made changes to suit the needs I encountered. I moved on and I am still moving on. I never have cared if I was Agile or not. That was not the problem I was faced with. The problem I am faced with everyday is how to develop software the best I can in the current situation I find myself.&lt;br /&gt;&lt;br /&gt;Is your problem whether or not you are Agile? Or is your problem developing software? If you recognize your problem to be developing software do your recognize what is causing the difficulty? If so then you can then say, "Will Agile practices address the issues I am faced with?" Think dog gone it. Think for yourself. Think and then apply yourself to the problems you face. Agile surely has many answers for many problems in Software development. Agile surely is not the answer all of the problems. And neither is CMMI, Lean, BDD, FDD, Spiral, Prototyping, or even DBU.&lt;br /&gt;&lt;br /&gt;I have read countless threads on Agile users groups on how do you sell your group or company on Agile. I see this and I sigh. I think, here we go again. Think for a moment. Sell your group or company on solutions to real problems that are being faced. I advise on looking for root problems! For instance, if one of the problems is that the software doesn't meet the requirements when it is shipped then maybe you should institute rigorous reviews of check-ins and have a requirements sign off check list. OR, maybe the problem would be better addressed if there were incremental releases of completed features which are accepted by those that defined the requirement. Dig for the deeper problems and solve them first! Think! Think dog gone it. THINK! Think, because either answer may be right.&lt;br /&gt;&lt;br /&gt;I have read countless threads on software development groups on the topic of "when should you optimize software". Often the posts are just a trap and have not disclosed the entire situation accurately or completely. That is, often the poster of the question has already identified that the software doesn't perform sufficiently and they are just waiting to have an argument. But if you are serious about the question then I say again, "Think!". If you are worried about scalability and user load then do you know which technologies are scalable? Do you know about load balancing? Do you know about distributed programming, or message queues? Do you know what about cluster? Virtual severs? Grid computing? If you are familiar with these subjects then you can at least say that we should develop our system to work behind an IP load balancer. These decisions must be made as soon as possible because they will effect how you develop the software. But if you understand such things as the Facade pattern then you can put off the decision until a bit later. But you have to know about alternatives and you have to think and apply.&lt;br /&gt;&lt;br /&gt;If you are concerned with the runtime performance of a particular algorithm or function then you have to know the answer to the question of "what is fast enough?" Once you know that then you can exercise and profile the code to see if it is fast enough. Think about this! If you have the answer for how fast it has to be before you develop the algorithm it might guide you to the correct solution the first time instead of having to write and and then hope that it meets some unknown performance requirement. Think! That's what it's about, thinking. Maybe this suggestion is right for your situation and maybe it is not. Don't accept it blindly.&lt;br /&gt;&lt;br /&gt;I have been told that I could not do a certain thing because the "agreed" upon software methodology doesn't allow one to do that. Bull pucky. People don't allow people to do things. Methodologies are neither alive nor can they hurt or heal. If that something needs to be done, and it is the right thing to do, then the problem must be real and identifiable. If it is all of these things then surely the problem and corresponding solution can be described. If it can be described then surely your peers can recognize the need or offer alternatives. It is not sufficient to dismiss the action on the basis of "the process doesn't allow for it." Think. THINK.&lt;br /&gt;&lt;br /&gt;Do your best, and view your peers with an eye that they are smart and thinking people and that the burden lies upon you to communicate with them. If both sides of the conversation hold these values then both will try their best to hear what the other is saying. If you feel that you are the only one with those values then try and prove yourself wrong.&lt;br /&gt;&lt;br /&gt;Think for yourself. It doesn't matter if the author of the latest and greatest software development methodology says you should do A and not do B. If you don't need to do A then don't do it. But know you don't need A for all of real reasons. Know why some people say you should do A and show how that doesn't apply. Don't follow for following's sake and don't be a contrar-ian for contrary's sake. Think. Learn. Share.&lt;br /&gt;&lt;br /&gt;I try to do those things. I fail at it often, but I try.&lt;br /&gt;&lt;br /&gt;Geoff&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/36645098-5035807522365953718?l=digerati-illuminatus.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://digerati-illuminatus.blogspot.com/feeds/5035807522365953718/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=36645098&amp;postID=5035807522365953718' title='5 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/36645098/posts/default/5035807522365953718'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/36645098/posts/default/5035807522365953718'/><link rel='alternate' type='text/html' href='http://digerati-illuminatus.blogspot.com/2008/02/its-okay-to-think-for-yourself.html' title='It&apos;s okay to THINK for Yourself'/><author><name>Geoff Slinker</name><uri>http://www.blogger.com/profile/12365501393247949005</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>5</thr:total></entry><entry><id>tag:blogger.com,1999:blog-36645098.post-9135876360667462198</id><published>2008-01-02T07:38:00.000-08:00</published><updated>2008-01-02T15:57:04.332-08:00</updated><title type='text'>Customer input, Who needs it!</title><content type='html'>When designing a product do you need active and continuous input from your customer?&lt;br /&gt;&lt;br /&gt;It seems logical that in order to control &lt;a href="http://digerati-illuminatus.blogspot.com/2007/11/code-debt-product-market-debt-and.html"&gt;Customer Debt&lt;/a&gt; one would want to involve the customer.&lt;br /&gt;&lt;br /&gt;Who is your customer? What are the concerns of your customer?&lt;br /&gt;&lt;br /&gt;Identifying customers or potential customers may be the easiest part. The concerns of the customer is the key! Suppose you identify ten customers and invite them to participate in the design of your product. The most important thing is to figure out the concerns of these ten people!&lt;br /&gt;&lt;br /&gt;For instance, if you are re-writing an existing product your existing customers may be concerned with keeping the new product exactly like the old product to minimize their learning curve and to allow them to maximize their use of the new product. Does this motivation, keeping the new product exactly like the old product, match the broader concerns for the future?&lt;br /&gt;&lt;br /&gt;Suppose your goal is to take the new product "into the future" and really change how things are done! If you have a group of customers that are worried about minimizing change they will not give you advice to take you into the future. If you ignore them then you will probably lose them when you release your new product. It is almost like "you can't win for trying".&lt;br /&gt;&lt;br /&gt;In software I have often found that customers do not know what could be developed. They base their vision of the future on the common User Interface Gadgets that they are accustomed to using. I started programming in 1984. I bought my first computer shortly there after and it was a Macintosh SE. (I still have it!) I experienced first hand the criticism and complaints from the DOS users. If it had been left to the existing "customer" base what would have been the results?&lt;br /&gt;&lt;br /&gt;Now a days people envision software based on the buttons, scroll bars, lists, and other gadgets with which they are familiar. They do not know that developers can make new custom controls or new input devices (or whatever). Many people can not envision a future unless it is just a baby step away from the present. Is your customer like that?&lt;br /&gt;&lt;br /&gt;Internet lore concerning the development of the legendary iPod suggests that only members Tony Fadell's team and a few select individuals which included Steve Jobs and some employees of PortalPlayer were ever allowed to see the new iPod.&lt;br /&gt;&lt;br /&gt;I wish I had the connections to talk to the iPod team and get the whole story!&lt;br /&gt;&lt;br /&gt;I also would love to talk to Toshiba about the development of the Gigabeat S and then to Microsoft about how they took that and made the Zune.&lt;br /&gt;&lt;br /&gt;While developing software often I have suggested enhancement or features. Often these suggestions have been discredited with the statement "you are a programmer". Since when are programmers NOT software users! I am not saying my suggestion should have been adopted. I am saying that their argument was invalid and that the suggestion should have been dismissed on other grounds.&lt;br /&gt;&lt;br /&gt;In order to properly consider customer input one must have a sound understanding of what the product is to do and for whom it is to do it. If you want to do some old thing in a new way in order to capture new users then you have to balance the needs of existing customers with new customers.&lt;br /&gt;&lt;br /&gt;If you are re-writing software that is in a market where it is to assist with some mundane and repetitive task I have noticed that the users only want incremental changes made to the product. Revolutionary change upsets their routine!&lt;br /&gt;&lt;br /&gt;If your software is in a market that is based on entertainment then I have noticed that revolutionary change is sought after and found to be enticing and exiting.&lt;br /&gt;&lt;br /&gt;Back to our ten customers helping us design our software. Suppose you use all of the advice of these ten customers and release a product. They are happy and suppose that the existing customer base is happy as well and everyone seems to be upgrading to the new product. Now suppose that your biggest competitor releases a new version of their competing product. It has some "really cool" feature and the blogs light up with praises for their product and criticism of your product for not having the feature. Now you have accrued some major &lt;a href="http://digerati-illuminatus.blogspot.com/2007/11/code-debt-product-market-debt-and.html"&gt;Customer Debt and Product Market Debt&lt;/a&gt;. Customer input is not a sure thing. It does not guarantee a win. At the same time customer input doesn't doom you to failure!&lt;br /&gt;&lt;br /&gt;As customers give input ultimately someone has to decide whether or not to follow the customer's suggestions. Here is a bit of reality for you. I worked for one of the largest software companies in the world for a while. I had recently came from a Department of Energy job. At the DOE I had been taking the MAN pages for a particular flavor of Unix and converting them into HTML so that we could browse them with the Mosaic browser. Browsing and HTML was something with which I was familiar. At my new job (at this large software company) a new product was being developed. Another developer came to me and said we should make this browser based. The term "browser based" had not even been coined yet! I wonder if he was the first to use it. I said that it seems like it would be a great fit to me. The product was customizable with a proprietary script-like programming language. I suggested we use a Hypertalk type language instead. My friend scheduled a meeting with the team and all of the management and presented his idea for a browser based product and showed them Mosaic, some HTML, and various things. The "boss" said authoritatively "NO". A friend came to us and said, "I was talking with your boss and he asked me if I knew anything about FTP and HTML". We were shocked. FTP had been around for ever for us Unix users. How could he set direction when he didn't know anything about existing technology such as FTP! How was he going to set vision and direction for technology when he didn't know anything about NEW technology like HTML and Browsers. My point is a customer may have a great idea and it may fall into the hands of someone that can't recognize it as that. If the idea my friend presented had been adopted Netscape would have never came into being and Java script probably would have never came into being. WordPerfect corporation would have had a web browser, with scripting like Hypertalk, and it would have been sitting on top of a database (DataPerfect) from day one! The reason I feel that Netscape would have never made it is the fact that at that time WordPerfect had one of the most powerful marketing channels and had an extremely loyal customer base!&lt;br /&gt;&lt;br /&gt;Why do I speak of things that could have happened? I do it to give you real life examples of the difficulties in choosing the best direction for technology and for your company.&lt;br /&gt;&lt;br /&gt;I end with this question:&lt;br /&gt;&lt;br /&gt;So, do you need customer input or not?&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/36645098-9135876360667462198?l=digerati-illuminatus.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://digerati-illuminatus.blogspot.com/feeds/9135876360667462198/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=36645098&amp;postID=9135876360667462198' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/36645098/posts/default/9135876360667462198'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/36645098/posts/default/9135876360667462198'/><link rel='alternate' type='text/html' href='http://digerati-illuminatus.blogspot.com/2008/01/customer-input-who-needs-it.html' title='Customer input, Who needs it!'/><author><name>Geoff Slinker</name><uri>http://www.blogger.com/profile/12365501393247949005</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-36645098.post-655578299028956599</id><published>2007-12-09T10:57:00.000-08:00</published><updated>2007-12-09T12:02:38.379-08:00</updated><title type='text'>Estimating Software Feature development...</title><content type='html'>I propose a different approach to software development estimation.&lt;br /&gt;&lt;br /&gt;The first question to be asked should be:&lt;br /&gt;&lt;br /&gt;1) When can you start development on feature X?&lt;br /&gt;&lt;br /&gt;This question should lead to discussion and not a simple answer like "In two weeks". If you get a simple answer then ask, "Why then?" This will cause an explanation of what has to be done before the new feature can be started. This will expose the developer's priorities of work and will allow new priorities to be considered.&lt;br /&gt;&lt;br /&gt;The second question immediately follows the discussion of the first question and is made up of two parts (so you might want to say it is really two questions).&lt;br /&gt;&lt;br /&gt;2) Do you feel that feature X is complex and have you ever done anything like feature X before?&lt;br /&gt;&lt;br /&gt;Notice there is no estimate of how long the development of the new feature will take. This is key. Also notice there is an estimate of what the developer is currently doing. This is exactly what is wanted. By saying when one can start working of feature X it requires one to estimate when they will finish with feature W. The estimation for completion of feature W happens after feature W has been started and thus the estimation is based on experience up to that point! I think that is great.&lt;br /&gt;&lt;br /&gt;This brings us back to the essential nature of question 2. If question two identifies the problem as being complex, unfamiliar, or both, then you should recognize that any estimates start out as complete guesses and as experience is gained the estimates take on the form of educated guesses.&lt;br /&gt;&lt;br /&gt;So lets go through a little example.&lt;br /&gt;&lt;br /&gt;New Feature W: Find all customers that have purchased a monthly subscription and have canceled that subscription within two months of purchase.&lt;br /&gt;&lt;br /&gt;Manager Lynn: Pat, when can you start on feature W?&lt;br /&gt;Developer Pat: Lynn, I can start on it in 3 days.&lt;br /&gt;Lynn: What happens in three days that will allow you to start on W?&lt;br /&gt;Pat: I finish up feature V. All I have left to do is hook up the list control, handle the selection event and it is done.&lt;br /&gt;Lynn: Okay. You've done a good job on feature V. Thanks.&lt;br /&gt;Pat: Sure. That's why I get paid the big bucks!&lt;br /&gt;Lynn and Pat chuckle.&lt;br /&gt;Lynn: Do you think feature W is complex and have you ever worked on anything like it before?&lt;br /&gt;Pat: It doesn't seem complex, but I am not familiar with the databases involved with making the queries, so I have to learn where and how to get to the data. I am pretty good with SQL so I don't think that will be a problem.&lt;br /&gt;Lynn: Okay, that's good to know. We'll talk more about feature W later. Thanks.&lt;br /&gt;&lt;br /&gt;Lynn goes away and starts to think:&lt;br /&gt;"I wonder where that data is? I wonder if Pat has rights to access the data? Maybe I should ask the IT department and the DB admins about this data."&lt;br /&gt;&lt;br /&gt;I hope this simple contrivance helps you imagine how this method of estimation works.&lt;br /&gt;&lt;br /&gt;How can this be applied to Product estimation? Well, if the development team is working on another product then question one applies in that, "When will they be done with Product A?"&lt;br /&gt;&lt;br /&gt;Question two still applies in that "Which aspects of product B are new and unfamiliar in concept and which aspects appear to be difficult or complex?"&lt;br /&gt;&lt;br /&gt;I hope this "new" way of estimating software helps. This is part of what I call "Experience Driven Development". One day I will get that darn book finished!&lt;br /&gt;&lt;br /&gt;You can do this method in conjunction with existing methods, that is, there is no rule that says you have to estimate using only one method! Use two, three, or four methods of estimation if you feel it is of value!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/36645098-655578299028956599?l=digerati-illuminatus.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://digerati-illuminatus.blogspot.com/feeds/655578299028956599/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=36645098&amp;postID=655578299028956599' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/36645098/posts/default/655578299028956599'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/36645098/posts/default/655578299028956599'/><link rel='alternate' type='text/html' href='http://digerati-illuminatus.blogspot.com/2007/12/estimating-software-feature-development.html' title='Estimating Software Feature development...'/><author><name>Geoff Slinker</name><uri>http://www.blogger.com/profile/12365501393247949005</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-36645098.post-4210429877742173084</id><published>2007-11-14T10:28:00.000-08:00</published><updated>2007-11-14T11:48:29.762-08:00</updated><title type='text'>Code Debt, Product Market Debt, and Customer Debt</title><content type='html'>During software development code debt is accrued when decisions adversely affect the ability to extend, expand, or maintain the software code base. It is hard for me to define code debt however I know when I am accruing code debt. For instance, if I copy and paste some code to create a new class instead of taking the time to figure out if there should be some base classes, virtual methods, or interfaces I know that I am accruing code debt. Often the choice to accrue code debt is based on expediency, stealing from the future to pay for today.&lt;br /&gt;&lt;br /&gt;Product Market Debt is accruing anytime a competitor has their product in the market and your's is not. It is also accruing if a competitor has a better product.&lt;br /&gt;&lt;br /&gt;Customer Debt accrues if your product is of poor quality, is missing essential features, is hard to use, or any other aspect that the customer finds less than satisfactory.&lt;br /&gt;&lt;br /&gt;Before the first release of the product the Code Debt is only known to the developers. The product marketing team will not recognize code debt and will not understand the concerns of the developers. Clearly the customers will not see any of the effects of code debt for a product that has not released!&lt;br /&gt;&lt;br /&gt;Before the first release of the product the Product Market Debt is the driving concern of the product marketing team. Often the developers do not feel the same sense of urgency that the product market team feels. Again the customers will not know of any Product Market Debt for a product that hasn't sipped.&lt;br /&gt;&lt;br /&gt;In order to avoid the accrual of too much Product Market Debt the product marketing team will set a release date. Product marketing knows that Customer Debt will be accrued if there are essential features missing and therefore product marketing creates a list of features to be released.&lt;br /&gt;&lt;br /&gt;The feature list and the release date become a concern for the developers. Development knows that if they try to do too much in too short of a time that they will accrue Code Debt. The developers know that too much code debt will result in Customer Debt followed immediately by the accrual of Product Market Debt. For example if the Code Debt is high and the product is unreliable the customer will immediately become dissatisfied with the product. Time and money spent to increase the product reliability is the monetary value of Code Debt. While the developers are spending their time fixing bugs to increase reliability they are NOT developing new features and thus we are now accruing Product Market Debt because essentially we are falling behind. Loss of market share can be calculated as a monetary value which is the value of Product Market Debt. Customers returning the product and the lack or loss of sales is the monetary value associated with Customer Debt.&lt;br /&gt;&lt;br /&gt;The interaction of each of these Debts and the effects of Debt weigh heavily on the company's decision making process. Often the group that has the most influence within the company will control which type of debt is the primary concern. Often if the company was founded on a software product and grew around this product the concern of debt will be Code Debt, Customer Debt, and finally Product Market Debt. This may help one understand why some software companies fail in the market place. If the company is not a software company and is a company that is developing software to assist in its operations then the company may focus on Product Market Debt, Customer Debt, and finally Code Debt. This may help one understand why such companies struggle with software development cost overruns, continuous emergencies and outages of the software, and conflicts between the developers, the I.T. department, and the "Business".&lt;br /&gt;&lt;br /&gt;Each type of Debt is constantly accruing. The plan is to manage the rate of accrual. Code Debt accrues even if you have the best code that has ever been developed. It accrues because the eventually re-write is always on its way. If your product is developed with .NET 2 for Windows XP eventually you will find that the Product Market Debt is sufficient to force a re-write for .NET 3 and Vista. The previous statement shows that Product Market Debt is always accruing as well such as the release of a competing product or a new development framework and a new computer operating system. Customer debt is always accruing as well. The customer sees new features of a new operating system and they want the product to take advantage of them or the customer sees a new technology and imagines how great it would be if the product integrated with that technology.&lt;br /&gt;&lt;br /&gt;Either of the three Debts can break your company.&lt;br /&gt;&lt;br /&gt;The position of the company influences which Debt will be of primary concern.&lt;br /&gt;&lt;br /&gt;If the company is creating a new software product for an existing space then Product Market Debt may be the greatest concern. You have to get the product out to compete with the existing products and hopefully you can leap ahead of the existing feature set. Underestimating the scope of the software development task often leads such a company to under staff development and thus create an environment that will heavily accrue Code Debt. I advise that you should remember that all three Debts are accruing for the competitors as well. If you are fortunate enough to plan the development of your product coinciding with the release of a new operating system (or other Product Market Debt driving force) then the competitors will be obliged to pay for their Product Market Debt and overhaul or maybe even re-write their product.&lt;br /&gt;&lt;br /&gt;If the company has a mature product with a loyal customer base then the company may choose to accrue more Code Debt and hurry out a new release to ward off a new competitor or a new release of an existing competitor's product. The accrual of the Code Debt will result in an increased rate of accrual for Customer Debt. The Code Debt will result in a lower quality product and thus the customer will be dissatisfied. If the goal is to quickly release software updates/patches to the customer to pay off the Customer Debt you will find you have fallen into a trap. There is no quick release when there is Code Debt. The need for the quick release will cause decisions such as "throwing more people" at the problem or accruing more Code Debt.&lt;br /&gt;&lt;br /&gt;If the company is developing a new software product for a new market space then there is no Customer Debt as of yet. Product Market Debt is hard to measure because you do not know if another company has had the same idea and is about to release. Code Debt does not exist yet because there is no code, however the first debt that will start to accrue is Code Debt, and it starts as soon as the first line of code is wrote.&lt;br /&gt;&lt;br /&gt;Sufficient funding is one aspect of controlling all three Debts. However it is not sufficient to guarantee success. If you have sufficient funding to hire enough product marketing people to define the product and the needed release schedule, and enough developers to create the product with all of the listed features by the release date with the highest quality code possible and enough customer interaction during development then all three Debts have been addressed. However the money is not sufficient to guarantee success because you may have hired enough developers, enough product marketers, and other persons necessary but if these people are inefficient or incompetent all of the money in the world will not "save you".&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/36645098-4210429877742173084?l=digerati-illuminatus.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://digerati-illuminatus.blogspot.com/feeds/4210429877742173084/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=36645098&amp;postID=4210429877742173084' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/36645098/posts/default/4210429877742173084'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/36645098/posts/default/4210429877742173084'/><link rel='alternate' type='text/html' href='http://digerati-illuminatus.blogspot.com/2007/11/code-debt-product-market-debt-and.html' title='Code Debt, Product Market Debt, and Customer Debt'/><author><name>Geoff Slinker</name><uri>http://www.blogger.com/profile/12365501393247949005</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-36645098.post-8317195533843704736</id><published>2007-11-08T10:07:00.001-08:00</published><updated>2007-11-08T15:31:48.577-08:00</updated><title type='text'>Process Rockstar</title><content type='html'>I'm through working with people &lt;br /&gt;that never listen&lt;br /&gt;It's like the bottom of the ninth&lt;br /&gt;And I'm never gonna win&lt;br /&gt;This life hasn't turned out&lt;br /&gt;Quite the way I want it to be&lt;br /&gt;&lt;br /&gt;(Tell me what you want)&lt;br /&gt;&lt;br /&gt;I want a brand new process&lt;br /&gt;With new buzz words&lt;br /&gt;I want a write a book&lt;br /&gt;for all those nerds&lt;br /&gt;And have all my friends rate it on Amazon for me&lt;br /&gt;&lt;br /&gt;(So what you need?)&lt;br /&gt;&lt;br /&gt;I need an internet connection that's got no limit&lt;br /&gt;And a new users group where I can spin it&lt;br /&gt;Gonna sign the manifesto and kiss everybody's feet&lt;br /&gt;&lt;br /&gt;(Been there, done that)&lt;br /&gt;&lt;br /&gt;I want a new certification &lt;br /&gt;that I control&lt;br /&gt;My name mentioned &lt;br /&gt;at conference shows&lt;br /&gt;Somewhere between Brookes &lt;br /&gt;and Gamma is fine with me.&lt;br /&gt;&lt;br /&gt;(So how you gonna do it?)&lt;br /&gt;&lt;br /&gt;I'm gonna trade programming for fortune and fame&lt;br /&gt;I'll even do the iteration planninng game&lt;br /&gt;&lt;br /&gt;'Cause we all just wanna be big Rock Stars....&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/36645098-8317195533843704736?l=digerati-illuminatus.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://digerati-illuminatus.blogspot.com/feeds/8317195533843704736/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=36645098&amp;postID=8317195533843704736' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/36645098/posts/default/8317195533843704736'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/36645098/posts/default/8317195533843704736'/><link rel='alternate' type='text/html' href='http://digerati-illuminatus.blogspot.com/2007/11/process-rockstar.html' title='Process Rockstar'/><author><name>Geoff Slinker</name><uri>http://www.blogger.com/profile/12365501393247949005</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-36645098.post-6757752850852491160</id><published>2007-10-23T14:32:00.000-07:00</published><updated>2007-10-25T07:34:43.320-07:00</updated><title type='text'>Database "Design By Use"</title><content type='html'>About two years ago I designed a database for managing customer information, billing information, product information, pricing information, shipping information, and subscription information. The method I used to design the database, tables, and queries was&lt;a href="http://home.comcast.net/~gslinker/maverick/DBU.html"&gt; Design By Use&lt;/a&gt; (DBU).&lt;br /&gt;&lt;br /&gt;I can not share the resulting system but I can tell you how DBU helped with the design process.&lt;br /&gt;&lt;br /&gt;The first step is to list as many of the "requests" you can define at the time. For example:&lt;br /&gt;&lt;br /&gt;Find all of the customers who purchased product X during the past 6 months.&lt;br /&gt;Find all of the products for sale in Spain.&lt;br /&gt;Find all of the monthly subscriptions that have expired.&lt;br /&gt;&lt;br /&gt;These examples are how the system will be used, thus we are designing the system in the manner we want to use the system.&lt;br /&gt;&lt;br /&gt;The above examples eventually became SQL queries.&lt;br /&gt;&lt;br /&gt;At the same time the usage examples are helping formulate the design the domain objects are being identified as well. The domain objects eventually found their representation in the database tables either as a table schema or as the results of joins on various tables.&lt;br /&gt;&lt;br /&gt;Knowing how the database was to be used also helped in figuring out the schema and which tables might need keys to be used in other tables.&lt;br /&gt;&lt;br /&gt;In the end I had designed a system that was exactly what was needed, thus YAGNI was satisfied. Also it was demonstrable in that the queries could be ran against test data and through automated testing show that the system correctly works.&lt;br /&gt;&lt;br /&gt;I have designed many databases over the years but this approach was by far the best. It was better because it did exactly what was needed, no more, no less, and that I could run the queries as regression tests. &lt;br /&gt;&lt;br /&gt;Often I have dealt with cross database joins in other systems and often I have found that such activities are the results of poor design.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://home.comcast.net/~gslinker/maverick/DBU.html"&gt;Design By Use&lt;/a&gt; works great for me. You should try it and see if you find it helpful as well!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/36645098-6757752850852491160?l=digerati-illuminatus.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://digerati-illuminatus.blogspot.com/feeds/6757752850852491160/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=36645098&amp;postID=6757752850852491160' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/36645098/posts/default/6757752850852491160'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/36645098/posts/default/6757752850852491160'/><link rel='alternate' type='text/html' href='http://digerati-illuminatus.blogspot.com/2007/10/database-design-by-use.html' title='Database &quot;Design By Use&quot;'/><author><name>Geoff Slinker</name><uri>http://www.blogger.com/profile/12365501393247949005</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-36645098.post-5915090328836805025</id><published>2007-09-08T07:15:00.001-07:00</published><updated>2007-09-08T11:25:26.499-07:00</updated><title type='text'>Maverick Web Site</title><content type='html'>Quick note: The maverick web site has been moved. The new URL is:&lt;br /&gt;&lt;a href="http://home.comcast.net/~gslinker/agile.html"&gt;http://home.comcast.net/~gslinker/agile.html&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/36645098-5915090328836805025?l=digerati-illuminatus.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://digerati-illuminatus.blogspot.com/feeds/5915090328836805025/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=36645098&amp;postID=5915090328836805025' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/36645098/posts/default/5915090328836805025'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/36645098/posts/default/5915090328836805025'/><link rel='alternate' type='text/html' href='http://digerati-illuminatus.blogspot.com/2007/09/httphomecomcastnetgslinkeragilehtml.html' title='Maverick Web Site'/><author><name>Geoff Slinker</name><uri>http://www.blogger.com/profile/12365501393247949005</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-36645098.post-2424890029568524474</id><published>2007-06-07T15:14:00.001-07:00</published><updated>2007-06-07T16:46:00.678-07:00</updated><title type='text'>What is Software?</title><content type='html'>Often I have heard people try to describe software. If it can be described then maybe we can formalize it and then make the process of software development more like a true engineering process.&lt;br /&gt;&lt;br /&gt;I propose that one should think of software like the blue prints of a house instead of thinking of software like components, objects, and building parts. Let me try to explain. I do not think that when a software developer is writing code he is building the metaphoric walls, floors, and roof of the house.&lt;br /&gt;&lt;br /&gt;Before I go any further I want to stop and say I am not saying modules, objects, and other abstraction and organization techniques should not be used.&lt;br /&gt;&lt;br /&gt;Software is a set of instructions that will be executed by a computer. These instructions are created in a manner that is suitable for humans to create, organize, and maintain but they are still just instructions. These instructions are turned over the the computer for processing. So if we go back to the house building analogy then the software engineer creates a set of instructions or blueprints on how to build the house and the computer's processor actually builds the house. Each time the software is launched the proverbial house is being rebuilt.&lt;br /&gt;&lt;br /&gt;To further the analogy it would be like delivering a blueprint of the house along with ordered sequential instructions to guide every step and every action of the house builders. It might go like this: "Worker pick up hammer. Worker drive nail." But wait, we didn't tell the worker to pick up a nail and we didn't even have the worker standing in front of the wall in which we wish to drive the nail.&lt;br /&gt;&lt;br /&gt;The interesting thing about using the house building analogy it is almost like the house is built when it is needed to be used and then it is torn down and all of its resources are available to be used by someone else. So it is like all of the nails that we used to build the house are available to use to build something else when our house is not in use. Nails are a resource needed to build a house. Similarly a storage device such as a hard drive is needed to store the software. Resources are finite that is to say there are only so many nails available or so much disk space available.&lt;br /&gt;&lt;br /&gt;Once a house is built it continues to consume resources such as water and electricity. Software after it is built consumes memory and use resources like the network or video card. If there is no electricity the "house" fails to provide such things as light or heat to the customer. If there is no more memory the software fails to perform desired functions.&lt;br /&gt;&lt;br /&gt;Thinking of software in this way helps one understand why software fails even though it had performed fine for months. Software depends upon the resources available in the environment for which it exists. The availability of resources change and thus software that worked before now fails. How the software fails is described as a level of robustness. Robust software fails nicely. That is the programmer provided instructions to the computer to do something in case there isn't enough memory or the network connection is down. To go back to the house building analogy it would be like giving instructions to the builder "Get a 6 penny nail. If there are no 6 penny nails then get an 8 penny nail. If there are no 8 penny nails then signal your boss you will wait until there are some nails..."&lt;br /&gt;&lt;br /&gt;Software is just a set of instructions to be performed by a computer processing unit. Software is not some carved out thing on a hard drive that leaps to the forefront when you click on it.&lt;br /&gt;&lt;br /&gt;To me that is what software is.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/36645098-2424890029568524474?l=digerati-illuminatus.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://digerati-illuminatus.blogspot.com/feeds/2424890029568524474/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=36645098&amp;postID=2424890029568524474' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/36645098/posts/default/2424890029568524474'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/36645098/posts/default/2424890029568524474'/><link rel='alternate' type='text/html' href='http://digerati-illuminatus.blogspot.com/2007/06/what-is-software.html' title='What is Software?'/><author><name>Geoff Slinker</name><uri>http://www.blogger.com/profile/12365501393247949005</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-36645098.post-1246523426394424900</id><published>2007-04-18T14:55:00.000-07:00</published><updated>2007-09-17T15:06:56.645-07:00</updated><title type='text'>Improving Software Estimates Part 3</title><content type='html'>In the first post entitled "Improving Software Estimates" I described two scenarios where the estimates were incorrect.&lt;br /&gt;&lt;br /&gt;First let me digress and say an estimate is neither right or wrong. It is an estimate. When I say an estimate was incorrect I mean the estimate and the actual results varied.  In the world I live in an estimate for when software will be finished is a prediction. Predictions for software delivery dates are used to schedule dependent tasks. So, when I use the term estimate I am using the common vernacular of the industry. I prefer prediction.&lt;br /&gt;&lt;br /&gt;Back to the point of this post. The second failure scenario is that the developer was developing something new and had no prior experience that could be directly applied. When faced with the unknown then I rely on "method" to help me through.&lt;br /&gt;&lt;br /&gt;The "method" I use for tackling the unknown is called "&lt;a href="http://home.comcast.net/~gslinker/maverick/Scouting.html"&gt;Software Scouting and Reconnaissance&lt;/a&gt;".&lt;br /&gt;&lt;br /&gt;“Scouting” is the metaphor. During the exploration of the American frontier, scouts were sent out ahead of the company to determine the safest path through unknown and hostile territory. Through software “scouting missions” one can save time and money, and reduce the risks to the company.&lt;br /&gt;&lt;br /&gt;When one is in unknown territory scout ahead for information and then come back and apply the knowledge gained. Have enough discipline not to get distracted by the sights along the way. Stay focused, travel light, and get back to camp as quickly as possible.&lt;br /&gt;&lt;br /&gt;This pattern of short scouting trips would continually repeat, making the technique both iterative and incremental.&lt;br /&gt;&lt;br /&gt;Before starting the journey into the unknown you must do as much study as possible.  Gain as much knowledge as you can so that you can apply it as you go.&lt;br /&gt;&lt;br /&gt;After the study is complete then define your domains and sub-domains. Create your dictionary of terms and metaphors that you will use to describe the potential solution. In other words I recommend coming up with a high level design. This design can be in your head, on paper with diagrams or text, what ever works for you.&lt;br /&gt;&lt;br /&gt;This design is used to break the whole into smaller tasks. These smaller tasks are your weigh stations along the journey.&lt;br /&gt;&lt;br /&gt;All of this is preparatory work so that you can take your first heading. Every journey starts in some direction.&lt;br /&gt;&lt;br /&gt;At this point I start writing code. Starting with the end in mind is one of the best ways I know to get you going. One can analyze and study the problem for way too long especially if you are nervous about the first step. I use Design By Use (DBU) to do this. I write the code as if the methods already exist. It is very much like Test First Programming described in Extreme Programming. In Part 2 of this series I described DBU as a method to synchronize two teams. DBU can be applied even if you are going to write all of the code and you have no external dependencies.&lt;br /&gt;&lt;br /&gt;"Code your way" towards the completion of the first small task. You will be learning as you go and now you can apply this knowledge and experience and revise your estimate of completion. You continue in this iterative and incremental fashion until the remaining task is so small that you feel you can't miss your estimate too badly or until you have enough experience that there is nothing unknown left and you can estimate the remaining work just like you would on a task where you have experience.&lt;br /&gt;&lt;br /&gt;To recap when I am faced with developing software where I do not have any experience I rely on processes and methods to carry me forward. Specifically I use &lt;a href="http://home.comcast.net/~gslinker/maverick/Scouting.html"&gt;Software Scouting and Reconn&lt;/a&gt; and &lt;a href="http://home.comcast.net/~gslinker/maverick/DBU.html"&gt;Design By Use&lt;/a&gt; to move forward in an incremental and iterative fashion until I have finished.&lt;br /&gt;&lt;br /&gt;Geoff&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/36645098-1246523426394424900?l=digerati-illuminatus.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://digerati-illuminatus.blogspot.com/feeds/1246523426394424900/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=36645098&amp;postID=1246523426394424900' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/36645098/posts/default/1246523426394424900'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/36645098/posts/default/1246523426394424900'/><link rel='alternate' type='text/html' href='http://digerati-illuminatus.blogspot.com/2007/04/improving-software-estimates-part-3.html' title='Improving Software Estimates Part 3'/><author><name>Geoff Slinker</name><uri>http://www.blogger.com/profile/12365501393247949005</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-36645098.post-8181689591270906110</id><published>2007-04-15T21:47:00.000-07:00</published><updated>2007-09-17T15:02:04.865-07:00</updated><title type='text'>Improving Software Estimates Part 2</title><content type='html'>In the first post I described two scenarios where the estimate was incorrect. In the first description the delivery estimate was incorrect because of external dependencies.&lt;br /&gt;&lt;br /&gt;Software is often developed by teams of engineers. Also it is common that several teams work simultaneously. Estimation is important when coordinating several teams.&lt;br /&gt;&lt;br /&gt;I have addressed the issue of team coordination with a process known as Design By Use (DBU). DBU is not intended to be the single solution to coordination issues but is intended as a tool.&lt;br /&gt;&lt;br /&gt;In the scenario previously described the developer was unable to meet his estimated delivery schedule because of an external dependency. This is often a "down stream" dependency. You can not continue until the other team has delivered so that you can link to their system. DBU addresses this issue by defining the integration interface early and integrating immediately.&lt;br /&gt;&lt;br /&gt;When designing code the "caller" has certain data available at specific levels of the system. The "callee" does not know what data is available to the caller and therefore it is risky for the callee to define the interface based on assumptions. Assumptions of data availability may break domain models and layers of separation. Therefore DBU teaches us that the caller should write a usage example and give it to the callee. Do you see how this addresses the coupling concerns had by the caller?&lt;br /&gt;&lt;br /&gt;Also the callee is benefitted by DBU. The principal of "you aint going to need it" (YAGNI) is addressed by DBU. I have written many internal utility libraries over the years. Without knowing exactly how your library is to be used by other teams at your company it is easy to add features and overloaded methods in the attempt to "be everything for everybody". This ultimately leads to lots of code that is never called and which become maintenance baggage from "then on out".&lt;br /&gt;&lt;br /&gt;By addressing YAGNI you gain the benefits of improved efficiency in that you are not writing anything extra. You only write what someone is going to use and you know that they are going to use it because they (the caller) specified the interface.&lt;br /&gt;&lt;br /&gt;How is software estimation improved?&lt;br /&gt;&lt;br /&gt;The caller controls their domain and abstraction layers and protects the coupling of the system. Loosely coupled systems are easier to work with and I propose that systems that are loosely coupled assists in the estimation process. If the caller discovers that additional systems must be coupled it is known sooner rather than later. This addresses integration issues which have proven to be one of the most costly activities of software development if ignored until the end.&lt;br /&gt;&lt;br /&gt;The callee is also helped with the estimation task by not having to design a system that will "be everything to everybody". They can focus on the specified interactions exclusively. The first thing they can do is provide a stubbed version of the system to the caller so that they can immediately link to their system. Then the caller can continue to work while the callee implements the solution. Pretty slick I do have to say.&lt;br /&gt;&lt;br /&gt;Here is a link to a specific application of DBU. It describes how DBU can be used to organize multiple teams.&lt;br /&gt;http://home.comcast.net/~gslinker/maverick/DBU.html&lt;br /&gt;&lt;br /&gt;If you address integration issues early and only write what is needed software estimates can be made simpler and it is my belief that reduced complexity is directly related to improved software estimation.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/36645098-8181689591270906110?l=digerati-illuminatus.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://digerati-illuminatus.blogspot.com/feeds/8181689591270906110/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=36645098&amp;postID=8181689591270906110' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/36645098/posts/default/8181689591270906110'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/36645098/posts/default/8181689591270906110'/><link rel='alternate' type='text/html' href='http://digerati-illuminatus.blogspot.com/2007/04/improving-software-estimates-part-2.html' title='Improving Software Estimates Part 2'/><author><name>Geoff Slinker</name><uri>http://www.blogger.com/profile/12365501393247949005</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-36645098.post-1030389159742802682</id><published>2007-04-14T15:09:00.000-07:00</published><updated>2007-09-17T14:53:54.173-07:00</updated><title type='text'>Improving Software Estimates</title><content type='html'>As I work on my book, Experience Driven Development, I am compelled to share thoughts.&lt;br /&gt;&lt;br /&gt;An important aspect of software development is the estimation of when software features will be complete. I have heard it said that the more you estimate the better you get at it. Is it true?&lt;br /&gt;&lt;br /&gt;The estimate for "work" may be different than the estimate for "delivery".&lt;br /&gt;&lt;br /&gt;Someone new at estimation may say "I will have the task done in 80 hours". While working on the task he soon finds out that a dependency is not ready and thus he has to wait. Suppose the delay is 40 hours so in the end it took 120 hours to complete the task. It is possible that if you only consider the person's time spent on the task it was 80 hours so their estimate of work was accurate. However the estimate of delivery was inaccurate because he spent 40 hours waiting on a dependency.&lt;br /&gt;&lt;br /&gt;I believe that the experience will help the person make a better estimate next time. A better estimate in that it is &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_0"&gt;more&lt;/span&gt; complete in considering dependencies.&lt;br /&gt;&lt;br /&gt;Now I will describe another scenario. Suppose someone estimates that their feature will be done in 80 hours. There are no external dependencies. In reality suppose it took 100 hours to finish the feature. In this scenario the reason it took longer than estimated was because it was a new task and the person had never done anything quite like it before. In my opinion this kind of estimate will not improve. I do not think you can get better at predicting the unknown. What has happened is that the person has gained new experience and if that person encounters a similar situation in the future then he can estimate how long it will take to develop the familiar "parts" and add some amount of a guess to the estimate for the unfamiliar parts.&lt;br /&gt;&lt;br /&gt;Experience improves estimates.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/36645098-1030389159742802682?l=digerati-illuminatus.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://digerati-illuminatus.blogspot.com/feeds/1030389159742802682/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=36645098&amp;postID=1030389159742802682' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/36645098/posts/default/1030389159742802682'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/36645098/posts/default/1030389159742802682'/><link rel='alternate' type='text/html' href='http://digerati-illuminatus.blogspot.com/2007/04/improving-software-estimates.html' title='Improving Software Estimates'/><author><name>Geoff Slinker</name><uri>http://www.blogger.com/profile/12365501393247949005</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-36645098.post-116762032221232991</id><published>2006-12-31T16:29:00.000-08:00</published><updated>2007-01-02T06:44:36.756-08:00</updated><title type='text'>The Initialize Pattern and the Open &amp; Close Pattern</title><content type='html'>&lt;p&gt;&lt;br /&gt;      I have often been confronted with the "initialize" pattern or the "open and close" pattern. For instance there is some object that you instantiate but before you use it you must call an initialization method often like SomeClass.Initialize(). A similar pattern is that with objects that you need to open before usage and make sure that they are closed on usage completion. Often the situation can be handled using "acquisition is initialization". This works well with exceptions and stack unwinding. Sometimes the use of factories can meet the needs. I have a solution that is based on both and is a pattern that I have used when necessary.&lt;br /&gt;  &lt;/p&gt;    &lt;p&gt;&lt;br /&gt;      In C# I use two classes an outer class and an inner class. The outer class's methods do not have public visibility, except for the constructor and a factory method. The inner class exposes the methods that can be performed on the outer class.&lt;/p&gt;        &lt;p&gt;&lt;br /&gt;      &lt;/p&gt;&lt;pre&gt;using System;&lt;br /&gt;using System.Collections.Generic;&lt;br /&gt;using System.Text;&lt;br /&gt;&lt;br /&gt;namespace NestedTypes&lt;br /&gt;{&lt;br /&gt;  public class CResource&lt;br /&gt;  {&lt;br /&gt;      public CResource()&lt;br /&gt;      {&lt;br /&gt;      }&lt;br /&gt;&lt;br /&gt;      protected void Open()&lt;br /&gt;      {&lt;br /&gt;      }&lt;br /&gt;&lt;br /&gt;      protected void Close()&lt;br /&gt;      {&lt;br /&gt;      }&lt;br /&gt;&lt;br /&gt;      protected void Read()&lt;br /&gt;      {&lt;br /&gt;      }&lt;br /&gt;&lt;br /&gt;      protected void Write()&lt;br /&gt;      {&lt;br /&gt;      }&lt;br /&gt;&lt;br /&gt;      public CResourceUser CreateUser()&lt;br /&gt;      {&lt;br /&gt;          return new CResourceUser(this);&lt;br /&gt;      }&lt;br /&gt;&lt;br /&gt;      public class CResourceUser : IDisposable&lt;br /&gt;      {&lt;br /&gt;          protected CResource resource;&lt;br /&gt;&lt;br /&gt;          internal CResourceUser(CResource resource)&lt;br /&gt;          {&lt;br /&gt;              this.resource = resource;&lt;br /&gt;              this.resource.Open();&lt;br /&gt;          }&lt;br /&gt;&lt;br /&gt;          public void Dispose()&lt;br /&gt;          {&lt;br /&gt;              this.resource.Close();&lt;br /&gt;          }&lt;br /&gt;&lt;br /&gt;          public void Read()&lt;br /&gt;          {&lt;br /&gt;              this.resource.Read();&lt;br /&gt;          }&lt;br /&gt;&lt;br /&gt;          public void Write()&lt;br /&gt;          {&lt;br /&gt;              this.resource.Write();&lt;br /&gt;          }&lt;br /&gt;      }&lt;br /&gt;  }&lt;br /&gt;}      &lt;br /&gt;      &lt;/pre&gt;&lt;br /&gt;      &lt;p&gt;&lt;/p&gt;&lt;br /&gt;      &lt;p&gt;&lt;br /&gt;          In this case I have the inner class implement the IDisposible interface which allows for the "using statement" in C#.&lt;/p&gt;    &lt;p&gt;&lt;br /&gt;      &lt;/p&gt;&lt;pre&gt;using System;&lt;br /&gt;using System.Collections.Generic;&lt;br /&gt;using System.Text;&lt;br /&gt;&lt;br /&gt;namespace NestedTypes&lt;br /&gt;{&lt;br /&gt;  class Program&lt;br /&gt;  {&lt;br /&gt;      static void Main(string[] args)&lt;br /&gt;      {&lt;br /&gt;          CResource resource = new CResource();&lt;br /&gt;          CResource.CResourceUser resourceUser = resource.CreateUser();&lt;br /&gt;          using (resourceUser)&lt;br /&gt;          {&lt;br /&gt;              resourceUser.Read();&lt;br /&gt;              resourceUser.Write();&lt;br /&gt;          }&lt;br /&gt;      }&lt;br /&gt;  }&lt;br /&gt;}      &lt;br /&gt;      &lt;/pre&gt;&lt;p&gt;&lt;/p&gt;&lt;br /&gt;      &lt;p&gt;&lt;br /&gt;          I have used this pattern for implementing logging facilities. I have used this pattern in multi-threaded environments and I have found that this pattern made it obvious where synchronization must be handled.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/36645098-116762032221232991?l=digerati-illuminatus.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://digerati-illuminatus.blogspot.com/feeds/116762032221232991/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=36645098&amp;postID=116762032221232991' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/36645098/posts/default/116762032221232991'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/36645098/posts/default/116762032221232991'/><link rel='alternate' type='text/html' href='http://digerati-illuminatus.blogspot.com/2006/12/initialize-pattern-and-open-close.html' title='The Initialize Pattern and the Open &amp; Close Pattern'/><author><name>Geoff Slinker</name><uri>http://www.blogger.com/profile/12365501393247949005</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-36645098.post-116647109018729152</id><published>2006-12-18T11:21:00.000-08:00</published><updated>2006-12-18T11:44:50.193-08:00</updated><title type='text'>Leader and Follower</title><content type='html'>In order to justify the risk in pursuing a course the leaders and the followers must:&lt;br /&gt;1) Believe in the cause&lt;br /&gt;2) Trust that there is an opportunity for success&lt;br /&gt;3) Believe that the outcome is worth the cost&lt;br /&gt;4) Believe that upon success he will receive his reward&lt;br /&gt;&lt;br /&gt;The cause has to be motivating and be aligned with one's goals, responsibilities, or beliefs. The cause should be fully disclosed naming all parties and interests concerned.&lt;br /&gt;&lt;br /&gt;There needs to be a real opportunity to succeed. For the follower success includes the allowance to act in the best manner, using one's faculties and skills, being respected, and having a voice that is heard. For the leader success includes the trust that the followers will act in the best manner, using their's faculties and skills, showing respect, and speaking when something needs to be said. The followers will do what they agreed to do and the leaders will do likewise.&lt;br /&gt;&lt;br /&gt;There must be a belief that the outcome is worth the cost.&lt;br /&gt;&lt;br /&gt;There must be a belief that at the journeys successful end that you will receive your wages. The follower expects the leader to reward them as agreed and that the leader will protect the follower's interests. The leader is in a position of trust and can not violate that trust by hiding the full agenda or by bowing to the interests of unnamed or undisclosed parties.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/36645098-116647109018729152?l=digerati-illuminatus.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://digerati-illuminatus.blogspot.com/feeds/116647109018729152/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=36645098&amp;postID=116647109018729152' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/36645098/posts/default/116647109018729152'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/36645098/posts/default/116647109018729152'/><link rel='alternate' type='text/html' href='http://digerati-illuminatus.blogspot.com/2006/12/leader-and-follower.html' title='Leader and Follower'/><author><name>Geoff Slinker</name><uri>http://www.blogger.com/profile/12365501393247949005</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-36645098.post-116603776960815677</id><published>2006-12-13T11:17:00.000-08:00</published><updated>2006-12-13T11:22:49.613-08:00</updated><title type='text'>Agile is not about doing as little as possible.</title><content type='html'>If Agile is about doing as little as possible then I do not practice Agile.&lt;br /&gt;&lt;br /&gt;From my understanding Agile reviewed practices and ceremonies and decided that many of them were out dated or not applicable in areas where change occurred often.&lt;br /&gt;&lt;br /&gt;The goal is to do only the necessary work with enough staff to handle the necessary tasks. If that means doing less then so be it, but it might mean doing more. Understand that it depends on each situation, organization, and environment. I am sorry that it isn't as simple as you hoped.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/36645098-116603776960815677?l=digerati-illuminatus.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://digerati-illuminatus.blogspot.com/feeds/116603776960815677/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=36645098&amp;postID=116603776960815677' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/36645098/posts/default/116603776960815677'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/36645098/posts/default/116603776960815677'/><link rel='alternate' type='text/html' href='http://digerati-illuminatus.blogspot.com/2006/12/agile-is-not-about-doing-as-little-as.html' title='Agile is not about doing as little as possible.'/><author><name>Geoff Slinker</name><uri>http://www.blogger.com/profile/12365501393247949005</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-36645098.post-116602367707758420</id><published>2006-12-13T07:20:00.000-08:00</published><updated>2006-12-13T07:28:45.446-08:00</updated><title type='text'>Leading and Leadership</title><content type='html'>Leading as in "being in front of" is not necessarily Leadership.&lt;br /&gt;&lt;br /&gt;"Apple is leading the market in the sales of high end MP3 players"&lt;br /&gt;"The University of Utah is leading the way in computer graphics research"&lt;br /&gt;&lt;br /&gt;Leading is similar to magnitude while Leadership is like a direction, or Leading is about how far you are in front and Leadership is concerned with going in the right way.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/36645098-116602367707758420?l=digerati-illuminatus.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://digerati-illuminatus.blogspot.com/feeds/116602367707758420/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=36645098&amp;postID=116602367707758420' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/36645098/posts/default/116602367707758420'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/36645098/posts/default/116602367707758420'/><link rel='alternate' type='text/html' href='http://digerati-illuminatus.blogspot.com/2006/12/leading-and-leadership.html' title='Leading and Leadership'/><author><name>Geoff Slinker</name><uri>http://www.blogger.com/profile/12365501393247949005</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-36645098.post-116577786890890093</id><published>2006-12-10T11:10:00.000-08:00</published><updated>2006-12-10T15:58:01.476-08:00</updated><title type='text'>Common Sense</title><content type='html'>Maybe the thoughts contained in the following lines aren't generally excepted or understood enough to gain general approval. It seems to be human nature that if over a long period of time something isn't challenged as being wrong or inefficient then the thing is accepted as being right or optimal. Any challenge to the long standing "thing" is usually at first met with resistance, but soon the commotion settles down and reason prevails.&lt;br /&gt;&lt;br /&gt; Long experience and empirical evidence of inefficiencies, failures, and abuses is sufficient reason to question the correctness of business management organization and process. These problems have caused people at all levels in business to question the generally accepted "ways" of managing and organizing a business.&lt;br /&gt;&lt;br /&gt;In this paper, I have avoided singling out any one management model as being good or bad, or any business leader as being good or bad. Those that have championed change do not depend on the success of my ranting. Also, in this paper, the arguments of those who prefer the status quo will ultimately be forgotten if there is not too much consideration given to their defensive remarks.&lt;br /&gt;&lt;br /&gt;The cause of the Worker is, in a great measure, the cause of all people. Many circumstances have, and will arise, which are not specific to a business sector or management style, but are universal, and through which the principles of  all those that desire the satisfaction of a "good days work" are affected, and because they are affect by these universal circumstances they are also rightly concerned. The using of employees in such a manner that  they are nothing more than a resource, like so much cattle, which destroys self worth and self esteem and ultimately works against a business' need for efficiency and profitability is the concern of every employer and employee that has the capacity of reason.&lt;br /&gt;&lt;br /&gt;The Origin and Design of Popular Business Organization and Process.&lt;br /&gt;&lt;br /&gt;SOME writers have so confounded the concept of Team with the management organization, as to leave little or no distinction between them. They are not only different but  have different origins. A Team is the organizational results of real need. Management organization is an attempt to deal with our weaknesses and pride. A Team promotes the happiness of each member by uniting on goals and needs where management organization is to minimize the negative affects of human vices. Teams encourage working together with a common cause while management organization creates distinctions, distinctions that have no correspondence with business efficiency or profitability. Team-ship is a patron. Management organization is a punisher.&lt;br /&gt;&lt;br /&gt;Team-ship, community-ship, sociocracy, or whatever the term, is a blessing, but the common management organization of business in its best state is but a necessary evil in its worst state an intolerable one; for when we suffer, or are exposed to the same miseries by a business organization, which we might expect in a business with no organization or chaos, our calamities is heightened by reflecting that we furnished the means by which we suffer. High ceremony business organization, like government, is the badge of lost innocence; the mansions and estates of CEOs are built on the ruins of the humble home with the white picket fence and have redefined the organization of the family unit. If the intrinsic desires of a clear conscience were obeyed then there would be no need for another set of guidance. Since that is not the case, it is necessary to surrender up a part of the business earnings to furnish a means for the protection of the rest; and this is induced by the same prudence which in every other case advises one to choose the lesser of two evils. Wherefore, security and predictability being the true design and end of business organization, it unanswerably follows that whatever form thereof appears most likely to ensure it to us, with the least expense and greatest benefit, is preferable to all others.&lt;br /&gt;&lt;br /&gt;In order to gain a clear and just idea of the  design and end of a business organization, let us suppose a small number  of persons start a new company, unconnected to existing companies. In this state of natural liberty, team work will be their first thought. A thousand motives will excite them thereto, the strength of one man is so unequal to his wants, and his mind so unfitted for perpetual solitude, that he is soon obliged to seek assistance and relief of another, who in his turn requires the same. Four or five united would be able to found a fledgling company, but one man might labor out the common period of a life without accomplishing any thing; when he had envisioned the business opportunity he could not bring it to market in a timely manner; the continuous burn of capital would drive him to more short term ventures, and every different want call him a different way.&lt;br /&gt;&lt;br /&gt;Thus necessity, like a gravitating and organizing power, would soon form our newly found company into a team or society, the reciprocal blessing of which, would supersede, and render the obligations of corporate government unnecessary while they remained perfectly just to each other; but as nothing but heaven is impregnable to vice, it will unavoidably happen, that in proportion as they surmount the first difficulties of team work, which bound them together in a common cause, they will begin to relax  in their duty and attachment to each other; and this remissness, will point out the necessity,  of establishing some form of organization to supply the defect of moral virtue. &lt;br /&gt;&lt;br /&gt;Some convenient empty office will afford them a conference room in which every employee of the company may assemble to deliberate on company matters. It is more than probable that their first by-laws will have the title of "company guidelines", and be enforced by no other penalty than company-wide  disesteem. In the first company organization every man, by natural right will have a seat.&lt;br /&gt;&lt;br /&gt;But as company portfolio and employment increases, the company concerns will increase likewise, and the distance at which the members may be separated,  will render it too inconvenient for  all of them to meet on every occasion as at first, when their number was small, their offices near, and the company concerns few and trifling. This will point out the convenience of their consenting to leave the business  management part to be managed by a select number of  chosen from the whole  body, who are supposed to have the same business concerns at stake which those have who appointed them, and who  will  act in the same manner as the whole body would act were they present. If the company continues to grow, it will become necessary to augment the number of representatives, and that the interest of every part of the company may be attended to, it will be found best to divide the whole into convenient parts, each part sending its proper number; and that the elected might never form to themselves an interest separate from the electors, prudence will point out the propriety of having elections often; because as the  elected might by that means return and work again with the general divisions of the company in a few months, their fidelity to the company division will be secured by the prudent reflection of not making themselves a permanent authority. And as this frequent interchange will establish a common interest with every part of the company, they will mutually and naturally support each other, and on this (not on the unmeaning title of CEO/President) depends the strength of the company, and the happiness of the employee.&lt;br /&gt;&lt;br /&gt;Here then is the origin and rise of business organization; namely, a mode rendered necessary by the inability of moral virtue to govern the company; here too is the design and end of business organization, that is to say., predictability and security. And however our eyes may be dazzled with snow, or our ears deceived by sound; however prejudice may warp our wills, or interest darken our understanding, the simple voice of nature and of reason will say, it is right.&lt;br /&gt;&lt;br /&gt;I draw my idea of the form of business organization from a principle in nature, which no art can overturn, that is to say., that the more simple any thing is, the less liable it is to be disordered, and the easier repaired when disordered; and with this maxim in view, I offer a few remarks on the so much boasted high ceremony organization of most businesses. That it was noble for the dark and slavish times in which it was erected is granted. When the world was overrun with tyranny, child labor, etc.,  the least therefrom was a glorious rescue. But that it is imperfect, subject to convulsions, and incapable of producing what it seems to promise, is easily demonstrated.&lt;br /&gt;&lt;br /&gt;Absolute leadership through a single office (though the disgrace of human nature) has this advantage with their kind, that they are simple; if the company suffers, they know the head from which their suffering springs, know likewise the remedy, and are not bewildered by a variety of causes and cures. But the corporate politics of high ceremony business organization is so exceedingly complex, that the company may suffer for years together without being able to discover in which part the fault lies, some will say in one and some in another, and every new management fad will advise a different course of action for remedy.&lt;br /&gt;&lt;br /&gt;I know it is difficult to get over local or long standing prejudices, yet if we will suffer ourselves to examine the component parts of high ceremony business, we shall find them to be the base remains of two ancient tyrannies, compounded with some new republican materials.&lt;br /&gt;&lt;br /&gt;First.- The remains of monarchical tyranny in the office of the CEO and other Chief positions&lt;br /&gt;&lt;br /&gt;Secondly.- The remains of aristocratical tyranny in the offices of the Executive committees, such as Vice Presidents and Directors.&lt;br /&gt;&lt;br /&gt;Thirdly.- The new republican materials, in the persons of the committees, offices, and middle management.&lt;br /&gt;&lt;br /&gt;The two first, by being appointed by the Board of Directors or the CEO, are independent of the employees and their business duties; wherefore in a constitutional sense they contribute nothing towards the representation of the needs of the divisions of the company.&lt;br /&gt;&lt;br /&gt;To say that the organization of the company is a union of three powers reciprocally checking each other, is farcical, either the words have no meaning, or they are flat contradictions.&lt;br /&gt;&lt;br /&gt;To say that the Board of Directors es a check upon the CEO, presupposes two things.&lt;br /&gt;&lt;br /&gt;First.- That the CEO is not to be trusted without being looked after, or in other words, that a thirst for absolute power is the natural disease of autocracy.&lt;br /&gt;&lt;br /&gt;Secondly.- That the Board, by being appointed for that purpose, are either wiser or more worthy of confidence than the CEO.&lt;br /&gt;&lt;br /&gt;But as the same business organization which gives the Board a power to check the CEO by withholding the supplies, gives afterwards the CEO a power to check the lower managers  and committees, by empowering him to reject their other bills; it again supposes that the CEO is wiser than those whom it has already supposed to be wiser than him. A mere absurdity!&lt;br /&gt;&lt;br /&gt;There is something exceedingly ridiculous in the composition of high ceremony business organization; it first excludes a man from the means of information, yet empowers him to act in cases where the highest judgment is required. The state of a CEO shuts him from the world, yet the business of a CEO requires him to know it thoroughly; wherefore the different parts, unnaturally opposing and destroying each other, prove the whole character to be absurd and useless.&lt;br /&gt;&lt;br /&gt;Some writers have explained high ceremony business thus; the CEO, say they, is one, the employee another; the Executive committee are an house in behalf of the CEO; the middle managers in behalf of the people; but this hath all the distinctions of an house divided against itself; and though the expressions be pleasantly arranged, yet when examined they appear idle and ambiguous; and it will always happen, that the nicest construction that words are capable of, when applied to the description of something which either cannot exist, or is too incomprehensible to be within the compass of description, will be words of sound only, and though they may amuse the ear, they cannot inform the mind, for this explanation includes a previous question, that is to say. How came the CEO by a power which the company is afraid to trust, and always obliged to check? Such a power could not be the gift of wise people, neither can any power, which needs checking, be from God; yet the provision, which high ceremony business makes, supposes such a power to exist.&lt;br /&gt;&lt;br /&gt;But the provision is unequal to the task; the means either cannot or will not accomplish the end, and the whole affair is an act of suicide; for as the greater weight will always carry up the less, and as all the wheels of a machine are put in motion by one, it only remains to know which office in the company has the most weight, for that will govern; and though the others, or a part of them, may clog, or, as the phrase is, check the rapidity of its motion, yet so long as they cannot stop it, their endeavors will be ineffectual; the first moving power will at last have its way, and what it wants in speed is supplied by time.&lt;br /&gt;&lt;br /&gt;That the CEO is this overbearing part in high ceremony business organization needs not be mentioned, and that it derives its whole consequence merely from being the giver of places pensions is self evident, wherefore, though we have and wise enough to shut and lock a door against absolute power, we at the same time have been foolish enough to put the CEO in possession of the key.&lt;br /&gt;&lt;br /&gt;The prejudice of business men, in favor of their own corporate government by CEO, Board of Directors, and Executive committees, arises as much or more from personal pride and self serving ambition than reason. Individuals are undoubtedly safer and treated more fairly than in the Industrial revolution, but the will of the CEO is as much the law of the land in Toyota as in Ford.&lt;br /&gt;&lt;br /&gt;An inquiry into the organizational errors in high ceremony form of corporate government is at this time highly necessary; for as we are never in a proper condition of doing justice to our work, while we continue under the influence of some leading partiality, so neither are we capable of doing it to ourselves while we remain fettered by any obstinate prejudice. And as a man, who is attached to a prostitute, is unfitted to choose or judge of a wife, so any prepossession in favor of a rotten high ceremony form of corporate government will disable us from discerning a good one.&lt;br /&gt;&lt;br /&gt;Thank you Thomas Paine.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/36645098-116577786890890093?l=digerati-illuminatus.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://digerati-illuminatus.blogspot.com/feeds/116577786890890093/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=36645098&amp;postID=116577786890890093' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/36645098/posts/default/116577786890890093'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/36645098/posts/default/116577786890890093'/><link rel='alternate' type='text/html' href='http://digerati-illuminatus.blogspot.com/2006/12/common-sense.html' title='Common Sense'/><author><name>Geoff Slinker</name><uri>http://www.blogger.com/profile/12365501393247949005</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-36645098.post-116551404860384133</id><published>2006-12-07T09:53:00.000-08:00</published><updated>2006-12-07T09:54:08.610-08:00</updated><title type='text'>Managers manage resources...</title><content type='html'>People are not resources.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/36645098-116551404860384133?l=digerati-illuminatus.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://digerati-illuminatus.blogspot.com/feeds/116551404860384133/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=36645098&amp;postID=116551404860384133' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/36645098/posts/default/116551404860384133'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/36645098/posts/default/116551404860384133'/><link rel='alternate' type='text/html' href='http://digerati-illuminatus.blogspot.com/2006/12/managers-manage-resources.html' title='Managers manage resources...'/><author><name>Geoff Slinker</name><uri>http://www.blogger.com/profile/12365501393247949005</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-36645098.post-116456890771211027</id><published>2006-11-26T11:21:00.000-08:00</published><updated>2006-11-26T11:21:47.723-08:00</updated><title type='text'>Leadership and Management</title><content type='html'>There is no one leader. Typically there is one manager. The leader rises to the occasion and situation.  Leader is not a title once bestowed and thusly endures, but it is a adjective for a moment. Granted there are great leaders but what makes them great? Is it  that the occasion and situation in which they rise is a situation with a fundamental concern such of freedom or religious belief? Is it that the situation itself is of great concern?&lt;br /&gt;&lt;br /&gt;For instance let me give an example concerning the founding of the United States of America (based upon my opinion that the founding of the USA is  a great and good thing). A leader arises in a situation to give guidance and share knowledge. The masses of people that lived in the colonies did not come to a common and practical definition of government. The common people may not have ever defined a government and constitution. However the fundamental need was something that was understood or was spreading in popularity. Those that had opinion, education, experience, and vision concerning sovereignty, how power can be used and misused, and other pertinent issues rose to  the occasion. These leaders left behind a document outlining what should be valued and what should be shunned. This document then is used  in the managing of the affairs.&lt;br /&gt;&lt;br /&gt;The "work place" tries to identify a leader and then assign them the task of being "the" leader from that point forward. Maybe it comes from military like organizations, maybe not, I do not know. Just because you were brilliant in one situation does not mean you will be so again in a different situation.&lt;br /&gt;&lt;br /&gt;Is a leader measured by his followers? I would think not. The follower can only be measured by how well the follower studies and internalizes the teachings of the leader. That is why I say that one should always understand the fundamental reasons behind a method. Lets say that some "leaders" in software development propose  that testing first is better than testing later. I want to know why it may be true and I care less about who said it. As the follower if I understand they why's then I can manage myself and I do not have to be lead continuously.&lt;br /&gt;&lt;br /&gt;What if a leader has no followers? It does not reflect that the person did not rise above a situation. Maybe this  person was in a unique situation. Or maybe the others in the same situation are blind to the advantage that the leader expounds. The number of followers do not validate or invalidate the leader.&lt;br /&gt;&lt;br /&gt;In business the number of people that are under a Manager is important. Head count is an essential part of the leverage and power of a manager in business. This head count should not be confused with "followers" but honestly is more inline with the concept of "cattle and ownership".&lt;br /&gt;&lt;br /&gt;I do not believe that Management is a science and Leadership and art. As a matter of fact I do not even separate science and art. &lt;br /&gt;&lt;br /&gt;Do we leave tactical issues to Leaders and strategic issues to Managers? I find this  to be overly simplistic.&lt;br /&gt;&lt;br /&gt;Leaders help define a set of guidelines for the situation as they traverse the situation.&lt;br /&gt;&lt;br /&gt;A fundamental attribute of a leader is  selflessness. This is not a necessary or needed attribute of a manager. A leader is  willing to suffer the results of his guidance along with those that follow. If there is a group that is following a leader and the group fails the leader does not blame the group for being poor followers but instead accepts responsibility for leading those that followed and usually blames himself for not having an better understanding of those individuals  that were following.  Management behaves differently is this situation.&lt;br /&gt;&lt;br /&gt;I do not feel that any other list of leadership attributes come close  to that of  selflessness.&lt;br /&gt;&lt;br /&gt;Can everyone be a leader? Yes in that I  think we are all equal in capacity (generally). Will everyone seize an opportunity to lead  when it presents itself? No. Not in my opinion. Even if someone is capable of leading in a situation there are infinite reasons why the person may chose to not act.&lt;br /&gt;&lt;br /&gt;Here is a snippet on a paper I wrote that includes sections on leadership and management.&lt;br /&gt;&lt;br /&gt;Leadership&lt;br /&gt;&lt;br /&gt;Maverick Development is based on leadership. Leadership is something above management. All leaders have management skills. The converse is not true. The bar has to be raised on managers. They have to be leaders.&lt;br /&gt;&lt;br /&gt;Agile methodologies depend upon emergent processes. Managers cannot control this type of process because of its very nature. Maverick Development goes where ever is necessary to get the work done. When an unexpected situation arises we do not plod along the same path just because the directions say to go that way. Instead, in Maverick, we say, "Hmm, an unforeseen problem. What should we do? Go on? Go back? Go around? ... "&lt;br /&gt;&lt;br /&gt;Leadership cannot be taught. Quoting Dr. Huge Nibley,&lt;br /&gt;&lt;br /&gt;"At the present time, Captain Grace Hoper, that grand old lady of the Navy, is calling our attention to the contrasting and conflicting natures of management and leadership. No one, she says, ever managed men into battle, and she wants more emphasis on teaching leadership. But leadership can no more be taught than creativity or how to be a genius. The Generalstab tried desperately for a hundred years to train up a generation of leaders for the German army, but it never worked, because the men who delighted their superiors (the managers) got the high commands, while the men who delighted the lower ranks (the leaders) got reprimands. Leaders are movers and shakers, original, inventive, unpredictable, imaginative, full of surprises that discomfit the enemy in war and the main office in peace. Managers, on the other hand, are safe, conservative, predictable, conforming organizational men and team players, dedicated to the establishment.&lt;br /&gt;&lt;br /&gt;The leader, for example, has a passion for equality. We think of great generals from David and Alexander on down, sharing their beans or maza with their men, calling them by their first names, marching along with them in the heat, sleeping on the ground and being first over the wall. A famous ode by a long-suffering Greek soldier named Archilochus, reminds us that the men in the ranks are not fooled for an instant by the executive type who thinks he is a leader.&lt;br /&gt;&lt;br /&gt;For the manager, on the other hand, the idea of equality is repugnant and indeed counterproductive. Where promotion, perks, privilege and power are the name of the game, awe and reverence for rank is everything and becomes the inspiration and motivation of all good men. Where would management be without the inflexible paper processing, dress standards, attention to proper social, political and religious affiliation, vigilant watch over habits and attitudes, etc., that gratify the stockholders and satisfy security? ... Managers do not promote individuals whose competence might threaten their own position, and so as the power of management spreads ever wider, the quality deteriorates, if that is possible. In short, while management shuns equality, if feeds on mediocrity... For the qualities of leadership are the same in all fields, the leader being simply the one who sets the highest example; and to do that and open the way to greater light and knowledge, the leader must break the mold. " A ship in port is safe," says Captain Hopper, speaking of management, 'but that is not what ships were built for," she adds, calling for leadership... True leaders are inspiring because they are inspired, caught up in a higher purpose, devoid of personal ambition, idealistic and incorruptible... So vast is the discrepancy between management and leadership that only a blind man would get them backwards... "&lt;br /&gt;&lt;br /&gt;It is a common known practice when hiring and retaining software engineers to retain what is referred to as the 10x performers. Maverick Development requires the same from its Leadership. Managers that are leaders will be 10x performers.&lt;br /&gt;&lt;br /&gt;Trust is the key and here is what Mr. Semler had to say,&lt;br /&gt;&lt;br /&gt;"We simply do not believe our employees have an interest in coming in late, leaving early, and doing as little as possible for as much money as their union can wheedle out of us. After all, these are the same people that raise children, join the PTA, elect mayors, governors, senators, and presidents. They are adults. At Semco, we treat them like adults. We trust them. We don't make our employees ask permission to go to the bathroom, nor have security guards search them as they leave for the day. We get out of their way and let them do their jobs."&lt;br /&gt;&lt;br /&gt;http://home.att.net/~geoffrey.slinker/maverick/MaverickDevelopment.html&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/36645098-116456890771211027?l=digerati-illuminatus.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://digerati-illuminatus.blogspot.com/feeds/116456890771211027/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=36645098&amp;postID=116456890771211027' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/36645098/posts/default/116456890771211027'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/36645098/posts/default/116456890771211027'/><link rel='alternate' type='text/html' href='http://digerati-illuminatus.blogspot.com/2006/11/leadership-and-management.html' title='Leadership and Management'/><author><name>Geoff Slinker</name><uri>http://www.blogger.com/profile/12365501393247949005</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-36645098.post-116439091831732031</id><published>2006-11-24T09:26:00.000-08:00</published><updated>2006-11-24T09:55:18.333-08:00</updated><title type='text'>What makes a good Software Design?</title><content type='html'>What makes a good software design? Can software be good and have a poor design?&lt;br /&gt;&lt;br /&gt;I will address the second question first. Can software be good and have a poor design? I think so. Of course this depends on my defintion of good. Good software meets the current goals of the user. For instance the software does what the user wants and it does it with no errors, mistakes, or unwanted side effects. The user usually does not care what language the software was developed with, or what  process was used to guide development, or how much the programmers were paid to write the software, or even if the  software has a good design.&lt;br /&gt;&lt;br /&gt;Software design is a practice that addresses issues the programmers find important. Such issues are changeability, extensibility, understandability, usability, and verifiability (if these are even words).&lt;br /&gt;&lt;br /&gt;In my opinion code must meet the usability quality in order for the design to be considered good. What does this mean?&lt;br /&gt;&lt;br /&gt;Code is developed to be called or in other words to be used. If the design is such that the code is easily called then it has an improved design. What makes code easily called? If it is easy to setup the state necessary to initiate a meaningful call. What makes state setup easy? That depends on the system and problem domain. Often this is an attribute of coupling and cohesion. Therefore, easily callable code is  often losely coupled and cohesive code.&lt;br /&gt;&lt;br /&gt;A good software design will make it possible to verify the software. How do you verify software? By using the code. Do you see the relationship? Usable code has a relationship to code verification. The easier it is to setup a call into the system maps directly to the ease of testing, validating, and verifying the sytem.&lt;br /&gt;&lt;br /&gt;The test that exercises code is just another user of the code. Therefore when you write code you have at least to customers or consumers of the code. The first customer is some part of the overall system you are developing. The second customer is the test code that exercises the code you are developing. There are always at leat these two customers. If the first customer doesn't exist then why bother writing the code? If the second customer doesn't exist then what will you use in place of testing code to exercise your code?&lt;br /&gt;&lt;br /&gt;A good software design is expressed in code that is usable. The easier it is to use the better.  This ease of use reflects the coupling and cohesion of the abstract model. Usable software can be used by multiple customers. One customer should be a verification customer which is a piece of code to  use your code and check if your code  did what is expected. I believe this leads to the important axiom that testable code is code with a good design. I think that testability is a subset of usability.&lt;br /&gt;&lt;br /&gt;Geoff&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/36645098-116439091831732031?l=digerati-illuminatus.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://digerati-illuminatus.blogspot.com/feeds/116439091831732031/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=36645098&amp;postID=116439091831732031' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/36645098/posts/default/116439091831732031'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/36645098/posts/default/116439091831732031'/><link rel='alternate' type='text/html' href='http://digerati-illuminatus.blogspot.com/2006/11/what-makes-good-software-design.html' title='What makes a good Software Design?'/><author><name>Geoff Slinker</name><uri>http://www.blogger.com/profile/12365501393247949005</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-36645098.post-116302549668637480</id><published>2006-11-08T14:33:00.000-08:00</published><updated>2006-11-08T14:43:35.673-08:00</updated><title type='text'>Democratic Workplaces</title><content type='html'>&lt;a href="www.worldblu.com"&gt;WorldBlu&lt;/a&gt; has started a search for the Most Democratic Workplaces.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;The WorldBlu Search: November 1, 2006 - February 16, 2007:&lt;br /&gt;&lt;/b&gt;The WorldBlu Search for the Most Democratic Workplaces is a GLOBAL search from November 1, 2006 until February 16, 2007 designed to identify organizations from the for-profit, non-profit, government, and education sectors practicing organizational democracy.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Recognizing the Mavericks, Inspiring Others:&lt;br /&gt;&lt;/b&gt;We believe there are many highly successful and profitable – yet often unnoticed – examples of democracy in the workplace. These organizations are defying convention, rewriting the rules of business, and pioneering the next generation of organizational design and leadership. The WorldBlu List of Most Democratic Workplaces seeks to shine a spotlight on these champions of freedom and inspire others in the process.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;The WorldBlu List of Most Democratic Workplaces 2007:&lt;br /&gt;&lt;/b&gt;On March 6, 2007, WorldBlu will announce the first annual WorldBlu List of Most Democratic Workplaces in conjunction with the celebration of Democracy in the Workplace Day.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;How it Works:&lt;br /&gt;&lt;/b&gt;Organizations apply to have their employees take the online WorldBlu Democratic Workplace Scorecard which measures the degree of organizational democracy in their workplace. The WorldBlu List will be comprised of organizations that took survey and scored at the top level, identifying them as one of the most democratic workplaces in the world. There is no fee to apply.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;All Sectors Invited to Participate:&lt;br /&gt;&lt;/b&gt;The WorldBlu List is open to any organization from the for-profit, non-profit, government and education sectors, as long as the organization has at least five regular full-time or part-time employees and has been in operation for at least three years.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Learn More + Get Started:&lt;br /&gt;&lt;/b&gt;To learn more or have your organization get started now to apply for the WorldBlu List, please go to &lt;a href="http://www.worldblu.com/"&gt;www.worldblu.com&lt;/a&gt; .&lt;br /&gt;&lt;br /&gt;If you are interested in discussing "Democratic Workplaces" there is a users group found at &lt;a href="http://tech.groups.yahoo.com/group/maverick_software_development/"&gt;Maverick Software Development&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/36645098-116302549668637480?l=digerati-illuminatus.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://digerati-illuminatus.blogspot.com/feeds/116302549668637480/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=36645098&amp;postID=116302549668637480' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/36645098/posts/default/116302549668637480'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/36645098/posts/default/116302549668637480'/><link rel='alternate' type='text/html' href='http://digerati-illuminatus.blogspot.com/2006/11/democratic-workplaces.html' title='Democratic Workplaces'/><author><name>Geoff Slinker</name><uri>http://www.blogger.com/profile/12365501393247949005</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-36645098.post-116242634306259482</id><published>2006-11-01T14:57:00.000-08:00</published><updated>2006-12-04T17:52:11.960-08:00</updated><title type='text'>Composite UI Application Block Model View Presenter</title><content type='html'>&lt;a href="http://www.google.com/search?hl=en&amp;lr=&amp;amp;q=Model+View+Presenter&amp;btnG=Search"&gt;Model View Presenter&lt;br /&gt;&lt;/a&gt; is a design pattern support by CAB and the Smart Client Software Factory (&lt;a href="http://www.gotdotnet.com/codegallery/codegallery.aspx?id=941d2228-3bb5-42fd-8004-c08595821170"&gt;SCSF&lt;/a&gt;).&lt;br /&gt;&lt;br /&gt;A View is a SmartPart.&lt;br /&gt;&lt;br /&gt;The Presenter calls methods of the View to update the information the View displays. The View should expose its methods to the Presenter through an Interface. The Presenter stores a reference to the View's interface.&lt;br /&gt;&lt;br /&gt;In my examples I have updated UserButton and added IUserButton and UserButtonPresenter.&lt;br /&gt;&lt;br /&gt;Here is IUserButton.cs:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;using System;&lt;br /&gt;using System.Collections.Generic;&lt;br /&gt;using System.Text;&lt;br /&gt;using System.Drawing;&lt;br /&gt;&lt;br /&gt;namespace CABTestOne&lt;br /&gt;{&lt;br /&gt;public interface IUserButton&lt;br /&gt;{&lt;br /&gt;    void SetColor( Color color );&lt;br /&gt;}&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Here is the new UserButton.cs:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;using System;&lt;br /&gt;using System.Collections.Generic;&lt;br /&gt;using System.ComponentModel;&lt;br /&gt;using System.Drawing;&lt;br /&gt;using System.Data;&lt;br /&gt;using System.Text;&lt;br /&gt;using System.Windows.Forms;&lt;br /&gt;using Microsoft.Practices.CompositeUI.SmartParts;&lt;br /&gt;using Microsoft.Practices.CompositeUI.EventBroker;&lt;br /&gt;using Microsoft.Practices.ObjectBuilder;&lt;br /&gt;&lt;br /&gt;namespace CABTestOne&lt;br /&gt;{&lt;br /&gt; [SmartPart]&lt;br /&gt; public partial class UserButton : UserControl, IUserButton&lt;br /&gt; {&lt;br /&gt;     public MyMessagePublisher publisher;&lt;br /&gt;     protected UserButtonPresenter _userButtonPresenter;&lt;br /&gt;&lt;br /&gt;     public UserButton( )&lt;br /&gt;     {&lt;br /&gt;         InitializeComponent( );&lt;br /&gt;     }&lt;br /&gt;&lt;br /&gt;     private void button1_MouseClick( object sender, MouseEventArgs e )&lt;br /&gt;     {&lt;br /&gt;         _userButtonPresenter.UserButtonClicked( sender, e );&lt;br /&gt;         publisher.UserButtonClicked( sender, e );&lt;br /&gt;     }&lt;br /&gt;&lt;br /&gt;     [&lt;span style="font-weight: bold;"&gt;CreateNew&lt;/span&gt;]&lt;br /&gt;     public UserButtonPresenter userButtonPresenter&lt;br /&gt;     {&lt;br /&gt;         set&lt;br /&gt;         {&lt;br /&gt;             _userButtonPresenter = value;&lt;br /&gt;             _userButtonPresenter.userButton = this;&lt;br /&gt;         }&lt;br /&gt;     }&lt;br /&gt;&lt;br /&gt;     public void SetColor( Color color )&lt;br /&gt;     {&lt;br /&gt;         this.button1.BackColor = color;&lt;br /&gt;     }&lt;br /&gt; }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Here is the new UserButtonPresenter.cs:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;using System;&lt;br /&gt;using System.Collections.Generic;&lt;br /&gt;using System.Text;&lt;br /&gt;using System.Drawing;&lt;br /&gt;using System.Windows.Forms;&lt;br /&gt;using Microsoft.Practices.ObjectBuilder;&lt;br /&gt;using Microsoft.Practices.CompositeUI;&lt;br /&gt;using Microsoft.Practices.CompositeUI.EventBroker;&lt;br /&gt;&lt;br /&gt;namespace CABTestOne&lt;br /&gt;{&lt;br /&gt;  public class UserButtonPresenter : IDisposable&lt;br /&gt;  {&lt;br /&gt;      protected WorkItem _workItem;&lt;br /&gt;      protected IUserButton _userButton;&lt;br /&gt;&lt;br /&gt;      ~UserButtonPresenter( )&lt;br /&gt;      {&lt;br /&gt;          Dispose(false);&lt;br /&gt;      }&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;      public void Dispose()&lt;br /&gt;      {&lt;br /&gt;          Dispose(true);&lt;br /&gt;          GC.SuppressFinalize(this);&lt;br /&gt;      }&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;      protected virtual void Dispose(bool disposing)&lt;br /&gt;      {&lt;br /&gt;          if (disposing)&lt;br /&gt;          {&lt;br /&gt;              if( _workItem != null )&lt;br /&gt;              {&lt;br /&gt;                  _workItem.Items.Remove( this );&lt;br /&gt;              }&lt;br /&gt;          }&lt;br /&gt;      }&lt;br /&gt;&lt;br /&gt;      [&lt;span style="font-weight: bold;"&gt;ServiceDependency&lt;/span&gt;]&lt;br /&gt;      public WorkItem workItem&lt;br /&gt;      {&lt;br /&gt;          set&lt;br /&gt;          {&lt;br /&gt;              _workItem = value;&lt;br /&gt;          }&lt;br /&gt;      }&lt;br /&gt;&lt;br /&gt;      public IUserButton userButton&lt;br /&gt;      {&lt;br /&gt;          set&lt;br /&gt;          {&lt;br /&gt;              _userButton = value;&lt;br /&gt;          }&lt;br /&gt;      }&lt;br /&gt;&lt;br /&gt;      [EventPublication( "topic://CABTestOne/UserButtonClick", PublicationScope.Global )]&lt;br /&gt;      public event EventHandler&lt;eventargs&gt; UserButtonClick;&lt;br /&gt;&lt;br /&gt;      public void UserButtonClicked( object sender, MouseEventArgs e )&lt;br /&gt;      {&lt;br /&gt;          _userButton.SetColor( System.Drawing.Color.Blue );&lt;br /&gt;&lt;br /&gt;          if( UserButtonClick != null )&lt;br /&gt;          {&lt;br /&gt;              UserButtonClick( this, null );&lt;br /&gt;          }&lt;br /&gt;      }&lt;br /&gt;  }&lt;br /&gt;}&lt;br /&gt;&lt;/eventargs&gt;&lt;/pre&gt;[ServiceDependency] tells the CAB framework to get the WorkItem from the collection of services maintained by CAB. The UserButtonPresenter needs the WorkItem in order to enhance the dispose method to remove itself from the WorkItem's Item collection.&lt;br /&gt;&lt;br /&gt;How did I know to modify the Dispose methods to remove the Presenter? I looked at lots of code I found on the net.&lt;br /&gt;&lt;br /&gt;Listening to a PodCast I learned that a WorkItem is two things.&lt;br /&gt;&lt;ol&gt;&lt;li&gt;Scoping Container&lt;/li&gt;&lt;li&gt;Lifetime Manager&lt;/li&gt;&lt;/ol&gt;[CreateNew] is an attribute added to a property in the UserButton. The CreateNew tells the dependency injector of COB to instantiate a new UserButtonPresenter.&lt;br /&gt;&lt;br /&gt;I moved the Event Publisher inside of the UserButton and put it in the UserButtonPresenter. I am not sure if it "should" be there it just seemed like the thing to do.&lt;br /&gt;&lt;br /&gt;In the UserButtonPresenter when the UserButtonClicked method is invoked it does two things:&lt;br /&gt;&lt;ol&gt;&lt;li&gt;Sets the color of the UserButton&lt;/li&gt;&lt;li&gt;Publishes the UserButtonClick event.&lt;/li&gt;&lt;/ol&gt;&lt;br /&gt;After I completed these code changes I then installed and started using the Smart Client Software Factory. I used the Guidance Package that was installed into Visual Studio 2005 to create a new solution that uses CAB and the MVP pattern. The guidance package auto generated all of the code.  Granted the auto generated code included things I had not yet studied but I found that I have turned the learning curve and have enough foundation and a feel for CAB that I am able to understand the auto generated code. So, this will probably be my last blog entry on the Composite UI Application Block. I have a lot to learn still but I can see enough now that I don't feel like I am lost in the dark.&lt;br /&gt;&lt;br /&gt;By the way, I have been learning CAB in this fashion because it is part of an approach I am working on called Experience Driven Development (EDD) and has a fundamental practices &lt;a href="http://home.att.net/~geoffrey.slinker/maverick/DBU.html"&gt;Design by Use&lt;/a&gt; and &lt;a href="http://home.att.net/~geoffrey.slinker/maverick/Scouting.html"&gt;Software Reconn&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/36645098-116242634306259482?l=digerati-illuminatus.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://digerati-illuminatus.blogspot.com/feeds/116242634306259482/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=36645098&amp;postID=116242634306259482' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/36645098/posts/default/116242634306259482'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/36645098/posts/default/116242634306259482'/><link rel='alternate' type='text/html' href='http://digerati-illuminatus.blogspot.com/2006/11/composite-ui-application-block-model.html' title='Composite UI Application Block Model View Presenter'/><author><name>Geoff Slinker</name><uri>http://www.blogger.com/profile/12365501393247949005</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-36645098.post-116239584243959630</id><published>2006-11-01T07:40:00.000-08:00</published><updated>2006-11-01T08:45:22.526-08:00</updated><title type='text'>Podcasts and Links about CAB</title><content type='html'>While experimenting and learning the Composite UI Application Block I am continuously searching for information. I have found these podcasts to be helpful.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://www.ddj.com/podcast/dotnetcast/"&gt;Dr. Dobb's .Net Cast&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;a href="http://www.ddj.com/showArticle.jhtml;jsessionid=VE2QA14RBNMDCQSNDLOSKH0CJUNN2JVN?articleID=190400301"&gt;Composite UI App Block (CAB) Internals&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;a href="http://www.ddj.com/showArticle.jhtml;jsessionid=VE2QA14RBNMDCQSNDLOSKH0CJUNN2JVN?articleID=191801368"&gt;Understanding Dependency Injection&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;a href="http://www.ddj.com/showArticle.jhtml;jsessionid=VE2QA14RBNMDCQSNDLOSKH0CJUNN2JVN?articleID=192203209"&gt;The Power of WorkItems, Events, and Services&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;a href="http://www.cabpedia.com/index.php?title=Composite_UI_Application_Block"&gt;Cabpedia&lt;br /&gt;&lt;/a&gt; is proving to be very helpful.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/36645098-116239584243959630?l=digerati-illuminatus.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://digerati-illuminatus.blogspot.com/feeds/116239584243959630/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=36645098&amp;postID=116239584243959630' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/36645098/posts/default/116239584243959630'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/36645098/posts/default/116239584243959630'/><link rel='alternate' type='text/html' href='http://digerati-illuminatus.blogspot.com/2006/11/podcasts-and-links-about-cab.html' title='Podcasts and Links about CAB'/><author><name>Geoff Slinker</name><uri>http://www.blogger.com/profile/12365501393247949005</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-36645098.post-116225261929344495</id><published>2006-10-30T15:53:00.000-08:00</published><updated>2006-11-01T08:02:09.746-08:00</updated><title type='text'>Composite UI Application Block EventBroker and Publish and Subscribe</title><content type='html'>&lt;p&gt;As I started learning how to use the CAB EventBroker with Publish (Pub) and Subscribe&lt;br /&gt; (Sub) I found many examples of simple event publishers. However the code was always&lt;br /&gt; confusing because the examples looked similar to this:&lt;br /&gt;&lt;/p&gt;  &lt;pre&gt;  [EventPublication( "topic://CABTestOne/UserButtonClick", PublicationScope.Global )]&lt;br /&gt; public event EventHandler&amp;lt;EventArgs&amp;gt; UserButtonClick;&lt;br /&gt;&lt;br /&gt; public void UserButtonClicked( object sender, MouseEventArgs e )&lt;br /&gt; {&lt;br /&gt;     if( &lt;strong&gt;UserButtonClick != null&lt;/strong&gt; )&lt;br /&gt;     {&lt;br /&gt;         UserButtonClick( this, null );&lt;br /&gt;     }&lt;br /&gt; }&lt;br /&gt;&lt;/pre&gt;        &lt;p&gt;      The confusing part to me was why would UserButtonClick ever be null or not null.&lt;br /&gt; Where did it get instantiated?&lt;br /&gt;&lt;br /&gt; As I studied the example code I came across a comment that Pub/Sub should be used&lt;br /&gt; to communicate between views and it should not be used to communicate between a&lt;br /&gt; view and its presenter.&lt;br /&gt;&lt;br /&gt; I recalled that a "view" is a SmartPart. My previous example has a SmartPart called&lt;br /&gt; UserButton. So I started modifying the UserButton class.&lt;br /&gt;&lt;br /&gt; First I added an event handler to the UserButton to handle "MouseClick" events.&lt;br /&gt; I did this through the designer by getting properties on UserButton and adding the&lt;br /&gt; event handler.&lt;br /&gt;&lt;/p&gt;  &lt;pre&gt;using System;&lt;br /&gt;using System.Collections.Generic;&lt;br /&gt;using System.ComponentModel;&lt;br /&gt;using System.Drawing;&lt;br /&gt;using System.Data;&lt;br /&gt;using System.Text;&lt;br /&gt;using System.Windows.Forms;&lt;br /&gt;using Microsoft.Practices.CompositeUI.SmartParts;&lt;br /&gt;using Microsoft.Practices.CompositeUI.EventBroker;&lt;br /&gt;&lt;br /&gt;namespace CABTestOne&lt;br /&gt;{&lt;br /&gt;[&lt;strong&gt;SmartPart&lt;/strong&gt;]&lt;br /&gt;public partial class UserButton : UserControl&lt;br /&gt;{&lt;br /&gt; public UserButton( )&lt;br /&gt; {&lt;br /&gt;     InitializeComponent( );&lt;br /&gt; }&lt;br /&gt;&lt;br /&gt; private void &lt;strong&gt;button1_MouseClick&lt;/strong&gt;( object sender, MouseEventArgs e )&lt;br /&gt; {&lt;br /&gt;     UserButtonClicked( sender, e );&lt;br /&gt; }&lt;br /&gt;}&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;  &lt;p&gt;      Then I added an EventPublication attribute to UserButton. (I will omit the using&lt;br /&gt; statements )&lt;br /&gt;&lt;/p&gt;&lt;br /&gt;&lt;pre&gt;namespace CABTestOne&lt;br /&gt;{&lt;br /&gt;[SmartPart]&lt;br /&gt;public partial class UserButton : UserControl&lt;br /&gt;{&lt;br /&gt; public UserButton( )&lt;br /&gt; {&lt;br /&gt;     InitializeComponent( );&lt;br /&gt; }&lt;br /&gt;&lt;br /&gt; private void button1_MouseClick( object sender, MouseEventArgs e )&lt;br /&gt; {&lt;br /&gt;     UserButtonClicked( sender, e );&lt;br /&gt; }&lt;br /&gt;&lt;br /&gt; [&lt;strong&gt;EventPublication&lt;/strong&gt;( "topic://CABTestOne/UserButtonClick", PublicationScope.Global )]&lt;br /&gt; public event EventHandler&amp;lt;EventArgs&amp;gt; UserButtonClick;&lt;br /&gt;&lt;br /&gt; public void UserButtonClicked( object sender, MouseEventArgs e )&lt;br /&gt; {&lt;br /&gt;     if( UserButtonClick != null )&lt;br /&gt;     {&lt;br /&gt;         UserButtonClick( this, null );&lt;br /&gt;     }&lt;br /&gt; }&lt;br /&gt;}&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;    &lt;p&gt;      An event has a "topic" and a scope. The topic is also referred to as the Event URI.&lt;br /&gt; The topic is the key that identifies an event. I do not mean to imply that there&lt;br /&gt; is a dictionary of events and that the topic is a key string because I have not&lt;br /&gt; inspected the implementation. I mean to say that the topic is used to publish the&lt;br /&gt; event and it is used by subscribers to listen for the event.&lt;br /&gt;&lt;br /&gt; The scope specifies the visibility of the event.&lt;/p&gt;    &lt;pre&gt;namespace Microsoft.Practices.CompositeUI.EventBroker&lt;br /&gt;{&lt;br /&gt;// Summary:&lt;br /&gt;//     Defines the scope for a publication of an Microsoft.Practices.CompositeUI.EventBroker.EventTopic.&lt;br /&gt;public enum PublicationScope&lt;br /&gt;{&lt;br /&gt; // Summary:&lt;br /&gt; //     Indicates that the topic should be fired on all the Microsoft.Practices.CompositeUI.EventBroker.PublicationScope.WorkItem&lt;br /&gt; //     instances, regarding where the publication firing occurred.&lt;br /&gt; Global = 0,&lt;br /&gt; //&lt;br /&gt; // Summary:&lt;br /&gt; //     Indicates that the topic should be fired only in the Microsoft.Practices.CompositeUI.EventBroker.PublicationScope.WorkItem&lt;br /&gt; //     instance where the publication firing occurred.&lt;br /&gt; WorkItem = 1,&lt;br /&gt; //&lt;br /&gt; // Summary:&lt;br /&gt; //     Indicates that the topic should be fired in the Microsoft.Practices.CompositeUI.EventBroker.PublicationScope.WorkItem&lt;br /&gt; //     instance where the publication firing occurred, and in all the Microsoft.Practices.CompositeUI.EventBroker.PublicationScope.WorkItem&lt;br /&gt; //     descendants.&lt;br /&gt; Descendants = 2,&lt;br /&gt;}&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;      &lt;p&gt;      WorkItems are a key component when defining scope.&lt;br /&gt;&lt;br /&gt; So, I have an event. That's great, but not very interesting. I want something to&lt;br /&gt; listen for the event or in other words subscribe to the event. So I create a class&lt;br /&gt; called MyMessageUser. Remember that all of these classes are in the same project.&lt;br /&gt; I have not yet experimented with Modules.&lt;br /&gt;&lt;br /&gt; I found many examples of what an event subscription looks like and so I implemented&lt;br /&gt; MyMessageUser thusly:&lt;/p&gt;  &lt;pre&gt;using System;&lt;br /&gt;using System.Collections.Generic;&lt;br /&gt;using System.Text;&lt;br /&gt;using System.Windows.Forms;&lt;br /&gt;using Microsoft.Practices.CompositeUI.EventBroker;&lt;br /&gt;&lt;br /&gt;namespace CABTestOne&lt;br /&gt;{&lt;br /&gt;public class MyMessageUser&lt;br /&gt;{&lt;br /&gt; [EventSubscription( "topic://CABTestOne/UserButtonClick", Thread = ThreadOption.UserInterface )]&lt;br /&gt; public void HandleUserButtonClickEvent( object sender, EventArgs args )&lt;br /&gt; {&lt;br /&gt;     int i = 3;&lt;br /&gt; }&lt;br /&gt;}&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;    &lt;p&gt;&lt;br /&gt; I put "int i = 3;" in the method so that I could place a break point there to see&lt;br /&gt; if and when the method was called.&lt;br /&gt;&lt;br /&gt; I set my break point on i = 3 and fired up the application and clicked on my UserButton.&lt;br /&gt; Nothing. So, I made MyMessageUser a SmartPart. Nothing. What was I missing? I couldn't&lt;br /&gt; find any example to shed some light. Then I remember that events are associated&lt;br /&gt; with WorkItems. So I decided to add MyMessageUser to my WorkItem's Items.&lt;/p&gt;    &lt;pre&gt;using System;&lt;br /&gt;using System.Collections.Generic;&lt;br /&gt;using System.Text;&lt;br /&gt;using Microsoft.Practices.CompositeUI;&lt;br /&gt;using Microsoft.Practices.CompositeUI.SmartParts;&lt;br /&gt;using Microsoft.Practices.CompositeUI.WinForms;&lt;br /&gt;using Microsoft.Practices.ObjectBuilder;&lt;br /&gt;&lt;br /&gt;namespace CABTestOne&lt;br /&gt;{&lt;br /&gt;public class MyWorkItem : WorkItem&lt;br /&gt;{&lt;br /&gt;&lt;br /&gt; protected override void OnRunStarted( )&lt;br /&gt; {&lt;br /&gt;     base.OnRunStarted( );&lt;br /&gt;&lt;br /&gt;     //Add my pub/sub stuff&lt;br /&gt;     &lt;strong&gt;this.Items.AddNew&amp;lt;MyMessageUser&amp;gt;( "MyMessageUser" ); &lt;/strong&gt;&lt;br /&gt;     //work spaces control the layout of items contained in the WorkItem&lt;br /&gt;     IWorkspace mainWorkSpace = this.Workspaces["MainFormWorkspace"];&lt;br /&gt;&lt;br /&gt;     //Add a user button to this work item.&lt;br /&gt;     UserButton db = this.Items.AddNew&amp;lt;UserButton&amp;gt;( "UserButton" );&lt;br /&gt;&lt;br /&gt;     //Add a control that has a SmartPartPlaceholder that will control the placement of the UserButton&lt;br /&gt;     SimpleView simpView = this.Items.AddNew&amp;lt;SimpleView&amp;gt;( "SimpleView" );&lt;br /&gt;&lt;br /&gt;     //show the view in the workspace...&lt;br /&gt;     mainWorkSpace.Show( simpView );&lt;br /&gt; }&lt;br /&gt;}&lt;br /&gt;}    &lt;/pre&gt;  &lt;p&gt;&lt;br /&gt; Now I ran it in the debugger and BANG it stopped on my break point in MyMessageUser.&lt;br /&gt; Sweet!&lt;/p&gt;  &lt;p&gt;&lt;br /&gt; Remember my concern?&lt;/p&gt;&lt;br /&gt;&lt;pre&gt;        public void UserButtonClicked( object sender, MouseEventArgs e )&lt;br /&gt; {&lt;br /&gt;     if( &lt;strong&gt;UserButtonClick != null&lt;/strong&gt; )&lt;br /&gt;     {&lt;br /&gt;         UserButtonClick( this, null );&lt;br /&gt;     }&lt;br /&gt; }&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;  &lt;p&gt;      When does the event handler get instantiated? It happens as a result of adding the&lt;br /&gt; SmartPart to a WorkItem. Exactly where it happens I haven't investigated.&lt;/p&gt;&lt;h2&gt;      Review&lt;/h2&gt;  &lt;ol&gt;&lt;br /&gt; &lt;li&gt;SmartParts (sometime referred to as Views) publish events. When the SmartPart is&lt;br /&gt;     added to a WorkItem the CAB framework wires up the event handler.&lt;/li&gt;&lt;br /&gt; &lt;li&gt;Any class can subscribe to events. It doesn't have to be a SmartPart or Controller.&lt;br /&gt;     It DOES have to be added to the items of the WorkItem.&lt;/li&gt;&lt;/ol&gt;  &lt;p&gt;      Please remember that these are my opinions on how things work and should be set&lt;br /&gt; up. As I learn more about CAB I am sure that some of my assumptions, metaphors,&lt;br /&gt; and descriptions will prove to be inaccurate.&lt;/p&gt;&lt;h2&gt;      Multiple Events with One Handler&lt;/h2&gt;&lt;p&gt;      Now I want to push my ideas a bit and see what can happen. Can one event handler&lt;br /&gt; subscribe to multiple events? Why yes it can!&lt;/p&gt;&lt;br /&gt;&lt;pre&gt;    public class MyMessageUser&lt;br /&gt;{&lt;br /&gt; [EventSubscription( "topic://CABTestOne/UserButtonClick", Thread = ThreadOption.UserInterface )]&lt;br /&gt; [&lt;strong&gt;EventSubscription( "topic://CABTestOne/UserButtonClick2", Thread = ThreadOption.UserInterface&lt;br /&gt;     )&lt;/strong&gt;]&lt;br /&gt; public void HandleUserButtonClickEvent( object sender, EventArgs args )&lt;br /&gt; {&lt;br /&gt;     int i = 3;&lt;br /&gt; }&lt;br /&gt;}    &lt;/pre&gt;  &lt;p&gt;      Now I need something that publishes this new event topic //CabTestOne/UserButtonClick2.&lt;br /&gt;&lt;br /&gt; I decided to make a new class called MyMessagePublisher. Here is the code:&lt;/p&gt;  &lt;pre&gt;using System;&lt;br /&gt;using System.Collections.Generic;&lt;br /&gt;using System.Text;&lt;br /&gt;using System.Windows.Forms;&lt;br /&gt;using Microsoft.Practices.CompositeUI.EventBroker;&lt;br /&gt;&lt;br /&gt;namespace CABTestOne&lt;br /&gt;{&lt;br /&gt;public class MyMessagePublisher&lt;br /&gt;{&lt;br /&gt; &lt;strong&gt;[EventPublication( "topic://CABTestOne/UserButtonClick2", PublicationScope.Global)]&lt;/strong&gt;&lt;br /&gt; public event EventHandler&amp;lt;EventArgs&amp;gt; UserButtonClick2;&lt;br /&gt;&lt;br /&gt; public void UserButtonClicked( object sender, MouseEventArgs e )&lt;br /&gt; {&lt;br /&gt;     if( UserButtonClick2 != null )&lt;br /&gt;     {&lt;br /&gt;         UserButtonClick2( this, null );&lt;br /&gt;     }&lt;br /&gt; }&lt;br /&gt;}&lt;br /&gt;}    &lt;/pre&gt;  &lt;p&gt;&lt;br /&gt; From my previous experiments I know that inorder to instantiate the event publisher&lt;br /&gt; UserButtonClick2 I have to add it to a WorkItem Items list. When you add an item&lt;br /&gt; to the WorkItems Item list you want to keep the reference it returns so I added&lt;br /&gt; a member variable to UserButton to keep the reference to the MyMessagePublisher.&lt;/p&gt;  &lt;pre&gt;using System.ComponentModel;&lt;br /&gt;using System.Drawing;&lt;br /&gt;using System.Data;&lt;br /&gt;using System.Text;&lt;br /&gt;using System.Windows.Forms;&lt;br /&gt;using Microsoft.Practices.CompositeUI.SmartParts;&lt;br /&gt;using Microsoft.Practices.CompositeUI.EventBroker;&lt;br /&gt;&lt;br /&gt;namespace CABTestOne&lt;br /&gt;{&lt;br /&gt;[SmartPart]&lt;br /&gt;public partial class UserButton : UserControl&lt;br /&gt;{&lt;br /&gt; &lt;strong&gt;public MyMessagePublisher publisher;&lt;/strong&gt;&lt;br /&gt;&lt;br /&gt; public UserButton( )&lt;br /&gt; {&lt;br /&gt;     InitializeComponent( );&lt;br /&gt; }&lt;br /&gt;&lt;br /&gt; private void button1_MouseClick( object sender, MouseEventArgs e )&lt;br /&gt; {&lt;br /&gt;     UserButtonClicked( sender, e );&lt;br /&gt;     &lt;strong&gt;publisher.UserButtonClicked( sender, e );&lt;/strong&gt;&lt;br /&gt; }&lt;br /&gt;&lt;br /&gt; [EventPublication( "topic://CABTestOne/UserButtonClick", PublicationScope.Global )]&lt;br /&gt; public event EventHandler&amp;lt;EventArgs&amp;gt; UserButtonClick;&lt;br /&gt;&lt;br /&gt; public void UserButtonClicked( object sender, MouseEventArgs e )&lt;br /&gt; {&lt;br /&gt;     if( UserButtonClick != null )&lt;br /&gt;     {&lt;br /&gt;         UserButtonClick( this, null );&lt;br /&gt;     }&lt;br /&gt; }&lt;br /&gt;}&lt;br /&gt;}    &lt;/pre&gt;  &lt;p&gt;&lt;br /&gt; When the UserButton recieves the MouseClick event it then calls the MyMessagePublisher.UserButtonClicked&lt;br /&gt; method.&lt;/p&gt;  &lt;p&gt;&lt;br /&gt; I modified MyWorkItem to add the MyMessagePublisher to UserButton.&lt;/p&gt;&lt;br /&gt;&lt;pre&gt;    public class MyWorkItem : WorkItem&lt;br /&gt;{&lt;br /&gt;&lt;br /&gt; protected override void OnRunStarted( )&lt;br /&gt; {&lt;br /&gt;     base.OnRunStarted( );&lt;br /&gt;&lt;br /&gt;     //Add my pub/sub stuff&lt;br /&gt;     this.Items.AddNew&amp;lt;MyMessageUser&amp;gt;( "MyMessageUser" );&lt;br /&gt;&lt;br /&gt;     //work spaces control the layout of items contained in the WorkItem&lt;br /&gt;     IWorkspace mainWorkSpace = this.Workspaces["MainFormWorkspace"];&lt;br /&gt;&lt;br /&gt;     //Add a user button to this work item.&lt;br /&gt;     UserButton db = this.Items.AddNew&amp;lt;UserButton&amp;gt;( "UserButton" );&lt;br /&gt;&lt;br /&gt;     //Add my pub/sub stuff&lt;br /&gt;     &lt;strong&gt;db.publisher = this.Items.AddNew&amp;lt;MyMessagePublisher&amp;gt;( "MyMessagePublisher" );&lt;br /&gt;&lt;/strong&gt;&lt;br /&gt;     //Add a control that has a SmartPartPlaceholder that will control the placement of the UserButton&lt;br /&gt;     SimpleView simpView = this.Items.AddNew&amp;lt;SimpleView&amp;gt;( "SimpleView" );&lt;br /&gt;&lt;br /&gt;     //show the view in the workspace...&lt;br /&gt;     mainWorkSpace.Show( simpView );&lt;br /&gt; }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;  &lt;p&gt;      Now when I run the application in the debugger it stops twice on my break point&lt;br /&gt; inside of MyMessageUser.HandlerUserButtonClickEvent.&lt;/p&gt;  &lt;p&gt;&lt;br /&gt; Pretty sweet!&lt;br /&gt;&lt;/p&gt;  &lt;h2&gt;      Conclusion&lt;br /&gt;&lt;/h2&gt;      &lt;p&gt;      The Event Broker and Publish Subscribe functionality of the Composite UI Application&lt;br /&gt; Block is a little tricky to understand. The tricky-ness has to do with finding simple&lt;br /&gt; examples that explain one aspect at a time. Even my example has to build upon the&lt;br /&gt; previous example.&lt;br /&gt;&lt;br /&gt; Publishers and Subscribers are "scanned" by the CAB framework when they are added&lt;br /&gt; to a WorkItem. This scanning looks for attributes and if CAB finds EvenPublication&lt;br /&gt; or EventSubscription attributes it auto-magically hooks things up!&lt;br /&gt;&lt;br /&gt; I read that SmartParts should communicate with other SmartParts via Pub/Sub and&lt;br /&gt; that SmartParts should not communicate to "presenters" via Pub/Sub. I don't know&lt;br /&gt; why that statement was made and I am confident that the reasoning will become apparent&lt;br /&gt; as I do more.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/36645098-116225261929344495?l=digerati-illuminatus.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://digerati-illuminatus.blogspot.com/feeds/116225261929344495/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=36645098&amp;postID=116225261929344495' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/36645098/posts/default/116225261929344495'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/36645098/posts/default/116225261929344495'/><link rel='alternate' type='text/html' href='http://digerati-illuminatus.blogspot.com/2006/10/composite-ui-application-block_30.html' title='Composite UI Application Block EventBroker and Publish and Subscribe'/><author><name>Geoff Slinker</name><uri>http://www.blogger.com/profile/12365501393247949005</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-36645098.post-116190369106902911</id><published>2006-10-26T15:52:00.000-07:00</published><updated>2006-10-26T16:01:31.110-07:00</updated><title type='text'>Composite UI Application Block Tutorial</title><content type='html'>I have recently started using the Microsoft .NET  &lt;a href="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnpag2/html/SCSFOverviewOfCompositeUIAppBlock.asp"&gt;Composite&lt;br /&gt;       UI Application Block&lt;/a&gt; (CAB) from &lt;a href="http://www.gotdotnet.com/codegallery/codegallery.aspx?id=22f72167-af95-44ce-a6ca-f2eafbf2653c"&gt;&lt;br /&gt;           Patterns and Practices&lt;/a&gt;. I immediately realized that there is a significant&lt;br /&gt;   learning curve and started searching the Web for examples and tutorials. For various&lt;br /&gt;   reasons I found the tutorials to be confusing so I decided that when I started to&lt;br /&gt;   get things figured out I would share my experience.&lt;br /&gt;&lt;br /&gt;  &lt;br /&gt;   Please note that I am new to the CAB and my current understanding may not be correct&lt;br /&gt;   with the overall architecture of CAB.&lt;br /&gt;&lt;br /&gt;  &lt;br /&gt;   First, down load &lt;a href="http://www.gotdotnet.com/codegallery/releases/viewuploads.aspx?id=22f72167-af95-44ce-a6ca-f2eafbf2653c"&gt;&lt;br /&gt;       CAB&lt;/a&gt;. I use the December 2005 release for C#. I also downloaded the documentation&lt;br /&gt;   and labs.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;   Install CAB and take note of where it is installed so that you can find the necessary&lt;br /&gt;   DLLs to include in a .NET 2.0 Windows Forms project.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;   There are five classes that will be needed to make a simple Windows Form application&lt;br /&gt;   using CAB.&lt;br /&gt;   &lt;ol&gt;&lt;br /&gt;       &lt;li&gt;Form. You will need a Form.&lt;/li&gt;&lt;br /&gt;       &lt;li&gt;WorkItem. You will need a WorkItem in conjunction with a Form.&lt;/li&gt;&lt;br /&gt;       &lt;li&gt;Shell. You will need a class that inherits from FormShellApplication. To create&lt;br /&gt;           a Shell you must have a Form and a WorkItem.&lt;/li&gt;&lt;br /&gt;       &lt;li&gt;Button View. You will need a UserControl which contains a Button control.&lt;/li&gt;&lt;/ol&gt;    &lt;p&gt;        After you create a new C# .NET 2.0 Windows Application open the Toolbox and drag&lt;br /&gt;       the CAB DLLs from the "Microsoft Composite UI App Block\CSharp\Source\CompositeUI.WinForms\bin\Debug"&lt;br /&gt;       directory into a new group so that you can drag &amp; drop CAB components in the&lt;br /&gt;       designer.&lt;/p&gt;&lt;h2&gt;        Form&lt;/h2&gt;&lt;p&gt;        The form is just a normal Windows Form. In the designer drag a "DeckWorkspace" onto&lt;br /&gt;       the form. Don't make it fill the entire Form inorder to see how the Workspace constrains/controls&lt;br /&gt;       the location of UI components such as a Button. Name the Workspace control "MainFormWorkspace".&lt;br /&gt;       The name is used as a key in collection therefore it is important to remember the&lt;br /&gt;       name you choose.&lt;/p&gt;    &lt;h2&gt;&lt;br /&gt;       Workspaces&lt;/h2&gt;A Workspace is a place where UI parts will be displayed.&lt;br /&gt;   &lt;h2&gt;&lt;br /&gt;       WorkItem&lt;/h2&gt;            &lt;p&gt;&lt;br /&gt;       A WorkItem is a container. It is associated to the application when the Shell is&lt;br /&gt;       created. When the application is run the CabApplication.Run() calls rootWorkItem.Run().&lt;br /&gt;       Inside of your subclass of WorkItem override the method OnRunStarted().&lt;br /&gt;&lt;br /&gt;       Inside of your OnRunStarted method you can access a collection of Workspaces. Remember&lt;br /&gt;       when we created the Form we added a DeckWorkspace and named it "MainFormWorkspace".&lt;br /&gt;       Use that name as a key and get an interface to the workspace.&lt;br /&gt;&lt;br /&gt;       IWorkspace mainWorkSpace = this.Workspaces["MainFormWorkspace"]; &lt;/p&gt;&lt;p&gt;        So, what can you do with a Workspace. You can call Workspace.Show! But what is it going to show?&lt;br /&gt;       This is where it gets a little confusing to me and it took me a while to get any controls to show up on my Form.&lt;/p&gt;&lt;p&gt;        Remember we are inside of OnRunStarted() of our WorkItem. The WorkItem has the Workspaces&lt;br /&gt;       collection and it has an Items collection. Before you call Show() on your Workspace&lt;br /&gt;       you must add your UserControls (that are also SmartParts), but the interesting thing&lt;br /&gt;       is that you add these UserControls to the WorkItem and NOT to the Workspace. I am&lt;br /&gt;       still new at this so I am not sure why the UserControls are added to the WorkItem&lt;br /&gt;       so when I get a better feel and understanding I will post why the architecture is&lt;br /&gt;       thus. Remember I just want to get a button up on the Form. I know it has to do with&lt;br /&gt;       seperation of concerns.&lt;/p&gt;    &lt;h2&gt;&lt;br /&gt;       Shell&lt;/h2&gt;    &lt;p&gt;&lt;br /&gt;       A CAB application runs in a shell. You will need a class that subclasses FormShellApplication.&lt;br /&gt;       The constructor of your shell will associate the Form and the WorkItem.&lt;/p&gt;&lt;p&gt;        You must update your static void Main method to call the run method on your shell.&lt;/p&gt;    &lt;h2&gt;&lt;br /&gt;       View&lt;/h2&gt;&lt;p&gt;        A View is a UserControl that is also a SmartPart. It seems that it has to be a UserControl.&lt;br /&gt;       In my first attempt I subclassed Button and couldn't get it to show up on the Form.&lt;br /&gt;       So, I made a UserControl and added a Button to that control. Then I put the attribute&lt;br /&gt;       [SmartPart] on the UserControl. Once I added the UserControl to the WorkItem.Items&lt;br /&gt;       collection and then called Show on my Workspace the UserControl appeared on the&lt;br /&gt;       Form.&lt;/p&gt;    &lt;h2&gt;&lt;br /&gt;       Source Code&lt;br /&gt;&lt;/h2&gt;    &lt;p&gt;        Find your static void Main() method and change it to run your CAB application. The&lt;br /&gt;       class that contains Main in my project is Program.cs.&lt;br /&gt;&lt;/p&gt;       &lt;pre&gt;&lt;br /&gt;//Program.cs&lt;br /&gt;using System;&lt;br /&gt;using System.Collections.Generic;&lt;br /&gt;using System.Windows.Forms;&lt;br /&gt;using Microsoft.Practices.CompositeUI;&lt;br /&gt;using Microsoft.Practices.CompositeUI.WinForms;&lt;br /&gt;using Microsoft.Practices.ObjectBuilder;&lt;br /&gt;&lt;br /&gt;namespace CABTestOne&lt;br /&gt;{&lt;br /&gt;   static class Program&lt;br /&gt;   {&lt;br /&gt;       /// &amp;lt;summary&amp;gt;&lt;br /&gt;       /// The main entry point for the application.&lt;br /&gt;       /// &amp;lt;/summary&amp;gt;&lt;br /&gt;       [STAThread]&lt;br /&gt;       static void Main( )&lt;br /&gt;       {&lt;br /&gt;           &lt;strong&gt;new MyFirstCabApplication().Run( );&lt;br /&gt;&lt;/strong&gt;        }&lt;br /&gt;   }&lt;br /&gt;}&lt;br /&gt;     &lt;br /&gt;&lt;/pre&gt;&lt;p&gt;    MyFirstCabApplication is a subclass of FormShellApplication. FormShellApplication&lt;br /&gt;   uses generics to associate the Form and the WorkItem.&lt;/p&gt;        &lt;pre&gt;&lt;br /&gt;//MyFirstCabApplication.cs&lt;br /&gt;using System;&lt;br /&gt;using System.Collections.Generic;&lt;br /&gt;using System.Text;&lt;br /&gt;using Microsoft.Practices.CompositeUI;&lt;br /&gt;using Microsoft.Practices.CompositeUI.WinForms;&lt;br /&gt;using Microsoft.Practices.CompositeUI.SmartParts;&lt;br /&gt;using Microsoft.Practices.ObjectBuilder;&lt;br /&gt;&lt;br /&gt;namespace CABTestOne&lt;br /&gt;{&lt;br /&gt;   public class MyFirstCabApplication : &lt;strong&gt;FormShellApplication&amp;lt;MyWorkItem,Form1&amp;gt;&lt;br /&gt;   &lt;/strong&gt;    {&lt;br /&gt;&lt;br /&gt;   }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;        &lt;p&gt;&lt;br /&gt;           MyWorkItem is a subclass of WorkItem. The application will call OnRunStarted of&lt;br /&gt;           the WorkItem. It is able to do this because the constructor of MyFirstCabApplication&lt;br /&gt;           specifies MyWorkItem.&lt;/p&gt;        &lt;pre&gt;&lt;br /&gt;//MyWorkItem.cs&lt;br /&gt;using System;&lt;br /&gt;using System.Collections.Generic;&lt;br /&gt;using System.Text;&lt;br /&gt;using Microsoft.Practices.CompositeUI;&lt;br /&gt;using Microsoft.Practices.CompositeUI.SmartParts;&lt;br /&gt;using Microsoft.Practices.CompositeUI.WinForms;&lt;br /&gt;using Microsoft.Practices.ObjectBuilder;&lt;br /&gt;&lt;br /&gt;namespace CABTestOne&lt;br /&gt;{&lt;br /&gt;   public class MyWorkItem : &lt;strong&gt;WorkItem&lt;/strong&gt;&lt;br /&gt;   {&lt;br /&gt;&lt;br /&gt;       protected override void OnRunStarted( )&lt;br /&gt;       {&lt;br /&gt;           base.OnRunStarted( );&lt;br /&gt;&lt;br /&gt;           //work spaces control the layout of items contained in the WorkItem&lt;br /&gt;           IWorkspace mainWorkSpace = this.Workspaces["MainFormWorkspace"];&lt;br /&gt;&lt;br /&gt;           //Add a user button to this work item.&lt;br /&gt;           UserButton db = this.Items.AddNew&amp;lt;UserButton&amp;gt;( "UserButton" );&lt;br /&gt;&lt;br /&gt;           //show the UserButton in the workspace...&lt;br /&gt;           mainWorkSpace.Show( db );&lt;br /&gt;       }&lt;br /&gt;   }&lt;br /&gt;}       &lt;br /&gt;&lt;/pre&gt;        &lt;p&gt;&lt;br /&gt;           UserButton is a subclass of UserControl. Because the IDE divides a custom UserControl&lt;br /&gt;           into two source files I will include them both. UserButton.cs and UserButton.Designer.cs.&lt;br /&gt;           &lt;span style="text-decoration: underline;"&gt;Notice that the UserButton class has the attribute&lt;br /&gt;               [&lt;strong&gt;SmartPart&lt;/strong&gt;]. This is essential.&lt;/span&gt;&lt;/p&gt;        &lt;pre&gt;&lt;br /&gt;//UserButton.cs&lt;br /&gt;using System;&lt;br /&gt;using System.Collections.Generic;&lt;br /&gt;using System.ComponentModel;&lt;br /&gt;using System.Drawing;&lt;br /&gt;using System.Data;&lt;br /&gt;using System.Text;&lt;br /&gt;using System.Windows.Forms;&lt;br /&gt;using Microsoft.Practices.CompositeUI.SmartParts;&lt;br /&gt;&lt;br /&gt;namespace CABTestOne&lt;br /&gt;{&lt;br /&gt;   [&lt;strong&gt;SmartPart&lt;/strong&gt;]&lt;br /&gt;   public partial class UserButton : &lt;strong&gt;UserControl&lt;/strong&gt;&lt;br /&gt;   {&lt;br /&gt;       public UserButton( )&lt;br /&gt;       {&lt;br /&gt;           InitializeComponent( );&lt;br /&gt;       }&lt;br /&gt;   }&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;       &lt;/pre&gt;        &lt;pre&gt;//UserButton.Designer.cs&lt;br /&gt;namespace CABTestOne&lt;br /&gt;{&lt;br /&gt;   partial class UserButton&lt;br /&gt;   {&lt;br /&gt;       /// &amp;lt;summary&amp;gt;&lt;br /&gt;       /// Required designer variable.&lt;br /&gt;       /// &amp;lt;/summary&amp;gt;&lt;br /&gt;       private System.ComponentModel.IContainer components = null;&lt;br /&gt;&lt;br /&gt;       /// &amp;lt;summary&amp;gt;&lt;br /&gt;       /// Clean up any resources being used.&lt;br /&gt;       /// &amp;lt;/summary&amp;gt;&lt;br /&gt;       /// &amp;lt;param name="disposing"&amp;gt;true if managed resources should be disposed; otherwise, false.&amp;lt;/param&amp;gt;&lt;br /&gt;       protected override void Dispose( bool disposing )&lt;br /&gt;       {&lt;br /&gt;           if( disposing &amp;amp;&amp; ( components != null ) )&lt;br /&gt;           {&lt;br /&gt;               components.Dispose( );&lt;br /&gt;           }&lt;br /&gt;           base.Dispose( disposing );&lt;br /&gt;       }&lt;br /&gt;&lt;br /&gt;       #region Component Designer generated code&lt;br /&gt;&lt;br /&gt;       /// &amp;lt;summary&amp;gt;&lt;br /&gt;       /// Required method for Designer support - do not modify&lt;br /&gt;       /// the contents of this method with the code editor.&lt;br /&gt;       /// &amp;lt;/summary&amp;gt;&lt;br /&gt;       private void InitializeComponent( )&lt;br /&gt;       {&lt;br /&gt;           this.button1 = new System.Windows.Forms.Button( );&lt;br /&gt;           this.SuspendLayout( );&lt;br /&gt;           //&lt;br /&gt;           // button1&lt;br /&gt;           //&lt;br /&gt;           this.button1.BackColor = System.Drawing.Color.Khaki;&lt;br /&gt;           this.button1.Dock = System.Windows.Forms.DockStyle.Fill;&lt;br /&gt;           this.button1.Location = new System.Drawing.Point( 0, 0 );&lt;br /&gt;           this.button1.Name = "button1";&lt;br /&gt;           this.button1.Size = new System.Drawing.Size( 69, 32 );&lt;br /&gt;           this.button1.TabIndex = 0;&lt;br /&gt;           this.button1.Text = "button1";&lt;br /&gt;           this.button1.UseVisualStyleBackColor = false;&lt;br /&gt;           //&lt;br /&gt;           // UserButton&lt;br /&gt;           //&lt;br /&gt;           this.AutoScaleDimensions = new System.Drawing.SizeF( 6F, 13F );&lt;br /&gt;           this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;&lt;br /&gt;           this.Controls.Add( this.button1 );&lt;br /&gt;           this.Name = "UserButton";&lt;br /&gt;           this.Size = new System.Drawing.Size( 69, 32 );&lt;br /&gt;           this.ResumeLayout( false );&lt;br /&gt;&lt;br /&gt;       }&lt;br /&gt;&lt;br /&gt;       #endregion&lt;br /&gt;&lt;br /&gt;       private System.Windows.Forms.Button button1;&lt;br /&gt;   }&lt;br /&gt;}       &lt;br /&gt;&lt;/pre&gt;&lt;p&gt;&lt;br /&gt;   The Form is also split across two files. I will include them both. Form1.cs and&lt;br /&gt;   Form1.Designer.cs.&lt;/p&gt;         &lt;pre&gt;//Form1.cs&lt;br /&gt;using System;&lt;br /&gt;using System.Collections.Generic;&lt;br /&gt;using System.ComponentModel;&lt;br /&gt;using System.Data;&lt;br /&gt;using System.Drawing;&lt;br /&gt;using System.Text;&lt;br /&gt;using System.Windows.Forms;&lt;br /&gt;&lt;br /&gt;namespace CABTestOne&lt;br /&gt;{&lt;br /&gt;   public partial class Form1 : Form&lt;br /&gt;   {&lt;br /&gt;       public Form1( )&lt;br /&gt;       {&lt;br /&gt;           InitializeComponent( );&lt;br /&gt;       }&lt;br /&gt;&lt;br /&gt;   }&lt;br /&gt;}       &lt;br /&gt;       &lt;/pre&gt;        &lt;pre&gt;//Form1.Designer.cs&lt;br /&gt;namespace CABTestOne&lt;br /&gt;{&lt;br /&gt;   partial class Form1&lt;br /&gt;   {&lt;br /&gt;       /// &amp;lt;summary&amp;gt;&lt;br /&gt;       /// Required designer variable.&lt;br /&gt;       /// &amp;lt;/summary&amp;gt;&lt;br /&gt;       private System.ComponentModel.IContainer components = null;&lt;br /&gt;&lt;br /&gt;       /// &amp;lt;summary&amp;gt;&lt;br /&gt;       /// Clean up any resources being used.&lt;br /&gt;       /// &amp;lt;/summary&amp;gt;&lt;br /&gt;       /// &amp;lt;param name="disposing"&amp;gt;true if managed resources should be disposed; otherwise, false.&amp;lt;/param&amp;gt;&lt;br /&gt;       protected override void Dispose( bool disposing )&lt;br /&gt;       {&lt;br /&gt;           if( disposing &amp;amp;&amp; ( components != null ) )&lt;br /&gt;           {&lt;br /&gt;               components.Dispose( );&lt;br /&gt;           }&lt;br /&gt;           base.Dispose( disposing );&lt;br /&gt;       }&lt;br /&gt;&lt;br /&gt;       #region Windows Form Designer generated code&lt;br /&gt;&lt;br /&gt;       /// &amp;lt;summary&amp;gt;&lt;br /&gt;       /// Required method for Designer support - do not modify&lt;br /&gt;       /// the contents of this method with the code editor.&lt;br /&gt;       /// &amp;lt;/summary&amp;gt;&lt;br /&gt;       private void InitializeComponent( )&lt;br /&gt;       {&lt;br /&gt;           this.MainFormWorkspace = new Microsoft.Practices.CompositeUI.WinForms.DeckWorkspace( );&lt;br /&gt;           this.SuspendLayout( );&lt;br /&gt;           //&lt;br /&gt;           // MainFormWorkspace&lt;br /&gt;           //&lt;br /&gt;           this.MainFormWorkspace.BackColor = System.Drawing.SystemColors.ControlDark;&lt;br /&gt;           this.MainFormWorkspace.Location = new System.Drawing.Point( 12, 12 );&lt;br /&gt;           this.MainFormWorkspace.Name = "MainFormWorkspace";&lt;br /&gt;           this.MainFormWorkspace.Size = new System.Drawing.Size( 268, 146 );&lt;br /&gt;           this.MainFormWorkspace.TabIndex = 0;&lt;br /&gt;           this.MainFormWorkspace.Text = "MainFormWorkspace";&lt;br /&gt;           //&lt;br /&gt;           // Form1&lt;br /&gt;           //&lt;br /&gt;           this.AutoScaleDimensions = new System.Drawing.SizeF( 6F, 13F );&lt;br /&gt;           this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;&lt;br /&gt;           this.ClientSize = new System.Drawing.Size( 292, 273 );&lt;br /&gt;           this.Controls.Add( this.MainFormWorkspace );&lt;br /&gt;           this.Name = "Form1";&lt;br /&gt;           this.Text = "Form1";&lt;br /&gt;           this.ResumeLayout( false );&lt;br /&gt;&lt;br /&gt;       }&lt;br /&gt;&lt;br /&gt;       #endregion&lt;br /&gt;&lt;br /&gt;       private Microsoft.Practices.CompositeUI.WinForms.DeckWorkspace MainFormWorkspace;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;   }&lt;br /&gt;}&lt;br /&gt;       &lt;/pre&gt;&lt;h2&gt;            Review&lt;/h2&gt;    &lt;ol&gt;&lt;br /&gt;       &lt;li&gt;Create a Form.&lt;/li&gt;&lt;br /&gt;       &lt;li&gt;Create a subclass of Microsoft.Practices.CompositeUI.WorkItem.&lt;/li&gt;&lt;br /&gt;       &lt;li&gt;Create a subclass of Microsoft.Practices.CompositeUI.WinForms.FormShellApplication.&lt;/li&gt;&lt;br /&gt;       &lt;li&gt;Update your static void Main to "RUN" your FormShellApplication subclass.&lt;/li&gt;&lt;br /&gt;       &lt;li&gt;Override the OnRunStarted method of your WorkItem class.&lt;/li&gt;&lt;br /&gt;       &lt;li&gt;In "your" WorkItem subclass' OnRunStarted add your SmartParts. In my example this&lt;br /&gt;           was the UserButton which is a subclass of the UserControl. Add these SmartParts&lt;br /&gt;           to the Items collection of your WorkItem.&lt;/li&gt;&lt;br /&gt;       &lt;li&gt;Get an interface to your Workspace. In this case it is the DeckWorkspace that was&lt;br /&gt;           "dropped" on the Form. The DeckWorkspace name is "MainFormWorkspace". This is a&lt;br /&gt;           key to access the Workspaces collection of the WorkItem.&lt;/li&gt;&lt;br /&gt;       &lt;li&gt;Call Show on the Workspace passing it the UserButton (which is a SmartPart).&lt;/li&gt;    &lt;/ol&gt;    &lt;h2&gt;&lt;br /&gt;       SmartPartPlaceholder&lt;/h2&gt;&lt;p&gt;        After figuring out how to get a Button on the Form I was a little confused that&lt;br /&gt;       it filled the entire area of the Workspace.&lt;/p&gt;&lt;p&gt;        After some study I figured out how to use Microsoft.Practices.CompositeUI.WinForms.SmartPartPlaceholder.&lt;/p&gt;    &lt;ol&gt;&lt;br /&gt;       &lt;li&gt;Create a new SmartPart by subclassing UserControl. I called this SimpleView.&lt;/li&gt;&lt;br /&gt;       &lt;li&gt;Drag a SmartPartPlaceholder onto the UserControl (SimpleView) and size it and position&lt;br /&gt;           it as you like.&lt;/li&gt;&lt;br /&gt;       &lt;li&gt;Set the "SmartPartName" to the ID of the UserButton. The ID of the UserButton is&lt;br /&gt;           the key string you use when you add the UserButton to your WorkItem's Item collection.&lt;br /&gt;           Look at MyWorkItem.cs and notice that when I added the UserButton I passed a string&lt;br /&gt;           with the value "UserButton". That string is the key and that key must be the SmartPartName.&lt;br /&gt;           The SmartPartName can be set by viewing the properties of the SmartPartPlaceholder&lt;br /&gt;           that you placed on the SimpleView UserControl.&lt;/li&gt;&lt;br /&gt;       &lt;li&gt;Add SimpleView to the WorkItem Items collection AFTER you have added the UserButton.&lt;br /&gt;           This is done in the OnRunStarted method of your WorkItem class. It must be done&lt;br /&gt;           after the UserButton was added or it doesn't work.&lt;/li&gt;&lt;br /&gt;       &lt;li&gt;Change the call to the Workspace Run method by passing the SimpleView instead of&lt;br /&gt;           the UserButton. This is critical.&lt;/li&gt;    &lt;/ol&gt;    &lt;p&gt;&lt;br /&gt;       Below is the source code. Notice that MyWorkItem was modified and that a new class&lt;br /&gt;       was added called SimpleView.&lt;/p&gt;        &lt;pre&gt;&lt;br /&gt;//MyWorkItem.cs&lt;br /&gt;using System;&lt;br /&gt;using System.Collections.Generic;&lt;br /&gt;using System.Text;&lt;br /&gt;using Microsoft.Practices.CompositeUI;&lt;br /&gt;using Microsoft.Practices.CompositeUI.SmartParts;&lt;br /&gt;using Microsoft.Practices.CompositeUI.WinForms;&lt;br /&gt;using Microsoft.Practices.ObjectBuilder;&lt;br /&gt;&lt;br /&gt;namespace CABTestOne&lt;br /&gt;{&lt;br /&gt;   public class MyWorkItem : &lt;strong&gt;WorkItem&lt;/strong&gt;&lt;br /&gt;   {&lt;br /&gt;&lt;br /&gt;       protected override void OnRunStarted( )&lt;br /&gt;       {&lt;br /&gt;           base.OnRunStarted( );&lt;br /&gt;&lt;br /&gt;           //work spaces control the layout of items contained in the WorkItem&lt;br /&gt;           IWorkspace mainWorkSpace = this.Workspaces["MainFormWorkspace"];&lt;br /&gt;&lt;br /&gt;           //Add a user button to this work item.&lt;br /&gt;           UserButton db = this.Items.AddNew&amp;lt;UserButton&amp;gt;( "UserButton" );&lt;br /&gt;&lt;br /&gt;           //Add a control that has a SmartPartPlaceholder that will control the placement of the UserButton&lt;br /&gt;           &lt;strong&gt;SimpleView simpView = this.Items.AddNew&amp;lt;SimpleView&amp;gt;( "SimpleView" );&lt;br /&gt;&lt;/strong&gt;&lt;br /&gt;           //show the view in the workspace...&lt;br /&gt;           mainWorkSpace.Show( &lt;strong&gt;simpView&lt;/strong&gt; );&lt;br /&gt;       }&lt;br /&gt;   }&lt;br /&gt;}       &lt;br /&gt;       &lt;/pre&gt;        &lt;pre&gt;&lt;br /&gt;//SimpleView.cs       &lt;br /&gt;using System;&lt;br /&gt;using System.Collections.Generic;&lt;br /&gt;using System.ComponentModel;&lt;br /&gt;using System.Drawing;&lt;br /&gt;using System.Data;&lt;br /&gt;using System.Text;&lt;br /&gt;using System.Windows.Forms;&lt;br /&gt;using Microsoft.Practices.CompositeUI.SmartParts;&lt;br /&gt;&lt;br /&gt;namespace CABTestOne&lt;br /&gt;{&lt;br /&gt;   &lt;strong&gt;[SmartPart] &lt;/strong&gt;    public partial class SimpleView : UserControl&lt;br /&gt;   {&lt;br /&gt;       public SimpleView( )&lt;br /&gt;       {&lt;br /&gt;           InitializeComponent( );&lt;br /&gt;       }&lt;br /&gt;   }&lt;br /&gt;}       &lt;br /&gt;       &lt;/pre&gt;        &lt;pre&gt;//SimpleView.Designer.cs&lt;br /&gt;namespace CABTestOne&lt;br /&gt;{&lt;br /&gt;   partial class SimpleView&lt;br /&gt;   {&lt;br /&gt;       /// &amp;lt;summary&amp;gt;&lt;br /&gt;       /// Required designer variable.&lt;br /&gt;       /// &amp;lt;/summary&amp;gt;&lt;br /&gt;       private System.ComponentModel.IContainer components = null;&lt;br /&gt;&lt;br /&gt;       /// &amp;lt;summary&amp;gt;&lt;br /&gt;       /// Clean up any resources being used.&lt;br /&gt;       /// &amp;lt;/summary&amp;gt;&lt;br /&gt;       /// &amp;lt;param name="disposing"&amp;gt;true if managed resources should be disposed; otherwise, false.&amp;lt;/param&amp;gt;&lt;br /&gt;       protected override void Dispose( bool disposing )&lt;br /&gt;       {&lt;br /&gt;           if( disposing &amp;amp;&amp; ( components != null ) )&lt;br /&gt;           {&lt;br /&gt;               components.Dispose( );&lt;br /&gt;           }&lt;br /&gt;           base.Dispose( disposing );&lt;br /&gt;       }&lt;br /&gt;&lt;br /&gt;       #region Component Designer generated code&lt;br /&gt;&lt;br /&gt;       /// &amp;lt;summary&amp;gt;&lt;br /&gt;       /// Required method for Designer support - do not modify&lt;br /&gt;       /// the contents of this method with the code editor.&lt;br /&gt;       /// &amp;lt;/summary&amp;gt;&lt;br /&gt;       private void InitializeComponent( )&lt;br /&gt;       {&lt;br /&gt;           this.smartPartPlaceholder2 = new Microsoft.Practices.CompositeUI.WinForms.SmartPartPlaceholder( );&lt;br /&gt;           this.SuspendLayout( );&lt;br /&gt;           //&lt;br /&gt;           // smartPartPlaceholder2&lt;br /&gt;           //&lt;br /&gt;           this.smartPartPlaceholder2.BackColor = System.Drawing.Color.Red;&lt;br /&gt;           this.smartPartPlaceholder2.Location = new System.Drawing.Point( 29, 28 );&lt;br /&gt;           this.smartPartPlaceholder2.Name = "smartPartPlaceholder2";&lt;br /&gt;           this.smartPartPlaceholder2.Size = new System.Drawing.Size( 75, 75 );&lt;br /&gt;           this.smartPartPlaceholder2.SmartPartName = "UserButton";&lt;br /&gt;           this.smartPartPlaceholder2.TabIndex = 1;&lt;br /&gt;           this.smartPartPlaceholder2.Text = "smartPartPlaceholder2";&lt;br /&gt;           //&lt;br /&gt;           // SimpleView&lt;br /&gt;           //&lt;br /&gt;           this.AutoScaleDimensions = new System.Drawing.SizeF( 6F, 13F );&lt;br /&gt;           this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;&lt;br /&gt;           this.BackColor = System.Drawing.Color.Gainsboro;&lt;br /&gt;           this.Controls.Add( this.smartPartPlaceholder2 );&lt;br /&gt;           this.Name = "SimpleView";&lt;br /&gt;           this.Size = new System.Drawing.Size( 147, 150 );&lt;br /&gt;           this.ResumeLayout( false );&lt;br /&gt;&lt;br /&gt;       }&lt;br /&gt;&lt;br /&gt;       #endregion&lt;br /&gt;&lt;br /&gt;       private Microsoft.Practices.CompositeUI.WinForms.SmartPartPlaceholder smartPartPlaceholder2;&lt;br /&gt;   }&lt;br /&gt;}       &lt;br /&gt;&lt;/pre&gt;        &lt;h2&gt;&lt;br /&gt;           Conclusion&lt;br /&gt;&lt;/h2&gt;    &lt;p&gt;        The Composite UI Application Block (CAB) can be a bit tricky. Just getting a simple&lt;br /&gt;       example up and running can take a lot of study.&lt;/p&gt;&lt;p&gt;        You have to have a Shell ( a subclass of FormShellApplication).&lt;/p&gt;&lt;p&gt;        In order to instantiate a Shell you have to have a Windows Form and a WorkItem.&lt;/p&gt;&lt;p&gt;        On the Windows Form you must place a Workspace. The Workspace defines the area of&lt;br /&gt;       the form where controls (SmartParts) will appear. The name of this Workspace is&lt;br /&gt;       used as a key in the WorkItem collection Workspaces. Be sure to make note of your&lt;br /&gt;       Workspace name. I used a DeckWorkspace in this example.&lt;/p&gt;&lt;p&gt;        SmartParts are subclasses of UserControl that have the attribute [SmartPart].&lt;/p&gt;&lt;p&gt;        Add the SmartParts to your WorkItem's collection called "Items".&lt;/p&gt;&lt;p&gt;        Call Show on the Workspace. This call is done inside of the WorkItem's OnRunStarted&lt;br /&gt;       method.&lt;/p&gt;&lt;p&gt;        SmartPartPlaceholders define size and location for SmartParts. The SmartPartPlaceholder&lt;br /&gt;       is added to a UserControl. SmartPartPlaceholder.SmartPartname is set to the ID of&lt;br /&gt;       some UserControl. The ID of a UserControl is the string passed into the WorkItem&lt;br /&gt;       Items collection when you call AddNew on that collection.&lt;/p&gt;&lt;p&gt;        Add the SmartPart that constains the SmartPartPlaceholder AFTER you have added the&lt;br /&gt;       UserControl that the SmartPartPlaceholder has identified in the SmartPartname.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/36645098-116190369106902911?l=digerati-illuminatus.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://digerati-illuminatus.blogspot.com/feeds/116190369106902911/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=36645098&amp;postID=116190369106902911' title='8 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/36645098/posts/default/116190369106902911'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/36645098/posts/default/116190369106902911'/><link rel='alternate' type='text/html' href='http://digerati-illuminatus.blogspot.com/2006/10/composite-ui-application-block.html' title='Composite UI Application Block Tutorial'/><author><name>Geoff Slinker</name><uri>http://www.blogger.com/profile/12365501393247949005</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g
