<?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-2291554078837078852</id><updated>2011-08-16T22:04:56.266-05:00</updated><category term='commons ToStringBuilder'/><category term='ssh rsa dsa private public key mac os x leopard'/><category term='local optimization lean'/><category term='team dynamics'/><category term='sharing information'/><category term='Hibernate'/><category term='Spring'/><category term='WebSphere Trace'/><category term='communication'/><category term='development knowledge'/><category term='knowledge sharing development team'/><category term='pairing'/><category term='LazyInitializationException'/><title type='text'>On Programming and Applications Development</title><subtitle type='html'>Lessons I learned, and my observations from the worlds of programming, software development, and IT</subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://tabdelmaguid.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2291554078837078852/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://tabdelmaguid.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>Tarek Abdelmaguid</name><uri>http://www.blogger.com/profile/11912000217230377978</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>15</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-2291554078837078852.post-9041040848361979016</id><published>2010-07-22T16:07:00.002-05:00</published><updated>2010-07-22T16:14:16.474-05:00</updated><title type='text'>A Story of a Software Project</title><content type='html'>Iteration 1: The team picks up the first stories, and makes good progress. The result is showcased to the customers. The mood is encouraging.&lt;br /&gt;Iteration 2: The team churns a bit, trying to get the first stories closed and iron out some technology choices.&lt;br /&gt;Iteration 3: Not enough stories are being closed. The team's velocity is lower than needed. The PM gets worried, and starts calling meetings and raising red flags. The PM declares that the team needs to catch up, and look for ways to increase velocity.&lt;br /&gt;Iteration 4: The team makes good strides, and appears to be back on track. Nerves settle down a bit.&lt;br /&gt;Iteration 5: The team's velocity is soaring. The PM says that given the current velocity, the team will meet its target date. The team starts taking care of technical debt.&lt;br /&gt;Iteration 6: The business functionality is taking shape. The customers start to get a feel of how the system works. They start asking for modifications.&lt;br /&gt;Iteration 7: The customers become more demanding. They notice some gaps between the functionality of the application, and what is needed to run the business. Defects start to creep in.&lt;br /&gt;Iteration 8: The PM talks the business out of some of their demands, and the team devises workarounds for some outstanding issues.&lt;br /&gt;Iteration 9: Faced with approaching deadlines, the PM asks developers to stay late and work over the weekends to finish the remaining tasks. The code quality suffers and technical debt increases.&lt;br /&gt;Iteration 10: The team manages to finish all the remaining tasks. The application is put in production, with minor hiccups. Time to celebrate.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Does this sound familiar?&lt;br /&gt;The team delivered on time. Is there a problem here?&lt;br /&gt;The above pattern causes hardship for the team. The resulting code quality is rarely satisfactory. But we shouldn't be surprised or get overly worked out because of things that are really to be expected:&lt;br /&gt;- Estimates are not always met, because they are estimates.&lt;br /&gt;- The team takes more time in the first iterations because it's the first time this team tackles this problem.&lt;br /&gt;- The customers don't like what they see the first time, because it's the first time they see it.&lt;br /&gt;- The project is taking more time than expected because our expectations are just now being reality checked.&lt;br /&gt;- The developers are being asked to work extra time because the team's management over-promised. However, the developers had no clue initially whether these promises can be met. Everything looked good on paper.&lt;br /&gt;&lt;br /&gt;What's the way out of this?&lt;br /&gt;This is not an easy problem. What makes it even more difficult is the fact that the team delivered after all, reducing the incentive for change.  There are ways, however, to make things better:&lt;br /&gt;- Educate all parties on all aspects of the project.&lt;br /&gt;- Get the customers involved as early as possible.&lt;br /&gt;- Manage all parties' expectations.&lt;br /&gt;- Communicate regularly, and facilitate information sharing.&lt;br /&gt;- Make it clear that the process of adaptation also includes dates and scope.&lt;br /&gt;- Learn from the past. If you've seen this before, it's likely that you'll see it again unless you change your approach.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2291554078837078852-9041040848361979016?l=tabdelmaguid.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://tabdelmaguid.blogspot.com/feeds/9041040848361979016/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2291554078837078852&amp;postID=9041040848361979016' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2291554078837078852/posts/default/9041040848361979016'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2291554078837078852/posts/default/9041040848361979016'/><link rel='alternate' type='text/html' href='http://tabdelmaguid.blogspot.com/2010/07/story-of-software-project.html' title='A Story of a Software Project'/><author><name>Tarek Abdelmaguid</name><uri>http://www.blogger.com/profile/11912000217230377978</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-2291554078837078852.post-7904347721055800088</id><published>2009-11-05T18:24:00.002-06:00</published><updated>2009-11-05T18:28:19.519-06:00</updated><title type='text'>Shouldn't We Local-Optimize at Bottlenecks?</title><content type='html'>The short answer is no. Once we start thinking local, we are heading down the wrong path.&lt;br /&gt;&lt;br /&gt;Consider what we should do at a bottleneck:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Increase the resource's throughput, by increasing its efficiencies.&lt;/li&gt;&lt;li&gt;Manage the flow in the system to reduce idle time at the resource.&lt;/li&gt;&lt;li&gt;Add more capacity, by introducing other resources capable of the same function.&lt;/li&gt;&lt;li&gt;Outsource a portion of the work to resources outside the system.&lt;/li&gt;&lt;li&gt;Rethink the need for some work to go through the bottleneck.&lt;/li&gt;&lt;/ul&gt;You'd notice that only the first of these points is local in nature, and we should only consider it as an option. It may not be the best one.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2291554078837078852-7904347721055800088?l=tabdelmaguid.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://tabdelmaguid.blogspot.com/feeds/7904347721055800088/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2291554078837078852&amp;postID=7904347721055800088' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2291554078837078852/posts/default/7904347721055800088'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2291554078837078852/posts/default/7904347721055800088'/><link rel='alternate' type='text/html' href='http://tabdelmaguid.blogspot.com/2009/11/shouldnt-we-local-optimize-at.html' title='Shouldn&apos;t We Local-Optimize at Bottlenecks?'/><author><name>Tarek Abdelmaguid</name><uri>http://www.blogger.com/profile/11912000217230377978</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-2291554078837078852.post-5666774504449107051</id><published>2009-10-23T18:16:00.003-05:00</published><updated>2009-10-23T19:17:11.209-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='local optimization lean'/><title type='text'>What is Wrong with Local Optimization Anyway?</title><content type='html'>How could it be wrong to optimize anything, local or not?&lt;br /&gt;Well, if by local optimization we mean having a resource in our system utilize an optimum amount of its inputs, to produce timely, sufficient, but not excessive, output to subsequent steps in the process, then there is nothing wrong, as long as this optimization contributes positively to the system's goal.&lt;br /&gt;Note that timely, sufficient, and not excessive, output is defined by subsequent steps in the process. As such, this output might, at times, be zero.&lt;br /&gt;Note also that optimizing the whole system may call for one step or process to be removed altogether.&lt;br /&gt;If this is how we are approaching the problem of efficiency, then we are not actually doing local optimization.&lt;br /&gt;&lt;br /&gt;Consider, however, the following approaches to optimization:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Increasing the resource utilization to 100%.&lt;/li&gt;&lt;li&gt;Getting the maximum possible throughput out of every resource.&lt;/li&gt;&lt;li&gt;Keeping everyone busy all the time.&lt;/li&gt;&lt;li&gt; Removing all idle time.&lt;/li&gt;&lt;/ul&gt;If this is our focus, then we are heading for trouble, and we are introducing a significant waste in our system.&lt;br /&gt;&lt;br /&gt;To see why this is the case, consider the following consequences of increasing a resource's throughput in our system to the maximum:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;More inventory to manage in subsequent processes, If these subsequent processes are not ready, or capable, of consuming all the output.&lt;/li&gt;&lt;li&gt;More load on subsequent processes, since now they will have more input to process.&lt;/li&gt;&lt;li&gt;Delays in getting urgent work done, since there is no slack in the system to handle occasional spikes, resulting from natural statistical variations.&lt;/li&gt;&lt;li&gt;More work being stuck at bottlenecks.&lt;/li&gt;&lt;li&gt;Increasing demand artificially on up-stream processes, since this demand is not driven by the needs of the market or the ultimate customers.&lt;/li&gt;&lt;li&gt;Increasing demand on resources required to maintain the high efficiency.&lt;/li&gt;&lt;li&gt;The process of optimization itself will consume resources. The overall gain may not exceed the cost.&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;Local efficiency, then, is a waste. One has to look for alignment with the system's goals to define what, where, how, and how much to optimize, weighing costs against benefits.&lt;br /&gt;&lt;br /&gt;"But wait," you may remark, "how about local optimization at bottlenecks?", which is, granted, a nice try. But this will have to wait for another post.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2291554078837078852-5666774504449107051?l=tabdelmaguid.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://tabdelmaguid.blogspot.com/feeds/5666774504449107051/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2291554078837078852&amp;postID=5666774504449107051' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2291554078837078852/posts/default/5666774504449107051'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2291554078837078852/posts/default/5666774504449107051'/><link rel='alternate' type='text/html' href='http://tabdelmaguid.blogspot.com/2009/10/what-is-wrong-with-local-optimization.html' title='What is Wrong with Local Optimization Anyway?'/><author><name>Tarek Abdelmaguid</name><uri>http://www.blogger.com/profile/11912000217230377978</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-2291554078837078852.post-7729972644897362150</id><published>2009-10-07T18:36:00.001-05:00</published><updated>2009-10-08T18:35:06.061-05:00</updated><title type='text'>Does Waterfall Make More Sense?</title><content type='html'>I came in contact with a few people who were actually content with waterfall.&lt;br /&gt;A senior dev explained to me that waterfall is simple, everyone gets it, and it's easy to implement. There are well defined, easy, consecutive steps to be followed.&lt;br /&gt;An upper manger was very keen to find ways to convince his company's leadership that waterfall fits his department really well, thus avoiding the drive to adopt agile. From his perspective, waterfall provided predictability. He new at the beginning of the year what his budget is, what projects he will be working on, and what the duration of each projects will be.&lt;br /&gt;&lt;br /&gt;It also makes sense to design something before building it. If you don't design it before hand, how do you know what you will be building? How do you know how much it will cost? How do you decide if it's worth it? How do you compare it to other options?&lt;br /&gt;&lt;br /&gt;In our day-to-day life, we demand predictability. Before we offer a job to a carpenter to install new kitchen cabinets, or ask a mechanic to service our car, for example, we want to know before hand how much it will cost, and how long it will take. We are really disturbed when either of these estimates are not met, although we know they are just estimates.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;So what is the problem in expecting the same from software projects?&lt;/span&gt;&lt;br /&gt;We can always give the example of an apparently simple job gone badly, as when an air conditioning engineer starts asking you when was the last time you cleaned your air vents, or changed the air filters, only to discover that you'd have to pay more and wait longer to have your air system fixed. Let's put this example aside for now.&lt;br /&gt;Instead, consider the how likely is the change in your project, from inception to project end, in the following areas:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;The business needs from your application.&lt;/li&gt;&lt;li&gt; The specified requirements from your application.&lt;/li&gt;&lt;li&gt; Your understanding of the requirements.&lt;/li&gt;&lt;li&gt; Technology.&lt;/li&gt;&lt;li&gt; The project team's mastery of the technology.&lt;/li&gt;&lt;li&gt; The people who are doing the work.&lt;/li&gt;&lt;/ul&gt;If your meter reads anything other than low for all the above, you should rethink waterfall.&lt;br /&gt;Because waterfall makes sense for certain types of projects. Software development projects are a breed of their own, with a lot of sub-varieties within.&lt;br /&gt;And change is inevitable in software projects, because you'll never build the same application twice, for the same business need, with the same people, who have the same experience, using the same technology, will you?&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2291554078837078852-7729972644897362150?l=tabdelmaguid.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://tabdelmaguid.blogspot.com/feeds/7729972644897362150/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2291554078837078852&amp;postID=7729972644897362150' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2291554078837078852/posts/default/7729972644897362150'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2291554078837078852/posts/default/7729972644897362150'/><link rel='alternate' type='text/html' href='http://tabdelmaguid.blogspot.com/2009/10/does-waterfall-make-more-sense.html' title='Does Waterfall Make More Sense?'/><author><name>Tarek Abdelmaguid</name><uri>http://www.blogger.com/profile/11912000217230377978</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-2291554078837078852.post-5037519932228654623</id><published>2009-09-09T17:39:00.001-05:00</published><updated>2009-09-09T17:41:54.722-05:00</updated><title type='text'>Thin Slice vs. Layer-wise, Or Depth-first vs. Width first</title><content type='html'>Agilists always advocate for incrementally  developing a thin slice of the application, in the form of a user story, that implements end-to-end changes that are required to deliver business value to the customer. This will normally entail changes to the UI, front-end logic, back-end components, databases, service interfaces, etc. This process results in the end user receiving value for every story delivered. The customer gets this value early, while developers have to manage only one small change at a time, and significantly reducing code integration overhead.&lt;br /&gt;&lt;span style="font-weight: bold; font-style: italic;"&gt;But what about efficiency?&lt;/span&gt;&lt;br /&gt;Some will argue that working on different layers requires different skills, and that there is a waste incurred in task switching, e.g., switching from working on the UI to working on the back end. It can be demonstrated that working width-first, as in developing 10 UI components (A1, A2, A3, ...), , then 10 back end components (B1, B2, B3, ...), etc., will require less time than working depth-first (A1, B1, ...), then (A2, B2, ...).&lt;br /&gt;&lt;span style="font-style: italic; font-weight: bold;"&gt;But then, who's right?&lt;/span&gt;&lt;br /&gt;In fact, both are. It is indeed more efficient to work on the same task type, since there is less task switching, and there are mass production techniques that could be employed. However, the customer gets value much later, process feedback is delayed, and there are more integration work and problems that are only discovered late in the process.&lt;br /&gt;It so happens that in software development, the Agile method is far more superior. The benefits of an Agile process increase in line with the rate of change in the process.&lt;br /&gt;&lt;span style="font-style: italic; font-weight: bold;"&gt;But what about efficiency?&lt;/span&gt;&lt;br /&gt;To the non-agilists, it should be noted that efficiency isn't the point. Thinking mainly about efficiency distracts from the goal of delivering more value to the customer, at a faster pace. To concentrate on efficiently producing UI components, for example, increases waste by delivering more than the customer needs, by increasing the rework required to adapt to changing/better understood customer needs, by delaying feedback, and by increasing work in progress. This is a form of local optimization that negatively impacts the overall goal.&lt;br /&gt;But also, to the agilists, the efficiency argument should be understood. There will be opportunities during development to queue up similar tasks, and leverage  specialized skills, and mass production techniques, to gain immediate task efficiency.&lt;br /&gt;The idea, then, is to never let efficiency distract you from your gaol, and to only pursue it if it doesn't increase work-in-process, and doesn't delay feedback or customer value.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2291554078837078852-5037519932228654623?l=tabdelmaguid.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://tabdelmaguid.blogspot.com/feeds/5037519932228654623/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2291554078837078852&amp;postID=5037519932228654623' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2291554078837078852/posts/default/5037519932228654623'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2291554078837078852/posts/default/5037519932228654623'/><link rel='alternate' type='text/html' href='http://tabdelmaguid.blogspot.com/2009/09/thin-slice-vs-layer-wise-or-depth-first.html' title='Thin Slice vs. Layer-wise, Or Depth-first vs. Width first'/><author><name>Tarek Abdelmaguid</name><uri>http://www.blogger.com/profile/11912000217230377978</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-2291554078837078852.post-6853371625207068740</id><published>2009-07-24T17:43:00.004-05:00</published><updated>2009-07-24T18:22:41.893-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='LazyInitializationException'/><category scheme='http://www.blogger.com/atom/ns#' term='WebSphere Trace'/><category scheme='http://www.blogger.com/atom/ns#' term='Spring'/><category scheme='http://www.blogger.com/atom/ns#' term='commons ToStringBuilder'/><category scheme='http://www.blogger.com/atom/ns#' term='Hibernate'/><title type='text'>WebSphere Trace, Spring, commons ToStringBuilder, Hibernate, and LazyInitializationException</title><content type='html'>We've seen the exception below, because WebSphere diagnostics and tracing was enabled.&lt;br /&gt;We disabled it by editing the logging properties from WebSphere console/Logs and Trace/select your server's/select Diagnostics Trace Server/Runtime/click Change Log Detail Levels, then editing logging information, and removing unneeded packages after "*=info:" ...&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:130%;"&gt;Stack trace:&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;[2009-07-23 15:56:10,078] WebContainer : 1651 org.hibernate.LazyInitializationException ERROR - could not initialize proxy - no Session&lt;br /&gt;org.hibernate.LazyInitializationException: could not initialize proxy - no Session&lt;br /&gt;    at org.hibernate.proxy.AbstractLazyInitializer.initialize(AbstractLazyInitializer.java:86)&lt;br /&gt;    at org.hibernate.proxy.AbstractLazyInitializer.getImplementation(AbstractLazyInitializer.java:140)&lt;br /&gt;    at org.hibernate.proxy.pojo.javassist.JavassistLazyInitializer.invoke(JavassistLazyInitializer.java:190)&lt;br /&gt;    at com.mycompany.myproject.domain.MyObject_$$_javassist_20.hashCode(MyObject_$$_javassist_20.java)&lt;br /&gt;    at org.apache.commons.lang.builder.HashCodeBuilder.append(HashCodeBuilder.java:452)&lt;br /&gt;    at org.apache.commons.lang.builder.HashCodeBuilder.reflectionAppend(HashCodeBuilder.java:413)&lt;br /&gt;    at org.apache.commons.lang.builder.HashCodeBuilder.reflectionHashCode(HashCodeBuilder.java:379)&lt;br /&gt;    at org.apache.commons.lang.builder.HashCodeBuilder.reflectionHashCode(HashCodeBuilder.java:155)&lt;br /&gt;    at com.mycompany.myproject.domain.DomainObject.hashCode(DomainObject.java:14)&lt;br /&gt;    at java.util.HashMap.hash(HashMap.java:324)&lt;br /&gt;    at java.util.HashMap.containsKey(HashMap.java:470)&lt;br /&gt;    at java.util.HashSet.contains(HashSet.java:207)&lt;br /&gt;    at org.apache.commons.lang.builder.ReflectionToStringBuilder.isRegistered(ReflectionToStringBuilder.java:135)&lt;br /&gt;    at org.apache.commons.lang.builder.ReflectionToStringBuilder.appendFieldsIn(ReflectionToStringBuilder.java:660)&lt;br /&gt;    at org.apache.commons.lang.builder.ReflectionToStringBuilder.toString(ReflectionToStringBuilder.java:867)&lt;br /&gt;    at org.apache.commons.lang.builder.ReflectionToStringBuilder.toString(ReflectionToStringBuilder.java:339)&lt;br /&gt;    at org.apache.commons.lang.builder.ReflectionToStringBuilder.toString(ReflectionToStringBuilder.java:173)&lt;br /&gt;    at org.apache.commons.lang.builder.ToStringBuilder.reflectionToString(ToStringBuilder.java:124)&lt;br /&gt;    at com.mycompany.myproject.domain.DomainObject.toString(DomainObject.java:24)&lt;br /&gt;    at java.lang.String.valueOf(String.java:1505)&lt;br /&gt;    at java.util.AbstractCollection.toString(AbstractCollection.java:469)&lt;br /&gt;    at com.ibm.ws.webcontainer.srt.SRTServletRequest.setAttribute(SRTServletRequest.java:488)&lt;br /&gt;    at org.springframework.web.servlet.view.AbstractView.exposeModelAsRequestAttributes(AbstractView.java:337)&lt;br /&gt;    at org.springframework.web.servlet.view.InternalResourceView.renderMergedOutputModel(InternalResourceView.java:206)&lt;br /&gt;    at org.springframework.web.servlet.view.AbstractView.render(AbstractView.java:257)&lt;br /&gt;    at org.springframework.web.servlet.DispatcherServlet.render(DispatcherServlet.java:1183)&lt;br /&gt;    at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:902)&lt;br /&gt;    at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:807)&lt;br /&gt;    at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:571)&lt;br /&gt;    at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:511)&lt;br /&gt;    at javax.servlet.http.HttpServlet.service(HttpServlet.java:763)&lt;br /&gt;    at javax.servlet.http.HttpServlet.service(HttpServlet.java:856)&lt;br /&gt;    at com.ibm.ws.webcontainer.servlet.ServletWrapper.service(ServletWrapper.java:1095)&lt;br /&gt;    at com.ibm.ws.webcontainer.servlet.ServletWrapper.service(ServletWrapper.java:1036)&lt;br /&gt;    at com.ibm.ws.webcontainer.filter.WebAppFilterChain.doFilter(WebAppFilterChain.java:118)&lt;br /&gt;    at com.ibm.ws.webcontainer.filter.WebAppFilterChain._doFilter(WebAppFilterChain.java:87)&lt;br /&gt;    at com.ibm.ws.webcontainer.filter.WebAppFilterManager.doFilter(WebAppFilterManager.java:832)&lt;br /&gt;    at com.ibm.ws.webcontainer.filter.WebAppFilterManager.doFilter(WebAppFilterManager.java:679)&lt;br /&gt;    at com.ibm.ws.webcontainer.servlet.ServletWrapper.handleRequest(ServletWrapper.java:565)&lt;br /&gt;    at com.ibm.ws.wswebcontainer.servlet.ServletWrapper.handleRequest(ServletWrapper.java:478)&lt;br /&gt;    at com.ibm.ws.webcontainer.webapp.WebAppRequestDispatcher.forward(WebAppRequestDispatcher.java:321)&lt;br /&gt;    at org.springframework.web.servlet.view.InternalResourceView.renderMergedOutputModel(InternalResourceView.java:236)&lt;br /&gt;    at org.springframework.web.servlet.view.AbstractView.render(AbstractView.java:257)&lt;br /&gt;    at org.springframework.web.servlet.DispatcherServlet.render(DispatcherServlet.java:1183)&lt;br /&gt;    at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:902)&lt;br /&gt;    at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:807)&lt;br /&gt;    at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:571)&lt;br /&gt;    at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:511)&lt;br /&gt;    at javax.servlet.http.HttpServlet.service(HttpServlet.java:763)&lt;br /&gt;    at javax.servlet.http.HttpServlet.service(HttpServlet.java:856)&lt;br /&gt;    at com.ibm.ws.webcontainer.servlet.ServletWrapper.service(ServletWrapper.java:1095)&lt;br /&gt;    at com.ibm.ws.webcontainer.servlet.ServletWrapper.service(ServletWrapper.java:1036)&lt;br /&gt;    at com.ibm.ws.webcontainer.filter.WebAppFilterChain.doFilter(WebAppFilterChain.java:145)&lt;br /&gt;    at com.opensymphony.module.sitemesh.filter.PageFilter.parsePage(PageFilter.java:119)&lt;br /&gt;    at com.opensymphony.module.sitemesh.filter.PageFilter.doFilter(PageFilter.java:55)&lt;br /&gt;    at com.ibm.ws.webcontainer.filter.FilterInstanceWrapper.doFilter(FilterInstanceWrapper.java:186)&lt;br /&gt;    at com.ibm.ws.webcontainer.filter.WebAppFilterChain.doFilter(WebAppFilterChain.java:130)&lt;br /&gt;    at com.ibm.ws.webcontainer.filter.WebAppFilterChain._doFilter(WebAppFilterChain.java:87)&lt;br /&gt;    at com.ibm.ws.webcontainer.filter.WebAppFilterManager.doFilter(WebAppFilterManager.java:832)&lt;br /&gt;    at com.ibm.ws.webcontainer.filter.WebAppFilterManager.doFilter(WebAppFilterManager.java:679)&lt;br /&gt;    at com.ibm.ws.webcontainer.servlet.ServletWrapper.handleRequest(ServletWrapper.java:565)&lt;br /&gt;    at com.ibm.ws.wswebcontainer.servlet.ServletWrapper.handleRequest(ServletWrapper.java:478)&lt;br /&gt;    at com.ibm.ws.webcontainer.servlet.CacheServletWrapper.handleRequest(CacheServletWrapper.java:90)&lt;br /&gt;    at com.ibm.ws.webcontainer.WebContainer.handleRequest(WebContainer.java:748)&lt;br /&gt;    at com.ibm.ws.wswebcontainer.WebContainer.handleRequest(WebContainer.java:1461)&lt;br /&gt;    at com.ibm.ws.webcontainer.channel.WCChannelLink.ready(WCChannelLink.java:118)&lt;br /&gt;    at com.ibm.ws.http.channel.inbound.impl.HttpInboundLink.handleDiscrimination(HttpInboundLink.java:458)&lt;br /&gt;    at com.ibm.ws.http.channel.inbound.impl.HttpInboundLink.handleNewInformation(HttpInboundLink.java:387)&lt;br /&gt;    at com.ibm.ws.http.channel.inbound.impl.HttpICLReadCallback.complete(HttpICLReadCallback.java:102)&lt;br /&gt;    at com.ibm.ws.tcp.channel.impl.AioReadCompletionListener.futureCompleted(AioReadCompletionListener.java:165)&lt;br /&gt;    at com.ibm.io.async.AbstractAsyncFuture.invokeCallback(AbstractAsyncFuture.java:217)&lt;br /&gt;    at com.ibm.io.async.AsyncChannelFuture.fireCompletionActions(AsyncChannelFuture.java:161)&lt;br /&gt;    at com.ibm.io.async.AsyncFuture.completed(AsyncFuture.java:136)&lt;br /&gt;    at com.ibm.io.async.ResultHandler.complete(ResultHandler.java:195)&lt;br /&gt;    at com.ibm.io.async.ResultHandler.runEventProcessingLoop(ResultHandler.java:743)&lt;br /&gt;    at com.ibm.io.async.ResultHandler$2.run(ResultHandler.java:873)&lt;br /&gt;    at com.ibm.ws.util.ThreadPool$Worker.run(ThreadPool.java:1473)&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:130%;"&gt;Analysis&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;It seems that enabling logging for the package com.ibm.ws.webcontainer causes WebSphere to log request attributes. During view rendering, the call to request.setAttribute(), in Spring's AbstractView.exposeModelAsRequestAttributes() , which is implemented by com.ibm.ws.webcontainer.srt.SRTServletRequest.setAttribute(),  attempts to log model attributes by calling toString(). We add our domain objects as values for model attributes, and our DomainObject implements toString() using Apache commons ToStringBuilder, which recursively walks the whole object graph, causing all references to be initialized. This all happens outside the boundaries of a transaction, and hence we get the exception above for our lazily loaded references.&lt;br /&gt;&lt;br /&gt;Now this should be searchable, just in case ...&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2291554078837078852-6853371625207068740?l=tabdelmaguid.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://tabdelmaguid.blogspot.com/feeds/6853371625207068740/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2291554078837078852&amp;postID=6853371625207068740' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2291554078837078852/posts/default/6853371625207068740'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2291554078837078852/posts/default/6853371625207068740'/><link rel='alternate' type='text/html' href='http://tabdelmaguid.blogspot.com/2009/07/websphere-trace-spring-commons.html' title='WebSphere Trace, Spring, commons ToStringBuilder, Hibernate, and LazyInitializationException'/><author><name>Tarek Abdelmaguid</name><uri>http://www.blogger.com/profile/11912000217230377978</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-2291554078837078852.post-251812094935739467</id><published>2009-06-27T22:45:00.002-05:00</published><updated>2009-06-27T23:34:17.950-05:00</updated><title type='text'>The Mythical Man-Month</title><content type='html'>(So at last I read it ...)&lt;br /&gt;&lt;br /&gt;By Frederick P. Brooks, JR.&lt;br /&gt;An enjoyable read indeed. The book is for those with passion for software development, from someone who shares this passion.&lt;br /&gt;The book contains a good deal of timeless advice, although one might wonder how much of the book is relevant today. I'd offer that most of the book is. There has been times when I was puzzled by the content, and totally missed references to the machines, tools, and procedures. Nevertheless, it's amazing to see how much had changed, yet how much really didn't. In that regard, the discussion around essential (irreducible core complexity) and accidental difficulties (those pertaining to technology limitations, etc) is especially illuminating.&lt;br /&gt;Here are some useful pointers:&lt;br /&gt;&lt;a href="http://www.cs.unc.edu/%7Ebrooks/"&gt;The authors homepage&lt;/a&gt;&lt;br /&gt;&lt;a href="http://www.amazon.com/Mythical-Man-Month-Software-Engineering-Anniversary/dp/0201835959"&gt;On Amazon&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2291554078837078852-251812094935739467?l=tabdelmaguid.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://tabdelmaguid.blogspot.com/feeds/251812094935739467/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2291554078837078852&amp;postID=251812094935739467' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2291554078837078852/posts/default/251812094935739467'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2291554078837078852/posts/default/251812094935739467'/><link rel='alternate' type='text/html' href='http://tabdelmaguid.blogspot.com/2009/06/mythical-man-month.html' title='The Mythical Man-Month'/><author><name>Tarek Abdelmaguid</name><uri>http://www.blogger.com/profile/11912000217230377978</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-2291554078837078852.post-6541358147384746998</id><published>2009-04-19T12:44:00.002-05:00</published><updated>2009-04-19T13:14:05.451-05:00</updated><title type='text'>Book: Radical Project Management</title><content type='html'>(Note: this is a personal memory entry)&lt;br /&gt;(Note on Note: More on this note later)&lt;br /&gt;&lt;br /&gt;The book "Radical Project Management" by Rob Thomsett, is very interesting. It introduces a lot of good practices, that are indeed in wide adoption today. I'd recommend it, if not for the actual practices, then for the underlying message to project managers.&lt;br /&gt;The Thomsett group website: &lt;a href="http://www.thomsett.com.au/"&gt;http://www.thomsett.com.au/&lt;/a&gt;.&lt;br /&gt;Supporting material and articles can be found here: &lt;a href="http://www.thomsettinternational.com/"&gt;http://www.thomsettinternational.com/&lt;/a&gt;. Of note are &lt;a href="http://www.thomsettinternational.com/main/articles/path/pathology.htm"&gt;Project Pathology&lt;/a&gt;, and &lt;a href="http://www.thomsettinternational.com/main/articles/hot/games.htm"&gt;Estimation Games&lt;/a&gt;. This is not to discount other articles or the site, but these were specifically mentioned in the book.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2291554078837078852-6541358147384746998?l=tabdelmaguid.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://tabdelmaguid.blogspot.com/feeds/6541358147384746998/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2291554078837078852&amp;postID=6541358147384746998' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2291554078837078852/posts/default/6541358147384746998'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2291554078837078852/posts/default/6541358147384746998'/><link rel='alternate' type='text/html' href='http://tabdelmaguid.blogspot.com/2009/04/book-radical-project-management.html' title='Book: Radical Project Management'/><author><name>Tarek Abdelmaguid</name><uri>http://www.blogger.com/profile/11912000217230377978</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-2291554078837078852.post-6837466854990779067</id><published>2008-10-26T14:07:00.003-05:00</published><updated>2008-10-26T14:45:35.901-05:00</updated><title type='text'>The Ultimate Continuous Integration Tool</title><content type='html'>Warning: this entry is out there. I can not be blamed for wasting your brain cycles. However, by taking things to the extreme, some value may be gained.&lt;br /&gt;&lt;br /&gt;I'd like to continuously integrate all the code I write, and I want this to happen very continuously. And that would happen if my code is integrated on every key stroke.&lt;br /&gt;My IDE, the build machine (CI server), and the source control system will be very smart. Every time I type key on the keyboard, they will mark a revision of the full code base and start running the build. Let's call this code revision a candidate revision (CR). The build, of course, includes compiling the code, running all unit tests, perhaps even functional tests, and whatever else we want to include. If the build passes, the CR is automatically checked into source control. If the build doesn't pass, then the whole thread is ignored. Obviously, since I won't stop pounding on the keyboard, the very powerful build machine will be running multiple builds at the same time. After all, the computers are not yet that advanced, that we should expect the build machine to be able to run builds instantly. Oh well.&lt;br /&gt;At the same time, the system will be doing the reverse: It will be continuously merging all successful revisions from source control (SC) into my local code base, since everyone else is so productively writing code at the same time as I am.&lt;br /&gt;How could this work? Well, my IDE will be so well integrated with the super powerful CI server. The CI server will be the single authority deciding whether a build is passing, and thus would be checked into source control. The CI server will be running many builds at the same time, but will act as if all the changes occurred sequentially.&lt;br /&gt;The CI server will be receiving a stream of candidate revisions (ok, just deltas) from multiple developer machines. It always starts from a successful source code revision (CR0). Based on the order a candidate revision (CR1) is received, it will run the build and determine if it should be checked into SC. At the same time, the CI server is also processing other candidate revisions (CR2, 3, ...) from myself and other developers. The CI server will be running multiple builds at the same time: a duild for CR1, another for CR2 (on top of CR1), another for CR2 on top of CR0, in case CR1 fails, and so on.&lt;br /&gt;&lt;br /&gt;Here is a diagram of the process:&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_KOmnh5DdiUE/SQTEmwZQhmI/AAAAAAAAARI/xoBQ3Kt7z7U/s1600-h/Slide1.jpg"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 400px; height: 300px;" src="http://2.bp.blogspot.com/_KOmnh5DdiUE/SQTEmwZQhmI/AAAAAAAAARI/xoBQ3Kt7z7U/s400/Slide1.jpg" alt="" id="BLOGGER_PHOTO_ID_5261546434780497506" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;This would be really nice. Don't you think?&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2291554078837078852-6837466854990779067?l=tabdelmaguid.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://tabdelmaguid.blogspot.com/feeds/6837466854990779067/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2291554078837078852&amp;postID=6837466854990779067' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2291554078837078852/posts/default/6837466854990779067'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2291554078837078852/posts/default/6837466854990779067'/><link rel='alternate' type='text/html' href='http://tabdelmaguid.blogspot.com/2008/10/ultimate-continuous-integration-tool.html' title='The Ultimate Continuous Integration Tool'/><author><name>Tarek Abdelmaguid</name><uri>http://www.blogger.com/profile/11912000217230377978</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/_KOmnh5DdiUE/SQTEmwZQhmI/AAAAAAAAARI/xoBQ3Kt7z7U/s72-c/Slide1.jpg' height='72' width='72'/><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2291554078837078852.post-9149947753464308108</id><published>2008-10-19T22:29:00.003-05:00</published><updated>2008-10-19T22:42:16.936-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ssh rsa dsa private public key mac os x leopard'/><title type='text'>ssh connection with public/private key pair not working on Leopard?</title><content type='html'>&lt;span style="font-weight: bold;"&gt;Solution&lt;/span&gt;: try passing the private key file to the ssh command using -i:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:Courier New;"&gt; ssh -i identity_file user@server &lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;The problem&lt;/span&gt;&lt;br /&gt;I tried setting up a DSA public/private key pair on Leopard. but I didn't accept the default private key file name. Leopard didn't prompt me for the passphrase, and instead was prompted for the normal username/password.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2291554078837078852-9149947753464308108?l=tabdelmaguid.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://tabdelmaguid.blogspot.com/feeds/9149947753464308108/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2291554078837078852&amp;postID=9149947753464308108' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2291554078837078852/posts/default/9149947753464308108'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2291554078837078852/posts/default/9149947753464308108'/><link rel='alternate' type='text/html' href='http://tabdelmaguid.blogspot.com/2008/10/ssh-connection-with-publicprivate-key.html' title='ssh connection with public/private key pair not working on Leopard?'/><author><name>Tarek Abdelmaguid</name><uri>http://www.blogger.com/profile/11912000217230377978</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-2291554078837078852.post-6427743451267457526</id><published>2008-10-19T21:50:00.005-05:00</published><updated>2008-10-19T22:28:24.124-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='knowledge sharing development team'/><title type='text'>Project Development Knowledge: Sharing and Enduring</title><content type='html'>&lt;a href="http://tabdelmaguid.blogspot.com/2008/10/keeping-project-development-knowledge.html"&gt;The previous entry&lt;/a&gt; introduced the problem. The following is a discussion around practices that can help address it.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Standups&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Daily standup meetings [1], aka daily scrums, are a great way for the team to share information about the current tasks being implemented by different team members. It's a quick forum, at the end of which, each team member will have basic knowledge of what other team members are up to. This can be very effective in eliminating duplicate efforts, as well as helping team members relate to other work affecting their own. Team members who notice the potential for cooperation and knowledge sharing during the standup, should get together after the meeting to carry on with further, more detailed examination of their work.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Pair programming&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Controversial as it may be, this practice is very effective in achieving higher team productivity through continuous knowledge sharing. The risk of the knowledge leaving the team is greatly reduced. And if we enhance this practice by frequent pair rotation, it's even more effective, as it spreads more knowledge throughout the development team, and it encourages cross-pollination of ideas.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Colocation&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Having to communicate information to other team members highlights a hand-off transition, that is better avoided. It's much better if all the team is there, witnessing and participating firsthand the effort underway, rather than being communicated what happened. Colocation of the team, or as much of the team as possible, is very effective at eliminating that need. And when information is communicated within a co-located team, it's at least an order of magnitude more effective, efficient, and complete, compared to other means.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Code reviews&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;When a pair spends a day modeling a piece of functionality, or refactoring a key part of the system, they are likely to want to tell other team members about it. Invariably, everyone in the team is interested to know what others are doing, and how certain problems are being addressed. While pair rotation helps here, getting the whole team to participate in a code review session can achieve some of this benefit to a wider audience. It's also a great forum for seeking guidance, sharing opinions, and exploring novel ways to address issues.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Automation&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Automating a certain task is an excellent way of sharing how it's done. Automation enables other team members to achieve the task, as well as serve as a documentation on how to accomplish it. For example, instead of me asking you how you query for the balance sheet, I can either use an automated script to get the information, or I could learn from the script how it can be done.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Self documenting, readable code&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Code can be considered a misnomer in this regard. We'd like to have code that does not require deciphering. We'd like to be able to know what the code is doing, and how it's done, clearly, with minimal effort. Herein lies an argument against clever programming techniques, that make it harder to reveal intent and side effects. Use code reviews to highlight less than obvious techniques, and have the team workout what it's most comfortable with. For example, if multiple team members are having issues with a piece of code that uses reflection, consider first informing more members how the piece works, and if necessary, consider an alternative implementation. Enabling higher team effectiveness is valued higher than programming cleverness.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Good check-in comments&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;These can go a long way in telling the story of project development. A check-in delta tells you what changed. The comment tells you why. When a developer has to go through source code history to understand the rationale behind a certain change or design decision, these comments can be very helpful in that regard. Try to be helpful to the consumer of the comment. For example,  instead of typing "implemented story #123", provide more information: "Story #123: added capability to classes x and y to access context z to achieve a and b."&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Wikis&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Project wikis have been around for while. Dare I say that they are the norm these days? Wikis are an excellent source of day-to-day knowledge needed by the team. For example, database connection information, URLs to local servers and useful documentation, pointers to tools, project and domain specific acronyms, etc. They are also useful in documenting repetitive development tasks, that are yet to be, or are difficult to automate.&lt;br /&gt;One particular use that I wish to highlight is documenting errors that are encountered during development, whether or not they are corrected. For example, if while starting a server we notice that we are getting an exception, we should start by documenting this fact. We then add the solution once we figure it out. Certain problems have the tendency to re-occur, while some are unlikely to occur once fixed. Nonetheless, a similar issue might arise and the fix may prove useful beyond the original use.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;A searchable, archived email list&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;I have not seen this one on many projects. However, a sizable portion of the project information is exchanged using emails. For example, feature discussions between developers and BAs, the resolution of design issues, technical announcements, in the form of the introduction of a new build tools or code libraries, and project course-changing decisions, to name a few. An automatically archived project specific email list that is searchable can be very valuable for future development. Using this knowledge base can aid in understanding why things came to be the way they are.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;This list isn't exhaustive, and each one deserves its own discussion. I meant to hint and introduce. None of these practices preclude another, and you can attempt all of them.&lt;br /&gt;A bit of warning though: do not over do any of these, and keep the practices light. After all, we are after agility. Don't let these, or any other practices slow down the gemba.&lt;br /&gt;&lt;br /&gt;As usual, I welcome, and appreciate, the reader's feedback.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;[1] http://martinfowler.com/articles/itsNotJustStandingUp.html&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2291554078837078852-6427743451267457526?l=tabdelmaguid.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://tabdelmaguid.blogspot.com/feeds/6427743451267457526/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2291554078837078852&amp;postID=6427743451267457526' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2291554078837078852/posts/default/6427743451267457526'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2291554078837078852/posts/default/6427743451267457526'/><link rel='alternate' type='text/html' href='http://tabdelmaguid.blogspot.com/2008/10/project-development-knowledge-sharing.html' title='Project Development Knowledge: Sharing and Enduring'/><author><name>Tarek Abdelmaguid</name><uri>http://www.blogger.com/profile/11912000217230377978</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-2291554078837078852.post-8821302716659899808</id><published>2008-10-11T09:11:00.002-05:00</published><updated>2008-10-11T09:17:04.873-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='development knowledge'/><title type='text'>Keeping Project Development Knowledge: The Problem</title><content type='html'>This is a two part entry. This entry is an introduction to the problems caused by the loss of development knowledge, that face  project teams. The second part will examine various practices and techniques that can be used to tackle these problems.&lt;br /&gt;&lt;br /&gt;By project development knowledge, I'm referring to the multitude of information required, and acquired, by the development team, that pertain to the project. This includes technical knowledge, concerning languages and tools, as well as development methodology, processes, business domain, etc.&lt;br /&gt;&lt;br /&gt;Is there a problem? To help answer this question, consider the following events:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;A long time team member is leaving the team.&lt;/li&gt;&lt;li&gt;An issue is identified with the software that the team is building. However, we know we've encountered this problem before. If only we can remember how we solved it.&lt;/li&gt;&lt;li&gt;A new team member is joining the team, and he's started asking questions about the project, or is encountering some issues setting up his environment, and we have to rely on memory or some veteran team members to answer these questions.&lt;/li&gt;&lt;li&gt;A BA notices that he is being asked the same question more than once by different team members.&lt;/li&gt;&lt;li&gt;The tech lead is noticing that the team members are not following coding standards, time and again.&lt;/li&gt;&lt;li&gt;Two team members are working separately on fixing the same problem.&lt;/li&gt;&lt;li&gt;A new team member is brought to take care of a code module, that no other team member knows about. For example, when code is inherited from another software company after their contract has ended, a team member is replacing another who was working alone on a piece of code, or when a certain area of the code has been dormant for a long time, that now requires changes.&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;These events represent times where project information is missed. This can be attributed to the following reasons:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Information leaves the team, along with parting team members.&lt;/li&gt;&lt;li&gt;Information is forgotten, thus, it needs to be reproduced.&lt;/li&gt;&lt;li&gt;The information exists, but is not readily accessible; the information is not easily communicated.&lt;/li&gt;&lt;li&gt;The information exists, but we don't know that.&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;How do we tackle these problems? The next entry will discuss some approaches that can help address some of these problems.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2291554078837078852-8821302716659899808?l=tabdelmaguid.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://tabdelmaguid.blogspot.com/feeds/8821302716659899808/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2291554078837078852&amp;postID=8821302716659899808' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2291554078837078852/posts/default/8821302716659899808'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2291554078837078852/posts/default/8821302716659899808'/><link rel='alternate' type='text/html' href='http://tabdelmaguid.blogspot.com/2008/10/keeping-project-development-knowledge.html' title='Keeping Project Development Knowledge: The Problem'/><author><name>Tarek Abdelmaguid</name><uri>http://www.blogger.com/profile/11912000217230377978</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-2291554078837078852.post-4961611707444357293</id><published>2008-09-28T22:32:00.004-05:00</published><updated>2008-09-28T22:38:31.721-05:00</updated><title type='text'>Building and Maintaining Outstanding Systems</title><content type='html'>A quote from "The Leader's Handbook", by Peter &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_0"&gt;Scholtes&lt;/span&gt;, under 'Outstanding Systems versus Outstanding People', subtitle 'What do leaders do?':&lt;br /&gt;&lt;br /&gt;&lt;blockquote&gt;Seek to create and maintain outstanding systems. The ideal is: outstanding systems, achieving excellent results, with the ordinary efforts of average people.&lt;/blockquote&gt;&lt;br /&gt;Pretty insightful, challenging, and most notably, sustainable.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2291554078837078852-4961611707444357293?l=tabdelmaguid.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://tabdelmaguid.blogspot.com/feeds/4961611707444357293/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2291554078837078852&amp;postID=4961611707444357293' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2291554078837078852/posts/default/4961611707444357293'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2291554078837078852/posts/default/4961611707444357293'/><link rel='alternate' type='text/html' href='http://tabdelmaguid.blogspot.com/2008/09/building-and-maintaining-outstanding.html' title='Building and Maintaining Outstanding Systems'/><author><name>Tarek Abdelmaguid</name><uri>http://www.blogger.com/profile/11912000217230377978</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-2291554078837078852.post-8700441979750270661</id><published>2008-08-22T21:34:00.002-05:00</published><updated>2008-08-22T21:52:05.529-05:00</updated><title type='text'>Incremental Release Always Advisable? Not so fast!</title><content type='html'>The benefits of the Agile practice of incrementally releasing software are well established. However, there are certain situations where it may not be the best fit for your client. This post considers one such scenario.&lt;br /&gt;&lt;br /&gt;In our example, the client is replacing an existing old system, which is currently being used to run the client's business. The client is launching a new project to adapt a new software package to address many of the shortcomings of the current system. However, the package will require a non trivial amount of customization. At this point, there are two options:&lt;br /&gt;1- Implement all the customizations necessary to the new package, migrate the data, then deploy the new package into production, and start using it instead of the old application.&lt;br /&gt;2- Implement a minimal set of of customization to the new package, and release that into production. Use the new customized functionality in the new system, while completing the business process in the old system. Once the functionality has stabilized, customize the next step in the business process, deploy it to production, and so on.&lt;br /&gt;&lt;br /&gt;The benefits of the second approach are well established, and there is no need to reiterate them. I'd like to concentrate on some of the challenges of this option.&lt;br /&gt;&lt;br /&gt;To aid the discussion, assume that the business process for the client includes the general steps A, B, and C. And assume that we start by customizing the new package to fulfill the needs of step A in the process, continuing B and C in the old system. To be able to do this, we have to perform the following:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Transfer the data captured in the new system to the old system, after completing step A.&lt;/li&gt;&lt;li&gt;Figure out how to trigger the data transfer from the new system to the old: at which event should the data be transferred to the old system?&lt;/li&gt;&lt;li&gt;Decide what to do if the data may be changed in the new system after it has been transferred to the old system: Should we push the data to the old system every time it changes? If not, at what events should this happen? Is it acceptable to prevent further data changes in the new system after it has been transferred?&lt;/li&gt;&lt;li&gt;Work out the changes to the reporting needs of the client: Which system is able to provide which pieces of the data?&lt;/li&gt;&lt;li&gt;Figure out the implications of having the data unavailable in the old system until it has been transferred. For example, a data entry to capture the requirements of step A in the process might be captured in the new system, but the data will not be available in the old system until it has been transferred. Will this have any implications on the business?&lt;/li&gt;&lt;li&gt;Work out the changes to the client's business process. For example, is there double data entry required to maintain the consistency of the configuration data? How and when should users use the new system as opposed to the old system?&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;We also may have to answer the following questions:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;If there is a data validation step that needs to be performed as part of step A, that requires the knowledge of previous transactions on related data from the old system, how will it be performed?&lt;/li&gt;&lt;li&gt;Is there a need to sync data changes from the old system back to the new system?&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;There are also requirements on data maintenance. The data in the old and the new system must be kept in sync. Otherwise, the syncing operations will fail to map the data to the correct business entities.&lt;br /&gt;&lt;br /&gt;It should also be noted that the new system may not be amenable to syncing out of the box, and that certain changes to the way it functions may be necessary to allow the integration to work properly. For example, we may need to introduce a new status to mark whether or not the data has been, or is available to be, transferred to the old system.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Implications of the phased release approach&lt;/span&gt;&lt;br /&gt;Given the above, we can see that the second approach has the following implications, as opposed to the first approach:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;The client can only implement a limited data restructuring or data cleanup in the new system, because this may break, or make very difficult, the process of mapping data between the new and the old system.&lt;/li&gt;&lt;li&gt;It also follows that there are certain realizations of the benefits of moving to the new system will be delayed, until all the steps in the process have been successfully moved to the new system.&lt;/li&gt;&lt;li&gt;In a similar vein, the business benefits that may be gained, or process improvements that can be attained, by moving to the new system will be delayed, because the new system will be constrained by the need to synchronize data to, and conform to the business process imposed by, the old system.&lt;/li&gt;&lt;li&gt;The old system will need to be up and running for a longer period of time, because the time required to build the customizations to the new system, plus coding for the synchronization logic, will require more time than simply implementing the customizations, then go live. I am assuming here that the team size remains the same.&lt;/li&gt;&lt;li&gt;A careful consideration of the client's budget is due. If the budget is tight, there may not be enough slack to accommodate the extra effort required to add the integration functionality between the new and the old systems.&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;And you should also consider:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;The cost to the business, in terms of delayed ROI, and time to market benefits, resulting from delaying release time until all the necessary functionality is developed in the new system. Your client may not have sufficient incentive to warrant the cost.&lt;/li&gt;&lt;li&gt;The risk of deploying all the functionality of the new system in one step. It may be the case that your client has ways of reducing the risk to the business, that makes the risk/reward balance weigh in favor of this option. For example, the client may have acceptable manual processes, or is able to revert to the old system, if part of the functionality in the new system is encountering issues.&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Conclusion&lt;/span&gt;&lt;br /&gt;There are certain situations where an incremental release to production may not be advisable. Although there is evident value associated with releasing fast, the cost and risks associated with this option may outweigh the benefits. Other approaches may weigh better on this scale. This entry introduced a situation where there are factors at play that should be considered before choosing an approach. Such factors include the client's budget, the benefits of going live faster, the cost of developing the integration code, the cost of delaying the release, and the risk in releasing all the functionality of the new system in one step.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2291554078837078852-8700441979750270661?l=tabdelmaguid.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://tabdelmaguid.blogspot.com/feeds/8700441979750270661/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2291554078837078852&amp;postID=8700441979750270661' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2291554078837078852/posts/default/8700441979750270661'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2291554078837078852/posts/default/8700441979750270661'/><link rel='alternate' type='text/html' href='http://tabdelmaguid.blogspot.com/2008/08/incremental-release-always-advisable.html' title='Incremental Release Always Advisable? Not so fast!'/><author><name>Tarek Abdelmaguid</name><uri>http://www.blogger.com/profile/11912000217230377978</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-2291554078837078852.post-7525332050584002266</id><published>2007-10-14T14:52:00.000-05:00</published><updated>2007-10-14T17:20:47.050-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='sharing information'/><category scheme='http://www.blogger.com/atom/ns#' term='communication'/><category scheme='http://www.blogger.com/atom/ns#' term='team dynamics'/><category scheme='http://www.blogger.com/atom/ns#' term='pairing'/><title type='text'>Make Yourself Dispensable</title><content type='html'>There is a lot of unique dynamics to teams that run for a long period of time. Eventually, as people roll on and off the team, some team members will have more information that others. Some members will have a wealth of technical and non-technical information, and their departure can leave the team less confident about its ability to make progress without taking a hit on productivity.&lt;br /&gt;More knowledgeable team members have an extra responsibility. The burden mainly lies on them to share their information with other members, and to make themselves more dispensable.&lt;br /&gt;While this goes against the common wisdom of job security prevalent in many environments, smart developers do not want to be stuck on the same project for an extended period of time. However, this is typically challenging to achieve. Here are some ideas:&lt;br /&gt;&lt;ol&gt;&lt;li&gt;Make sure you always pair on the more difficult tasks.&lt;/li&gt;&lt;li&gt;If you find yourself the only goto person for certain tasks, make sure you have a pair. And the next time they come your way, delegate.&lt;/li&gt;&lt;li&gt;Get information out of your head to the team's wiki, especially those questions you are the only one able to answer.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Instead of signing up for difficult tasks, let others dive in, and support them instead.&lt;/li&gt;&lt;li&gt;Automate your routine tasks. When asked to do something, deliver a do-it-yourself tool instead of, well, doing it.&lt;/li&gt;&lt;li&gt;Take some time off and see if you get any phone calls :-)&lt;br /&gt;&lt;/li&gt;&lt;/ol&gt;Another issue with projects running for a long time is maintaining team history, in terms of lessons learned, how issues were resolved, etc. Let that be the subject of another post.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2291554078837078852-7525332050584002266?l=tabdelmaguid.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://tabdelmaguid.blogspot.com/feeds/7525332050584002266/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2291554078837078852&amp;postID=7525332050584002266' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2291554078837078852/posts/default/7525332050584002266'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2291554078837078852/posts/default/7525332050584002266'/><link rel='alternate' type='text/html' href='http://tabdelmaguid.blogspot.com/2007/10/make-yourself-dispensable.html' title='Make Yourself Dispensable'/><author><name>Tarek Abdelmaguid</name><uri>http://www.blogger.com/profile/11912000217230377978</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry></feed>
