<?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-356226683788078026</id><updated>2012-01-28T11:06:48.407-08:00</updated><category term='non-recurring meetings'/><category term='Windows Service file download rename renaming automatic disambiguate unique'/><category term='legacy code large scale eclipse single source root cycles cyclic dependencies projects'/><category term='legacy code large scale eclipse single source root projects'/><category term='flow state'/><category term='distraction'/><category term='mandatory meetings'/><category term='Android Eclipse multiple projects unit tests Verify error class resolved by unexpected DEX error IllegalAccessError cross-loader access from pre-verified class'/><category term='legacy code large scale Eclipse Perforce single source root projects'/><category term='eclipse plugin java dependency analysis analyzer static analysis reports'/><category term='unit testing utilities 100% coverage high coverage open source'/><category term='recurring meetings'/><category term='interruptions'/><category term='time management'/><category term='open cubicles'/><category term='legacy code'/><category term='eclipse plugin java dependency analysis analyzer static analysis'/><category term='cube farms'/><category term='flow'/><category term='coverage tools Clover EMMA JaCoCo EclEmma Cobertura JMockit Google Android'/><category term='legacy code large scale Eclipse single source root runtime classes linked resources'/><category term='Android reuse reusable layering'/><category term='programmer productivity'/><category term='legacy code large scale eclipse single source root links projects'/><category term='cognition'/><category term='open cubes'/><category term='noise'/><title type='text'>Software, Technology, and Science</title><subtitle type='html'></subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://jimshowalter.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/356226683788078026/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://jimshowalter.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>Jim Showalter</name><uri>http://www.blogger.com/profile/01963552914376132590</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>23</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-356226683788078026.post-924510454341774712</id><published>2012-01-28T11:06:00.000-08:00</published><updated>2012-01-28T11:06:13.089-08:00</updated><title type='text'>The Tyranny Of Extroverts</title><content type='html'>Here's a book that provides insight into why some people love open cubicles and a highly collaborative/noisy environment, and others don't:&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;a href="http://www.amazon.com/exec/obidos/ASIN/0307352145/"&gt;http://www.amazon.com/exec/obidos/ASIN/0307352145/&lt;/a&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;It's unfortunate that the extroverts got the upper hand, because it's easy to work as an extrovert in an environment designed for introverts, but the converse is not true.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;The author lists some contributions made by introverts. For example, the theory of relativity. Who knows what other contributions we're forfeiting, or at least slowing down, by creating environments in which introverts cannot be productive?&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/356226683788078026-924510454341774712?l=jimshowalter.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jimshowalter.blogspot.com/feeds/924510454341774712/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://jimshowalter.blogspot.com/2012/01/tyranny-of-extroverts.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/356226683788078026/posts/default/924510454341774712'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/356226683788078026/posts/default/924510454341774712'/><link rel='alternate' type='text/html' href='http://jimshowalter.blogspot.com/2012/01/tyranny-of-extroverts.html' title='The Tyranny Of Extroverts'/><author><name>Jim Showalter</name><uri>http://www.blogger.com/profile/01963552914376132590</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-356226683788078026.post-4652386753035185249</id><published>2010-05-31T18:54:00.000-07:00</published><updated>2010-08-08T10:09:13.343-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='programmer productivity'/><category scheme='http://www.blogger.com/atom/ns#' term='open cubes'/><category scheme='http://www.blogger.com/atom/ns#' term='noise'/><category scheme='http://www.blogger.com/atom/ns#' term='cube farms'/><category scheme='http://www.blogger.com/atom/ns#' term='distraction'/><category scheme='http://www.blogger.com/atom/ns#' term='flow'/><category scheme='http://www.blogger.com/atom/ns#' term='open cubicles'/><title type='text'>Open Cubicles Must Die</title><content type='html'>&lt;span class="text3"&gt;&lt;/span&gt;&lt;blockquote&gt;&lt;span class="text3"&gt;"The cynic knows the price of everything and the  value of nothing." - Oscar Wilde&lt;/span&gt;&lt;/blockquote&gt;In 1987, Tom DeMarco and Timothy Lister published the first edition of "Peopleware: Productive Projects and Teams".&lt;br /&gt;&lt;br /&gt;The book discusses many reasons software projects fail, and provides numerous recommendations for making projects succeed.&lt;br /&gt;&lt;br /&gt;Part II of the book discusses the effect a bad office environment has on productivity, and recommends (among other suggestions) private offices as a significant productivity enhancer. The book provides &lt;span style="font-style: italic;"&gt;quantitative&lt;/span&gt; evidence to substantiate the recommendation. And the book eviscerates the productivity claims of cubicleware vendors, which are shown to have no substantiation (the book calls those claims "proof by repeated assertion").&lt;br /&gt;&lt;br /&gt;Fittingly, the book is out of print.&lt;br /&gt;&lt;br /&gt;If anything, in the decades since the book was published, things have gotten worse (other than getting rid of P.A. systems). We are in the grip of an industry-wide pathology that produces expensive, flow-disrupting buildings.&lt;br /&gt;&lt;br /&gt;How did we get here?&lt;br /&gt;&lt;br /&gt;A lot of it has a lot to do with the counting of beans.&lt;br /&gt;&lt;br /&gt;It is easy for a bean counter to count tangible things, like square feet.&lt;br /&gt;&lt;br /&gt;It is not easy for a bean counter to count intangible things, like lost productivity due to a noisy work environment yanking programmers out of flow.&lt;br /&gt;&lt;br /&gt;Suppose at some point a bean counter notices that their company spends more for facilities than "comparable" companies spend. This seems to the bean counter like fiduciary irresponsibility, so the bean counter launches an investigation.&lt;br /&gt;&lt;br /&gt;Because the bean counter cannot count intangibles, the bean counter does a poor job of counting beans, and works up an Excel spreadsheet that shows how, if they get rid of walls and doors, and reduce the space each programmer gets, and eliminate bookshelves, and generally pack programmers into "pods" where they're practically sitting in each other's laps, the company will save a bundle.&lt;br /&gt;&lt;br /&gt;On paper at least.&lt;br /&gt;&lt;br /&gt;Intrigued by the putative savings to be had, the exec staff--sitting in their capacious, private, quiet offices--decides to engage the services of a cubicleware vendor to "work up" some designs for how the building could look. (Note that open cubicles are by this point a foregone conclusion, and that by involving a cubicleware vendor as the consultant, we have an instance of bid rigging so egregious that if this was a government contract somebody would go to jail.)&lt;br /&gt;&lt;br /&gt;The designs are very slick. Spiffy in color, appealing in the abstract, the revamped building will "facilitate collaboration" (and who would question the need for that?), foster "inter-departmental serendipity" (which also sounds desirable, whatever that is), and so forth.&lt;br /&gt;&lt;br /&gt;Nobody asks the programmers for their input. Or they do ask, but when the programmers say they want private offices so they can focus on work, this is dismissed as "impractical", even though drywall is cheaper than cubicleware.&lt;br /&gt;&lt;br /&gt;The building is revamped, the programmers move into it, and are pissed off because they feel like they're regarded as interchangeable, revenue-producing, chunks of meat. Morale drops and productivity goes into a tailspin.&lt;br /&gt;&lt;br /&gt;Adding insult to injury, the company newsletter makes a big deal about how the building, in a triumph of form over function, won an &lt;a href="http://www.aia.org/"&gt;AIA&lt;/a&gt; award for "design excellence".&lt;br /&gt;&lt;br /&gt;Those programmers who stick around find ways to circumvent the limitations of the building. For example, they take refuge in the server room (lots of white noise), or work at home.&lt;br /&gt;&lt;br /&gt;But these strategies ultimately backfire, because the bean counter's minions notice that a lot of cubicles--the ones occupied by programmers hiding in the server room or working at home--are empty, and conclude that the building was in fact &lt;span style="font-style: italic;"&gt;overprovisioned&lt;/span&gt;--that there could have been smaller cubicles, and fewer of them. Inevitably, the bean counter concludes that cubicles shouldn't even be allocated to individual programmers, but instead should come from a pool, first-come/first-served.&lt;br /&gt;&lt;br /&gt;Because programmers are now sharing keyboards and mice, &lt;a href="http://www.informationweek.com/news/hardware/peripherals/showArticle.jhtml?articleID=207501332"&gt;they share flu germs&lt;/a&gt;, and occupancy rates go down again. As does productivity.&lt;br /&gt;&lt;br /&gt;To make up for the loss of productivity, the company needs to hire more programmers. But where to put them? Clearly cubicles take up too much room. Programmers should just work on long tables, like medieval craftsmen.&lt;br /&gt;&lt;br /&gt;Meanwhile, the aggressive reduction in facilities costs is noticed by other companies' bean counters, who don't want to look like spendthrifts based on the latest "comparables".&lt;br /&gt;&lt;br /&gt;And so continues the industry-wide death spiral.&lt;br /&gt;&lt;br /&gt;Another reason we have open cubicles is due to differences between how programmers work and how the execs making the decisions work.&lt;br /&gt;&lt;br /&gt;Execs are people people. They like to meet new people. They like to shake hands. They like conversation. They're extroverts.&lt;br /&gt;&lt;br /&gt;Cubicleware vendors are also people people. They're in sales, so &lt;span style="font-style: italic;"&gt;of course&lt;/span&gt; they're extroverts.&lt;br /&gt;&lt;br /&gt;Programmers are, well, if you're a programmer you know what we are. It's not that we're necessarily ugly, or antisocial, but we're a lot more likely to send an IM to somebody 10 feet away than to get up and walk over there to talk. We like to get into flow and stay there. We like to solve problems.&lt;br /&gt;&lt;br /&gt;When people people design a work environment, they design it how they like to work. Which involves a lot of face-to-face interaction with other people, long phone conversations, open airy spaces, etc. It's almost the exact opposite of the conditions that foster flow.&lt;br /&gt;&lt;br /&gt;A few companies ago, Lisa was in a cube farm at a Fortune 50 company, concentrating, when some ninny of a people person walked into the area and, apparently discomfited by the unfamiliar sound of work getting done, said: "There isn't enough visitin' going on".&lt;br /&gt;&lt;br /&gt;Visitin'.&lt;br /&gt;&lt;br /&gt;Honestly?&lt;br /&gt;&lt;br /&gt;Another reason we have open cubicles is that private offices are seen as a "perk". But they're not a perk, they're a software-development &lt;span style="font-style: italic;"&gt;tool&lt;/span&gt;, and an effective one. Programmers don't care about status or prestige. They care about being effective. And they need good tools to do that.&lt;br /&gt;&lt;br /&gt;Unfortunately, many execs do care about status and prestige, and they see private offices as a perk. It's a problem of semiotics.&lt;br /&gt;&lt;br /&gt;Another reason we have open cubicles--and this is a self-inflicted wound--is that some of the newer methodologies emphasize collaboration, pair programming, etc.&lt;br /&gt;&lt;br /&gt;But one person's collaboration is another person's pointless interruption.&lt;br /&gt;&lt;br /&gt;When people are yakking around a programmer who's trying to get into flow or stay in flow, that constitutes &lt;span style="font-style: italic;"&gt;involuntary&lt;/span&gt; collaboration. It's like being on an airplane before they banned smoking--there was no way to escape.&lt;br /&gt;&lt;br /&gt;With private offices, programmers can always opt into collaboration by opening their door, sitting down in a communal work area, etc.&lt;br /&gt;&lt;br /&gt;Without private offices, programmers can't opt out of collaboration. Which is a shame, because at some point, somebody, somehow, has to actually write some code.&lt;br /&gt;&lt;br /&gt;But, you say, the programmer can always put on headphones. Yes, they can, except that page 78 of the second edition of Peopleware explains why that's a bad idea (a Cornell study showing that creativity is hampered by listening to music while programming).&lt;br /&gt;&lt;br /&gt;The saddest part of all of this is that if companies would focus on maximizing programmer productivity instead of on minimizing facilities costs, they could accomplish a lot more work with far fewer programmers, which would save so much money in salaries it would dwarf the incremental cost of private offices.&lt;br /&gt;&lt;br /&gt;Penny-wise, pound foolish.&lt;br /&gt;&lt;br /&gt;Not all companies make this mistake. For example, when Adobe was building its headquarters in San Jose, they asked the programmers what they wanted, and then did something crazy: they listened. (Guess what the programmers wanted.)&lt;br /&gt;&lt;br /&gt;Sometimes I get the argument that young programmers prefer open cubicles and more collaboration, but how would young programmers know? Did a lot of them previously work in large, quiet, private offices? Doubtful--cubiclitis has been infecting the industry since the 1960s, which is longer than young programmers have been working (indeed, longer than many of them have been alive).&lt;br /&gt;&lt;br /&gt;Claiming that young programmers prefer it this way implies they ever had a choice. But they didn't have a choice, so there's no control group, and this is just more self-serving nonsense.&lt;br /&gt;&lt;br /&gt;I'll close with a visit a few companies ago to one of the largest cubicleware vendors in Silicon Valley. We went there because we were opening up a development center, and needed furniture. The vendor took us on a tour of their facility, which doubled as a showroom and their headquarters. As the tour lady stood there telling us about the merits of this or that piece of furniture, I noticed some employees of the vendor in the background, in the accounting department.&lt;br /&gt;&lt;br /&gt;They were glaring at us, because we were making too much noise.&lt;br /&gt;&lt;br /&gt;Some interesting articles about or related to this topic:&lt;ul&gt;&lt;li&gt;&lt;a href="http://www.bizjournals.com/buffalo/stories/2001/07/16/focus2.html"&gt;http://www.bizjournals.com/buffalo/stories/2001/07/16/focus2.html&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://www.bosti.com/public.htm"&gt;http://www.bosti.com/public.htm&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://www.joelonsoftware.com/articles/DevelopmentAbstraction.html"&gt;http://www.joelonsoftware.com/articles/DevelopmentAbstraction.html&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://www.joelonsoftware.com/articles/fog0000000050.html"&gt;http://www.joelonsoftware.com/articles/fog0000000050.html&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://www.joelonsoftware.com/articles/BionicOffice.html"&gt;http://www.joelonsoftware.com/articles/BionicOffice.html&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://en.wikipedia.org/wiki/Open_plan#Which_is_best.2C_open-plan_or_otherwise.3F"&gt;http://en.wikipedia.org/wiki/Open_plan#Which_is_best.2C_open-plan_or_otherwise.3F&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;Note: Although out of print, Peopleware can be found online as a PDF, or purchased used for around a hundred dollars.&lt;br /&gt;&lt;br /&gt;Update: Look how far we have fallen--a friend sent: "In the '60's my father took me through his insurance company offices  after hours. Most of the desks were in open bays. Then we came to the  computer area and he pointed out the leased IBM 360/30. Nearby there were  several special rooms along the wall with doors and glass walls. I asked why  some of the desks were sealed off like that and he told me that the  programmers needed quiet places to work without interruption because it was  so important that their programs be correct. Your article brought back that  memory."&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/356226683788078026-4652386753035185249?l=jimshowalter.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jimshowalter.blogspot.com/feeds/4652386753035185249/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://jimshowalter.blogspot.com/2010/05/open-cubicles-must-die.html#comment-form' title='11 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/356226683788078026/posts/default/4652386753035185249'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/356226683788078026/posts/default/4652386753035185249'/><link rel='alternate' type='text/html' href='http://jimshowalter.blogspot.com/2010/05/open-cubicles-must-die.html' title='Open Cubicles Must Die'/><author><name>Jim Showalter</name><uri>http://www.blogger.com/profile/01963552914376132590</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>11</thr:total></entry><entry><id>tag:blogger.com,1999:blog-356226683788078026.post-1612189382858452296</id><published>2010-05-31T16:01:00.000-07:00</published><updated>2010-05-31T16:09:06.428-07:00</updated><title type='text'>Scrum Is A Flow-state Interrupter</title><content type='html'>Overall, &lt;a href="http://en.wikipedia.org/wiki/Scrum_%28development%29"&gt;Scrum&lt;/a&gt; is useful.&lt;br /&gt;&lt;br /&gt;But the &lt;a href="http://en.wikipedia.org/wiki/Scrum_%28development%29#Meetings"&gt;Daily Interruption&lt;/a&gt; is an abomination.&lt;br /&gt;&lt;br /&gt;First of all, because the Daily Interruption is supposed to be held every workday, it interferes with &lt;a href="http://jimshowalter.blogspot.com/2010/05/huge-gain-in-productivity-for-tiny.html"&gt;no-interruptions days&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;Second, the Daily Interruption serves no purpose.&lt;br /&gt;&lt;br /&gt;I realize this is heresy, but look at what is supposed to happen in the Daily Interruption. Every team participant is supposed to answer three questions:&lt;ol&gt;&lt;li&gt;What have you done since yesterday?&lt;/li&gt;&lt;li&gt;What are you planning to do today?&lt;/li&gt;&lt;li&gt;Is anything blocking you?&lt;/li&gt;&lt;/ol&gt;The first two questions can and should be replaced by emailed status reports. Why waste time telling me something I can read (if I care, which I don't)?&lt;br /&gt;&lt;br /&gt;The third question is even more asinine. Why would a programmer wait an average of 12 hours to bring up something that's blocking them? Shouldn't they deal with the problem right away?&lt;br /&gt;&lt;br /&gt;If someone comes to a Daily Interruption to kvetch about a blocker, my question to them is always why haven't you dealt with this already, dummy.&lt;br /&gt;&lt;br /&gt;Because the Daily Interruption serves no purpose, requiring programmers to attend it is fiduciary irresponsibility.&lt;br /&gt;&lt;br /&gt;The Daily Interruption was invented to solve communication problems on dysfunctional teams. If a team is not dysfunctional, the Daily Interruption is make-work. Wasteful, flow-killing make-work.&lt;br /&gt;&lt;br /&gt;But just try convincing a ScrumMaster that the team can do without the Daily Interruption. They've been to ScrumSchool, you see. They're ScrumCertified.&lt;br /&gt;&lt;br /&gt;Except they didn't read the whole book. If they had, they'd know that &lt;a href="http://en.wikipedia.org/wiki/Agile_software_development"&gt;Agile methodologies&lt;/a&gt; (of which Scrum is an instance) support &lt;a href="http://en.wikipedia.org/wiki/Method_engineering#Method_tailoring"&gt;Method Tailoring&lt;/a&gt;. And Method Tailoring allows a team to modify a methodology to fit the needs of the team and the project the team is working on.&lt;br /&gt;&lt;br /&gt;In other words, a team can, with the blessing of Agile, tailor Scrum to &lt;span style="font-style: italic;"&gt;eliminate&lt;/span&gt; the Daily Interruption.&lt;br /&gt;&lt;br /&gt;As a compromise, if a team simply must have the Daily Interruption, at least only have it on the three days of the week that are already contaminated by other meetings. Leave the no-interruptions days alone.&lt;br /&gt;&lt;br /&gt;Because our team has enlightened management, the Daily Interruption is not scheduled on no-interruptions days, and attendance is optional on the other three days.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/356226683788078026-1612189382858452296?l=jimshowalter.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jimshowalter.blogspot.com/feeds/1612189382858452296/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://jimshowalter.blogspot.com/2010/05/scrum-is-flow-state-interrupter.html#comment-form' title='8 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/356226683788078026/posts/default/1612189382858452296'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/356226683788078026/posts/default/1612189382858452296'/><link rel='alternate' type='text/html' href='http://jimshowalter.blogspot.com/2010/05/scrum-is-flow-state-interrupter.html' title='Scrum Is A Flow-state Interrupter'/><author><name>Jim Showalter</name><uri>http://www.blogger.com/profile/01963552914376132590</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-356226683788078026.post-5173683588909194819</id><published>2010-05-31T15:50:00.001-07:00</published><updated>2010-05-31T15:50:57.141-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='mandatory meetings'/><category scheme='http://www.blogger.com/atom/ns#' term='time management'/><title type='text'>Mandatory Meetings</title><content type='html'>Unless required by law, there should be no such thing as a mandatory meeting.&lt;br /&gt;&lt;br /&gt;The best way to get people to attend a meeting is to make the meeting worth attending.&lt;br /&gt;&lt;br /&gt;Mandatory meetings are particularly annoying when they're supposed to be "fun" (for example, a team-building offsite). Mandatory fun is an oxymoron.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/356226683788078026-5173683588909194819?l=jimshowalter.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jimshowalter.blogspot.com/feeds/5173683588909194819/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://jimshowalter.blogspot.com/2010/05/mandatory-meetings.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/356226683788078026/posts/default/5173683588909194819'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/356226683788078026/posts/default/5173683588909194819'/><link rel='alternate' type='text/html' href='http://jimshowalter.blogspot.com/2010/05/mandatory-meetings.html' title='Mandatory Meetings'/><author><name>Jim Showalter</name><uri>http://www.blogger.com/profile/01963552914376132590</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-356226683788078026.post-217941429582872096</id><published>2010-05-31T15:42:00.001-07:00</published><updated>2010-05-31T15:47:51.273-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='non-recurring meetings'/><category scheme='http://www.blogger.com/atom/ns#' term='interruptions'/><category scheme='http://www.blogger.com/atom/ns#' term='flow state'/><category scheme='http://www.blogger.com/atom/ns#' term='time management'/><category scheme='http://www.blogger.com/atom/ns#' term='flow'/><title type='text'>Feedback On Non-recurring Meetings</title><content type='html'>Because meetings are flow-state interrupters, companies should have a process for improving the quality of all meetings, including non-recurring meetings.&lt;br /&gt;&lt;br /&gt;After every non-recurring meeting, a survey should be sent to everyone who attended the meeting, asking some questions:&lt;ul&gt;&lt;li&gt;Did the meeting start on time?&lt;/li&gt;&lt;li&gt;Did the meeting end on time?&lt;/li&gt;&lt;li&gt;Do you understand the purpose of this meeting?&lt;/li&gt;&lt;li&gt;Do you feel that this meeting met its stated purpose?&lt;/li&gt;&lt;li&gt;Based on the average fully burdened salary of the attendees, the cost of this meeting (not counting opportunity cost) was $&amp;lt;put cost here&amp;gt;. Do you think that cost was justified?&lt;/li&gt;&lt;li&gt;Is there any information communicated during the meeting that should be communicated by some other means (for example, in email)?&lt;/li&gt;&lt;li&gt;Which of the following actions would have improved the meeting (check as many as apply)?:&lt;/li&gt;&lt;ul&gt;&lt;li&gt;Add ______ to the agenda.&lt;/li&gt;&lt;li&gt;Remove ______ from the agenda.&lt;/li&gt;&lt;li&gt;Change the allocated time to ______.&lt;/li&gt;&lt;li&gt;Reduce the number of attendees.&lt;/li&gt;&lt;/ul&gt;&lt;/ul&gt;Meeting ratings should be considered in employee's annual reviews.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/356226683788078026-217941429582872096?l=jimshowalter.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jimshowalter.blogspot.com/feeds/217941429582872096/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://jimshowalter.blogspot.com/2010/05/feedback-on-non-recurring-meetings.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/356226683788078026/posts/default/217941429582872096'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/356226683788078026/posts/default/217941429582872096'/><link rel='alternate' type='text/html' href='http://jimshowalter.blogspot.com/2010/05/feedback-on-non-recurring-meetings.html' title='Feedback On Non-recurring Meetings'/><author><name>Jim Showalter</name><uri>http://www.blogger.com/profile/01963552914376132590</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-356226683788078026.post-880329978220717064</id><published>2010-05-31T14:58:00.000-07:00</published><updated>2010-05-31T16:15:20.523-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='flow state'/><category scheme='http://www.blogger.com/atom/ns#' term='recurring meetings'/><category scheme='http://www.blogger.com/atom/ns#' term='time management'/><category scheme='http://www.blogger.com/atom/ns#' term='flow'/><title type='text'>Winnowing Recurring Meetings</title><content type='html'>Whenever someone takes over an IT department, the first thing they're supposed to do is cancel all reports.&lt;br /&gt;&lt;br /&gt;The thinking is that many reports are leftovers nobody cares about anymore, and shutting them off is the best way to find out which ones matter to someone.&lt;br /&gt;&lt;br /&gt;Have you ever found yourself in a recurring meeting where you wonder what the point of the meeting is?&lt;br /&gt;&lt;br /&gt;That meeting is like a zombie report. Nobody really needs it anymore, but there's no process in place for getting rid of the meeting. It just lurches along on inertia, wasting everyone's time.&lt;br /&gt;&lt;br /&gt;Because meetings are flow-state interrupters, companies should be proactive about getting rid of recurring meetings nobody needs anymore.&lt;br /&gt;&lt;br /&gt;Every recurring meeting should have to interview for its job on an ongoing basis.&lt;br /&gt;&lt;br /&gt;After every recurring meeting--or at least quarterly--a &lt;a href="http://www.surveymonkey.com/"&gt;survey&lt;/a&gt; should be sent to everyone who attended the meeting, asking some questions:&lt;ul&gt;&lt;li&gt;Did the meeting start on time?&lt;/li&gt;&lt;li&gt;Did the meeting end on time?&lt;/li&gt;&lt;li&gt;Do you understand the purpose of this meeting?&lt;/li&gt;&lt;li&gt;Do you feel that this meeting met its stated purpose?&lt;/li&gt;&lt;li&gt;Based on the average fully burdened salary of the attendees, the cost of this meeting (not counting opportunity cost) was $&amp;lt;put cost here&amp;gt;. Do you think that cost was justified?&lt;/li&gt;&lt;li&gt;If you do not feel this meeting is justified, do you feel that it should simply be cancelled, or improved?&lt;/li&gt;&lt;li&gt;If you feel the meeting should be cancelled, is there any information communicated during the meeting that should be communicated by some other means (for example, in email)?&lt;/li&gt;&lt;li&gt;If you do not feel that this meeting should be cancelled but instead should be improved, which of the following actions do you think should be taken to improve it (check as many as apply)?:&lt;/li&gt;&lt;ul&gt;&lt;li&gt;Add ______ to the agenda.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Remove ______ from the agenda.&lt;/li&gt;&lt;li&gt;Change the allocated time to ______.&lt;/li&gt;&lt;li&gt;Hold it less often.&lt;/li&gt;&lt;li&gt;Make it non-recurring (only hold it when needed).&lt;/li&gt;&lt;li&gt;Reduce the number of attendees.&lt;/li&gt;&lt;li&gt;Combine it with the ______ meeting.&lt;/li&gt;&lt;li&gt;Reschedule it to ______ to leave a larger contiguous block of uninterrupted time available.&lt;/li&gt;&lt;/ul&gt;&lt;/ul&gt;If a meeting fails the interview, it should be cancelled, no matter how important the meeting owner thinks the meeting is.&lt;br /&gt;&lt;br /&gt;Constant review and winnowing of meetings can, over time, convert this:&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_MuoEQTr-jEM/TARCsRR2dxI/AAAAAAAAAFg/XCmqVlmgHt0/s1600/NoScheduledMeetingsDays.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 320px; height: 282px;" src="http://2.bp.blogspot.com/_MuoEQTr-jEM/TARCsRR2dxI/AAAAAAAAAFg/XCmqVlmgHt0/s320/NoScheduledMeetingsDays.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5477576375109318418" /&gt;&lt;/a&gt;to this:&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_MuoEQTr-jEM/TARC6KCg2gI/AAAAAAAAAFo/zTxORhKb_MA/s1600/FewerMeetings.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 320px; height: 282px;" src="http://3.bp.blogspot.com/_MuoEQTr-jEM/TARC6KCg2gI/AAAAAAAAAFo/zTxORhKb_MA/s320/FewerMeetings.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5477576613684107778" /&gt;&lt;/a&gt;If a meeting passes the interview but needs improvement, it should be improved per the survey feedback.&lt;br /&gt;&lt;br /&gt;Meeting ratings should be considered in employee's annual reviews.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/356226683788078026-880329978220717064?l=jimshowalter.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jimshowalter.blogspot.com/feeds/880329978220717064/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://jimshowalter.blogspot.com/2010/05/winnowing-recurring-meetings.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/356226683788078026/posts/default/880329978220717064'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/356226683788078026/posts/default/880329978220717064'/><link rel='alternate' type='text/html' href='http://jimshowalter.blogspot.com/2010/05/winnowing-recurring-meetings.html' title='Winnowing Recurring Meetings'/><author><name>Jim Showalter</name><uri>http://www.blogger.com/profile/01963552914376132590</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/_MuoEQTr-jEM/TARCsRR2dxI/AAAAAAAAAFg/XCmqVlmgHt0/s72-c/NoScheduledMeetingsDays.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-356226683788078026.post-2257448011884733799</id><published>2010-05-31T14:08:00.000-07:00</published><updated>2010-05-31T22:00:51.441-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='interruptions'/><category scheme='http://www.blogger.com/atom/ns#' term='flow state'/><category scheme='http://www.blogger.com/atom/ns#' term='time management'/><category scheme='http://www.blogger.com/atom/ns#' term='flow'/><title type='text'>A Huge Gain In Productivity For A Tiny Amount Of Effort</title><content type='html'>Does this look familiar to you?:&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_MuoEQTr-jEM/TAQlhju_7mI/AAAAAAAAAFQ/aV70jXJTpNA/s1600/FracturedSchedule.png"&gt;&lt;img style="display: block; margin: 0px auto 10px; text-align: center; cursor: pointer; width: 249px; height: 320px;" src="http://4.bp.blogspot.com/_MuoEQTr-jEM/TAQlhju_7mI/AAAAAAAAAFQ/aV70jXJTpNA/s320/FracturedSchedule.png" alt="" id="BLOGGER_PHOTO_ID_5477544305247645282" border="0" /&gt;&lt;/a&gt;If so, there's no way you can get into flow during work hours. You either don't get into flow (bad), or work evenings and weekends to get anything done (also bad).&lt;br /&gt;&lt;br /&gt;Fortunately, there is a simple, free, and ridiculously effective solution to this problem.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://jimshowalter.blogspot.com/2010/05/fighting-for-flow.html"&gt;Working with management&lt;/a&gt;, institute two no-interruptions days per week.&lt;br /&gt;&lt;br /&gt;Stagger the two days to avoid being out of contact with others for two days in a row. (I recommend Tuesday and Thursday, but Tuesday and Friday also work well.)&lt;br /&gt;&lt;br /&gt;Make the two days sacrosanct.&lt;br /&gt;&lt;br /&gt;Have everyone on your team reserve the two days on their calendars:&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_MuoEQTr-jEM/TAQl8M7zuFI/AAAAAAAAAFY/hg7kikmR-Uc/s1600/NoScheduledMeetingsDays.png"&gt;&lt;img style="display: block; margin: 0px auto 10px; text-align: center; cursor: pointer; width: 320px; height: 282px;" src="http://2.bp.blogspot.com/_MuoEQTr-jEM/TAQl8M7zuFI/AAAAAAAAAFY/hg7kikmR-Uc/s320/NoScheduledMeetingsDays.png" alt="" id="BLOGGER_PHOTO_ID_5477544762983823442" border="0" /&gt;&lt;/a&gt;Make your calendars public so everyone can clearly see the two days blocked out.&lt;br /&gt;&lt;br /&gt;Politely decline all meeting invites on the two days, with the explanation that the two days are for focused work, and suggest scheduling the meeting on one of the three non-focus days that can be wasted playing  office.&lt;br /&gt;&lt;br /&gt;Be firm.&lt;br /&gt;&lt;br /&gt;And also be firm with yourself. The two days are &lt;span style="font-style: italic;"&gt;not&lt;/span&gt; for running personal errands, goofing off, etc. The two days are for focused working. If you screw this up, management will consider the experiment a failure, you'll lose credibility, and it will be hard to convince them to remove other, more difficult obstacles.&lt;br /&gt;&lt;br /&gt;On the two days, shut off IM, Twitter, RSS, your cellphone, etc. It will be hard to do that at first. You'll feel cut off, out of the loop, going through withdrawal.&lt;br /&gt;&lt;br /&gt;Good. That means it's working.&lt;br /&gt;&lt;br /&gt;Ideally, assuming you have a good home-office work environment, work at home on the two days. That way you can roll out of bed, grab something quick to eat, and start coding.&lt;br /&gt;&lt;br /&gt;Be sure to put in a full eight hours of focused time on each of the two days. (You will find this easy to do, because you'll be in flow.)&lt;br /&gt;&lt;br /&gt;Congratulations, you just worked your 16 hours/week! You are 33% more efficient than the industry average. If you manage to work a few more hours on the other three days of the week, that's all upside.&lt;br /&gt;&lt;br /&gt;Some people can get really offended that you declined their super-important meeting. Boo hoo. This is when it's vital to have management backing, so you can send the invitee to management for goal alignment. You need management to make it clear that interrupting a programmer on a no-interruptions day is &lt;span style="font-style: italic;"&gt;stealing from the company&lt;/span&gt;.&lt;br /&gt;&lt;br /&gt;Because you will actually be able to clock 16+ hours a week with this system, management will give you the backing you need.&lt;br /&gt;&lt;br /&gt;You also need management backing if you work across teams, so that the no-interruptions days can be aligned. (It does no good to declare Tuesday as a no-interruptions day if a team you have to work with picks a different day.)&lt;br /&gt;&lt;br /&gt;If you can't get management backing for this and/or if upper management is for it but your own manager is against it, change jobs. Seriously.&lt;br /&gt;&lt;br /&gt;How dogmatic should you be about no interruptions on those days? Well, there's sort of an art to getting it correct. Obviously if you are blocked because you have to ask somebody else a question, it would be nice to be able to get an answer right away. But it's a slippery slope. You have to be careful to only interrupt when it's really important. And you should never, ever, accept an invite for a recurring meeting on a no-interruptions day.&lt;br /&gt;&lt;br /&gt;The irony of this system is that it costs the company nothing to implement. Mostly it just involves changing the days for some meetings. A simple, mechanical process.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/356226683788078026-2257448011884733799?l=jimshowalter.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jimshowalter.blogspot.com/feeds/2257448011884733799/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://jimshowalter.blogspot.com/2010/05/huge-gain-in-productivity-for-tiny.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/356226683788078026/posts/default/2257448011884733799'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/356226683788078026/posts/default/2257448011884733799'/><link rel='alternate' type='text/html' href='http://jimshowalter.blogspot.com/2010/05/huge-gain-in-productivity-for-tiny.html' title='A Huge Gain In Productivity For A Tiny Amount Of Effort'/><author><name>Jim Showalter</name><uri>http://www.blogger.com/profile/01963552914376132590</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/_MuoEQTr-jEM/TAQlhju_7mI/AAAAAAAAAFQ/aV70jXJTpNA/s72-c/FracturedSchedule.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-356226683788078026.post-2414707985228249458</id><published>2010-05-31T13:05:00.000-07:00</published><updated>2010-06-01T09:27:50.961-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='flow state'/><category scheme='http://www.blogger.com/atom/ns#' term='cognition'/><category scheme='http://www.blogger.com/atom/ns#' term='flow'/><title type='text'>Flow Versus "New Cognition"</title><content type='html'>There has been some speculation online that kids these days aren't actually interrupted all the time and incapable of concentrating, but are instead just better at multitasking, and are in effect changing the way people think--that we're witnessing the emergence of a new kind of cognition. Evidence for this includes measurable changes to brain structures from playing lots of video games, and so forth. Some posts have gone so far as to say that because of this new cognitive style, kids shouldn't have to learn to spell, because good spelling isn't required for online communication. And of course anyone who disagrees is an old fogey who just can't keep up. ADHD isn't a disease, it's a New Way Of Thinking.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://news.stanford.edu/news/2009/august24/multitask-research-study-082409.html"&gt;Uh huh.&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;a href="http://en.wikipedia.org/wiki/Andrew_Wiles"&gt;Andrew Wiles&lt;/a&gt; spent seven years secluded in an attic. When he emerged, he had proven &lt;a href="http://en.wikipedia.org/wiki/Fermat%27s_Last_Theorem"&gt;Fermat's Last Theorem&lt;/a&gt; as a &lt;span style="font-style: italic;"&gt;side-effect&lt;/span&gt; of proving a much more general and profound result.&lt;br /&gt;&lt;br /&gt;Now suppose he had been one of these New Cognition types. How far do you suppose he'd have gotten on that proof?&lt;br /&gt;&lt;br /&gt;I think he'd still be in the attic, banging away on his Wii.&lt;br /&gt;&lt;br /&gt;As an old fogey who can spend hours at a time in flow, I'm worried that kids will grow up never entering a state of flow at work, and the cost to humanity in lost productivity will be gigantic. Our best and brightest will &lt;a href="http://headrush.typepad.com/creating_passionate_users/2006/12/httpwww37signal.html"&gt;constantly thrash&lt;/a&gt;, never achieving their potential.&lt;br /&gt;&lt;br /&gt;They'll be totally pwnd.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/356226683788078026-2414707985228249458?l=jimshowalter.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jimshowalter.blogspot.com/feeds/2414707985228249458/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://jimshowalter.blogspot.com/2010/05/flow-versus-new-cognition.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/356226683788078026/posts/default/2414707985228249458'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/356226683788078026/posts/default/2414707985228249458'/><link rel='alternate' type='text/html' href='http://jimshowalter.blogspot.com/2010/05/flow-versus-new-cognition.html' title='Flow Versus &quot;New Cognition&quot;'/><author><name>Jim Showalter</name><uri>http://www.blogger.com/profile/01963552914376132590</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-356226683788078026.post-5236693976168105465</id><published>2010-05-31T12:33:00.000-07:00</published><updated>2010-05-31T15:39:17.810-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='programmer productivity'/><category scheme='http://www.blogger.com/atom/ns#' term='flow state'/><category scheme='http://www.blogger.com/atom/ns#' term='time management'/><category scheme='http://www.blogger.com/atom/ns#' term='flow'/><title type='text'>Fighting For Flow</title><content type='html'>&lt;blockquote&gt;"And George, while his intelligence was way above normal, had a little mental handicap radio in his ear. He was required by law to wear it at all times. It was tuned to a government transmitter. Every twenty seconds or so, the transmitter would send out some sharp noise to keep people like George from taking unfair advantage of their brains." - Harrison Bergeron, by Kurt Vonnegut&lt;/blockquote&gt;&lt;br /&gt;&lt;a href="http://en.wikipedia.org/wiki/Flow_%28psychology%29"&gt;Flow&lt;/a&gt; is the highest-productivity mental state of which humans are capable.&lt;br /&gt;&lt;br /&gt;A person operating in flow can be vastly more productive than a person who is not in flow.&lt;br /&gt;&lt;br /&gt;A person in flow often starts working in the morning when it is light, and snaps out of flow late at night when it is dark, with no sense of the passage of time.&lt;br /&gt;&lt;br /&gt;A person in flow sometimes forgets to eat.&lt;br /&gt;&lt;br /&gt;A programmer in flow can do a week's worth of work in an afternoon, and a month's worth of work in a couple of days.&lt;br /&gt;&lt;br /&gt;A company that makes it easy for programmers to work in a state of flow has a strategic advantage over companies that have not figured this out.&lt;br /&gt;&lt;br /&gt;A programmer who learns to maintain a state of flow has a career advantage over programmers who have not learned how to do this.&lt;br /&gt;&lt;br /&gt;Unfortunately, it is becoming increasingly difficult to maintain a state of flow.&lt;br /&gt;&lt;br /&gt;Some of this is the fault of programmers. It is easy to be &lt;a href="http://comics.com/pearls_before_swine?DateAfter=2010-05-23&amp;amp;DateBefore=2010-05-23&amp;amp;Order=&amp;amp;PerPage=1&amp;amp;x=25&amp;amp;y=11&amp;amp;Search="&gt;seduced by email, IM, Twitter, etc.&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Fortunately, this can be rectified by self-discipline. Shut down email, log out of IM and Twitter, turn off the cellphone, and &lt;span style="font-style: italic;"&gt;focus&lt;/span&gt;.&lt;br /&gt;&lt;br /&gt;But companies also contribute to the problem. Perversely, they seem to go out of their way to squander programmer productivity. Instead of uninterrupted blocks of time, days are broken up with meetings. Instead of quiet offices, they stick programmers in noisy "pods". Instead of encouraging working at home, they disproportionally terminate remote workers during layoffs (then wonder why so few employees become remote workers).&lt;br /&gt;&lt;br /&gt;It can become pathological. Several companies ago, a colleague took two weeks of vacation so he could come to work every day and focus on something he'd been trying to get done for over a year. If anyone stopped by to ask him something, he'd tell them he was on vacation, and tell them to go away.&lt;br /&gt;&lt;br /&gt;I didn't make that up.&lt;br /&gt;&lt;br /&gt;Programmers need to fight back. It's a matter of self-preservation.&lt;br /&gt;&lt;br /&gt;Just complaining won't change anything. You'll just be seen as a "troublemaker".&lt;br /&gt;&lt;br /&gt;But there is one stick big enough to beat management over the head with to get them to listen.&lt;br /&gt;&lt;br /&gt;Money.&lt;br /&gt;&lt;br /&gt;Programmers cost money. They cost more money than anything else in the budget. A Silicon Valley programmer, fully burdened, can cost $250k/year.&lt;br /&gt;&lt;br /&gt;Wasting programmer productivity is fiduciary irresponsibility.&lt;br /&gt;&lt;br /&gt;Mechanisms that preserve programmer productivity deliver tangible benefits to the bottom line.&lt;br /&gt;&lt;br /&gt;The industry average for under-the-headphones actual coding--and this is criminal--is only about 12 hours/week. Not per day. Per. Week.&lt;br /&gt;&lt;br /&gt;That's crazy.&lt;br /&gt;&lt;br /&gt;There are 168 hours in a week.&lt;br /&gt;&lt;br /&gt;Where do the rest of the hours in the week go? WoW? Air hockey? American Idol?&lt;br /&gt;&lt;br /&gt;Now suppose instead you can eke out a whopping 16 hours/week. That doesn't seem like much, but it's a 33% improvement. It's like being able to hire 33% more programmers &lt;span style="font-style: italic;"&gt;without spending another penny&lt;/span&gt;. Think what the company could do with that much additional engineering resource! They could deliver more features. They could fix more bugs. They could crush their competition.&lt;br /&gt;&lt;br /&gt;But it's not even just a 33% improvement, because you're shooting for achieving 16 hours a week of hours in flow, so the productivity gains are much higher than a mere tally of hours indicates. Both the number of hours and the quality of hours increase. It's a &lt;a href="http://en.wikipedia.org/wiki/Force_multiplier"&gt;force multiplier&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;Now you're talking a language management understands.&lt;br /&gt;&lt;br /&gt;So go to management, and make the &lt;span style="font-style: italic;"&gt;business case&lt;/span&gt;. Tell them you want to help the company be more successful by removing obstacles to programmer productivity. List the obstacles, and suggest how each could be eliminated.&lt;br /&gt;&lt;br /&gt;Start with something small, so their heads don't explode with concerns about "risk". I recommend starting with &lt;a href="http://jimshowalter.blogspot.com/2010/05/huge-gain-in-productivity-for-tiny.html"&gt;this&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;Then when you show that the small change resulted in a measurable improvement, move to the next obstacle.&lt;br /&gt;&lt;br /&gt;Your team will be vastly more productive than teams that still suffer from the obstacles. Other managers will start to panic and want to know what the "secret" is, and start removing obstacles as well. Management will stop muttering about reducing costs by "offshoring" (because you found a way to reduce costs while keeping the jobs local).&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/356226683788078026-5236693976168105465?l=jimshowalter.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jimshowalter.blogspot.com/feeds/5236693976168105465/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://jimshowalter.blogspot.com/2010/05/fighting-for-flow.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/356226683788078026/posts/default/5236693976168105465'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/356226683788078026/posts/default/5236693976168105465'/><link rel='alternate' type='text/html' href='http://jimshowalter.blogspot.com/2010/05/fighting-for-flow.html' title='Fighting For Flow'/><author><name>Jim Showalter</name><uri>http://www.blogger.com/profile/01963552914376132590</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-356226683788078026.post-4656891564858256869</id><published>2010-05-30T18:20:00.000-07:00</published><updated>2010-05-31T22:05:02.339-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='legacy code'/><title type='text'>The Joy Of Legacy Code</title><content type='html'>The project I'm currently working on consists of more than a million lines of legacy code.&lt;br /&gt;&lt;br /&gt;Every other project I worked on was a "greenfield" project--a blank sheet of paper.&lt;br /&gt;&lt;br /&gt;It took a while to adjust.&lt;br /&gt;&lt;br /&gt;I'd always thought of legacy code as something that dull people maintained in the basements of banks.&lt;br /&gt;&lt;br /&gt;I was an idiot.&lt;br /&gt;&lt;br /&gt;In fact, legacy code is &lt;span style="font-style: italic;"&gt;important code&lt;/span&gt;. If it wasn't important, a company would simply decommission it, but instead a company continues to fund its development (or at least its maintenance), despite all the problems the programmers who work on the code complain about.&lt;br /&gt;&lt;br /&gt;Legacy code is virtually bug-free code, at least on the happy path. If it wasn't virtually bug-free, end users would complain and/or the code would crash. But it doesn't do that. Instead, it hums merrily away, the bugs having been dispatched years ago.&lt;br /&gt;&lt;br /&gt;Working on legacy code, you don't have to worry about the project getting cancelled, the start-up running out of money, etc. You already have customers, and you already have revenue.&lt;br /&gt;&lt;br /&gt;Legacy code pays well. A company can find millions of programmers who can write hello world, but not many programmers can do things like:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Migrate a legacy database to a non-backward-compatible schema without impacting end users&lt;/li&gt;&lt;li&gt;Revamp a legacy user interface to use Flex&lt;/li&gt;&lt;li&gt;Convert a legacy build system to Maven&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Replace homegrown legacy infrastructure components with open-source libraries&lt;/li&gt;&lt;li&gt;Refactor unstructured legacy code into layers&lt;/li&gt;&lt;/ul&gt;Those are hard problems, like cutting a diamond without shattering it. In comparison, writing code from scratch is trivial.&lt;br /&gt;&lt;br /&gt;Besides, new code is just legacy code in waiting. Assuming some new code proves useful and survives, it eventually turns into legacy code. Yesterday's spiffy greenfield project is today's legacy codebase.&lt;br /&gt;&lt;br /&gt;In most contexts, the word "legacy" has a positive connotation: freedom is the Founding Fathers' legacy; the National Park System is Teddy Roosevelt's legacy; prudent saving and investing leaves a legacy for one's children to inherit. This should be true for legacy code as well.&lt;br /&gt;&lt;br /&gt;Consider yourself lucky if you get an opportunity to work on legacy code!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/356226683788078026-4656891564858256869?l=jimshowalter.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jimshowalter.blogspot.com/feeds/4656891564858256869/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://jimshowalter.blogspot.com/2010/05/joy-of-legacy-code.html#comment-form' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/356226683788078026/posts/default/4656891564858256869'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/356226683788078026/posts/default/4656891564858256869'/><link rel='alternate' type='text/html' href='http://jimshowalter.blogspot.com/2010/05/joy-of-legacy-code.html' title='The Joy Of Legacy Code'/><author><name>Jim Showalter</name><uri>http://www.blogger.com/profile/01963552914376132590</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-356226683788078026.post-5921974153880096742</id><published>2010-05-09T13:35:00.000-07:00</published><updated>2010-05-16T22:31:44.497-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Windows Service file download rename renaming automatic disambiguate unique'/><title type='text'>Automatic File Renaming While Downloading</title><content type='html'>I got tired of having to rename files when downloading them, so I wrote a &lt;a href="http://blog-code-hosting.googlecode.com/svn/trunk/dotnet/FileRenamer.zip"&gt;Windows Service to automate it&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/356226683788078026-5921974153880096742?l=jimshowalter.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jimshowalter.blogspot.com/feeds/5921974153880096742/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://jimshowalter.blogspot.com/2010/05/file-renamer.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/356226683788078026/posts/default/5921974153880096742'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/356226683788078026/posts/default/5921974153880096742'/><link rel='alternate' type='text/html' href='http://jimshowalter.blogspot.com/2010/05/file-renamer.html' title='Automatic File Renaming While Downloading'/><author><name>Jim Showalter</name><uri>http://www.blogger.com/profile/01963552914376132590</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-356226683788078026.post-6681187626695117184</id><published>2010-03-20T18:40:00.000-07:00</published><updated>2010-04-17T11:03:25.549-07:00</updated><title type='text'>A Tool That Does Not Exist</title><content type='html'>Moved to &lt;a href="http://free-inventions.blogspot.com/2010/04/super-tool-for-refactoring.html"&gt;http://free-inventions.blogspot.com/2010/04/super-tool-for-refactoring.html&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/356226683788078026-6681187626695117184?l=jimshowalter.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jimshowalter.blogspot.com/feeds/6681187626695117184/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://jimshowalter.blogspot.com/2010/03/one-of-our-projects-at-work-involves.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/356226683788078026/posts/default/6681187626695117184'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/356226683788078026/posts/default/6681187626695117184'/><link rel='alternate' type='text/html' href='http://jimshowalter.blogspot.com/2010/03/one-of-our-projects-at-work-involves.html' title='A Tool That Does Not Exist'/><author><name>Jim Showalter</name><uri>http://www.blogger.com/profile/01963552914376132590</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-356226683788078026.post-5670384246651536685</id><published>2009-12-19T14:04:00.000-08:00</published><updated>2010-05-16T22:49:37.790-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Android reuse reusable layering'/><title type='text'>Structuring An Android Application For Reuse</title><content type='html'>The Android application I'm working on consists mostly of code that's not Android-specific:&lt;br /&gt;&lt;br /&gt;- Database schema creation.&lt;br /&gt;- SQL queries.&lt;br /&gt;- Data access (objects mapped to and from database).&lt;br /&gt;- Business logic.&lt;br /&gt;&lt;br /&gt;There is only a small amount (less than 10%) of Android-specific GUI and notification code.&lt;br /&gt;&lt;br /&gt;Other than the code that creates the database schema (which is database-specific), all of the non-Android code is device- and OS-agnostic. It just needs a Java runtime.&lt;br /&gt;&lt;br /&gt;I wanted to be able to easily reuse the portable code to run the application on a website, and on other Java-based handhelds.&lt;br /&gt;&lt;br /&gt;The first step involved abstracting the database so that any database can be used, instead of just Android's binding to SQLite:&lt;br /&gt;&lt;br /&gt;&lt;a href="http://code.google.com/p/blog-code-hosting/source/browse/#svn/trunk/android/reuse/CommonPortable/src/main/java/com/jimandlisa/common/database"&gt;http://code.google.com/p/blog-code-hosting/source/browse/#svn/trunk/android/reuse/CommonPortable/src/main/java/com/jimandlisa/common/database&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;and also abstracting the logger:&lt;br /&gt;&lt;br /&gt;&lt;a href="http://code.google.com/p/blog-code-hosting/source/browse/#svn/trunk/android/reuse/CommonPortable/src/main/java/com/jimandlisa/common/logging"&gt;http://code.google.com/p/blog-code-hosting/source/browse/#svn/trunk/android/reuse/CommonPortable/src/main/java/com/jimandlisa/common/logging&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Once that was done, I could test the database and logger independently from Android:&lt;br /&gt;&lt;br /&gt;&lt;a href="http://code.google.com/p/blog-code-hosting/source/browse/#svn/trunk/android/reuse/CommonPortableTestUtils/src/main/java/com/jimandlisa/common/testutils"&gt;http://code.google.com/p/blog-code-hosting/source/browse/#svn/trunk/android/reuse/CommonPortableTestUtils/src/main/java/com/jimandlisa/common/testutils&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;a href="http://code.google.com/p/blog-code-hosting/source/browse/#svn/trunk/android/reuse/CommonDatabaseTestUtils/src/main/java/com/jimandlisa/common/testutils/database"&gt;http://code.google.com/p/blog-code-hosting/source/browse/#svn/trunk/android/reuse/CommonDatabaseTestUtils/src/main/java/com/jimandlisa/common/testutils/database&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;a href="http://code.google.com/p/blog-code-hosting/source/browse/#svn/trunk/android/reuse/CommonPortableTests/src/test/java/com/jimandlisa/common/tests"&gt;http://code.google.com/p/blog-code-hosting/source/browse/#svn/trunk/android/reuse/CommonPortableTests/src/test/java/com/jimandlisa/common/tests&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;The portable business logic is in another set of projects:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:85%;"&gt;MyAppPortable&lt;br /&gt;com.jimandlisa.myapp.common&lt;br /&gt;com.jimandlisa.myapp.controller&lt;br /&gt;com.jimandlisa.myapp.database&lt;br /&gt;com.jimandlisa.myapp.model&lt;br /&gt;&lt;br /&gt;MyAppPortableTestUtils&lt;br /&gt;com.jimandlisa.myapp.testutils&lt;br /&gt;&lt;br /&gt;MyAppPortableTests&lt;br /&gt;com.jimandlisa.myapp.tests&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Finally, the Android-specific code is in two more projects:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:85%;"&gt;MyAppAndroid&lt;br /&gt;com.jimandlisa.myapp&lt;br /&gt;&lt;br /&gt;MyAppAndroidTests&lt;br /&gt;com.jimandlisa.myapp.android.tests&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;The inter-project dependencies look like this:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:85%;"&gt;CommonPortable:&lt;br /&gt;n/a&lt;br /&gt;&lt;br /&gt;CommonPortableTestUtils:&lt;br /&gt;CommonPortable&lt;br /&gt;&lt;br /&gt;CommonPortableDatabaseTestUtils:&lt;br /&gt;CommonPortable&lt;br /&gt;CommonPortableTestUtils&lt;br /&gt;&lt;br /&gt;CommonPortableTests:&lt;br /&gt;CommonPortable&lt;br /&gt;CommonPortableTestUtils&lt;br /&gt;CommonPortableDatabaseTestUtils&lt;br /&gt;&lt;br /&gt;MyAppPortable:&lt;br /&gt;CommonPortable&lt;br /&gt;&lt;br /&gt;MyAppPortableTestUtils:&lt;br /&gt;CommonPortable&lt;br /&gt;MyAppPortable&lt;br /&gt;&lt;br /&gt;MyAppPortableTests:&lt;br /&gt;CommonPortable&lt;br /&gt;CommonPortableTestUtils&lt;br /&gt;CommonDatabaseTestUtils&lt;br /&gt;MyAppPortable&lt;br /&gt;MyAppPortableTestUtils&lt;br /&gt;&lt;br /&gt;MyAppAndroid:&lt;br /&gt;CommonPortable&lt;br /&gt;MyAppPortable&lt;br /&gt;&lt;br /&gt;MyAppAndroidTests:&lt;br /&gt;CommonPortable/target/classes&lt;br /&gt;MyAppPortable/target/classes&lt;br /&gt;MyAppAndroid/bin&lt;br /&gt;CommonPortableTestUtils&lt;br /&gt;MyAppPortableTestUtils&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:100%;"&gt;The CommonDatabaseTestUtils are &lt;/span&gt;broken out from &lt;span style="font-size:100%;"&gt;CommonPortableTestUtils &lt;/span&gt;because they depend on JARs that aren't loaded on the device, so they can't be included in the dependencies for MyAppAndroidTests.&lt;br /&gt;&lt;br /&gt;MyAppAndroidTests depends on target/classes and bin for reasons explained in &lt;a href="http://jimshowalter.blogspot.com/2009/10/developing-android-with-multiple.html"&gt;http://jimshowalter.blogspot.com/2009/10/developing-android-with-multiple.html&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;So was it worth it?&lt;br /&gt;&lt;br /&gt;Well, yes, and no.&lt;br /&gt;&lt;br /&gt;There are definitely advantages:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;I can write any other database-intensive application by cloning this setup and reusing the code in com.intuit.jimandlisa.common.*.&lt;/li&gt;&lt;li&gt;The database-abstraction layer doesn't have the problems reported in Google Android issues #&lt;a href="http://code.google.com/p/android/issues/detail?id=3302"&gt;3302&lt;/a&gt;, &lt;a href="http://code.google.com/p/android/issues/detail?id=3296"&gt;3296&lt;/a&gt;, and &lt;a href="http://code.google.com/p/android/issues/detail?id=3304"&gt;3304&lt;/a&gt;.&lt;/li&gt;&lt;li&gt;Having much of the code be regular, portable Java makes it easier to write coverage tests because &lt;a href="http://easymock.org/"&gt;EasyMoc&lt;/a&gt;k, &lt;a href="http://code.google.com/p/jmockit"&gt;JMockit&lt;/a&gt;, and &lt;a href="http://cobertura.sourceforge.net/"&gt;Cobertura&lt;/a&gt; are available.&lt;/li&gt;&lt;/ul&gt;But there are also disadvantages:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;This approach creates a lot of separate projects, and that's kind of a pain to set up.&lt;/li&gt;&lt;li&gt;I have to maintain the database-abstraction layer.&lt;/li&gt;&lt;li&gt;More work is required to mature the database-abstraction layer. (It currently doesn't support binding args or compound keys, all keys must be longs, etc.)&lt;/li&gt;&lt;li&gt;Because the database-abstraction layer isn't a native binding, it's slower. For a cellphone app with a few database operations per hour, this doesn't matter, but it will matter on a website.&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;On balance, the approach makes sense for the particular application I'm working on, because it is almost entirely not tied to Android. But the approach wouldn't be appropriate for a GUI-intensive application that makes a lot of calls to Android APIs.&lt;br /&gt;&lt;br /&gt;It might be better to model the application, and generate the code. With so many devices, OSs, and vendors, code generation might be the only pragmatic way to develop a cross-platform application.&lt;br /&gt;&lt;br /&gt;Update: The sample code has been updated to add createSchema and updateSchema to AbstractDatabase in order to make execSql private.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/356226683788078026-5670384246651536685?l=jimshowalter.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jimshowalter.blogspot.com/feeds/5670384246651536685/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://jimshowalter.blogspot.com/2009/12/structuring-android-application-for.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/356226683788078026/posts/default/5670384246651536685'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/356226683788078026/posts/default/5670384246651536685'/><link rel='alternate' type='text/html' href='http://jimshowalter.blogspot.com/2009/12/structuring-android-application-for.html' title='Structuring An Android Application For Reuse'/><author><name>Jim Showalter</name><uri>http://www.blogger.com/profile/01963552914376132590</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-356226683788078026.post-6748994401295351815</id><published>2009-10-04T13:20:00.001-07:00</published><updated>2010-03-14T16:34:58.646-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Android Eclipse multiple projects unit tests Verify error class resolved by unexpected DEX error IllegalAccessError cross-loader access from pre-verified class'/><title type='text'>Developing Android With Multiple Eclipse Projects</title><content type='html'>The Android application I'm developing at home has non-Android-specific schema, database access, and business logic, so it makes sense to partition the application into multiple Eclipse projects, some Android-specific and others not.&lt;br /&gt;&lt;br /&gt;One benefit of using separate projects is that I can write a second version of the application that runs on a website instead of on a handheld without having to rewrite the bulk of the code.&lt;br /&gt;&lt;br /&gt;But there's a catch: when the Android-specific unit tests are moved into a separate Eclipse project, the loader reports "Class resolved by unexpected DEX error" and the unit tests fail with "java.lang.IllegalAccessError: cross-loader access from pre-verified class". (In 2.1 the error remains, but the message has changed to "Class ref in pre-verified class resolved to unexpected implementation".)&lt;br /&gt;&lt;br /&gt;I first ran into this problem in 1.5 Android, and upgraded to 1.6 hoping it would go away, because in 1.6 using separate Eclipse projects for unit tests is recommended:&lt;br /&gt;&lt;a href="http://mobilebytes.wordpress.com/2009/09/19/new-eclipse-android-test-features"&gt;&lt;br /&gt;http://mobilebytes.wordpress.com/2009/09/19/new-eclipse-android-test-features&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;a href="http://www.danielswisher.com/2009/06/as-new-android-developer-i-have-been.html"&gt;http://www.danielswisher.com/2009/06/as-new-android-developer-i-have-been.html&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;There is even a toolbar icon and wizard to create an Android test project that points to a separate Android project to be tested.&lt;br /&gt;&lt;br /&gt;Googling around, I found other programmers having the same or similar problems:&lt;br /&gt;&lt;br /&gt;&lt;a href="http://groups.google.com/group/android-platform/browse_thread/thread/20ff41b925e04dd4"&gt;http://groups.google.com/group/android-platform/browse_thread/thread/20ff41b925e04dd4&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;But googling also found programmers with multiple projects but not the problem:&lt;br /&gt;&lt;br /&gt;&lt;a href="http://www.anddev.org/unit_testing_private_methods-t7847.html"&gt;http://www.anddev.org/unit_testing_private_methods-t7847.html&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;What makes some programmers have no problem using multiple Eclipse projects to separate Android application code from Android unit-test code, while other programmers get the loader errors?&lt;br /&gt;&lt;br /&gt;The problem shows up when the loader sees the same class loaded more than once:&lt;br /&gt;&lt;br /&gt;&lt;a href="http://groups.google.com/group/android-developers/browse_thread/thread/3440dd8e11a1b481"&gt;http://groups.google.com/group/android-developers/browse_thread/thread/3440dd8e11a1b481&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;which can happen if the main Android code and the Android unit tests share code from another Eclipse project:&lt;br /&gt;&lt;br /&gt;&lt;a href="http://groups.google.com/group/android-developers/browse_thread/thread/5537ae10e4143240"&gt;http://groups.google.com/group/android-developers/browse_thread/thread/5537ae10e4143240&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;which is the setup I have.&lt;br /&gt;&lt;br /&gt;To reproduce the problem:&lt;ol&gt;&lt;li&gt;Create an ordinary Java project called LoaderProblemCommon, and create this class in it:&lt;br /&gt;&lt;/li&gt;&lt;pre&gt;package com.loaderproblem;&lt;br /&gt;&lt;br /&gt;public class LoaderLogger&lt;br /&gt;{&lt;br /&gt;public static void log(String message)&lt;br /&gt;{&lt;br /&gt;System.out.println(message);&lt;br /&gt;}&lt;br /&gt;}&lt;/pre&gt;&lt;li&gt;Create an Android project called LoaderProblem, add the LoaderProblemCommon project to its build path, and create this class in it:&lt;/li&gt;&lt;pre&gt;package com.loaderproblem;&lt;br /&gt;&lt;br /&gt;import android.app.Activity;&lt;br /&gt;import android.os.Bundle;&lt;br /&gt;&lt;br /&gt;public class Hello extends Activity&lt;br /&gt;{&lt;br /&gt;public void onCreate(Bundle savedInstanceState)&lt;br /&gt;{&lt;br /&gt;super.onCreate(savedInstanceState);&lt;br /&gt;setContentView(R.layout.main);&lt;br /&gt;logHello();&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;public static void logHello()&lt;br /&gt;{&lt;br /&gt;LoaderLogger.log("Hello");&lt;br /&gt;}&lt;br /&gt;}&lt;/pre&gt;&lt;li&gt;Add LoaderProblem to the Android manifest.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Create an ordinary Java project called LoaderProblemTestUtils, and create this class in it:&lt;/li&gt;&lt;pre&gt;package com.loaderproblem.testutils;&lt;br /&gt;&lt;br /&gt;public class TestUtil&lt;br /&gt;{&lt;br /&gt;public static final void doNothing()&lt;br /&gt;{&lt;br /&gt;}&lt;br /&gt;}&lt;/pre&gt;&lt;li&gt;Create an Android test project called LoaderProblemTests, add the other three projects to its build path, and create this class in it:&lt;/li&gt;&lt;pre&gt;package com.loaderproblem.tests;&lt;br /&gt;&lt;br /&gt;import android.test.AndroidTestCase;&lt;br /&gt;&lt;br /&gt;import com.loaderproblem.Hello;&lt;br /&gt;import com.loaderproblem.LoaderLogger;&lt;br /&gt;import com.loaderproblem.testutils.TestUtil;&lt;br /&gt;&lt;br /&gt;public class LogHelloTest extends AndroidTestCase&lt;br /&gt;{&lt;br /&gt;public void testLogHello()&lt;br /&gt;{&lt;br /&gt;LoaderLogger.log("Hello");&lt;br /&gt;Hello.logHello();&lt;br /&gt;TestUtil.doNothing();&lt;br /&gt;}&lt;br /&gt;}&lt;/pre&gt;&lt;/ol&gt;The result should look like this:&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_MuoEQTr-jEM/SskWNvKBkRI/AAAAAAAAAC8/CQD9BcWlz5Y/s1600-h/LoaderProblem.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 123px; height: 320px;" src="http://3.bp.blogspot.com/_MuoEQTr-jEM/SskWNvKBkRI/AAAAAAAAAC8/CQD9BcWlz5Y/s320/LoaderProblem.png" alt="" id="BLOGGER_PHOTO_ID_5388862854378131730" border="0" /&gt;&lt;/a&gt;Compile all four projects, create a brand-new AVD, and run LoaderProblem as an Android application. It should deploy and display:&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_MuoEQTr-jEM/SskXfTerDZI/AAAAAAAAADE/vcQhwS7aeVQ/s1600-h/LoaderProblemHello.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 320px; height: 140px;" src="http://4.bp.blogspot.com/_MuoEQTr-jEM/SskXfTerDZI/AAAAAAAAADE/vcQhwS7aeVQ/s320/LoaderProblemHello.png" alt="" id="BLOGGER_PHOTO_ID_5388864255697816978" border="0" /&gt;&lt;/a&gt;Now try to run LoaderProblemTests as an Android JUnit test. It will fail with:&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_MuoEQTr-jEM/SskY-XJ4IsI/AAAAAAAAADM/Pdzfm5EfDs8/s1600-h/LoaderProblemTestError1.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 304px; height: 320px;" src="http://1.bp.blogspot.com/_MuoEQTr-jEM/SskY-XJ4IsI/AAAAAAAAADM/Pdzfm5EfDs8/s320/LoaderProblemTestError1.png" alt="" id="BLOGGER_PHOTO_ID_5388865888771908290" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_MuoEQTr-jEM/SskZEGHTScI/AAAAAAAAADU/rq3hr6YzDhs/s1600-h/LoaderProblemTestError2.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 320px; height: 68px;" src="http://3.bp.blogspot.com/_MuoEQTr-jEM/SskZEGHTScI/AAAAAAAAADU/rq3hr6YzDhs/s320/LoaderProblemTestError2.png" alt="" id="BLOGGER_PHOTO_ID_5388865987276917186" border="0" /&gt;&lt;/a&gt;Or, for 2.1, it will fail with:&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_MuoEQTr-jEM/S51u0SArHZI/AAAAAAAAAEg/sLYIHOrSNLs/s1600-h/LoaderProblemTestError3.png"&gt;&lt;img style="display: block; margin: 0px auto 10px; text-align: center; cursor: pointer; width: 320px; height: 85px;" src="http://4.bp.blogspot.com/_MuoEQTr-jEM/S51u0SArHZI/AAAAAAAAAEg/sLYIHOrSNLs/s320/LoaderProblemTestError3.png" alt="" id="BLOGGER_PHOTO_ID_5448632968655084946" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;I first tried to fix this problem by editing the build path for LoaderProblemTests so it only depends on the LoaderProblemTestUtils Eclipse project, and then adding back the necessary classes by adding dependencies on the other projects' class folders:&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_MuoEQTr-jEM/SskgFMycLeI/AAAAAAAAADc/Nro0auPEKYQ/s1600-h/LoaderProblemClassFolders1.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 261px; height: 320px;" src="http://4.bp.blogspot.com/_MuoEQTr-jEM/SskgFMycLeI/AAAAAAAAADc/Nro0auPEKYQ/s320/LoaderProblemClassFolders1.png" alt="" id="BLOGGER_PHOTO_ID_5388873702829731298" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_MuoEQTr-jEM/SskgLV77eSI/AAAAAAAAADk/UGoz2FOL8uo/s1600-h/LoaderProblemClassFolders2.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 320px; height: 258px;" src="http://4.bp.blogspot.com/_MuoEQTr-jEM/SskgLV77eSI/AAAAAAAAADk/UGoz2FOL8uo/s320/LoaderProblemClassFolders2.png" alt="" id="BLOGGER_PHOTO_ID_5388873808364665122" border="0" /&gt;&lt;/a&gt;This "worked", but it introduced several unwanted side effects:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Now that the dependent  project's source is  seen as a class folder, one can no longer smoothly  refactor across projects or navigate into classes (via F3, for  instance), because these files are now treated as a compiled objects. Attaching the source to the classfolder  library sort of works, but then it brings up an uneditable version of the source. [reported by a reader]&lt;/li&gt;&lt;li&gt;It screws up EclEmma. For details see  https://sourceforge.net/tracker/?func=detail&amp;amp;atid=883351&amp;amp;aid=2934081&amp;amp;group_id=177969.&lt;/li&gt;&lt;/ul&gt;The proper way to fix this problem was reported by another reader:&lt;br /&gt;&lt;ol&gt;&lt;li&gt;In the build path for LoaderProblem, click on "Order and  Export".&lt;/li&gt;&lt;li&gt;Check the box for LoaderCommon, to let LoaderProblem  export the LoaderCommon classes as well as its own.&lt;/li&gt;&lt;li&gt;In the build path for LoaderProblemTests, remove the dependency on the  LoaderCommon project. The dependency is already now covered by the  LoaderProblem dependency.&lt;/li&gt;&lt;li&gt;Clean, build, rerun LoaderProblem, then rerun LoaderProblemTests.&lt;/li&gt;&lt;/ol&gt;This solution also fixes the EclEmma problem.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/356226683788078026-6748994401295351815?l=jimshowalter.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jimshowalter.blogspot.com/feeds/6748994401295351815/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://jimshowalter.blogspot.com/2009/10/developing-android-with-multiple.html#comment-form' title='14 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/356226683788078026/posts/default/6748994401295351815'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/356226683788078026/posts/default/6748994401295351815'/><link rel='alternate' type='text/html' href='http://jimshowalter.blogspot.com/2009/10/developing-android-with-multiple.html' title='Developing Android With Multiple Eclipse Projects'/><author><name>Jim Showalter</name><uri>http://www.blogger.com/profile/01963552914376132590</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/_MuoEQTr-jEM/SskWNvKBkRI/AAAAAAAAAC8/CQD9BcWlz5Y/s72-c/LoaderProblem.png' height='72' width='72'/><thr:total>14</thr:total></entry><entry><id>tag:blogger.com,1999:blog-356226683788078026.post-3560555685986819202</id><published>2009-09-26T10:53:00.000-07:00</published><updated>2009-09-26T11:58:48.119-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='legacy code large scale Eclipse Perforce single source root projects'/><title type='text'>Using Eclipse With Large Code Bases, Part V</title><content type='html'>&lt;a href="http://jimshowalter.blogspot.com/2009/08/using-eclipse-with-large-codebases-part.html"&gt;Previous posts&lt;/a&gt; described how to use file-system links and various Eclipse features to make a large, single-rooted source tree look like a set of smaller, multi-rooted Eclipse projects.&lt;br /&gt;&lt;br /&gt;But there's a catch: the Perforce Eclipse plugin doesn't work, because the Perforce client spec specifies the root of the actual source tree on disk, but the Eclipse Perforce plugin thinks the source tree is rooted at the directory that contains the Eclipse projects.&lt;br /&gt;&lt;br /&gt;For example, if we start with this client spec:&lt;pre&gt;Client: originalclient&lt;br /&gt;Root: C:\&lt;br /&gt;View:&lt;br /&gt;//trunk/src/... //originalclient/src/...&lt;/pre&gt;and use links to create this Eclipse structure:&lt;pre&gt;C:\projects\&lt;br /&gt;  Child1\&lt;br /&gt;      .classpath&lt;br /&gt;      .project&lt;br /&gt;      src\&lt;br /&gt;          com\&lt;br /&gt;              parent\&lt;br /&gt;                  child1 → linked to&lt;br /&gt;                  C:\src\com\parent\child1&lt;br /&gt;  Child2\&lt;br /&gt;      .classpath&lt;br /&gt;      .project&lt;br /&gt;      src\&lt;br /&gt;          com\&lt;br /&gt;              parent\&lt;br /&gt;                  child2 → linked to&lt;br /&gt;                  C:\src\com\parent\child2&lt;/pre&gt;then the Perforce root is C:, but the Eclipse Perforce plugin thinks the root is C:\projects.&lt;br /&gt;&lt;br /&gt;To fix this, we updated our link-generation script to generate a second client spec, where the client spec's root is the directory that contains the Eclipse projects, and the client spec maps individual sub-roots to their counterparts in the Eclipse projects (a one-for-one mapping between Perforce and the links):&lt;pre&gt;Client: myclient&lt;br /&gt;Root: C:\projects&lt;br /&gt;View:&lt;br /&gt;//trunk/src/com/parent/child1/... //myclient/Child1/src/com/parent/child1/...&lt;br /&gt;//trunk/src/com/parent/child2/... //myclient/Child2/src/com/parent/child1/...&lt;/pre&gt;Note that although we have three different "views" of the source tree (two in Perforce and one in Eclipse), there is only one actual occurrence of each source file on disk, which means changes are kept in sync among all three views.&lt;br /&gt;&lt;br /&gt;So if Perforce can do this mapping, why do we need the links at all? In many cases, you might not. In our case, though, the file layout in Perforce is really complicated, and it would be painful to create a client spec that maps all of the files to the file system. For example, there are sixty or so files at the very root of the Perforce tree, and these would have to be mapped to a directory on disk while using client-view exclusions to prevent mapping everything else in the root to that same directory. For us, it's easier to use the second client spec to map only the files we need in Eclipse--and to map them to directories that are actually links into the full tree.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/356226683788078026-3560555685986819202?l=jimshowalter.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jimshowalter.blogspot.com/feeds/3560555685986819202/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://jimshowalter.blogspot.com/2009/09/using-eclipse-with-large-code-bases.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/356226683788078026/posts/default/3560555685986819202'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/356226683788078026/posts/default/3560555685986819202'/><link rel='alternate' type='text/html' href='http://jimshowalter.blogspot.com/2009/09/using-eclipse-with-large-code-bases.html' title='Using Eclipse With Large Code Bases, Part V'/><author><name>Jim Showalter</name><uri>http://www.blogger.com/profile/01963552914376132590</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-356226683788078026.post-4716372219446103886</id><published>2009-09-26T10:27:00.001-07:00</published><updated>2009-09-26T10:42:34.138-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='eclipse plugin java dependency analysis analyzer static analysis reports'/><title type='text'>A Powerful And Flexible Java Dependency Analyzer</title><content type='html'>An &lt;a href="http://jimshowalter.blogspot.com/2009/08/eclipse-plugins-for-java-dependency.html"&gt;earlier post&lt;/a&gt; evaluated two Java dependency-analysis plugins for Eclipse. Both plugins are very good at providing an interactive, dynamic view of the code, which allows a programmer to explore dependencies and evaluate the impact of changes.&lt;br /&gt;&lt;br /&gt;Recently I had a different requirement: generate reports that summarize dependencies, and provide those reports to management in a format that doesn't require having the code or Eclipse available.&lt;br /&gt;&lt;br /&gt;A bit of googling brought up &lt;a href="http://depfind.sourceforge.net"&gt;Dependency Finder&lt;/a&gt;, which turned out to be an excellent tool--scalable, fast, flexible, well-documented, and easy to install. It comes with a set of reports, with numerous options, and it can be customized to produce specialized reports. It also has a GUI, although that wasn't needed for what I'm using it for.&lt;br /&gt;&lt;br /&gt;Support is excellent--a question to the author was answered within a few minutes.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/356226683788078026-4716372219446103886?l=jimshowalter.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jimshowalter.blogspot.com/feeds/4716372219446103886/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://jimshowalter.blogspot.com/2009/09/powerful-and-flexible-java-dependency.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/356226683788078026/posts/default/4716372219446103886'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/356226683788078026/posts/default/4716372219446103886'/><link rel='alternate' type='text/html' href='http://jimshowalter.blogspot.com/2009/09/powerful-and-flexible-java-dependency.html' title='A Powerful And Flexible Java Dependency Analyzer'/><author><name>Jim Showalter</name><uri>http://www.blogger.com/profile/01963552914376132590</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-356226683788078026.post-26289790690545811</id><published>2009-09-12T15:06:00.000-07:00</published><updated>2010-03-20T19:23:43.387-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='unit testing utilities 100% coverage high coverage open source'/><title type='text'>Test Utils are now open-source</title><content type='html'>At work, we've been encouraged to find ways to open-source technologies that are useful but aren't core to our business.&lt;br /&gt;&lt;br /&gt;While writing unit tests over the past several years, I developed some utilities that make it easier to perform some common test tasks, particularly when used with &lt;a href="https://jmockit.dev.java.net/"&gt;JMockit&lt;/a&gt; and &lt;a href="http://easymock.org/"&gt;EasyMock&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;The utilities are &lt;a href="https://code.intuit.com/sf/projects/testutils"&gt;now available as open source&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;Update: The genius who develops JMockit has added so many features it's not necessary to use reflection to populate fields, so there's no need for TestUtils to be used with JMockit. TestUtils are still useful with other mocking tools, and when you just want to use reflection for something in a test where you aren't using mocking.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/356226683788078026-26289790690545811?l=jimshowalter.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jimshowalter.blogspot.com/feeds/26289790690545811/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://jimshowalter.blogspot.com/2009/09/test-utils-are-now-open-source.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/356226683788078026/posts/default/26289790690545811'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/356226683788078026/posts/default/26289790690545811'/><link rel='alternate' type='text/html' href='http://jimshowalter.blogspot.com/2009/09/test-utils-are-now-open-source.html' title='Test Utils are now open-source'/><author><name>Jim Showalter</name><uri>http://www.blogger.com/profile/01963552914376132590</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-356226683788078026.post-7609850076569600250</id><published>2009-08-30T15:52:00.000-07:00</published><updated>2010-05-22T19:51:20.726-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='coverage tools Clover EMMA JaCoCo EclEmma Cobertura JMockit Google Android'/><title type='text'>Selecting A Coverage Tool</title><content type='html'>At work, we use &lt;a href="http://www.atlassian.com/software/clover"&gt;Clover&lt;/a&gt; to track coverage.&lt;br /&gt;&lt;br /&gt;For programming at home, a Clover license is &lt;a href="http://www.atlassian.com/software/clover/pricing.jsp"&gt;way too expensive&lt;/a&gt; (not as bad as those software vendors that used to not list prices and instead said "Call for quote", but close).&lt;br /&gt;&lt;br /&gt;Also, we've had some issues with Clover:&lt;br /&gt;&lt;ol&gt;&lt;li&gt;It sometimes falsely claims that code is covered when it isn't.&lt;/li&gt;&lt;li&gt;It doesn't support branch coverage.&lt;/li&gt;&lt;li&gt;It can't instrument assignments in conditionals.&lt;/li&gt;&lt;/ol&gt;(The Clover rep confirmed the above problems a couple of years ago. These may have been fixed by now. However, because the licenses are so expensive, we haven't upgraded, so we're stuck with the problems even if they're fixed in the current version. Also, the Clover rep didn't think the third issue would ever be fixed due to the way they instrument the code.)&lt;br /&gt;&lt;br /&gt;For a simple example of problem #2, start with a function like this:&lt;br /&gt;&lt;pre&gt;public boolean eval(boolean x, boolean y, boolean z)&lt;br /&gt;{&lt;br /&gt;return x &amp;amp;&amp;amp; (y || z);&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;Clover scores 100% coverage if the entire expression evaluates at least once to true and at least once to false, so this is sufficient:&lt;pre&gt;assertTrue(eval(true, true, false));&lt;br /&gt;assertFalse(eval(true, false, false));&lt;br /&gt;&lt;/pre&gt;But evaluating all of the meaningfully distinct ways for the expression to evaluate requires more tests:&lt;pre&gt;assertTrue(eval(true, true, false));&lt;br /&gt;assertTrue(eval(true, false, true));&lt;br /&gt;assertFalse(eval(true, false, false));&lt;br /&gt;assertFalse(eval(false, true, false));&lt;br /&gt;&lt;/pre&gt;Problem #3 means that this code can't be covered:&lt;pre&gt;while (currentLine = stream.readLine() != null)&lt;/pre&gt;Covering that code with Clover requires rewriting it as a do/while.&lt;br /&gt;&lt;br /&gt;For the above reasons, I went in search of a coverage tool other than Clover for programming at home.&lt;br /&gt;&lt;br /&gt;Googling around, &lt;a href="http://emma.sourceforge.net/"&gt;EMMA&lt;/a&gt; and &lt;a href="http://www.eclemma.org/"&gt;EclEmma&lt;/a&gt; (an Eclipse plugin for EMMA) kept showing up, so I tried them.&lt;br /&gt;&lt;br /&gt;Unfortunately, where Clover incorrectly says that uncovered code is covered, EMMA incorrectly says that covered code is not covered:&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_MuoEQTr-jEM/SpsL5GvnQUI/AAAAAAAAACk/_oG6ozmfyhk/s1600-h/EMMASaysLineIsNotCovered.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 320px; height: 119px;" src="http://1.bp.blogspot.com/_MuoEQTr-jEM/SpsL5GvnQUI/AAAAAAAAACk/_oG6ozmfyhk/s320/EMMASaysLineIsNotCovered.png" alt="" id="BLOGGER_PHOTO_ID_5375903655887585602" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_MuoEQTr-jEM/SpsMC_zo5MI/AAAAAAAAACs/3gcBzvTpggs/s1600-h/StoppedOnSameLineInDebuggerInSameTest.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 320px; height: 270px;" src="http://1.bp.blogspot.com/_MuoEQTr-jEM/SpsMC_zo5MI/AAAAAAAAACs/3gcBzvTpggs/s320/StoppedOnSameLineInDebuggerInSameTest.png" alt="" id="BLOGGER_PHOTO_ID_5375903825824113858" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;True, it only screws up occasionally, but if you're five lines short of 100% coverage, and the five lines are spurious tool errors, it's annoying.&lt;br /&gt;&lt;br /&gt;This was unfortunate, because the EclEmma plugin is very fast and completely non-intrusive, and would be great to use. Plus, it's currently the only coverage tool that works with Android.&lt;br /&gt;&lt;br /&gt;After reporting these problems, I looked around for alternatives. A bunch of coverage tools were listed &lt;a href="http://java-source.net/open-source/code-coverage"&gt;here&lt;/a&gt;, and I tried each of them out. Most didn't install, or weren't compatible with the latest Eclipse, or hadn't been maintained for a number of years, etc.&lt;br /&gt;&lt;br /&gt;But &lt;a href="http://cobertura.sourceforge.net/index.html"&gt;Cobertura&lt;/a&gt; works really well.&lt;br /&gt;&lt;br /&gt;Unfortunately, there's no Eclipse plugin for Cobertura, and it's slower than the other two tools, but compared to getting the wrong answer, that's not too much to give up. The dream tool would combine Cobertura's accuracy with EclEmma's speed and usability, but no such tool exists.&lt;br /&gt;&lt;br /&gt;This table compares the three tools:&lt;style type="text/css"&gt;.nobrtable br { display: none }&lt;/style&gt;&lt;br /&gt;&lt;div class="nobrtable"&gt;&lt;br /&gt;&lt;table border="1"&gt;&lt;br /&gt;&lt;tbody&gt;&lt;tr&gt;&lt;br /&gt;&lt;td&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;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;/td&gt;&lt;td&gt;Clover&lt;/td&gt;&lt;td&gt;EMMA/EclEmma&lt;/td&gt;&lt;td&gt;Cobertura&lt;/td&gt;&lt;br /&gt;&lt;/tr&gt;&lt;br /&gt;&lt;tr&gt;&lt;br /&gt;&lt;td&gt;Statement coverage&lt;/td&gt;&lt;td&gt;yes&lt;/td&gt;&lt;td&gt;yes&lt;/td&gt;&lt;td&gt;yes&lt;/td&gt;&lt;br /&gt;&lt;/tr&gt;&lt;br /&gt;&lt;tr&gt;&lt;br /&gt;&lt;td&gt;Branch coverage&lt;/td&gt;&lt;td&gt;no&lt;/td&gt;&lt;td&gt;no&lt;/td&gt;&lt;td&gt;yes&lt;/td&gt;&lt;br /&gt;&lt;/tr&gt;&lt;br /&gt;&lt;tr&gt;&lt;td&gt;No quirks or bugs&lt;/td&gt;&lt;td&gt;no&lt;/td&gt;&lt;td&gt;no&lt;/td&gt;&lt;td&gt;yes&lt;/td&gt;&lt;br /&gt;&lt;/tr&gt;&lt;br /&gt;&lt;tr&gt;&lt;td&gt;Fast&lt;/td&gt;&lt;td&gt;yes&lt;/td&gt;&lt;td&gt;yes&lt;/td&gt;&lt;td&gt;no&lt;/td&gt;&lt;br /&gt;&lt;/tr&gt;&lt;br /&gt;&lt;tr&gt;&lt;td&gt;Reports&lt;/td&gt;&lt;td&gt;yes&lt;/td&gt;&lt;td&gt;yes&lt;/td&gt;&lt;td&gt;yes&lt;/td&gt;&lt;br /&gt;&lt;/tr&gt;&lt;br /&gt;&lt;tr&gt;&lt;td&gt;Maven integration&lt;/td&gt;&lt;td&gt;yes&lt;/td&gt;&lt;td&gt;yes&lt;/td&gt;&lt;td&gt;sort of&lt;br /&gt;&lt;/td&gt;&lt;br /&gt;&lt;/tr&gt;&lt;br /&gt;&lt;tr&gt;&lt;td&gt;Works with mocking tools&lt;/td&gt;&lt;td&gt;yes&lt;/td&gt;&lt;td&gt;yes&lt;/td&gt;&lt;td&gt;yes&lt;/td&gt;&lt;br /&gt;&lt;/tr&gt;&lt;br /&gt;&lt;tr&gt;&lt;td&gt;Eclipse plugin&lt;/td&gt;&lt;td&gt;yes&lt;/td&gt;&lt;td&gt;yes&lt;/td&gt;&lt;td&gt;sort of&lt;br /&gt;&lt;br /&gt;&lt;/td&gt;&lt;br /&gt;&lt;/tr&gt;&lt;br /&gt;&lt;tr&gt;&lt;td&gt;Free&lt;/td&gt;&lt;td&gt;no&lt;/td&gt;&lt;td&gt;yes&lt;/td&gt;&lt;td&gt;yes&lt;/td&gt;&lt;br /&gt;&lt;/tr&gt;&lt;br /&gt;&lt;tr&gt;&lt;td&gt;Active community&lt;/td&gt;&lt;td&gt;yes&lt;/td&gt;&lt;td&gt;yes&lt;/td&gt;&lt;td&gt;sort of&lt;br /&gt;&lt;br /&gt;&lt;/td&gt;&lt;br /&gt;&lt;/tr&gt;&lt;br /&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;Notes:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Maven integration for Cobertura is provided by a &lt;a href="http://cobertura.sourceforge.net/maven.html"&gt;separate open-source project&lt;/a&gt;. This project has been around for a while. There are some problems using the integration.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Eclipse integration for Cobertura is provided by &lt;a href="http://ecobertura.johoop.de/"&gt;a separate open-source project&lt;/a&gt;. This project is new and not very mature yet.&lt;/li&gt;&lt;li&gt;Cobertura's community support is rated "sort of" because the only forum is via an email distribution list, and responses can take a couple of days. On the other hand, the code is mature and easy to use, so there isn't much need for help (most of the emails I sent were questions about setting up the ant scripts).&lt;/li&gt;&lt;li&gt;JMockit can be configured to generate coverage reports, but currently only statement covered is supported. The author plans to add additional features (including branch coverage), at which point it should be evaluated like the other three tools.&lt;/li&gt;&lt;li&gt;For a comparison of coverage tools that arrives at the opposite conclusion to mine (partly due to other requirements), see http://javapulse.net/2008/09/02/coverage-emma-cobertura-maven.&lt;/li&gt;&lt;/ul&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/356226683788078026-7609850076569600250?l=jimshowalter.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jimshowalter.blogspot.com/feeds/7609850076569600250/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://jimshowalter.blogspot.com/2009/08/selecting-coverage-tool.html#comment-form' title='6 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/356226683788078026/posts/default/7609850076569600250'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/356226683788078026/posts/default/7609850076569600250'/><link rel='alternate' type='text/html' href='http://jimshowalter.blogspot.com/2009/08/selecting-coverage-tool.html' title='Selecting A Coverage Tool'/><author><name>Jim Showalter</name><uri>http://www.blogger.com/profile/01963552914376132590</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/_MuoEQTr-jEM/SpsL5GvnQUI/AAAAAAAAACk/_oG6ozmfyhk/s72-c/EMMASaysLineIsNotCovered.png' height='72' width='72'/><thr:total>6</thr:total></entry><entry><id>tag:blogger.com,1999:blog-356226683788078026.post-6111218572446121336</id><published>2009-08-25T18:48:00.000-07:00</published><updated>2009-09-26T10:45:20.312-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='eclipse plugin java dependency analysis analyzer static analysis'/><title type='text'>Eclipse Plugins For Java Dependency Analysis</title><content type='html'>Once I got our project's code imported into Eclipse in a usable way, the real work started.&lt;br /&gt;&lt;br /&gt;The plan is to upgrade the code to use newer APIs and services. To do that, we need a way to analyze the dependencies, to identify cycles, determine the easiest places to refactor, etc.&lt;br /&gt;&lt;br /&gt;A web search found &lt;a href="http://dev.eclipse.org/blogs/seva/2008/02/01/java-code-structure-and-dependencies-analysis-tools-for-eclipse"&gt;a useful evaluation of various dependency-analyzers for Eclipse&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;I tried all of the tools listed in the evaluation, and liked &lt;a href="http://stan4j.com/"&gt;STAN&lt;/a&gt; the best.&lt;br /&gt;&lt;br /&gt;STAN installs easily, is intuitive to use, and doesn't choke on our million-plus lines of code (after configuring it to analyze class-to-class dependencies instead of at the method level). Plus, questions emailed to STAN are answered quickly--the support is good. We bought a license.&lt;br /&gt;&lt;br /&gt;But STAN is a commercial product, and I also needed something to use at home. Something inexpensive.&lt;br /&gt;&lt;br /&gt;That's when I noticed a comment at the bottom of the evaluation. (It had been there all the time, but who reads comments, right?)&lt;br /&gt;&lt;br /&gt;The comment recommends &lt;a href="http://cap.xore.de/"&gt;CAP&lt;/a&gt;, and it's a good recommendation. CAP is similar to STAN in terms of ease of installation and use, it doesn't choke on our million-line project, and it's faster than STAN and uses less memory. Plus it's free, which is hard to beat.&lt;br /&gt;&lt;br /&gt;However, CAP hasn't been upgraded for a while, and the author is intermittently difficult to contact. Also, STAN has a better display of rolled-up package dependencies (for example, if you have com.abc and com.abc.def, you can see dependencies on com.abc, or com.abc.def, or com.abc*, but in CAP you can only see com.abc or com.abc.def individually).&lt;br /&gt;&lt;br /&gt;STAN doesn't offer floating licenses, which makes it pretty expensive if more than a couple engineers will be using it. Dependency analysis is something an engineer might do while learning or refactoring a code base, and then not do again for months, so floating licenses would make sense.&lt;br /&gt;&lt;br /&gt;Both tools are good. STAN's package roll-ups are really useful when you have a lot of subpackages. CAP's price is hard to beat.&lt;br /&gt;&lt;br /&gt;If you do use CAP, please support open source and send the author a donation. I was the first person to do that, which is kind of a shame.&lt;br /&gt;&lt;br /&gt;Update: See &lt;a href="http://jimshowalter.blogspot.com/2009/09/powerful-and-flexible-java-dependency.html"&gt;this post&lt;/a&gt; for another good Java dependency analyzer.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/356226683788078026-6111218572446121336?l=jimshowalter.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jimshowalter.blogspot.com/feeds/6111218572446121336/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://jimshowalter.blogspot.com/2009/08/eclipse-plugins-for-java-dependency.html#comment-form' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/356226683788078026/posts/default/6111218572446121336'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/356226683788078026/posts/default/6111218572446121336'/><link rel='alternate' type='text/html' href='http://jimshowalter.blogspot.com/2009/08/eclipse-plugins-for-java-dependency.html' title='Eclipse Plugins For Java Dependency Analysis'/><author><name>Jim Showalter</name><uri>http://www.blogger.com/profile/01963552914376132590</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>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-356226683788078026.post-4061714725575080203</id><published>2009-08-23T12:25:00.000-07:00</published><updated>2009-10-03T16:40:07.230-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='legacy code large scale Eclipse single source root runtime classes linked resources'/><title type='text'>Using Eclipse With Large Code Bases, Part IV</title><content type='html'>&lt;span style="font-size:100%;"&gt;Previous &lt;a href="http://jimshowalter.blogspot.com/2009/08/using-eclipse-with-large-codebases-part.html"&gt;posts&lt;/a&gt; described how we created a set of Eclipse projects that break up our million-line, single-rooted source tree into manageable chunks.&lt;br /&gt;&lt;br /&gt;Today, I'll describe how we solved a similar problem with our runtime classes:&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="font-style: italic;font-size:100%;" &gt;5. JAXB is used to generate some .class files into a runtime directory "rt", but that same directory contains all of the .class files for the system&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-size:100%;"&gt;Some details on the situation:&lt;br /&gt;&lt;/span&gt;&lt;ul&gt;&lt;li&gt;&lt;span style="font-size:100%;"&gt;Our project currently uses gmake to compile the million-plus lines of code.&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="font-size:100%;"&gt;Builds output to a runtime directory on the developer's machine called "rt". All classes required to launch the application are either in rt, or in JARs in a "lib" directory.&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="font-size:100%;"&gt;Many of the classes in the rt directory are duplicates of classes Eclipse compiles in the projects, but some of the classes in the rt directory are generated by JAXB (which is executed by gmake as part of the builds), and are not in the source tree.&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="font-size:100%;"&gt;Eclipse needs to see the generated classes in order to compile.&lt;/span&gt;&lt;/li&gt;&lt;/ul&gt;&lt;span style="font-size:100%;"&gt;For example:&lt;pre&gt;package com.parent.child1;&lt;br /&gt;&lt;br /&gt;import com.parent.Parent;&lt;br /&gt;&lt;br /&gt;import com.parent.child1.generated.Gen1;&lt;br /&gt;&lt;br /&gt;public class Child1 extends Parent&lt;br /&gt;{&lt;br /&gt;   private Gen1 gen1;&lt;br /&gt;}&lt;/pre&gt;Eclipse supports linked resources, so at first it seemed like we just needed to define a linked resource for external classes that pointed to rt. Unfortunately, there are so many classes in rt that Eclipse again ground to a halt.&lt;br /&gt;&lt;br /&gt;Fortunately, by now we were experienced with using links to subset a source directory hierarchy, so I just used the same approach to subset the runtime directory hierarchy.&lt;br /&gt;&lt;br /&gt;First, run commands to add a link into the rt directory at the desired location:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:100%;"&gt;&lt;span style="font-family:courier new;"&gt;mkdir C:\projects\Child1\rt\com\parent\child1\generated&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;junction C:\projects\Child1\rt\com\parent\child1\generated C:\rt\com\parent\child1\generated&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Then add the rt directory to the .classpath:&lt;pre  style="font-family:courier new;"&gt;&lt;span style="font-size:100%;"&gt;&amp;lt;classpathentry kind="lib" path="rt"/&amp;gt;&lt;/span&gt;&lt;/pre&gt;Refresh in Eclipse, and the code builds:&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_MuoEQTr-jEM/SpGjiVI9Q3I/AAAAAAAAACc/pmquccqqrbc/s1600-h/LinkedRuntimeClasses.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 231px; height: 238px;" src="http://2.bp.blogspot.com/_MuoEQTr-jEM/SpGjiVI9Q3I/AAAAAAAAACc/pmquccqqrbc/s320/LinkedRuntimeClasses.png" alt="" id="BLOGGER_PHOTO_ID_5373255640615306098" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;Notes:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;As was the case with source files, multiple links to runtime-class directories can be created for a single project.&lt;/li&gt;&lt;li&gt;If multiple projects need the same .class files from an rt directory, the rt link should be set only in the project that generates the .class files. Other projects should point to that rt link via Build Path → Add Class Folder...&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;In &lt;a href="http://jimshowalter.blogspot.com/2009/09/using-eclipse-with-large-code-bases.html"&gt;Part V&lt;/a&gt;, I'll describe how we fixed a problem with the Perforce Eclipse plugin caused by using links.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/356226683788078026-4061714725575080203?l=jimshowalter.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jimshowalter.blogspot.com/feeds/4061714725575080203/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://jimshowalter.blogspot.com/2009/08/using-eclipse-with-large-code-bases_23.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/356226683788078026/posts/default/4061714725575080203'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/356226683788078026/posts/default/4061714725575080203'/><link rel='alternate' type='text/html' href='http://jimshowalter.blogspot.com/2009/08/using-eclipse-with-large-code-bases_23.html' title='Using Eclipse With Large Code Bases, Part IV'/><author><name>Jim Showalter</name><uri>http://www.blogger.com/profile/01963552914376132590</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/_MuoEQTr-jEM/SpGjiVI9Q3I/AAAAAAAAACc/pmquccqqrbc/s72-c/LinkedRuntimeClasses.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-356226683788078026.post-7283988049403479697</id><published>2009-08-22T13:25:00.000-07:00</published><updated>2009-09-26T11:41:59.130-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='legacy code large scale eclipse single source root cycles cyclic dependencies projects'/><title type='text'>Using Eclipse With Large Code Bases, Part III</title><content type='html'>In &lt;a href="http://jimshowalter.blogspot.com/2009/08/using-eclipse-with-large-code-bases.html"&gt;Part II&lt;/a&gt;, we saw how to use links to break a large single-rooted source tree into separate Eclipse projects.&lt;br /&gt;&lt;br /&gt;In those examples, the packages didn't have mutual dependencies--they were a &lt;a href="http://en.wikipedia.org/wiki/Directed_acyclic_graph"&gt;directed, acyclic graph&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;But in my project's legacy code base, there is another complication:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style: italic;font-size:100%;" &gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span style="font-style: italic;font-size:100%;" &gt;4. Packages and layers have mutual dependencies (for example, business logic in the UI layer), but Eclipse treats cycles among projects as compile errors&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Of course, it would be better not to have cycles, but in a legacy code base it's not always easy, or even tractable, to remove them. Remember that my project has to work with this constraint:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:100%;"&gt;&lt;span style="font-style: italic;"&gt;6. None of this can be changed, at least not any time soon&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;So, a more realistic example has child1 depend on child2, and vice-versa:&lt;pre&gt;package com.parent.child1;&lt;br /&gt;&lt;br /&gt;import com.parent.Parent;&lt;br /&gt;import com.parent.child2.Child2;&lt;br /&gt;&lt;br /&gt;public class Child1 extends Parent&lt;br /&gt;{&lt;br /&gt;  private Child2 child2;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;package com.parent.child2;&lt;br /&gt;&lt;br /&gt;import com.parent.Parent;&lt;br /&gt;import com.parent.child1.Child1;&lt;br /&gt;&lt;br /&gt;public class Child2 extends Parent&lt;br /&gt;{&lt;br /&gt;  private Child1 child1;&lt;br /&gt;}&lt;/pre&gt;This is allowed by Java, but not allowed (by default) by Eclipse for packages in separate projects, even after adding the project dependencies:&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_MuoEQTr-jEM/SpBWzLnNo6I/AAAAAAAAABs/ImtrwvbdRkc/s1600-h/CyclesError1.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 208px; height: 320px;" src="http://4.bp.blogspot.com/_MuoEQTr-jEM/SpBWzLnNo6I/AAAAAAAAABs/ImtrwvbdRkc/s320/CyclesError1.png" alt="" id="BLOGGER_PHOTO_ID_5372889792743580578" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_MuoEQTr-jEM/SpBW7SX0wrI/AAAAAAAAAB0/W0JCT3ivbq8/s1600-h/CyclesError2.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 320px; height: 74px;" src="http://4.bp.blogspot.com/_MuoEQTr-jEM/SpBW7SX0wrI/AAAAAAAAAB0/W0JCT3ivbq8/s320/CyclesError2.png" alt="" id="BLOGGER_PHOTO_ID_5372889931997037234" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;Fortunately, Eclipse allows cycles to be a warning instead of an error:&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_MuoEQTr-jEM/SpBY6XJ_9eI/AAAAAAAAACE/EEY5I8xCKAQ/s1600-h/CyclesWarning1.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 320px; height: 262px;" src="http://3.bp.blogspot.com/_MuoEQTr-jEM/SpBY6XJ_9eI/AAAAAAAAACE/EEY5I8xCKAQ/s320/CyclesWarning1.png" alt="" id="BLOGGER_PHOTO_ID_5372892115124614626" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;Unfortunately, that just converts the errors into warnings, which clutter the window (we already know we have cycles):&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_MuoEQTr-jEM/SpBZOf0GfGI/AAAAAAAAACM/MHGbt1iZS3I/s1600-h/CyclesWarning2.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 320px; height: 56px;" src="http://2.bp.blogspot.com/_MuoEQTr-jEM/SpBZOf0GfGI/AAAAAAAAACM/MHGbt1iZS3I/s320/CyclesWarning2.png" alt="" id="BLOGGER_PHOTO_ID_5372892461046070370" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;Fortunately, Eclipse supports filtering out specific warnings. In the Problems window, click the down-arrow icon on the right (View Menu), select Configure Contents..., and add a filter:&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_MuoEQTr-jEM/SpBaWMrLnWI/AAAAAAAAACU/4p2xt20fPS0/s1600-h/SuppressWarning.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 320px; height: 182px;" src="http://2.bp.blogspot.com/_MuoEQTr-jEM/SpBaWMrLnWI/AAAAAAAAACU/4p2xt20fPS0/s320/SuppressWarning.png" alt="" id="BLOGGER_PHOTO_ID_5372893692858965346" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;And now the Problems window is empty.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://jimshowalter.blogspot.com/2009/08/using-eclipse-with-large-code-bases_23.html"&gt;Part IV&lt;/a&gt; describes how we fixed this remaining issue:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style: italic;font-size:100%;" &gt;5. JAXB is used to generate some .class files into a runtime directory "rt", but that same directory contains all of the .class files for the system&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/356226683788078026-7283988049403479697?l=jimshowalter.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jimshowalter.blogspot.com/feeds/7283988049403479697/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://jimshowalter.blogspot.com/2009/08/using-eclipse-with-large-code-bases_22.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/356226683788078026/posts/default/7283988049403479697'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/356226683788078026/posts/default/7283988049403479697'/><link rel='alternate' type='text/html' href='http://jimshowalter.blogspot.com/2009/08/using-eclipse-with-large-code-bases_22.html' title='Using Eclipse With Large Code Bases, Part III'/><author><name>Jim Showalter</name><uri>http://www.blogger.com/profile/01963552914376132590</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/_MuoEQTr-jEM/SpBWzLnNo6I/AAAAAAAAABs/ImtrwvbdRkc/s72-c/CyclesError1.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-356226683788078026.post-8796177980631669778</id><published>2009-08-21T18:51:00.000-07:00</published><updated>2009-09-26T11:00:10.881-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='legacy code large scale eclipse single source root links projects'/><title type='text'>Using Eclipse With Large Code Bases, Part II</title><content type='html'>In &lt;a href="http://jimshowalter.blogspot.com/2009/08/using-eclipse-with-large-codebases-part.html"&gt;Part I&lt;/a&gt;, linked source with excludes failed to solve the problem of how to break up a large, single-rooted source tree into multiple projects in Eclipse.&lt;br /&gt;&lt;br /&gt;After a night off, I thought of using file-system links to create the illusion of multiple directory roots. But we needed directory-to-directory links, not file-to-file links, and Windows doesn't directly support those.&lt;br /&gt;&lt;br /&gt;A coworker found the Windows-specific "junction" command, which can be &lt;a href="http://technet.microsoft.com/en-us/sysinternals/bb896768.aspx"&gt;downloaded from Microsoft&lt;/a&gt;. It's an add-on to Windows, not part of the standard set of shell commands. With the junction command, I was able to create a multi-rooted source tree that points to the source it needs from the single-rooted source tree.&lt;br /&gt;&lt;br /&gt;For example, starting with:&lt;pre&gt;C:\src\&lt;br /&gt;  com\&lt;br /&gt;      parent\&lt;br /&gt;          Parent.java&lt;br /&gt;          child1\&lt;br /&gt;              Child1.java&lt;br /&gt;          child2\&lt;br /&gt;              Child.java&lt;/pre&gt;Create a parallel structure:&lt;pre&gt;C:\projects\&lt;br /&gt;  Child1\&lt;br /&gt;      .classpath&lt;br /&gt;      .project&lt;br /&gt;      src\&lt;br /&gt;  Child2\&lt;br /&gt;      .classpath&lt;br /&gt;      .project&lt;br /&gt;      src\&lt;/pre&gt;&lt;span style=";font-family:verdana;font-size:100%;"  &gt;The .project files don't have linked-source directives in them, and the .classpath files just have the standard &amp;lt;classpathentry including="**/*.java" kind="src" path="src"/&amp;gt; entries.&lt;br /&gt;&lt;br /&gt;From a command prompt, execute commands to create links from the project src directories into the real source tree:&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:100%;"&gt;&lt;span style="font-family:courier new;"&gt;mkdir C:\projects\Child1\src\com\parent\child1&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;junction C:\projects\Child1\src\com\parent\child1 C:\src\com\parent\child1&lt;/span&gt;&lt;span style="font-family:courier new;"&gt;&lt;br /&gt;&lt;br /&gt;mkdir C:\projects\Child2\src\com\parent\child2&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;junction C:\projects\Child2\src\com\parent\child2 C:\src\com\parent\child2&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;(The commands for creating directory and file links in linux/Mac are of course different, but the concepts are the same.)&lt;br /&gt;&lt;br /&gt;The resulting directory structure looks like this:&lt;pre&gt;C:\projects\&lt;br /&gt;  Child1\&lt;br /&gt;      .classpath&lt;br /&gt;      .project&lt;br /&gt;      src\&lt;br /&gt;          com\&lt;br /&gt;              parent\&lt;br /&gt;                  child1 → linked to&lt;br /&gt;                  C:\src\com\parent\child1&lt;br /&gt;  Child2\&lt;br /&gt;      .classpath&lt;br /&gt;      .project&lt;br /&gt;      src\&lt;br /&gt;          com\&lt;br /&gt;              parent\&lt;br /&gt;                  child2 → linked to&lt;br /&gt;                  C:\src\com\parent\child2&lt;/pre&gt;&lt;span style=";font-family:verdana;font-size:100%;"  &gt;After refreshing the projects in Eclipse, the unwanted packages and source files are gone:&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_MuoEQTr-jEM/SpBGFz77C4I/AAAAAAAAABU/ZYl4BCKVtSw/s1600-h/UsingLinks.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 236px; height: 238px;" src="http://1.bp.blogspot.com/_MuoEQTr-jEM/SpBGFz77C4I/AAAAAAAAABU/ZYl4BCKVtSw/s320/UsingLinks.png" alt="" id="BLOGGER_PHOTO_ID_5372871421107833730" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;Unfortunately, the code doesn't compile:&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_MuoEQTr-jEM/SpBGovewTyI/AAAAAAAAABc/2jJMZq2_b1g/s1600-h/DoesNotCompile.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 229px; height: 237px;" src="http://1.bp.blogspot.com/_MuoEQTr-jEM/SpBGovewTyI/AAAAAAAAABc/2jJMZq2_b1g/s320/DoesNotCompile.png" alt="" id="BLOGGER_PHOTO_ID_5372872021207174946" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;Remember the third item in the list of problems?:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;3. Some source files used throughout the code are located in the top of the source tree&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;It has come back to haunt us. We have to have visibility to Parent.java in both projects, but we can't link to the root of the source tree, because that's the problem we're trying to solve with links.&lt;br /&gt;&lt;br /&gt;To fix this, create another project, Parent, but use a file link instead of a directory link:&lt;br /&gt;&lt;br /&gt;&lt;span style=";font-family:courier new;font-size:100%;"  &gt;mkdir C:\projects\Parent\src\com\parent&lt;br /&gt;fsutil hardlink create C:\projects\Parent\src\com\parent\Parent.java C:\src\com\parent\Parent.java&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Then add the Parent project to the dependencies of Child1 and Child2, and now it does compile:&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_MuoEQTr-jEM/SpBHQ-pDmfI/AAAAAAAAABk/ledAkisM_2g/s1600-h/ParentProject.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 204px; height: 320px;" src="http://1.bp.blogspot.com/_MuoEQTr-jEM/SpBHQ-pDmfI/AAAAAAAAABk/ledAkisM_2g/s320/ParentProject.png" alt="" id="BLOGGER_PHOTO_ID_5372872712471681522" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style=";font-family:verdana;font-size:100%;"  &gt;This approach works very well--the entire million-plus lines of code is broken up into 40+ projects in Eclipse, and the code compiles quickly after the initial import.&lt;br /&gt;&lt;br /&gt;You can envision an Eclipse plugin that would semi-automate this process. At a minimum it would be nice to generate the projects and link scripts from some kind of description, instead of editing the files by hand. Unfortunately, by the time I had worked out the pattern, the projects and links were mostly already finished.&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style=";font-family:verdana;font-size:100%;"  &gt;Note: Although it's not shown in the examples above, this approach can also be used to link to multiple child nodes in a source tree to produce a combined tree for a project. For example:&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:100%;"&gt;&lt;span style="font-family:courier new;"&gt;mkdir C:\projects\Child1\src\com\parent\child1&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;junction C:\projects\Child1\src\com\parent\child1 C:\src\com\parent\child1&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:100%;"&gt;&lt;span style="font-family:courier new;"&gt;mkdir C:\projects\Child1\src\com\parent\otherChild&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;junction C:\projects\Child1\src\com\parent\otherChild C:\src\com\parent\otherChild&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style=";font-family:verdana;font-size:100%;"  &gt;&lt;br /&gt;In &lt;a href="http://jimshowalter.blogspot.com/2009/08/using-eclipse-with-large-code-bases_22.html"&gt;Part III&lt;/a&gt;, I'll describe how we dealt with this issue:&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="font-style: italic;font-size:100%;" &gt;&lt;span&gt;4. &lt;/span&gt;&lt;/span&gt;&lt;span style="font-style: italic;font-size:100%;" &gt;Packages and layers have mutual dependencies (for example, business logic in the UI layer), but Eclipse treats cycles among projects as compile errors&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/356226683788078026-8796177980631669778?l=jimshowalter.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jimshowalter.blogspot.com/feeds/8796177980631669778/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://jimshowalter.blogspot.com/2009/08/using-eclipse-with-large-code-bases.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/356226683788078026/posts/default/8796177980631669778'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/356226683788078026/posts/default/8796177980631669778'/><link rel='alternate' type='text/html' href='http://jimshowalter.blogspot.com/2009/08/using-eclipse-with-large-code-bases.html' title='Using Eclipse With Large Code Bases, Part II'/><author><name>Jim Showalter</name><uri>http://www.blogger.com/profile/01963552914376132590</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/_MuoEQTr-jEM/SpBGFz77C4I/AAAAAAAAABU/ZYl4BCKVtSw/s72-c/UsingLinks.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-356226683788078026.post-4652849103929716702</id><published>2009-08-20T19:25:00.000-07:00</published><updated>2009-09-26T10:59:20.426-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='legacy code large scale eclipse single source root projects'/><title type='text'>Using Eclipse With Large Code Bases, Part I</title><content type='html'>&lt;span style=";font-family:verdana;font-size:100%;"  &gt;&lt;span style="font-family:verdana;"&gt;The project I'm currently working on has more than a million lines of source code. Some of the code was written as long ago as 1998, so as odd as it sounds to call anything involving Java "legacy", this is a legacy Java codebase.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:verdana;"&gt;I wanted to bring the code into Eclipse, but not as one giant million-line project. Instead, I wanted to break it up into smaller projects.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:verdana;"&gt;But there were complications:&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;&lt;ol  style="font-family:verdana;"&gt;&lt;li&gt;&lt;span style="font-size:100%;"&gt;The source tree has a single root directory&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="font-size:100%;"&gt;Eclipse can't nest projects&lt;br /&gt;&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="font-size:100%;"&gt;Some source files used throughout the code are located in the top of the source tree&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="font-size:100%;"&gt;Packages and layers have mutual dependencies (for example, business logic in the UI layer), but Eclipse treats cycles among projects as compile errors&lt;br /&gt;&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="font-size:100%;"&gt;JAXB is used to generate some .class files into a runtime directory "rt", but that same directory contains all of the .class files for the system&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="font-size:100%;"&gt;None of this can be changed, at least not any time soon&lt;br /&gt;&lt;/span&gt;&lt;/li&gt;&lt;/ol&gt;&lt;span style=";font-family:verdana;font-size:100%;"  &gt;Items #1 and #2 mean that the Eclipse projects have to be located outside the source tree, and point to source in the source tree.&lt;br /&gt;&lt;br /&gt;Fortunately, Eclipse supports linked source, so I cre&lt;/span&gt;&lt;span style=";font-family:verdana;font-size:100%;"  &gt;ated the Eclipse projects in a different location, and set their build paths to have linked-source entries that pointed to the source tree.&lt;br /&gt;&lt;br /&gt;The first step is to create a global linked-resource variable that points to the root of the source tree:&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_MuoEQTr-jEM/SpA_Fi6bQNI/AAAAAAAAABM/_g0Y92p7V-E/s1600-h/LinkedResourceGlobalVariable.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 320px; height: 203px;" src="http://4.bp.blogspot.com/_MuoEQTr-jEM/SpA_Fi6bQNI/AAAAAAAAABM/_g0Y92p7V-E/s320/LinkedResourceGlobalVariable.png" alt="" id="BLOGGER_PHOTO_ID_5372863719956758738" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;Then right-click on each project and select&lt;/span&gt;&lt;span style=";font-family:verdana;font-size:100%;"  &gt; Build Path → Configure Build Path... &lt;/span&gt;&lt;span style=";font-family:verdana;font-size:100%;"  &gt;→&lt;/span&gt;&lt;span style=";font-family:verdana;font-size:100%;"  &gt; Link Source... &lt;/span&gt;&lt;span style=";font-family:verdana;font-size:100%;"  &gt;→ Variables..., and select the global linked-resource variable.&lt;br /&gt;&lt;br /&gt;Saving the changes results in a .classpath entry like this:&lt;pre&gt;&amp;lt;classpathentry kind="src" path="src"/&amp;gt;&lt;/pre&gt;and a .project entry like this:&lt;pre&gt;&amp;lt;linkedResources&amp;gt;&lt;br /&gt;   &amp;lt;link&amp;gt;&lt;br /&gt;       &amp;lt;name&amp;gt;src&amp;lt;/name&amp;gt;&lt;br /&gt;       &amp;lt;type&amp;gt;2&amp;lt;/type&amp;gt;&lt;br /&gt;       &amp;lt;locationURI&amp;gt;src&amp;lt;/locationURI&amp;gt;&lt;br /&gt;   &amp;lt;/link&amp;gt;&lt;br /&gt;&amp;lt;/linkedResources&amp;gt;&lt;/pre&gt;for each project.&lt;br /&gt;&lt;/span&gt;&lt;span style=";font-family:verdana;font-size:100%;"  &gt;&lt;br /&gt;(&lt;/span&gt;&lt;span style=";font-family:verdana;font-size:100%;"  &gt;Because I had so many projects to manage, I edited the .project files directly, instead of interactively.)&lt;/span&gt;&lt;br /&gt;&lt;span style=";font-family:verdana;font-size:100%;"  &gt;&lt;br /&gt;Unfortunately, item #1 complicated linking to the source, because every Eclipse project linked to the same root directory, which meant every Eclipse project saw the same source instead of just seeing the source for that project.&lt;br /&gt;&lt;br /&gt;For example, if the source tree looks like:&lt;/span&gt;&lt;pre&gt;C:\src\&lt;br /&gt;   com\&lt;br /&gt;       parent\&lt;br /&gt;           Parent.java&lt;br /&gt;               child1\&lt;br /&gt;                   Child1.java&lt;br /&gt;               child2\&lt;br /&gt;                   Child.java&lt;/pre&gt;&lt;tab  style="font-family:verdana;"&gt;&lt;span style="font-size:100%;"&gt;and we want two Eclipse projects, "Child1" and "Child2", they both have to start their source trees at C:\src. So Child1 sees Child2's code in the child2\ directory, and Child2 sees Child1's code in the child1\ directory:&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_MuoEQTr-jEM/SpA-UsQZRqI/AAAAAAAAABE/x-1gX_G_n3g/s1600-h/LinkedSourceNoExcludes.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 184px; height: 320px;" src="http://2.bp.blogspot.com/_MuoEQTr-jEM/SpA-UsQZRqI/AAAAAAAAABE/x-1gX_G_n3g/s320/LinkedSourceNoExcludes.png" alt="" id="BLOGGER_PHOTO_ID_5372862880651232930" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;/span&gt;&lt;/tab&gt;&lt;tab  style="font-family:verdana;"&gt;&lt;span style="font-size:100%;"&gt;Fortunately, Eclipse supports source exclusion. To exclude source, right-click on a project and select&lt;/span&gt;&lt;/tab&gt;&lt;span style=";font-family:verdana;font-size:100%;"  &gt; Build Path → Configure Build Path... &lt;/span&gt;&lt;span style=";font-family:verdana;font-size:100%;"  &gt;→&lt;/span&gt;&lt;span style=";font-family:verdana;font-size:100%;"  &gt; Source, Excluded &lt;/span&gt;&lt;span style=";font-family:verdana;font-size:100%;"  &gt;→&lt;/span&gt;&lt;span style=";font-family:verdana;font-size:100%;"  &gt; Edit... &lt;/span&gt;&lt;span style=";font-family:verdana;font-size:100%;"  &gt;→&lt;/span&gt;&lt;span style=";font-family:verdana;font-size:100%;"  &gt; Exclusion Patterns: &lt;/span&gt;&lt;span style=";font-family:verdana;font-size:100%;"  &gt;→&lt;/span&gt;&lt;span style=";font-family:verdana;font-size:100%;"  &gt; Add..., and add every package and/or file you don't want included.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:verdana;"&gt;This modifies the .classpath files to have entries like:&lt;/span&gt;&lt;pre&gt;&amp;lt;classpathentry kind="src" path="src"&lt;br /&gt;&lt;span style="color:red;"&gt;excluding="com/parent/child1/&lt;/span&gt;"/&amp;gt;&lt;/pre&gt;&lt;tab  style="font-family:verdana;"&gt;&lt;/tab&gt;&lt;tab  style="font-family:verdana;"&gt;&lt;span style="font-size:100%;"&gt;Using this approach, I was able to exclude unwanted packages from each project. Because there are a &lt;span style="font-style: italic;"&gt;lot&lt;/span&gt; of packages, this was tedious and took hours, but it worked:&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_MuoEQTr-jEM/SpA9XsmkmNI/AAAAAAAAAA8/EAtDoWevEYc/s1600-h/LinkedSourceWithExcludes.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 178px; height: 320px;" src="http://1.bp.blogspot.com/_MuoEQTr-jEM/SpA9XsmkmNI/AAAAAAAAAA8/EAtDoWevEYc/s320/LinkedSourceWithExcludes.png" alt="" id="BLOGGER_PHOTO_ID_5372861832772229330" border="0" /&gt;&lt;/a&gt;&lt;/span&gt;&lt;/tab&gt;&lt;tab  style="font-family:verdana;"&gt;&lt;span style="font-size:100%;"&gt;&lt;br /&gt;Unfortunately, once everything was configured and I launched Eclipse, it took 35 minutes to load.&lt;br /&gt;&lt;br /&gt;35. Minutes.&lt;br /&gt;&lt;br /&gt;It turned out that Eclipse bogs down if it has to import a lot of source code and then filter it out. Ideally it would filter it out first and only load the remainder, but it doesn't seem to do that.&lt;br /&gt;&lt;br /&gt;After &lt;a href="https://bugs.eclipse.org/bugs/show_bug.cgi?id=281136"&gt;reporting this problem&lt;/a&gt;&lt;/span&gt;&lt;/tab&gt;&lt;tab style="font-family: verdana;"&gt;&lt;span style="font-size:100%;"&gt;, I switched to plan B, which is described in &lt;a href="http://jimshowalter.blogspot.com/2009/08/using-eclipse-with-large-code-bases.html"&gt;Part II&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;/tab&gt;&lt;tab face="verdana"&gt;&lt;span style="font-size:100%;"&gt;&lt;/span&gt;&lt;/tab&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/356226683788078026-4652849103929716702?l=jimshowalter.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jimshowalter.blogspot.com/feeds/4652849103929716702/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://jimshowalter.blogspot.com/2009/08/using-eclipse-with-large-codebases-part.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/356226683788078026/posts/default/4652849103929716702'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/356226683788078026/posts/default/4652849103929716702'/><link rel='alternate' type='text/html' href='http://jimshowalter.blogspot.com/2009/08/using-eclipse-with-large-codebases-part.html' title='Using Eclipse With Large Code Bases, Part I'/><author><name>Jim Showalter</name><uri>http://www.blogger.com/profile/01963552914376132590</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/_MuoEQTr-jEM/SpA_Fi6bQNI/AAAAAAAAABM/_g0Y92p7V-E/s72-c/LinkedResourceGlobalVariable.png' height='72' width='72'/><thr:total>0</thr:total></entry></feed>
