<?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-32881756</id><updated>2012-01-23T05:31:08.438-06:00</updated><category term='Glimmer'/><category term='Mobile'/><category term='Scala'/><category term='Community'/><category term='Conferences'/><category term='Agile Methodologies'/><category term='Ruby'/><category term='Craftsmanship'/><category term='User Experience'/><category term='Eclipse'/><category term='Rails'/><category term='Consulting'/><category term='Tools'/><category term='Technologies'/><category term='Miscellaneous'/><category term='Object Oriented Programming'/><category term='Java'/><category term='Software Architecture'/><title type='text'>Code Painter</title><subtitle type='html'>Programming in Service to People
&lt;br&gt;
&lt;br&gt;
Topics in Ruby, Java, Rails, Eclipse RCP, Software Craftsmanship, User Experience, and Agile Methodologies</subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://andymaleh.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/32881756/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://andymaleh.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><link rel='next' type='application/atom+xml' href='http://www.blogger.com/feeds/32881756/posts/default?start-index=101&amp;max-results=100'/><author><name>Annas "Andy" Maleh</name><uri>http://www.blogger.com/profile/10268484073612495328</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/-f6UYG8WIYJI/Tpw6vYi2nTI/AAAAAAAAAPk/ICI9GDbAxh4/s1600/7312067a2015194b853856820711a178%253Fsize%253D200'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>199</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-32881756.post-5475774716400216126</id><published>2012-01-11T09:05:00.000-06:00</published><updated>2012-01-16T10:39:48.654-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Object Oriented Programming'/><category scheme='http://www.blogger.com/atom/ns#' term='Ruby'/><title type='text'>Software Design Trilogy - Part II: Design Patterns for Rubyists</title><content type='html'>&lt;p&gt;Yesterday, I gave this talk at Groupon's weekly GeekFest event: Design Patterns for Rubyists - Who Said Dynamic Languages Can't Have Patterns?&lt;/p&gt;&lt;p&gt;It is part II of the Software Design Trilogy. You can check part I (&lt;a href="http://andymaleh.blogspot.com/2011/12/software-design-trilogy-part-i.html"&gt;Responsibility Driven Design for Rubyists&lt;/a&gt;) over here.&lt;/p&gt;&lt;p&gt;The slides are included below. Here is the abstract:&lt;/p&gt;&lt;em&gt;&lt;p&gt;Design Patterns have gained a lot of popularity for helping programmers achieve polymorphic object oriented code in statically typed programming languages like Java and C++. However, although the original Design Patterns book by the Gang of Four used Smalltalk, a dynamically typed language, in some of its examples, Design Patterns have not nearly gotten the same popularity in Ruby, and sometimes for good reasons. Ruby supports duck-typing and makes it very easy to do meta-programming, which alleviates the need for many of the Gang of Four Design Patterns. Additionally, Ruby can often provide easier implementation alternatives for certain Design Patterns such as State, Strategy, and Adapter. That said, Design Patterns can still offer a great value in Ruby as problem-solving tools that yield better object oriented code with higher cohesion and cleaner separation of concerns. This is clearly demonstrated in Design Patterns like State, Composite, and Decorator.&lt;/p&gt;&lt;p&gt;Outline:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;Design Patterns Pop Quiz&lt;/li&gt;&lt;li&gt;Practical Applications of Design Patterns in Ruby&lt;/li&gt;&lt;li&gt;Alternative Implementations in Ruby&lt;/li&gt;&lt;li&gt;Deprecated Design Patterns in Ruby&lt;/li&gt;&lt;li&gt;Summary&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;Attendees should walk away with a good overview of Design Patterns as well as examples of applications in Ruby and corresponding implementations. This will help them get a head start on sharpening their Design Patterns skill in Ruby, thus recognizing when they can benefit from applying them in day-to-day work to improve code structure and maintainability.&lt;/p&gt;&lt;/em&gt;&lt;div style="width:425px" id="__ss_10964924"&gt; &lt;strong style="display:block;margin:12px 0 4px"&gt;&lt;a href="http://www.slideshare.net/AndyMaleh/software-design-trilogy-part-ii-design-patterns-for-rubyists" title="Software Design Trilogy Part II - Design Patterns for Rubyists" target="_blank"&gt;Software Design Trilogy Part II - Design Patterns for Rubyists&lt;/a&gt;&lt;/strong&gt; &lt;iframe src="http://www.slideshare.net/slideshow/embed_code/10964924" width="425" height="355" frameborder="0" marginwidth="0" marginheight="0" scrolling="no"&gt;&lt;/iframe&gt; &lt;div style="padding:5px 0 12px"&gt; View more &lt;a href="http://www.slideshare.net/" target="_blank"&gt;presentations&lt;/a&gt; from &lt;a href="http://www.slideshare.net/AndyMaleh" target="_blank"&gt;AndyMaleh&lt;/a&gt; &lt;/div&gt; &lt;/div&gt;&lt;p&gt;Stay tuned for Part III of the Software Design Trilogy: Domain Drive Design for Ruby on Rails&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/32881756-5475774716400216126?l=andymaleh.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://andymaleh.blogspot.com/feeds/5475774716400216126/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=32881756&amp;postID=5475774716400216126' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/32881756/posts/default/5475774716400216126'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/32881756/posts/default/5475774716400216126'/><link rel='alternate' type='text/html' href='http://andymaleh.blogspot.com/2012/01/software-design-trilogy-part-ii-design.html' title='Software Design Trilogy - Part II: Design Patterns for Rubyists'/><author><name>Annas "Andy" Maleh</name><uri>http://www.blogger.com/profile/10268484073612495328</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/-f6UYG8WIYJI/Tpw6vYi2nTI/AAAAAAAAAPk/ICI9GDbAxh4/s1600/7312067a2015194b853856820711a178%253Fsize%253D200'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-32881756.post-4696319625137374029</id><published>2011-12-06T13:44:00.001-06:00</published><updated>2012-01-16T10:38:06.755-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Object Oriented Programming'/><title type='text'>Software Design Trilogy - Part I: Responsibility Driven Design for Rubyists</title><content type='html'>&lt;div dir="ltr" style="text-align: left;" trbidi="on"&gt;&lt;br /&gt;Today, I gave a talk at Groupon's weekly GeekFest event &lt;b&gt;titled&lt;/b&gt; &lt;i&gt;Responsibility Driven Design for Rubyists - An Outside-In OO Design Approach&lt;/i&gt;.&lt;br /&gt;&lt;br /&gt;It is Part I of the Software Design Trilogy, with Part II and III following in January and February.&lt;br /&gt;&lt;br /&gt;Here is the &lt;b&gt;abstract&lt;/b&gt; of the talk:&lt;br /&gt;&lt;br /&gt;&lt;i&gt;Ever encountered an ActiveRecord model that has become so large you had to split it into other objects, but was unsure how? Ever wondered what principles might encourage splitting presentation logic into a presenter for a particular situation? Ever pondered whether to put a piece of logic on the controller, the model, or somewhere else in an application?&lt;/i&gt;&lt;br /&gt;&lt;i&gt;&lt;br /&gt;&lt;/i&gt;&lt;i&gt;This talk will help address these questions by introducing you to Responsibility-Driven Design, a technique that provides the underpinnings for object oriented design and underlying principles for patterns such as MVC that we follow in day-to-day user-facing application development.&lt;/i&gt;&lt;br /&gt;&lt;i&gt;&lt;br /&gt;&lt;/i&gt;&lt;i&gt;Rebecca Wirfs-Brock came up with Responsibility-Driven Design in 1989 as a reaction to Data-Driven Design's breaking of encapsulation that increased coupling and decreased maintainability. Responsibility-Driven Design helped divide and conquer complexity in code by thinking of its work as responsibilities that can be assigned to highly cohesive objects, hiding algorithmic details in abstractions that make it easier to reason about the behavior of an application at a high level.&lt;/i&gt;&lt;br /&gt;&lt;i&gt;&lt;br /&gt;&lt;/i&gt;&lt;i&gt;Alistair Cockburn came up with Responsibility Based Modeling in 1999, which is a way of getting to Responsibility-Driven Design from business high level requirements in the form use cases.&lt;/i&gt;&lt;br /&gt;&lt;i&gt;&lt;br /&gt;&lt;/i&gt;&lt;i&gt;Craig Larman identified a set of general responsibility assignment software patterns (GRASP patterns) in 2004 that help developers balance trade-offs among alternative designs to ensure they reach the object oriented structure that best fits their needs.&lt;/i&gt;&lt;br /&gt;&lt;i&gt;&lt;br /&gt;&lt;/i&gt;&lt;i&gt;This talk will cover all three approaches, providing a consolidated process for object oriented design in Ruby that begins with a business use case and ends with objects. The goal is to help developers get more comfortable with practical object oriented design in business application development, paying attention to all the variables that need to be balanced to achieve the necessary maintainability and flexibility.&lt;/i&gt;&lt;br /&gt;&lt;br /&gt;And here are the slides:&lt;br /&gt;&lt;br /&gt;&lt;div id="__ss_10487550" style="width: 425px;"&gt;&lt;strong style="display: block; margin: 12px 0 4px;"&gt;&lt;a href="http://www.slideshare.net/AndyMaleh/software-design-trilogy-part-i-responsibility-driven-design-for-rubyists" title="Software Design Trilogy Part I - Responsibility Driven Design for Rubyists"&gt;Software Design Trilogy Part I - Responsibility Driven Design for Rubyists&lt;/a&gt;&lt;/strong&gt;&lt;object height="355" id="__sse10487550" width="425"&gt;&lt;param name="movie" value="http://static.slidesharecdn.com/swf/ssplayer2.swf?doc=softwaredesigntrilogypart1-responsibilitydrivendesignforrubyists-111206134801-phpapp01&amp;stripped_title=software-design-trilogy-part-i-responsibility-driven-design-for-rubyists&amp;userName=AndyMaleh" /&gt;&lt;param name="allowFullScreen" value="true"/&gt;&lt;param name="allowScriptAccess" value="always"/&gt;&lt;param name="wmode" value="transparent"/&gt;&lt;embed name="__sse10487550" src="http://static.slidesharecdn.com/swf/ssplayer2.swf?doc=softwaredesigntrilogypart1-responsibilitydrivendesignforrubyists-111206134801-phpapp01&amp;stripped_title=software-design-trilogy-part-i-responsibility-driven-design-for-rubyists&amp;userName=AndyMaleh" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" wmode="transparent" width="425" height="355"&gt;&lt;/embed&gt;&lt;/object&gt;&lt;br /&gt;&lt;div style="padding: 5px 0 12px;"&gt;View more presentations from &lt;a href="http://www.slideshare.net/AndyMaleh"&gt;AndyMaleh&lt;/a&gt;.&lt;/div&gt;&lt;/div&gt;&lt;br /&gt;If you have any questions, please let me know in the comments section. Thanks to everyone who attended and stay tuned for Part II (&lt;a href="http://andymaleh.blogspot.com/2012/01/software-design-trilogy-part-ii-design.html"&gt;Design Patterns for Rubyists&lt;/a&gt;) and III (Domain Driven Design for RoR Apps).&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/32881756-4696319625137374029?l=andymaleh.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://andymaleh.blogspot.com/feeds/4696319625137374029/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=32881756&amp;postID=4696319625137374029' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/32881756/posts/default/4696319625137374029'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/32881756/posts/default/4696319625137374029'/><link rel='alternate' type='text/html' href='http://andymaleh.blogspot.com/2011/12/software-design-trilogy-part-i.html' title='Software Design Trilogy - Part I: Responsibility Driven Design for Rubyists'/><author><name>Annas "Andy" Maleh</name><uri>http://www.blogger.com/profile/10268484073612495328</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/-f6UYG8WIYJI/Tpw6vYi2nTI/AAAAAAAAAPk/ICI9GDbAxh4/s1600/7312067a2015194b853856820711a178%253Fsize%253D200'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-32881756.post-4810810983646091343</id><published>2011-11-06T10:39:00.001-06:00</published><updated>2011-12-02T15:58:04.928-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Craftsmanship'/><category scheme='http://www.blogger.com/atom/ns#' term='Agile Methodologies'/><title type='text'>Agile Processes/Technologies in Non-Agile Hands - Part 1 of 4</title><content type='html'>&lt;p&gt;One of the things that I encounter often with folks disenchanted with Agile processes/technologies is that they tried them without guidance or proper training (e.g. XP or Ruby on Rails), failed due to reasons mostly related to lack of skill, and then too quickly blamed the failure on the technology and/or Agile process. However, too often what I see when I check their codebase or environment is not Agile, yet Adhoc software development disguised as Agile and sprinkled with a few Agile practices here and there superficially applied. &lt;/p&gt;&lt;p&gt;To be more specific, here are the things I see in their environment:&lt;/p&gt;&lt;ol&gt;&lt;li&gt;Under-engineered code design with too much coupling between all the different pieces.&lt;/li&gt;&lt;li&gt;Difficult-to-maintain test suite.&lt;/li&gt;&lt;li&gt;Lack of long term vision for features being developed.&lt;/li&gt;&lt;li&gt;Extremely under-optimized code performance.&lt;/li&gt;&lt;/ol&gt;&lt;p&gt;Now, let's address each of these items in their own blog post, including what the misconceptions Non-Agile folks have about them.&lt;p&gt;&lt;p&gt;&lt;strong&gt;"Under-engineered code design with too much coupling between all the different pieces"&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;In the Waterfall process, it is recommended for developers to spend time designing the code up-front before diving into implementation. That prompts developers to often think of all the pieces, study coupling and cohesion, and come up with a design flexible enough to handle future requirements. Now, it's important to have software design as a skill for any developer Agile or not in order to ensure the code is maintainable. But, here is where misconceptions come into play with many inexperienced developers. Waterfall developers think that if you design for any possible future requirements, the codebase will be so easy to maintain when the future requirements come that they will be extremely productive. Thinking of it black (extremely engineered) and white (no engineering) like that results in code so over engineered that developing to meet today's business requirements comes to a crawl in terms of productivity since the code design tries to address requirements way far into the future, maybe even 6 months or a year ahead. This in my experience results in code so difficult to maintain that it discourages developers from following good design practices in the long term as they take shortcuts here and there due to business pressure whenever adding new features, resulting in a terrible code base.&lt;/p&gt;&lt;p&gt;People new to Agile that are not skilled with it get a different misconception as a result. They think that Agile is a license to under-architect software for the sake of simplicity, forgetting about Agile incremental evolutionary software design. That works well for the first few weeks of a project, but then very quickly deteriorates to extremely under-engineered software for business requirements, and extremely terrible software performance, either making the developers eventually get disenchanted with Agile, or making developers outside of the Agile community snicker (whenever you snicker know you're risking loss of insight about something) thinking "we are disciplined spending time on architecting for performance and future requirements from the start unlike these folks". Unfortunately, that statement also shows lack of experience with successful sustainable business software delivery as the reality of a system over-architected from the start is like I said before, extreme lack of productivity at the beginning of a project that loses business trust, and then neglect of developers to keep the code design of high quality in the future due to how over-complex it is, resulting in a code base that keeps getting worse in over-complexity till the project needs a rewrite. Though some developers accept that as a fact of software development, in my opinion and experience, that's not true beyond that they choose to write code that makes their life hell and then convince themselves that they are just accepting the &lt;a href="https://twitter.com/#!/AndyMaleh/status/139467558419042304"&gt;"reality"&lt;/a&gt; that they themselves created.&lt;/p&gt;&lt;p&gt;Now, to best explain how Agile code design flows through a project, here is a diagram that contrasts code design complexity in Agile over time vs code design complexity flow in Waterfall and Adhoc processes (note that the diagram is used strictly for communication. It is not based on statistically collected data):&lt;/p&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://4.bp.blogspot.com/-wH08QXgPeOE/TtE5GUXbMVI/AAAAAAAAARw/2EPDpzSZavQ/s1600/Agile%2Bin%2BNon-Agile%2BHands%2B-%2BCode%2BDesign%2BComplexity.png" imageanchor="1" style=""&gt;&lt;img border="0" height="297" width="480" src="http://4.bp.blogspot.com/-wH08QXgPeOE/TtE5GUXbMVI/AAAAAAAAARw/2EPDpzSZavQ/s400/Agile%2Bin%2BNon-Agile%2BHands%2B-%2BCode%2BDesign%2BComplexity.png" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;p&gt;Code design complexity goes higher as more structure is added to the code. Think of 0 as an entire code blob lumped together in one file and 12 as code organized into many files along the lines of object oriented domain driven design and design patterns.&lt;/p&gt;&lt;p&gt;There are multiple things to note about the diagram:&lt;/p&gt;&lt;ol&gt;&lt;li&gt;Complexity in the Adhoc process remains quite low over time as Adhoc developers tend to be averse to advanced design techniques such as object oriented design, inheritance, and design patterns since they consider them over-engineering.&lt;/li&gt;&lt;li&gt;Complexity in the Waterfall process tends to go up in spikes since Waterfall developers tend to do big up-front design of software adding a lot of structure way before the need has presented itself.&lt;/li&gt;&lt;li&gt;Complexity in the Agile process gradually climbs up following day-to-day business requirement complexity instead of preparing for future business requirements far in advance or simply ignoring complex design techniques in the name of simplification. Notice how the Agile graph overlaps the Adhoc graph in the first 2 months before it diverges later to handle increased complexity in business needs.&lt;/li&gt;&lt;li&gt;Complexity in the Agile process tends to have dips that signal how Agile developers occasionally refactor their code to simplify when business requirements have changed and the code has become over-engineered for their current requirements.&lt;/li&gt;&lt;li&gt;The area in the diagram between the Waterfall graph and Agile graph represents lost productivity by Waterfall developers due to having to work around over-engineered code.&lt;/li&gt;&lt;li&gt;The area in the diagram between the Adhoc graph and Agile graph represents lost productivity by Adhoc developers due to having to work too hard with weak or non-existant abstractions (under-engineering) that makes them have to deal with difficult to detangle code (lack of separation of concerns).&lt;/li&gt;&lt;/ol&gt;&lt;p&gt;Now, all of this might be common sense to a lot of developers. But, it takes a lot of practice to get disciplined at refactoring your code design regularly and boldly (with the protection of automated tests) to ensure it is neither over-engineered nor under-engineered per today's business requirements.&lt;/p&gt;&lt;p&gt;Still, there are quite a few other misconceptions that I would like to address, such as:&lt;p&gt;&lt;ul&gt;&lt;li&gt;&lt;em&gt;This all sounds good, but in &lt;a href="https://twitter.com/#!/AndyMaleh/status/139467558419042304"&gt;"reality"&lt;/a&gt; developers do not have time to refactor their code regularly while still meeting goals for today's business requirements&lt;/em&gt;: This is like saying "All the health professional talk about food and exercise sounds good, but who has time to eat well and exercise while still being able to earn their buck for their families". Indeed, this can be a dilemma for many people, and I do not deny it. I am not the most disciplined at exercising for example. But, this is not how I think of it. The way I like to think of it is more along the lines of: "If I were to actually eat well and exercise, would I perform better in other areas of life?". Since the answer is yes, I trained myself to appreciate the taste of healthy food, thus eventually effortlessly consuming such food out of habit. I also figured out alternative ways to exercising like snowboarding, frequent longboarding, and playing the drums, keeping myself in shape, again effortlessly. Going back to our original point, "If I were to become very disciplined at refactoring code regularly, will I be better able to meet business demands in the long term?". The answer from my experience is a most certain yes. In fact, you end up meeting the goals of today's business requirements much more often in the long term if you have a code base that is neither over-engineered nor under-engineered for today's needs. So, the key thing in the short term is to keep practicing the skills of Agile software development until you effortlessly develop the habit of just-enough-design and disciplined refactoring.&lt;/li&gt;&lt;li&gt;&lt;em&gt;What you describe as helpful in increased software design complexity is not really helpful for me. I never quite got the point of object oriented design, and I like to break my code into many small methods to handle complexity&lt;/em&gt;: While code design is certainly subjective to an extent. When working with a large code base that will be maintained by many future developers. In my experience, organizing code in an &lt;a href="http://domaindrivendesign.org/"&gt;object oriented fashion around the business domain concepts&lt;/a&gt; helps free my mind from thinking about blobs of code to focus on abstract concepts that relate to business directly, thus better manage complexity. It takes quite the skill to think of code as abstract concepts instead of low level data shuffling with for loops and if loops, bringing us back to the idea that this misconception might be more due to lack of skill in object oriented design as opposed to a problem with the methodology itself. The same way structured procedural design is a step-up from being able to code if statements and loops in one procedure effectively, object oriented design is a step up for business application development in my opinion from structured procedural design, and it assumes you are quite skilled in structured procedural design as a pre-requisite. Of course, there are domains that benefit better from other paradigms, like the functional programming paradigm for mathematical computing and logic paradigm for boolean algebra, which is why I am recommending object oriented programming specifically for domain business model related code that has gone far in complexity beyond the manageability of structured procedural programming. If you find yourself uncomfortable with object oriented design, I strongly recommend getting more training in it, especially from people that are skilled at applying it in practical enterprise environments as opposed to class room settings.&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;My next blog post will focus on "&lt;strong&gt;Difficult-to-maintain test suite.&lt;/strong&gt;". Stay tuned for part 2.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/32881756-4810810983646091343?l=andymaleh.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://andymaleh.blogspot.com/feeds/4810810983646091343/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=32881756&amp;postID=4810810983646091343' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/32881756/posts/default/4810810983646091343'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/32881756/posts/default/4810810983646091343'/><link rel='alternate' type='text/html' href='http://andymaleh.blogspot.com/2011/11/agile-processestechnologies-in-non.html' title='Agile Processes/Technologies in Non-Agile Hands - Part 1 of 4'/><author><name>Annas "Andy" Maleh</name><uri>http://www.blogger.com/profile/10268484073612495328</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/-f6UYG8WIYJI/Tpw6vYi2nTI/AAAAAAAAAPk/ICI9GDbAxh4/s1600/7312067a2015194b853856820711a178%253Fsize%253D200'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/-wH08QXgPeOE/TtE5GUXbMVI/AAAAAAAAARw/2EPDpzSZavQ/s72-c/Agile%2Bin%2BNon-Agile%2BHands%2B-%2BCode%2BDesign%2BComplexity.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-32881756.post-8660645828645207954</id><published>2011-11-03T18:56:00.001-05:00</published><updated>2011-12-13T09:34:08.487-06:00</updated><title type='text'>The Rails Engine That Could - In Motion</title><content type='html'>&lt;div dir="ltr" style="text-align: left;" trbidi="on"&gt;&lt;p&gt;A couple months ago, I gave a lightning talk at Groupon's GeekFest event titled "&lt;a href="http://andymaleh.blogspot.com/2011/09/rails-engine-that-could.html"&gt;The Rails Engine That Could&lt;/a&gt;". Since then, several people asked me to provide more details about my successful use of Rails Engines, so I did by giving a longer one-hour talk at this week's Groupon's GeekFest.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;Here are the slides of the talk:&lt;/p&gt;&lt;div style="width:425px" id="__ss_10016300"&gt; &lt;strong style="display:block;margin:12px 0 4px"&gt;&lt;a href="http://www.slideshare.net/AndyMaleh/the-rails-engine-that-could-in-motion" title="The Rails Engine That Could - In Motion" target="_blank"&gt;The Rails Engine That Could - In Motion&lt;/a&gt;&lt;/strong&gt; &lt;iframe src="http://www.slideshare.net/slideshow/embed_code/10016300" width="425" height="355" frameborder="0" marginwidth="0" marginheight="0" scrolling="no"&gt;&lt;/iframe&gt; &lt;div style="padding:5px 0 12px"&gt; View more &lt;a href="http://www.slideshare.net/" target="_blank"&gt;presentations&lt;/a&gt; from &lt;a href="http://www.slideshare.net/AndyMaleh" target="_blank"&gt;AndyMaleh&lt;/a&gt; &lt;/div&gt; &lt;/div&gt;&lt;br /&gt;&lt;p&gt;Let me know if you have any questions.&lt;/p&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/32881756-8660645828645207954?l=andymaleh.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://andymaleh.blogspot.com/feeds/8660645828645207954/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=32881756&amp;postID=8660645828645207954' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/32881756/posts/default/8660645828645207954'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/32881756/posts/default/8660645828645207954'/><link rel='alternate' type='text/html' href='http://andymaleh.blogspot.com/2011/11/rails-engine-that-could-in-motion.html' title='The Rails Engine That Could - In Motion'/><author><name>Annas "Andy" Maleh</name><uri>http://www.blogger.com/profile/10268484073612495328</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/-f6UYG8WIYJI/Tpw6vYi2nTI/AAAAAAAAAPk/ICI9GDbAxh4/s1600/7312067a2015194b853856820711a178%253Fsize%253D200'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-32881756.post-1968931127546084341</id><published>2011-10-26T08:18:00.000-05:00</published><updated>2011-11-09T11:59:05.882-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Craftsmanship'/><title type='text'>Cheaper Than The Cost of Failure</title><content type='html'>&lt;div dir="ltr" style="text-align: left;" trbidi="on"&gt;Applying certain quality practices for software development may not be cheap, but is cheaper than the cost of failure, whether it is &lt;a href="http://en.wikipedia.org/wiki/Test-driven_development"&gt;TDD&lt;/a&gt; (Test-Driven Development), &lt;a href="http://en.wikipedia.org/wiki/Pair_programming"&gt;pair-programming&lt;/a&gt;, or &lt;a href="http://en.wikipedia.org/wiki/Usability_testing"&gt;usability testing&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;Let's talk about TDD for example. Although it significantly decreases the cost of building reliable software for developers experienced with the technique, TDD requires a 3 month learning curve for a team new to it before they can start becoming more productive with it than without it from my experience. And, that's with the help of an experienced TDD coach.&amp;nbsp;Now that may seem like a prohibitive cost when business development is in full swing demanding that developers deliver yesterday. That is why often the teams that hire Agile consulting folks are the ones who are already in dire trouble with their managers for being unable to deliver quality software on schedule. They are often stuck in bug fixing mode for both older and newer features, and thus are willing to pay the cost of learning better software development practices. They may resist suggested practices like TDD at first, but then when they see that software releases requiring weeks of bug fixing pretty much fail to wow customers or gain the trust of their stakeholders, that's when they realize that the cost of learning TDD may not be cheap, but is a hell of a lot cheaper than the cost of failure!&lt;br /&gt;&lt;br /&gt;Usability testing is another example.&amp;nbsp;I worked on a project several years ago where the stakeholders were exploring new user interface ideas mixing social networking with education. That seemed like the perfect situation to benefit from usability testing with paper prototypes. We tried the process for a feature or two and noticed that it was taking us about 3-4 hours per feature to come up with the paper prototypes and test them given our lack of experience with the technique. The cost of it seemed prohibitive for stakeholders, so management decided to drop the practice. Six months later, when the project was slated for release, stakeholders realized many&amp;nbsp;inefficiencies&amp;nbsp;in the user interface with beta-testing and wanted developers to rework certain areas completely. Unfortunately, that took a lot longer than revising user interfaces in paper prototype format (think 3-5 days vs 2-4 hours per feature) and investors had almost ran out of money by then, so they had to release the project the way it was. The released website did not end up as revolutionary as they originally intended it to be, and business had to accept the inefficient first-cut designs they had for most of the user interfaces.&lt;br /&gt;&lt;br /&gt;Morale of the story? The next time, people try to pressure you into giving up certain practices just because of the cost associated with them, emphasize the importance of the benefits and tell them "It may not be cheap, but it's cheaper than the cost of failure!"&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/32881756-1968931127546084341?l=andymaleh.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://andymaleh.blogspot.com/feeds/1968931127546084341/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=32881756&amp;postID=1968931127546084341' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/32881756/posts/default/1968931127546084341'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/32881756/posts/default/1968931127546084341'/><link rel='alternate' type='text/html' href='http://andymaleh.blogspot.com/2011/10/cheaper-than-cost-of-failure.html' title='Cheaper Than The Cost of Failure'/><author><name>Annas "Andy" Maleh</name><uri>http://www.blogger.com/profile/10268484073612495328</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/-f6UYG8WIYJI/Tpw6vYi2nTI/AAAAAAAAAPk/ICI9GDbAxh4/s1600/7312067a2015194b853856820711a178%253Fsize%253D200'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-32881756.post-7628077337766050860</id><published>2011-10-22T15:42:00.000-05:00</published><updated>2011-10-24T15:13:32.521-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Miscellaneous'/><category scheme='http://www.blogger.com/atom/ns#' term='Craftsmanship'/><title type='text'>Influential Books On My Career in Software Development</title><content type='html'>&lt;div dir="ltr" style="text-align: left;" trbidi="on"&gt;I was just thinking about how much influence certain books had on my career, whether concerning object-oriented design, enterprise architecture, or even business soft skills, so I decided to list them in this post.&lt;br /&gt;&lt;br /&gt;Here are the technology books that had the most influence:&lt;br /&gt;&lt;ul style="text-align: left;"&gt;&lt;li&gt;&lt;b&gt;&lt;a href="http://www.amazon.com/Pragmatic-Programmer-Journeyman-Master/dp/020161622X"&gt;The Pragmatic&amp;nbsp;Programmer:&lt;/a&gt;&lt;/b&gt; I still remember the&amp;nbsp;fascination&amp;nbsp;I had with this book after reading the story about Stone Soup in the first few chapters. It was one of those soft skill patterns that come in extremely handy when you think you have a great idea to improve effectiveness at work, but are faced with a lot of resistance to it by coworkers (especially novel ideas like Pair-Programming). In summary, the lesson from Stone Soup is to walk the walk first, and then let people talk the talk for you, instead of starting with the talk before any walk. You start applying the idea at a very small scale, and if it demonstrates benefits, people testify for you, encouraging the application of the idea on a larger scale. And if not, no harm was done given the small scale you started with. You got to try the idea at least, and can rule it out moving on to another idea instead of dwelling on people's resistance to talking about it with no action taken. I found this book a great read when I stumbled upon it several years ago as it contains many lessons in soft skills in addition to technical skills as developers need both to succeed at work after all.&lt;/li&gt;&lt;li&gt;&lt;b&gt;&lt;a href="http://www.amazon.com/First-Design-Patterns-Elisabeth-Freeman/dp/0596007124"&gt;Head First Design Patterns:&lt;/a&gt; &lt;/b&gt;This was one of the most entertaining technology book reads I have ever had, and I still find the comedy in it extremely enjoyable and educational. It is my favorite on &lt;a href="http://obtiva.com/blurbs/107-learn-to-apply-design-patterns-with-andy-maleh"&gt;how to learn practical application of Design Patterns&lt;/a&gt;, and by practical I mean, knowing when it is appropriate to apply them, not just how to apply them.&amp;nbsp;&lt;/li&gt;&lt;li&gt;&lt;b&gt;&lt;a href="http://www.amazon.com/Applying-UML-Patterns-Craig-Larman/dp/0137488807"&gt;Applying UML and Patterns:&lt;/a&gt;&lt;/b&gt; This book has been perhaps one of the most influential books on my object-oriented design skills as well as integrating the process with Agile software development. And, don't let the name of the book fool you. It is not focused mainly on applying UML. It just emphasizes Agile UML diagramming (mostly on paper or whiteboards) as a healthy communication mechanism between team members to better brainstorm and get ideas across. GRASP Patterns (e.g. Coupling and Cohesion) are a huge takeaway in this book as they serve as the underpinnings of successful object-oriented design, and &lt;a href="http://obtiva.com/blurbs/107-learn-to-apply-design-patterns-with-andy-maleh"&gt;knowing when design patterns are beneficial&lt;/a&gt;.&amp;nbsp;&lt;/li&gt;&lt;li&gt;&lt;a href="http://www.amazon.com/Domain-Driven-Design-Tackling-Complexity-Software/dp/0321125215"&gt;&lt;b&gt;Domain Driven Design: &lt;/b&gt;&lt;/a&gt;One cannot do object-oriented design well in isolation from business. Knowing how to speak the language of the business domain is crucial in achieving an easy-to-maintain-and-extend software design.&amp;nbsp;&lt;/li&gt;&lt;li&gt;&lt;b&gt;&lt;a href="http://www.amazon.com/Refactoring-Patterns-Joshua-Kerievsky/dp/0321213351"&gt;Refactoring to Patterns: &lt;/a&gt;&lt;/b&gt;Design Patterns are often best applied gradually in response to new business needs as opposed to prescriptively without the business needs being present yet. For example, if an application only seems to need two ways of sorting data on a report at the moment, a simple "if" statement might get the job done well. If in the future, new business demands required more sorting options that need to be reused in multiple parts of the application, then sticking with the same code design simply expands the use of the "if" statement with more branches. That makes readability&amp;nbsp;of the code less abstract and understandable at a glance, and requires duplication of the "if" statement in all parts of the app that require the same sorting options (unless procedural method reuse was done). That is an example of a need to refactor the code to the Strategy design pattern in order to replace the if statement with reliance on polymorphism (GRASP Pattern) via sort strategy objects. "Refactoring to Patterns"&amp;nbsp;is a great read on&amp;nbsp;this extremely useful Agile skill, and so is its predecessor&amp;nbsp;&lt;a href="http://www.amazon.com/Refactoring-Improving-Design-Existing-Code/dp/0201485672"&gt;Refactoring&lt;/a&gt;.&lt;/li&gt;&lt;li&gt;&lt;b&gt;&lt;a href="http://www.amazon.com/Extreme-Programming-Explained-Embrace-Change/dp/0321278658"&gt;XP Explained:&lt;/a&gt; &lt;/b&gt;Reference book on the radical ideas of &lt;a href="http://www.extremeprogramming.org/"&gt;eXtreme Programming&lt;/a&gt;. A must read for any software developer who wants to go beyond the overly-controlling Waterfall process or out-of-control adhoc process in software development, even if they cannot apply all its ideas in their environment. It is eXtremely mind expanding as it pushes your thinking outside the boring box that the masses tend to constrain their thinking to.&lt;/li&gt;&lt;li&gt;&lt;b&gt;&lt;a href="http://www.amazon.com/Apprenticeship-Patterns-Guidance-Aspiring-Craftsman/dp/0596518382"&gt;Apprenticeship Patterns:&lt;/a&gt; &lt;/b&gt;Awesome book on how to become a quick learner (a must in the technology field), stay humble despite experience, and remain open to new ideas the way beginners are. Some of my favorite patterns are "Wear the White Belt", "Expose Your Ignorance", and "Breakable Toys".&lt;/li&gt;&lt;/ul&gt;&lt;div&gt;Notice how I did not mention any books on Test-Driven Development or Pair-Programming. That is because from my experience, the best way to learn them is not through reading books, yet through actual daily experience via pair-programming with other developers (apprenticeship) that are quite experienced with both skills (these two skills go hand in hand). I have seen developers inexperienced with test-driven development miserably produce difficult to maintain test suites with complex code implementations that are difficult to refactor. I have also seen developers nod off or waste time tweeting while pretending to pair-program. To avoid such pitfalls, it is extremely important to pair-program with experienced pair-programmers, and to&amp;nbsp;learn all different styles of test-driven development (e.g. state-based vs interaction-based, outside-in vs inside-out, integration vs unit, etc...) to understand their trade-offs and when to apply each. After all, badly done Test-Driven Development and Pair-Programming is like badly done anything. It will result in worse results, and unless the developer had enough&amp;nbsp;foresight, they might then blame the technique instead of their lack of skill in it, and thus miss out on the benefits of learning completely. Just think, a non-skilled skiier might not enjoy skiing very much. But, is it the activity of skiing or their lack of skill in it that is responsible (assuming they are quite interested in it)?&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Here are a few non-technology books that also had a huge influence on my success at work:&lt;/div&gt;&lt;div&gt;&lt;ul style="text-align: left;"&gt;&lt;li&gt;&lt;a href="http://www.amazon.com/Habits-Highly-Effective-People/dp/0671708635"&gt;&lt;b&gt;The 7 Habits of Highly Effective People:&lt;/b&gt;&lt;/a&gt; Helped me direct my career and sort my priorities as taught in the habits "Begin With The End In Mind" and "First Things First". Also, it had a huge influence on the way I try to come up with solutions that bring everybody in the company together, whether in development, QA, or business &amp;nbsp;(the "Think Win-Win" habit) and be open minded to collaboration that achieves much more creative solutions to problems than flying solo (the "Synergy" habit)&lt;/li&gt;&lt;li&gt;&lt;a href="http://www.amazon.com/How-Win-Friends-Influence-People/dp/0671723650"&gt;&lt;b&gt;How to Win Friends and Influence People:&lt;/b&gt;&lt;/a&gt; Great aid in social skills for a techie like me, helping with public speaking skills and learning respect for non-autonomous and barely-logical entities (a.k.a non-computers, a.k.a. human beings!)&amp;nbsp;&lt;/li&gt;&lt;li&gt;&lt;a href="http://www.amazon.com/Magic-Thinking-Big-David-Schwartz/dp/0671646788"&gt;&lt;b&gt;The Magic of Thinking Big:&lt;/b&gt;&lt;/a&gt; This was the book that shattered all artificial and societal constraints that I had acquired over the years about how much I can achieve in life. After reading it, I stopped believing that I am&amp;nbsp;constrained&amp;nbsp;to my I.Q. (or maybe realized you can increase your I.Q. indefinitely) and stopped seeing any boundaries to anything I can do at any organization or in life in general for that matter. Let's just say that not only did I eventually learn to do public speaking in front of masses of people (EclipseCon, EclipseWorld, RubyConf, etc...) after a quarter century of being a shielded introverted shy person, but I also learned rudimentary drumming skills in the last 3 years and now perform in two rock bands (&lt;a href="http://www.gagordertheband.com/"&gt;Gag Order&lt;/a&gt; and &lt;a href="http://www.facebook.com/pages/Cletus-Darby/259509910185?sk=wall"&gt;Cletus Darby&lt;/a&gt;) around the city of Chicago.&amp;nbsp;&lt;/li&gt;&lt;/ul&gt;&lt;div&gt;What are the books that had the most positive influence on your career?&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/32881756-7628077337766050860?l=andymaleh.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://andymaleh.blogspot.com/feeds/7628077337766050860/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=32881756&amp;postID=7628077337766050860' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/32881756/posts/default/7628077337766050860'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/32881756/posts/default/7628077337766050860'/><link rel='alternate' type='text/html' href='http://andymaleh.blogspot.com/2011/10/influential-books-on-my-career-in.html' title='Influential Books On My Career in Software Development'/><author><name>Annas "Andy" Maleh</name><uri>http://www.blogger.com/profile/10268484073612495328</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/-f6UYG8WIYJI/Tpw6vYi2nTI/AAAAAAAAAPk/ICI9GDbAxh4/s1600/7312067a2015194b853856820711a178%253Fsize%253D200'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-32881756.post-7077044523883553867</id><published>2011-10-17T21:34:00.001-05:00</published><updated>2011-10-17T21:52:20.124-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Craftsmanship'/><category scheme='http://www.blogger.com/atom/ns#' term='Agile Methodologies'/><title type='text'>Any Good in Learning Big Up Front Design?</title><content type='html'>&lt;p&gt;Since the beginning of the Agile movement, people have been renouncing big up front design in favor of incremental emerging design of software. It occurred mostly as a reaction to overly complex designs and application architectures that slowed down productivity to a crawl, especially on new projects. Anyone remembers the days of &lt;a href="http://www.techrepublic.com/article/a-brief-review-of-the-ejb-21-specification/1049431"&gt;EJB 2.1&lt;/a&gt;? You had to configure a handful of XML file descriptors and write quite a bit of code following the EJB 2.1 conventions before you got anywhere on a new project. Now, contrast that with the Ruby on Rails architecture and how it enabled developers to get a CRUD web application up and running within minutes. Most people miss out on the other side of the story though, that is the part about why EJB's architecture was so complex to begin with. After all, development with a technology like Java's JSP alone was a lot simpler. &lt;/p&gt;&lt;p&gt;EJB came out as a reaction to insecure badly written Java web applications that did not take advantage of transactions and threading correctly, and mixed data persistence concerns with web flow concerns. Enterprise JavaBeans's main innovation was aspect orientation of concerns like transactions, security, threading, and caching, enabling Developers to get their benefits without coding them directly. All they had to do is configure the XML descriptors to enable them, and voila! Additionally, Entity Beans were of the earliest forms of ORM (Object Relational Mapping), Session Beans were one of the earliest forms of controllers, and Message Driven Beans were one of the earliest forms of web background workers (think &lt;a href="https://github.com/defunkt/resque"&gt;Resque&lt;/a&gt; in the Ruby on Rails world). Also, Enterprise JavaBeans allowed nice separation between web flow and data persistance at the time (albeit with non-existent OO inheritance support), providing one of the most primitive versions of Web-MVC.&lt;/p&gt;&lt;p&gt;Now, if you look at many of today's web frameworks, like Rails for example, you notice that they got many of the same features that EJBs innovated, such as easy transaction support, ORM, security (authentication via &lt;a href="https://github.com/plataformatec/devise"&gt;Devise&lt;/a&gt; and authorization via &lt;a href="https://github.com/ryanb/cancan"&gt;CanCan&lt;/a&gt; for Rails), threading (automatic spawning of threads for requests in web servers like Phusion Passenger), and caching.&lt;/p&gt;&lt;p&gt;Sure, if you needed something much simpler, you can start a Rails app without any of the complexities of caching or other advanced features getting in the way. You may even use Sinatra and avoid reverting to Rails until your app grows large enough to warrant the shift in complexity of design.&lt;/p&gt;&lt;p&gt;However, if people did not spend time solving the problems plaguing web applications in the early 2000s, doing some big up front design, we might have not had any of the solutions that can help an Agile business scale up with Rails today once they have more than a handful visitors an hour.&lt;/p&gt;&lt;p&gt;How does this idea transfer to software design?&lt;/p&gt;&lt;p&gt;Developers new to object oriented programming often encounter topics such as inheritance vs composition and design patterns. If they were to bypass such topics with excuses like "inheritance produces overly complex code over procedural code reuse" or "design patterns make for overly complex designs", their blaming of the tools is sure a sign that they are not skilled with them and that they use them like a golden hammer, potentially in the wrong situations. Now, if they were to avoid learning them however, and they eventually work on a business domain that grows enough in complexity to a level where switch/giant-if statements are plaguing the code everywhere (lack of use of object oriented polymorphism/inheritance or design patterns), given that they skipped learning the techniques of big up front design, they will unfortunately fail in incremental designs as they will always stick to the primitive design techniques they started programming with (like structured decomposition of logic into methods) and thus not be able to scale up their code base to handle more complexity while remaining clear and maintainable to their fellow programmers.&lt;/p&gt;&lt;p&gt;That is why I strongly suggest to developers spending time learning many of the big up front design techniques out there, such as &lt;a href="http://wirfs-brock.com/Design.html"&gt;Responsibility Driven Design&lt;/a&gt;, &lt;a href="http://www.amazon.com/Domain-Driven-Design-Tackling-Complexity-Software/dp/0321125215"&gt;Domain Driven Design&lt;/a&gt;, &lt;a href="http://www.amazon.com/First-Design-Patterns-Elisabeth-Freeman/dp/0596007124"&gt;Design Patterns&lt;/a&gt;, &lt;a href="http://www.amazon.com/Pattern-Oriented-Software-Architecture-System-Patterns/dp/0471958697"&gt;Architectural Patterns&lt;/a&gt;, &lt;a href="http://www.ibm.com/developerworks/rational/library/769.html"&gt;UML Modeling&lt;/a&gt;, and even &lt;a href="http://www.embedded360.com/model_based_development/model_based_development.htm"&gt;Model Based Development&lt;/a&gt; (foundation behind use of DSLs) , simply for the sake of expanding their toolset for when their small simple solutions no longer provide high productivity and maintainability for the increased complexity of their project. In other words, practicing big up front design in a safe learning setting enables developers to actually become (Oh My!) more Agile when the time comes for employing the advanced design skills.&lt;/p&gt;&lt;p&gt;I am sure I missed a handful of useful design tools out there, so I would like others to pitch in. What design tools would you recommend to others to learn and employ in their toolset? &lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/32881756-7077044523883553867?l=andymaleh.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://andymaleh.blogspot.com/feeds/7077044523883553867/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=32881756&amp;postID=7077044523883553867' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/32881756/posts/default/7077044523883553867'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/32881756/posts/default/7077044523883553867'/><link rel='alternate' type='text/html' href='http://andymaleh.blogspot.com/2011/10/any-good-in-learning-big-up-front.html' title='Any Good in Learning Big Up Front Design?'/><author><name>Annas "Andy" Maleh</name><uri>http://www.blogger.com/profile/10268484073612495328</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/-f6UYG8WIYJI/Tpw6vYi2nTI/AAAAAAAAAPk/ICI9GDbAxh4/s1600/7312067a2015194b853856820711a178%253Fsize%253D200'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-32881756.post-5826571255345586083</id><published>2011-10-16T22:43:00.000-05:00</published><updated>2011-10-24T09:37:56.338-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Ruby'/><category scheme='http://www.blogger.com/atom/ns#' term='Rails'/><title type='text'>Rails Flash for Presentation Logic: Good Idea or Cause for Trouble?</title><content type='html'>&lt;div dir="ltr" style="text-align: left;" trbidi="on"&gt;Rails comes with a feature called Flash that simplifies displaying messages to users after redirecting them to another page on the site. Such messages can include confirmations, greetings, congratulations, etc.. &lt;br /&gt;&lt;br /&gt;For example, upon a user submitting a help request on the site, they see a flash message on the next page confirming that the request has been submitted and is being reviewed.&lt;br /&gt;&lt;br /&gt;The HelpRequestsController create action code would contain logic like the following:&lt;br /&gt;&lt;br /&gt;if help_request.save&lt;br /&gt;&amp;nbsp; flash[:notice] = 'Your help request has been submitted and is being reviewed.'&lt;br /&gt;&amp;nbsp; redirect_to root_path&lt;br /&gt;else&lt;br /&gt;&amp;nbsp; flash[:error] = 'The help request is missing required information.'&lt;br /&gt;&amp;nbsp; render :action =&amp;gt; 'new'&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;This would display a view element as follows, typically at the top of the page:&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://1.bp.blogspot.com/-IWNaJNQs-kw/TpuaPEwH6EI/AAAAAAAAAOo/e4yiWlGcaiI/s1600/Screen%2Bshot%2B2011-10-16%2Bat%2B9.55.14%2BPM.png" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="18" src="http://1.bp.blogspot.com/-IWNaJNQs-kw/TpuaPEwH6EI/AAAAAAAAAOo/e4yiWlGcaiI/s400/Screen%2Bshot%2B2011-10-16%2Bat%2B9.55.14%2BPM.png" width="400" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;The key benefit to using the flash hash is that its data persists whether the controller action renders a page in the same request, or redirects to another page initializing a new request. It relies on the session store behind the scenes to persist data and clear the flash after the next request, saving the developer from performing that work themselves.&lt;br /&gt;&lt;br /&gt;Now, this blog post is not about use of the flash hash for displaying messages. It is about whether it is a good idea to rely on the flash ability to keep data for one more request to store data that will affect presentation logic.&lt;br /&gt;&lt;br /&gt;I recently saw an example of using the flash to store variables that get rendered in hidden fields and later used by&amp;nbsp;JavaScript&amp;nbsp;logic on the page for determining whether to display certain pieces of data or not.&lt;br /&gt;&lt;br /&gt;The logic unfortunately broke the moment someone Ajaxified the&amp;nbsp;JavaScript&amp;nbsp;logic as it ended up hitting another controller action that was not redirected to from the original action that requested the page, thus losing the flash data in the process.&lt;br /&gt;&lt;br /&gt;To illustrate:&lt;br /&gt;&lt;br /&gt;Originally:&lt;br /&gt;&lt;br /&gt;Action 1 sets flash and redirects to Action 2&lt;br /&gt;Action 2 uses flash in rendering elements&lt;br /&gt;&lt;br /&gt;After Ajaxification:&lt;br /&gt;&lt;br /&gt;Action 1 sets flash and redirects to Action 2&lt;br /&gt;Action 2 renders a page that performs an Ajax request in its JavaScript&lt;br /&gt;Action 3&amp;nbsp;attempts to use flash in rendering elements but does not find data&lt;br /&gt;&lt;br /&gt;One way to fix the problem that a developer attempted was to use the flash.keep method in the last redirected action to keep the flash data for one more request. Unfortunately, that approach is fickle because if multiple Ajax requests hit the server, the flash data will get lost eventually unless all their actions perform a flash.keep. Also, if the code ends up performing flash.keep everywhere, that defeats the purpose of using flash&amp;nbsp;over the session.&lt;br /&gt;&lt;br /&gt;My understanding is the flash hash was created to flash a message to the user once after a certain request. So, I personally limit its use only to that use case to keep any code around it easily understandable and maintainable by other developers. If I needed to persist presentation logic data across requests, I usually rely on the session instead.&lt;br /&gt;&lt;br /&gt;What is your opinion on the matter?&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/32881756-5826571255345586083?l=andymaleh.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://andymaleh.blogspot.com/feeds/5826571255345586083/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=32881756&amp;postID=5826571255345586083' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/32881756/posts/default/5826571255345586083'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/32881756/posts/default/5826571255345586083'/><link rel='alternate' type='text/html' href='http://andymaleh.blogspot.com/2011/10/rails-flash-for-presentation-logic-good.html' title='Rails Flash for Presentation Logic: Good Idea or Cause for Trouble?'/><author><name>Annas "Andy" Maleh</name><uri>http://www.blogger.com/profile/10268484073612495328</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/-f6UYG8WIYJI/Tpw6vYi2nTI/AAAAAAAAAPk/ICI9GDbAxh4/s1600/7312067a2015194b853856820711a178%253Fsize%253D200'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/-IWNaJNQs-kw/TpuaPEwH6EI/AAAAAAAAAOo/e4yiWlGcaiI/s72-c/Screen%2Bshot%2B2011-10-16%2Bat%2B9.55.14%2BPM.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-32881756.post-1110527436514779709</id><published>2011-10-02T11:47:00.003-05:00</published><updated>2011-10-18T13:20:20.482-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Software Architecture'/><category scheme='http://www.blogger.com/atom/ns#' term='Rails'/><title type='text'>Decoupling Views from Controllers in Rails (Smalltalk MVC Style)</title><content type='html'>&lt;div dir="ltr" style="text-align: left;" trbidi="on"&gt;Last week, I gave a talk at the Groupon weekly GeekFest event titled &lt;a href="http://andymaleh.blogspot.com/2011/09/smalltalk-mvc-applied-in-rails.html"&gt;"Smalltalk MVC Applied in Rails"&lt;/a&gt;. Though the talk briefly touched upon Smalltalk's original &lt;a href="http://en.wikipedia.org/wiki/Model%E2%80%93view%E2%80%93controller"&gt;MVC&lt;/a&gt; pattern and how it is applied in desktop development, the main focus of the talk was on decoupling views from controllers in Rails the way they are decoupled in Smalltalk MVC, so I would like to elaborate more on that in this blog post.&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://3.bp.blogspot.com/-4eW59Ao0ess/ToiBzAiYdZI/AAAAAAAAAOg/SiYa6XHwBFE/s1600/Screen+shot+2011-10-02+at+10.22.11+AM.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="226" src="http://3.bp.blogspot.com/-4eW59Ao0ess/ToiBzAiYdZI/AAAAAAAAAOg/SiYa6XHwBFE/s320/Screen+shot+2011-10-02+at+10.22.11+AM.png" width="320" /&gt;&lt;/a&gt;&lt;/div&gt;The diagram above shows the relationship between Model, View, and Controller in Smalltalk MVC with desktop development.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;ul style="text-align: left;"&gt;&lt;li&gt;The Controller observes the View for changes caused by user interactions (e.g. clicking a button, making a selectiong, etc...)&lt;/li&gt;&lt;li&gt;The Controller causes updates in the Model when it receives a notification from the View&lt;/li&gt;&lt;li&gt;The View observes the Model for changes caused by invokations from the Controller (e.g. add a new contact) or by Model change events (e.g. a customer birthday has been reached in system time)&lt;/li&gt;&lt;li&gt;The View refreshes itself automatically from the appropriate models it is providing a view of.&lt;/li&gt;&lt;/ul&gt;&lt;div&gt;Notice that nowhere in that flow does the Controller directly interact with the View to update it with Model data. In fact, well written desktop applications avoid that sort of coupling to ensure clean separation between control flow and presentation logic.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;One thing to note also about Smalltalk MVC on the desktop is that Views are objects in desktop applications with the intelligence of any other objects. Like Models, they are responsible for maintaining their own state as per the object oriented paradigm. They do not require another class like a Controller to update them. However, when presentation logic gets complex enough, it is a good practice to then split that into a Presenter layer between Views and Models that follows the Adapter design pattern, adapting View state (e.g. index of contact selected in a list of contacts) into Models (the actual contact object representing the index)&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Now, if we were to transfer all of these ideas transparently to the web, View state is simply the parameters (request or session) that are populated by user actions. Controllers get access to them temporarily on user actions to cause updates in Models, but then once they render a View, the View itself can be responsible for translating its state (parameters) into Model objects via a Presenter layer. The Presenter layer in Rails is nothing but the good old (badly named) Rails Helpers. They automatically get access to the View context (request and session parameters), allowing them to act as Adapters that neatly hide the details of converting request and session parameters into Model objects the View can rely on to render its contents. This frees Controllers to focus only on Model updates and routing control logic, avoiding the typical clutter with Model loading logic that we often see in Rails applications. This then decouples the Views from Controllers the way they are in original Smalltalk MVC.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Here is an example of typical Rails MVC code:&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Controller:&lt;br /&gt;&lt;br /&gt;def show&lt;br /&gt;&amp;nbsp; @contact = Contact.find(params[:id])&lt;br /&gt;&amp;nbsp; @region = Region.find(session[:region_id])&lt;br /&gt;&amp;nbsp; @friend_contacts = @contact.friends_by(@region)&lt;br /&gt;&amp;nbsp; @news = News.latest&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;View:&lt;br /&gt;&lt;br /&gt;_contact.html.erb:&lt;br /&gt;&lt;br /&gt;Name: &amp;lt;%= @contact.first_name %&amp;gt;&lt;br /&gt;Last Name: &amp;lt;%= @contact.last_name %&amp;gt;&lt;br /&gt;Phone: &amp;lt;%= @contact.phone_number %&amp;gt;&lt;br /&gt;...&lt;br /&gt;&lt;br /&gt;_region_header.html.erb:&lt;br /&gt;&lt;br /&gt;&amp;lt;%= @region.name %&amp;gt;&lt;br /&gt;&amp;lt;%= @region.state %&amp;gt;&lt;br /&gt;&amp;lt;%= @region.city %&amp;gt;&lt;br /&gt;...&lt;br /&gt;&lt;br /&gt;_friends.html.erb:&lt;br /&gt;&lt;br /&gt;Friends&lt;br /&gt;&amp;lt;%= @friend_contacts.each do |friend_contact| %&amp;gt;&lt;br /&gt;&amp;lt;%= link_to friend_contact.name, contact_path(friend_contact) %&amp;gt;&lt;br /&gt;&amp;lt;% end %&amp;gt;&lt;br /&gt;...&lt;br /&gt;&lt;br /&gt;_news_feed.html.erb:&lt;br /&gt;&lt;br /&gt;Latest Happenings:&lt;br /&gt;&amp;lt;%= @news.each do |news_feed_item| %&amp;gt;&lt;br /&gt;&amp;nbsp; &amp;lt;%= news_feed_item.story %&amp;gt;&lt;br /&gt;&amp;lt;% end %&amp;gt;&lt;br /&gt;...&lt;br /&gt;&lt;br /&gt;Here is the same example benefiting from the Smalltalk MVC pattern:&lt;br /&gt;&lt;br /&gt;Controller:&lt;br /&gt;&lt;br /&gt;def show&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;Helper (Presenter):&lt;br /&gt;&lt;br /&gt;def contact&lt;br /&gt;&amp;nbsp; Contact.find(params[:id])&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;def region&lt;br /&gt;&amp;nbsp; Region.find(session[:region_id])&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;def friend_contacts&lt;br /&gt;&amp;nbsp; contact.friends_by(region)&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;View:&lt;br /&gt;&lt;br /&gt;_contact.html.erb:&lt;br /&gt;&lt;br /&gt;Name: &amp;lt;%= contact.first_name %&amp;gt;&lt;br /&gt;Last Name: &amp;lt;%= contact.last_name %&amp;gt;&lt;br /&gt;Phone: &amp;lt;%= contact.phone_number %&amp;gt;&lt;br /&gt;...&lt;br /&gt;&lt;br /&gt;_region_header.html.erb:&lt;br /&gt;&lt;br /&gt;&amp;lt;%= region.name %&amp;gt;&lt;br /&gt;&amp;lt;%= region.state %&amp;gt;&lt;br /&gt;&amp;lt;%= region.city %&amp;gt;&lt;br /&gt;...&lt;br /&gt;&lt;br /&gt;_friends.html.erb:&lt;br /&gt;&lt;br /&gt;Friends&lt;br /&gt;&amp;lt;%= friend_contacts.each do |friend_contact| %&amp;gt;&lt;br /&gt;&amp;nbsp; &amp;lt;%= link_to friend_contact.name, contact_path(friend_contact) %&amp;gt;&lt;br /&gt;&amp;lt;% end %&amp;gt;&lt;br /&gt;...&lt;br /&gt;&lt;br /&gt;_news_feed.html.erb:&lt;br /&gt;&lt;br /&gt;Latest Happenings:&lt;br /&gt;&amp;lt;%= News.latest.each do |news_feed_item| %&amp;gt;&lt;br /&gt;&amp;lt;%= news_feed_item.story %&amp;gt;&lt;br /&gt;&amp;lt;% end %&amp;gt;&lt;br /&gt;...&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Notice how the last partial did not even need a Presenter and went to the Model directly since it did not rely on any specific View state (parameters)&lt;/div&gt;&lt;br /&gt;&lt;div&gt;Here is a summary of the benefits of decoupling Views from Controllers by allowing them to refresh their data directly from Models as per Smalltalk MVC or use Helpers as Presenters/Adapters for View state (request and session parameters):&lt;/div&gt;&lt;div&gt;&lt;ol&gt;&lt;li&gt;Unclutter Controllers from data loading logic for multiple objects that the View needs, allowing each part of the View to load its data directly.&lt;/li&gt;&lt;li&gt;Make View partials easily reusable as they rely on Presenters/Adapters (Helpers) to load their data by pull instead of having to include code in every reusing Controller to push the data into the Views.&lt;/li&gt;&lt;li&gt;Easily test-drive and maintain the logic of Presenting/Adapting View data in small cleanly separated methods instead of having that logic all mixed in Controllers.&lt;/li&gt;&lt;li&gt;When Models needed for the View have dependencies in their load order, there is no need to explicitly order their loading in the Controller. Helper methods can be composed of other helper methods, resolving the dependencies automatically.&lt;/li&gt;&lt;li&gt;Avoid the dissonance in View code caused by a mix of "@object" references and Helper "object" references. All objects in the View get populated from Helpers with "object" references or directly from model classes making the code more readable.&lt;/li&gt;&lt;li&gt;Trivial extraction of partials from Views given that they do not contain any "@object" variables and all references are "object" references. Developers thus do not need to put any effort into error-prone switching of "@object" variables into "object" locals. The helper "object" references can already serve as locals.&lt;/li&gt;&lt;li&gt;Controllers already have access to the context of Presenters (Helpers) thus are able to reuse the View data loading logic without need to duplicate.&lt;/li&gt;&lt;li&gt;If multiple Controller actions and Views rely on the same data object being present as in the new, create, edit, update, and show actions (e.g. contact object). A single Presenter method (e.g. "contact" helper) can take care of loading that object regardless of whether new or existing in the database already (e.g. Contact.find_or_initialize_by_id(params[:id], params[:contact])&amp;nbsp;&lt;/li&gt;&lt;/ol&gt;&lt;div&gt;These are some of the benefits experienced in my last three Rails projects, giving the team great flexibility in maintaining Views, Models, Controllers, and Presenters without the mix of concerns typically experienced in Controllers, allowing for much easier test-driven development and flexibility in composing/modifying features for customers.&lt;/div&gt;&lt;br /&gt;&lt;div&gt;&lt;div&gt;p.s. The "region" Helper above can optionally be enhanced to manage the region session state in isolation of any Controller, thus maximizing reuse for the Views relying on that View state (parallel to how desktop Views manage their own on-going state as smart objects). Here is one of several ways to do this: &lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;div&gt;def region&lt;br /&gt;&amp;nbsp; session[:region_id] = params[:region_id] if params[:region_id]&lt;br /&gt;&amp;nbsp; Region.find(session[:region_id])&lt;br /&gt;end&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;div&gt;p.s.2 Though "before_filter"s in Rails can be used to easily load data in controllers. They still put the onus on the controller to do the data loading by push, requiring developers to add such logic to every controller that will reuse a particular View partial, and adding complexity to reasoning about the code.&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;div&gt;     &lt;script type="text/javascript"&gt;      slashdot_url="https://bitly.com/q7k4FG";     &lt;/script&gt;     &lt;script src="http://slashdot.org/slashdot-it.js" type="text/javascript"&gt;&lt;/script&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/32881756-1110527436514779709?l=andymaleh.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://andymaleh.blogspot.com/feeds/1110527436514779709/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=32881756&amp;postID=1110527436514779709' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/32881756/posts/default/1110527436514779709'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/32881756/posts/default/1110527436514779709'/><link rel='alternate' type='text/html' href='http://andymaleh.blogspot.com/2011/10/decoupling-views-from-controllers-in.html' title='Decoupling Views from Controllers in Rails (Smalltalk MVC Style)'/><author><name>Annas "Andy" Maleh</name><uri>http://www.blogger.com/profile/10268484073612495328</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/-f6UYG8WIYJI/Tpw6vYi2nTI/AAAAAAAAAPk/ICI9GDbAxh4/s1600/7312067a2015194b853856820711a178%253Fsize%253D200'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/-4eW59Ao0ess/ToiBzAiYdZI/AAAAAAAAAOg/SiYa6XHwBFE/s72-c/Screen+shot+2011-10-02+at+10.22.11+AM.png' height='72' width='72'/><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-32881756.post-8712974623757181368</id><published>2011-09-27T07:08:00.001-05:00</published><updated>2011-09-27T07:11:45.744-05:00</updated><title type='text'>Smalltalk MVC Applied in Rails</title><content type='html'>&lt;div dir="ltr" style="text-align: left;" trbidi="on"&gt;I am giving a talk today at the weekly Groupon GeekFest event titled "Smalltalk MVC Applied in Rails."&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Abstract:&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;MVC was an architectural pattern that originated in desktop development with Smalltalk. It helped decouple application domain logic from user interface presentation and control flow. Since it relied heavily on observers and the web paradigm does not support observers cheaply, MVC got twisted quite a bit in order to provide some of the same benefits in web development. Unfortunately, the baby got thrown with the bath water on certain fronts... &lt;a href="http://geekfest.gathers.us/events/geekfest-20110927"&gt;Read More&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;If you're in the Chicago area, you can attend at lunch time by RSVPing over here:&lt;br /&gt;&lt;a href="http://geekfest.gathers.us/events/geekfest-20110927"&gt;http://geekfest.gathers.us/events/geekfest-20110927&lt;/a&gt;&lt;br /&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/32881756-8712974623757181368?l=andymaleh.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://andymaleh.blogspot.com/feeds/8712974623757181368/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=32881756&amp;postID=8712974623757181368' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/32881756/posts/default/8712974623757181368'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/32881756/posts/default/8712974623757181368'/><link rel='alternate' type='text/html' href='http://andymaleh.blogspot.com/2011/09/smalltalk-mvc-applied-in-rails.html' title='Smalltalk MVC Applied in Rails'/><author><name>Annas "Andy" Maleh</name><uri>http://www.blogger.com/profile/10268484073612495328</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/-f6UYG8WIYJI/Tpw6vYi2nTI/AAAAAAAAAPk/ICI9GDbAxh4/s1600/7312067a2015194b853856820711a178%253Fsize%253D200'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-32881756.post-7345195446729087542</id><published>2011-09-18T14:19:00.000-05:00</published><updated>2011-09-18T14:37:56.698-05:00</updated><title type='text'>Cucumber tests run twice in Rails 3 using an engine (fixed)</title><content type='html'>&lt;div dir="ltr" style="text-align: left;" trbidi="on"&gt;Recently, I had a problem with Cucumber tests running twice in a Rails 3 web app after I added a dependency on a Rails engine that I have extracted from another web app. After some investigation, I found out that given that the engine has its own Cucumber.rake, it ends up getting automatically included in the rake tasks of the web app when running "rake", thus queuing Cucumber tests to be run twice.&lt;br /&gt;&lt;br /&gt;I solved the problem by adding the following in the Rails engine's Cucumber.rake file:&lt;br /&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;begin&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;&amp;nbsp; EngineModuleName::Application&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;&amp;nbsp; ... original Cucumber.rake content&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;&amp;nbsp; rescue NameError =&amp;gt; e&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;end&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Of course, for that to work, you need to make sure that you have defined an "application.rb" for the engine project with the correct engine module name namespace. That is usually done as part of setting up a new Rails engine project to allow invoking tests in the engine independently of any particular Rails project (by faking a Rails app in the engine).&lt;br /&gt;&lt;br /&gt;Then, by adding the code above around Cucumber.rake's original content in the Rails engine project, you are saying that unless you are running within the scope of the engine's application, do not run the original content of Cucumber.rake. That gets rid of the problem of Cucumber tests running twice in any web app consuming the engine.&lt;br /&gt;&lt;br /&gt;Happy Cucumber testing with Rails engine reuse!&lt;br /&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/32881756-7345195446729087542?l=andymaleh.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://andymaleh.blogspot.com/feeds/7345195446729087542/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=32881756&amp;postID=7345195446729087542' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/32881756/posts/default/7345195446729087542'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/32881756/posts/default/7345195446729087542'/><link rel='alternate' type='text/html' href='http://andymaleh.blogspot.com/2011/09/cucumber-tests-run-twice-in-rails-3.html' title='Cucumber tests run twice in Rails 3 using an engine (fixed)'/><author><name>Annas "Andy" Maleh</name><uri>http://www.blogger.com/profile/10268484073612495328</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/-f6UYG8WIYJI/Tpw6vYi2nTI/AAAAAAAAAPk/ICI9GDbAxh4/s1600/7312067a2015194b853856820711a178%253Fsize%253D200'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-32881756.post-6417375496541765091</id><published>2011-09-17T14:45:00.002-05:00</published><updated>2011-09-17T15:15:54.396-05:00</updated><title type='text'>More Productive Rails Engine Development via Symlinking</title><content type='html'>&lt;div dir="ltr" style="text-align: left;" trbidi="on"&gt;I have been using &lt;a href="http://andymaleh.blogspot.com/2011/09/rails-engine-that-could.html"&gt;Rails Engines&lt;/a&gt; in Rails 3 quite successfully recently on a client project, enabling the team to reuse functionality that cuts through the MVC layers including front-end Javascript while still being able to customize it for the different web apps we are building.&lt;br /&gt;&lt;br /&gt;The price we pay for such reuse though is having to keep updating the git repo reference in Gemfile for the web app on every Rails engine update.&lt;br /&gt;&lt;br /&gt;Here is an example of that reference line in Gemfile:&lt;br /&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;gem 'national_search_map', :git =&amp;gt; 'ssh://our_git_account@git.our_project_repo.org/var/git/national_search_map.git', :ref =&amp;gt; 'f11671a'&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Fortunately, I have found a remedy for that challenge by writing a rake task that creates a symlink for the Rails engine project within the gemset of the web app. That enables developers to make back-and-forth changes in both application and engine with no interruption until completely done working on their feature. Only then do they have to commit the engine code, get a new revision ref number, and then insert it in the web app Gemfile &lt;u&gt;to ensure linkage to a fixed version of the engine code upon deployment&lt;/u&gt;.&lt;br /&gt;&lt;br /&gt;Here is the code of the rake task I wrote:&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;namespace "engine" do&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;&amp;nbsp;desc "Symlinks an engine gem into a local project for development productivity purposes"&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;&amp;nbsp;task :symlink, :gem_name do |t, args|&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;&amp;nbsp; &amp;nbsp;gem_name = args[:gem_name]&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;&amp;nbsp; &amp;nbsp;gem_file_path = `bundle exec gem which #{gem_name}`&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;&amp;nbsp; &amp;nbsp;gem_file_path_match = gem_file_path.match(/(.*)\/lib.*/)&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;&amp;nbsp; &amp;nbsp;gem_path = gem_file_path_match[1]&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;&amp;nbsp; &amp;nbsp;system "rm -rf #{gem_path}"&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;&amp;nbsp; &amp;nbsp;project_gem_path = File.expand_path("#{Rails.root}/../#{gem_name}", __FILE__)&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;&amp;nbsp; &amp;nbsp;system "ln -s #{project_gem_path} #{gem_path}"&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;&amp;nbsp; &amp;nbsp;puts "Symlinking Complete: #{gem_path} now points to #{project_gem_path}"&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;&amp;nbsp;end&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;end&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;The rake task can be invoked via: "rake engine:symlink[engine_project_gem_name]".&amp;nbsp;I have it saved under lib/tasks/engine.rake. If you put it in a Rails engine or gem that is reused across all your web apps, then all of them inherit that rake task and you would not have to duplicate it across projects (meta meta!)&lt;br /&gt;&lt;br /&gt;Once you are done working in both engine and web app, have all tests passing, and are ready to deploy, make sure to follow these steps to lock a specific version of the gem in the web app for a safe predictable deployment:&lt;br /&gt;&lt;br /&gt;&lt;ul style="text-align: left;"&gt;&lt;li&gt;commit engine code, obtaining a new git ref revision number&lt;/li&gt;&lt;li&gt;update Gemfile in web app to point to the new engine git ref revision number&lt;/li&gt;&lt;li&gt;bundle install the web app (this automatically gets rid of the rake task symlink) and then run rake again to ensure all tests are passing after linking to the engine via the git repository&lt;/li&gt;&lt;li&gt;commit web app code and deploy&lt;/li&gt;&lt;/ul&gt;&lt;div&gt;That's all folks. You are welcome to share questions and experiences via comments.&lt;/div&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/32881756-6417375496541765091?l=andymaleh.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://andymaleh.blogspot.com/feeds/6417375496541765091/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=32881756&amp;postID=6417375496541765091' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/32881756/posts/default/6417375496541765091'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/32881756/posts/default/6417375496541765091'/><link rel='alternate' type='text/html' href='http://andymaleh.blogspot.com/2011/09/more-productive-rails-engine.html' title='More Productive Rails Engine Development via Symlinking'/><author><name>Annas "Andy" Maleh</name><uri>http://www.blogger.com/profile/10268484073612495328</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/-f6UYG8WIYJI/Tpw6vYi2nTI/AAAAAAAAAPk/ICI9GDbAxh4/s1600/7312067a2015194b853856820711a178%253Fsize%253D200'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-32881756.post-8312572349018306641</id><published>2011-09-07T08:27:00.000-05:00</published><updated>2011-11-03T18:58:09.060-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Ruby'/><category scheme='http://www.blogger.com/atom/ns#' term='Software Architecture'/><category scheme='http://www.blogger.com/atom/ns#' term='Rails'/><title type='text'>The Rails Engine That Could</title><content type='html'>&lt;div dir="ltr" style="text-align: left;" trbidi="on"&gt;I gave a lightning talk at Groupon's weekly tech event "GeekFest" the other day titled "The Rails Engine That Could"&lt;br /&gt;&lt;br /&gt;The talk covered a successful utilization of Rails Engines in a Rails 3 project to modularize MVC features as reusable components. These components provide the best of both worlds,&amp;nbsp;improved productivity through reusable MVC code, and better flexibility by allowing different applications to customize behavior as needed without &lt;a href="http://www.codinghorror.com/blog/2006/05/code-smells.html"&gt;dirty conditionals&lt;/a&gt; by relying on the &lt;a href="http://wiki.eclipse.org/FAQ_What_are_extensions_and_extension_points%3F"&gt;Extension Point pattern&lt;/a&gt; (as used in the &lt;a href="http://www.eclipse.org/"&gt;Eclipse IDE&lt;/a&gt;). Of course, given the benefits of Ruby, no XML is involved in the extension points, but how that was accomplished is beyond the scope of the lightning talk and can be covered in a future blog post.&lt;br /&gt;&lt;br /&gt;Check out the slides over here:&lt;br /&gt;&lt;div id="__ss_9162144" style="width: 425px;"&gt;&lt;strong style="display: block; margin: 12px 0 4px;"&gt;&lt;a href="http://www.slideshare.net/AndyMaleh/the-rails-engine-that-could-9162144" title="The Rails Engine That Could"&gt;The Rails Engine That Could&lt;/a&gt;&lt;/strong&gt;&lt;object height="355" id="__sse9162144" width="425"&gt;&lt;param name="movie" value="http://static.slidesharecdn.com/swf/ssplayer2.swf?doc=therailsenginethatcould-110907082501-phpapp02&amp;stripped_title=the-rails-engine-that-could-9162144&amp;userName=AndyMaleh" /&gt;&lt;param name="allowFullScreen" value="true"/&gt;&lt;param name="allowScriptAccess" value="always"/&gt;&lt;embed name="__sse9162144" src="http://static.slidesharecdn.com/swf/ssplayer2.swf?doc=therailsenginethatcould-110907082501-phpapp02&amp;stripped_title=the-rails-engine-that-could-9162144&amp;userName=AndyMaleh" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="425" height="355"&gt;&lt;/embed&gt;&lt;/object&gt;&lt;br /&gt;&lt;div style="padding: 5px 0 12px;"&gt;View more &lt;a href="http://www.slideshare.net/"&gt;presentations&lt;/a&gt; from &lt;a href="http://www.slideshare.net/AndyMaleh"&gt;AndyMaleh&lt;/a&gt;.&lt;/div&gt;&lt;/div&gt;&lt;br /&gt;&lt;p&gt;Follow-up one-hour long presentation has been posted over here: &lt;a href="http://andymaleh.blogspot.com/2011/11/rails-engine-that-could-in-motion.html"&gt;The Rails Engine That Could - In Motion&lt;/a&gt;&lt;/p&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/32881756-8312572349018306641?l=andymaleh.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://andymaleh.blogspot.com/feeds/8312572349018306641/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=32881756&amp;postID=8312572349018306641' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/32881756/posts/default/8312572349018306641'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/32881756/posts/default/8312572349018306641'/><link rel='alternate' type='text/html' href='http://andymaleh.blogspot.com/2011/09/rails-engine-that-could.html' title='The Rails Engine That Could'/><author><name>Annas "Andy" Maleh</name><uri>http://www.blogger.com/profile/10268484073612495328</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/-f6UYG8WIYJI/Tpw6vYi2nTI/AAAAAAAAAPk/ICI9GDbAxh4/s1600/7312067a2015194b853856820711a178%253Fsize%253D200'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-32881756.post-4363135113703721786</id><published>2011-03-18T14:15:00.019-05:00</published><updated>2011-03-18T19:28:47.283-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Ruby'/><category scheme='http://www.blogger.com/atom/ns#' term='Conferences'/><title type='text'>MountainWest RubyConf 2011: Day 2</title><content type='html'>So, I am not doing as much coverage today as &lt;a href="http://andymaleh.blogspot.com/2011/03/mountainwest-rubyconf-2011-day-1.html"&gt;yesterday&lt;/a&gt;, but I will cover interesting tid bits here and there.&lt;br /&gt;&lt;br /&gt;Just saw an interesting lightning talk about a new project on GitHub called &lt;a href="https://github.com/jenseng/trigger_happy"&gt;trigger_happy&lt;/a&gt; that allows you to generate triggers from active record models, thus get all the benefits of triggers and the expressibility/db-independence of Ruby abstraction. &lt;br /&gt;&lt;br /&gt;Another lightning talk was given on &lt;a href="http://university.rubymendicant.com/"&gt;Ruby Mendicant University&lt;/a&gt;, which provides real world training for intermediate Ruby programmers. &lt;br /&gt;&lt;br /&gt;In one very cool talk titled "Using Ruby with Xbox Kinect for fun and profit" by Nate Peel, the presenter showed us how to interface with the new XBOX Kinect technology using Ruby. He then concluded with a demo of it capturing his motion while waving at the audience. Not my cup of tea of programming, but I am sure a lot of developers find that interesting.&lt;br /&gt;&lt;br /&gt;Next, Joe O'Brien from EdgeCase talks about Android Development With Ruby. One cool thing he showed is his own DSL for the views to avoid the annoying reliance on XML for views. Also, it was interesting how he relied on the typed version of Ruby, Mirah, to program the Android Java libraries since Mirah has a closer gap to Java given the typing.&lt;br /&gt;&lt;br /&gt;Evan Light talks next about "Tiny Tools Tidy Tests", in which he mentions how he built coulda as a simpler Cucumber alternative because he did a lot of testing in his job yet really felt bogged down by Cucumber. He recommends developers write their own tools if they are not pleased with the ones they have, yet use them for the majority of the time in their job.&lt;br /&gt;&lt;br /&gt;Afterward, I presented "&lt;a href="http://mtnwestrubyconf.org/2011/sessions#AndyMaleh"&gt;Whatever Happened To Desktop Development with Ruby.&lt;/a&gt;". The presentation will be posted on the &lt;a href="http://confreaks.net/"&gt;Confreaks website&lt;/a&gt; sometime in the near future. I will announce it when it happens.&lt;br /&gt;&lt;br /&gt;Yahuda Katz is concluding the day with his keynote speech "Ruby: The Challenges Ahead". He is not pleased with Ruby developers sticking with the 80/20 rule without eventually (gradually?) going beyond it and solving the problem 100%. He thinks it discourages developers from taking Ruby seriously in comparison to languages like Java or C#. He emphasizes that protocols implemented in the standard Ruby library, such as RSS, may not have nice APIs, but are meant to be 100% solutions, so other gems can simply provide better APIs for them. There is no need to rewrite them. Often Ruby developers bite more than they could chew because they are not satisfied with a library, tackling a problem outside of their domain of expertise when they could have reused a reliable library but improved its APIs.  He mentions how protocol libraries that do not change often are usually stable because they have a complete implementation, and thus are considered reliable. On the other hand, libraries that are more like frameworks (e.g. Rails) have to change often to express the latest needs. Yahuda gives examples of people's abuse of TheadLocal, Constant re-assignment, and inheritance instead of trying to solve problems the right way completely or rely on a library that does (albeit sometimes with an ugly API). He encourages developers to seek cooperation over NIH (not invented here), so maybe look for something out there first before rewriting things yourself. He also encourages pure Ruby over bindings for problem that are not too tough to rewrite in Ruby over C, such as YML parsing. The last thing he pointed out is encouraging streaming IO over blocking IO. He closed the presentation with emphasis on solving the 20 part of the 80/20, ending with "Let's Grow Up Together"&lt;br /&gt;&lt;br /&gt;Thanks to everyone who helped with organizing this conference and thanks to all the presenters.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/32881756-4363135113703721786?l=andymaleh.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://andymaleh.blogspot.com/feeds/4363135113703721786/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=32881756&amp;postID=4363135113703721786' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/32881756/posts/default/4363135113703721786'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/32881756/posts/default/4363135113703721786'/><link rel='alternate' type='text/html' href='http://andymaleh.blogspot.com/2011/03/mountainwest-rubyconf-2011-day-2.html' title='MountainWest RubyConf 2011: Day 2'/><author><name>Annas "Andy" Maleh</name><uri>http://www.blogger.com/profile/10268484073612495328</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/-f6UYG8WIYJI/Tpw6vYi2nTI/AAAAAAAAAPk/ICI9GDbAxh4/s1600/7312067a2015194b853856820711a178%253Fsize%253D200'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-32881756.post-1240418475476572699</id><published>2011-03-17T21:08:00.017-05:00</published><updated>2011-03-17T21:30:53.137-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Ruby'/><category scheme='http://www.blogger.com/atom/ns#' term='Glimmer'/><title type='text'>Glimmer 0.1.3 Release</title><content type='html'>Just released a new version of Glimmer (0.1.3):&lt;br /&gt;&lt;a href="https://rubygems.org/gems/glimmer"&gt;https://rubygems.org/gems/glimmer&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;New and noteworthy:&lt;/b&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Made SWT the default DSL to avoid forcing developers to specify the DSL explicitly with the "&lt;a href="http://andymaleh.blogspot.com/2011/02/glimmer-012-release.html"&gt;dsl&lt;/a&gt;" method. Sample applications run successfully again as a result.&lt;/li&gt;&lt;li&gt;Revised SWT styling support to rely on Ruby symbols instead of Eclipse SWT's bit ORing via the &lt;a href="http://andymaleh.blogspot.com/2008/01/glimmer-is-stylin.html"&gt;SWT constant DSL&lt;/a&gt; as that better matches Ruby's conventions and avoids method name clashing.&lt;/li&gt;&lt;li&gt;Added swt_widget and swt_constant methods to String and Symbol to allow easy inflection of SWT Widgets and Constants via strings and symbols.&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Before/After examples of the new SWT styling syntax:&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;table(SWT::BORDER) =&gt; table(:border)&lt;br /&gt;&lt;br /&gt;text(SWT::PASSWORD | SWT::BORDER) =&gt; text(:password, :border)&lt;br /&gt;&lt;br /&gt;layout_data GridData.new(SWT::FILL, SWT::FILL, true, true) =&gt;&lt;br /&gt;layout_data GridData.new(:fill.swt_constant, :fill.swt_constant, true, true)&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Enjoy the release and stay tuned for the next one.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/32881756-1240418475476572699?l=andymaleh.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://andymaleh.blogspot.com/feeds/1240418475476572699/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=32881756&amp;postID=1240418475476572699' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/32881756/posts/default/1240418475476572699'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/32881756/posts/default/1240418475476572699'/><link rel='alternate' type='text/html' href='http://andymaleh.blogspot.com/2011/03/glimmer-013-release.html' title='Glimmer 0.1.3 Release'/><author><name>Annas "Andy" Maleh</name><uri>http://www.blogger.com/profile/10268484073612495328</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/-f6UYG8WIYJI/Tpw6vYi2nTI/AAAAAAAAAPk/ICI9GDbAxh4/s1600/7312067a2015194b853856820711a178%253Fsize%253D200'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-32881756.post-7429299447278387055</id><published>2011-03-17T10:49:00.033-05:00</published><updated>2011-03-18T14:20:09.489-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Ruby'/><category scheme='http://www.blogger.com/atom/ns#' term='Conferences'/><title type='text'>MountainWest RubyConf 2011: Day 1</title><content type='html'>Missed keynote by Zed Shaw (will watch on Video on ConFreaks), but I saw David Brady talk about "Monkey Patching your Brain". And yes, he hacked our brain well! The talk was mostly about how to work harder without overthinking and how to form efficient effortless habits fast via the power of strong emotions. Favorite brain hack: "I get the feeling that when there's a big elephant in the room, I gotta go poke it in the eye!"&lt;br /&gt;&lt;br /&gt;Next, Bobbie Wilson talks about visualization of git data via &lt;a href="http://grit.rubyforge.org/"&gt;Grit&lt;/a&gt;, &lt;a href="http://vis.stanford.edu/protovis/"&gt;Protovis&lt;/a&gt;, MongoDB, and Map/Reduce algorithms. Grit is a package that gives you Ruby object oriented APIs for Git data. Protovis visualizes data via Javascript. MongoDB was used to store raw data obtained from Git before going over it with Map/Reduce to visualize it. He showed us how many commits Ruby had since its Repo inception as well as a graph of how it increased in frequency over time.&lt;br /&gt;&lt;br /&gt;Next up, Wayne Seguin talks about the Ruby Community, covering the benefits it offers such as open-source projects, opportunities, education &amp; mentorship, social interaction &amp; communication, personal growth, satisfaction &amp; happiness, and relationships &amp; friendships.&lt;br /&gt;&lt;br /&gt;After lunch break, people are giving lightning talks. David Henner just talked about his Rails E-Commerce solution, which offers quite a few unique features over other solutions, such as double-checked accounting and optimized image upload. The project is called &lt;a href="http://www.ror-e.com/"&gt;ror-e&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;Next, someone talks about remote pairing via &lt;a href="http://tmux.sourceforge.net/"&gt;tmux&lt;/a&gt;, a terminal multiplexer.&lt;br /&gt;&lt;br /&gt;Next up, a developer from PivotalLabs talked about how to make it easy for people to contribute to open source, which summarizes to writing tests first, ensuring rake works, integrating contributor changes often, and keeping contributors happy by making eager ones members of the project direct committers.&lt;br /&gt;&lt;br /&gt;Next, a guy from Chef, talks about &lt;a href="http://tmux.sourceforge.net/"&gt;tmux&lt;/a&gt;, a terminal multiplexer that enables remote pair programming with features such as simultaneous coding and screen splitting.&lt;br /&gt;&lt;br /&gt;Next, a guy talks about &lt;a href="http://vimgolf.com/"&gt;VimGolf&lt;/a&gt;, a tool that counts every keystroke you perform with VIM to test how efficient you are in using its shortcuts (LOVE THE IDEA!). This goes beyond the "Avoid using the mouse" advice into "Avoid using inefficient shortcuts"! It is in fact a great tool for motivating developers to learn the best shortcuts as it ranks people via different &lt;a href="http://vimgolf.com/"&gt;VimGolf&lt;/a&gt; games on the site.&lt;br /&gt;&lt;br /&gt;Next up, Zed Shaw is talking about his book "Learn Python The Hard Way", in which he tries to get as many non-programmers as possible to get into programming. He does so as he believes that these people will bring their own very different perspective to the field and thus help improve it in unpredictable ways.&lt;br /&gt;&lt;br /&gt;Next, a developer talks about the &lt;a href="http://kidsruby.com/"&gt;kidsruby.com&lt;/a&gt; website inspired by Hackety Hack that helps kids get started withi Ruby programming. They need help with contributors with regards to the editor and system installers. &lt;br /&gt;&lt;br /&gt;Next, a fedora wearing developer talks about &lt;a href="https://github.com/mirah/dubious"&gt;Dubious&lt;/a&gt;, a project that allows running Mirah projects (Mirah is a statically typed version of Ruby formerly known as Duby) on Google App Engine.&lt;br /&gt;&lt;br /&gt;Next talk is about "why do gems break and what you can do and don't about it". Causes for problems are: &lt;br /&gt;1. Not declaring dependencies: use a clean RVM gemset to reveal missing dependencies.&lt;br /&gt;2. declaring invalid, stale, old, or difficult to find dependencies: before packaging make sure what you are using is valid all the way down&lt;br /&gt;3. declaring yourself as a dependency (cyclic dependency? BAD): use yourself as your testing framework!&lt;br /&gt;4. not declaring absolute or minimal and maximal versions of dependencies: at least declare the versions you tested with.&lt;br /&gt;5. tests broken: declare test frameworks as dependencies, including version. Declare development dependencies. Set tests not to run from the root of the project.&lt;br /&gt;&lt;br /&gt;Next, Wayne Seguin talks about EngineYard's community commitment.&lt;br /&gt;&lt;br /&gt;Next, a developer talks about how to generate class diagrams ( in SVG) from a Rails code base.&lt;br /&gt;&lt;br /&gt;Next, Mike Moore talkes about Project "M". (Minaswan?). He's talking about the older Matz initiative of "Be Nice. Ruby developers are Nice! Bring niceness to the Ruby Community!"&lt;br /&gt;&lt;br /&gt;After a quick break, longer talks resumed, and Joshua Timberman talked about Chef Cookbook Design Pattern. He starts by explaining how Chef's model compares to MVC where node specifications are the models, configured nodes are the view, and the controller is the recipe in pure Ruby. &lt;br /&gt;&lt;br /&gt;Next, Wesley Beary presented "Fog OR: How I Learned to Stop Worrying and Love the Cloud". &lt;br /&gt;What's the cloud?&lt;br /&gt;-On demand (pay for what you use)&lt;br /&gt;-Flexible (add and remove resources in minutes)&lt;br /&gt;-Repeatable (code, test, repeat)&lt;br /&gt;-Resilient (build better systems with transient resources)&lt;br /&gt;Why worry?&lt;br /&gt;-Option overload&lt;br /&gt;-Expertise required&lt;br /&gt;-Tool variety&lt;br /&gt;-Standards slow&lt;br /&gt;Solution?&lt;br /&gt;&lt;a href="https://github.com/engineyard/fog"&gt;Fog&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Next, Nick Quaranto talks about Redis and how to make Ruby applications run faster.&lt;br /&gt;&lt;br /&gt;Had a quick break, and then Chris Wychoff presented "Refactoring Monolithic Rails Apps with SOA" starting with how these apps were born as simple humble apps and then grew to behemoth applications. Recommendation is to separate responsibilities, handle them asynchronously, and make incremental steps. Gotchas include  overly decomposed services, &lt;br /&gt;&lt;br /&gt;Next up, Brian Helmkamp presented on "Service Oriented Design in Practice", focusing on Service Oriented Design as opposed to Service Oriented Architecture (anyone remembers difference between software design and software architecture? bonus points for you).  Benefits of SOD are isolation, robustness, scalability, agility, interoperability, and reuse. &lt;br /&gt;&lt;br /&gt;A very anticipated talk is next, which is "Securing Your Rails App" by Jim Weirich and Matt Yoho from EdgeCase (I did a &lt;a href="http://andymaleh.blogspot.com/2010/08/craftsmanship-swap.html"&gt;craftsmanship swap&lt;/a&gt; with them last year).&lt;br /&gt;Summary:&lt;br /&gt;-Trust nothing&lt;br /&gt;-Stay up to date on security patches&lt;br /&gt;-Always scope your finds with proper privileges &lt;br /&gt;-Whitelist properties/data being set&lt;br /&gt;-Do a security audit&lt;br /&gt;&lt;br /&gt;And that's a wrap! Day 1 ends with a HackFest sponsored by EngineYard.&lt;br /&gt;&lt;br /&gt;Stay tuned for &lt;a href="http://andymaleh.blogspot.com/2011/03/mountainwest-rubyconf-2011-day-2.html"&gt;tomorrow&lt;/a&gt; as I will be presenting on &lt;a href="http://andymaleh.blogspot.com/2011/02/presenting-at-mountainwest-magicruby.html"&gt;"Whatever happened to desktop development in Glimmer?"&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/32881756-7429299447278387055?l=andymaleh.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://andymaleh.blogspot.com/feeds/7429299447278387055/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=32881756&amp;postID=7429299447278387055' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/32881756/posts/default/7429299447278387055'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/32881756/posts/default/7429299447278387055'/><link rel='alternate' type='text/html' href='http://andymaleh.blogspot.com/2011/03/mountainwest-rubyconf-2011-day-1.html' title='MountainWest RubyConf 2011: Day 1'/><author><name>Annas "Andy" Maleh</name><uri>http://www.blogger.com/profile/10268484073612495328</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/-f6UYG8WIYJI/Tpw6vYi2nTI/AAAAAAAAAPk/ICI9GDbAxh4/s1600/7312067a2015194b853856820711a178%253Fsize%253D200'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-32881756.post-6404532315043701209</id><published>2011-02-22T06:31:00.004-06:00</published><updated>2011-02-23T09:11:15.122-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Ruby'/><category scheme='http://www.blogger.com/atom/ns#' term='Glimmer'/><title type='text'>Glimmer 0.1.2 Release</title><content type='html'>Just made a new release of Glimmer (version 0.1.2):&lt;br /&gt;&lt;a href="https://rubygems.org/gems/glimmer"&gt;https://rubygems.org/gems/glimmer&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;New and noteworthy:&lt;/b&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Official multiple-DSL support ability: You can now switch between the &lt;a href="http://andymaleh.blogspot.com/2007/11/sneak-peak-at-glimmer.html"&gt;SWT&lt;/a&gt; and &lt;a href="http://andymaleh.blogspot.com/2008/01/xml-is-dead-welcome-glimmerized-xml.html"&gt;XML&lt;/a&gt; DSLs by invoking the included "dsl" method with the Glimmer module. This feature was needed in order to run all tests without DSL name clashes. Now, each test file specifies its DSL explicitly to ensure that when the XML DSL tests operate, they do not end up rendering SWT widgets for example.&lt;/li&gt;&lt;li&gt;Tests were also repaired to pass again given the latest changes in SWT, JRuby, and Facets.&lt;/li&gt;&lt;li&gt;Added a new sample app called "samples/hello_combo.rb"&lt;/li&gt;&lt;li&gt;License was switched to MIT License&lt;/li&gt;&lt;/ul&gt;&lt;b&gt;Outstanding issue:&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;One thing that is not working on the Mac for some odd reason is "rake test" as I included this required Mac Java option in the rake test task (needed for SWT):&lt;pre&gt;test.ruby_opts = ['-J-XstartOnFirstThread']&lt;/pre&gt;And, it is making rake bomb with the following message:&lt;pre&gt;jruby: unknown option -J-XstartOnFirstThread&lt;/pre&gt;However, when manually running the command that the rake task renders in the output, it works like charm. I will report back once I have found a solution to this odd problem.&lt;br /&gt;&lt;br /&gt;In the meantime, enjoy the release and stay tuned for more features.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/32881756-6404532315043701209?l=andymaleh.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://andymaleh.blogspot.com/feeds/6404532315043701209/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=32881756&amp;postID=6404532315043701209' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/32881756/posts/default/6404532315043701209'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/32881756/posts/default/6404532315043701209'/><link rel='alternate' type='text/html' href='http://andymaleh.blogspot.com/2011/02/glimmer-012-release.html' title='Glimmer 0.1.2 Release'/><author><name>Annas "Andy" Maleh</name><uri>http://www.blogger.com/profile/10268484073612495328</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/-f6UYG8WIYJI/Tpw6vYi2nTI/AAAAAAAAAPk/ICI9GDbAxh4/s1600/7312067a2015194b853856820711a178%253Fsize%253D200'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-32881756.post-2412255045809569944</id><published>2011-02-18T15:33:00.007-06:00</published><updated>2011-02-18T17:33:33.238-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Ruby'/><category scheme='http://www.blogger.com/atom/ns#' term='Glimmer'/><title type='text'>Glimmer's Officially Back on GitHub</title><content type='html'>Yes, it's official! Glimmer is back on GitHub with support for JRuby 1.5.6 and Facets 2.9.0.&lt;br /&gt;&lt;br /&gt;It also now includes an .rvmrc file to facilitate working with JRuby via RVM and a Gemfile to facilitate pulling in libraries like Facets with the right version.&lt;br /&gt;&lt;br /&gt;The project will no longer be hosted on eclipse.org&lt;br /&gt;&lt;br /&gt;Check out the GitHub repository over here:&lt;br /&gt;&lt;a target="_blank" href="https://github.com/AndyObtiva/glimmer"&gt;https://github.com/AndyObtiva/glimmer&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;This will be the main home for the project from this point on.&lt;br /&gt;&lt;br /&gt;If you need a refresher on the project, here are some good resources:&lt;br /&gt;-&lt;a target="_blank" href="http://andymaleh.blogspot.com/2008/06/glimmer-introductory-tutorial.html"&gt;Tutorial&lt;/a&gt;&lt;br /&gt;-&lt;a target="_blank" href="http://www.infoq.com/news/2008/02/glimmer-jruby-swt"&gt;Article&lt;/a&gt;&lt;br /&gt;-&lt;a target="_blank" href="http://andymaleh.blogspot.com/2008/11/video-of-glimmer-talk-rubyconf-2008.html"&gt;Video&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Happy Glimmering!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/32881756-2412255045809569944?l=andymaleh.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://andymaleh.blogspot.com/feeds/2412255045809569944/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=32881756&amp;postID=2412255045809569944' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/32881756/posts/default/2412255045809569944'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/32881756/posts/default/2412255045809569944'/><link rel='alternate' type='text/html' href='http://andymaleh.blogspot.com/2011/02/glimmers-back-on-github.html' title='Glimmer&apos;s Officially Back on GitHub'/><author><name>Annas "Andy" Maleh</name><uri>http://www.blogger.com/profile/10268484073612495328</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/-f6UYG8WIYJI/Tpw6vYi2nTI/AAAAAAAAAPk/ICI9GDbAxh4/s1600/7312067a2015194b853856820711a178%253Fsize%253D200'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-32881756.post-1483705337237143216</id><published>2011-02-08T19:40:00.004-06:00</published><updated>2011-03-17T19:20:42.385-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Ruby'/><category scheme='http://www.blogger.com/atom/ns#' term='Conferences'/><title type='text'>Presenting at MountainWest RubyConf 2011</title><content type='html'>For those who missed my talk at &lt;a href="http://magic-ruby.com/"&gt;MagicRuby 2011&lt;/a&gt; on &lt;a href="http://andymaleh.blogspot.com/2010/11/magicruby-whatever-happened-to-desktop.html"&gt;"Whatever happened to desktop development in Ruby?"&lt;/a&gt;, I will be giving an &lt;a href="http://bit.ly/gIMsz8"&gt;updated version&lt;/a&gt; of the talk at &lt;a href="http://mtnwestrubyconf.org/2011/"&gt;MountainWest RubyConf 2011&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/32881756-1483705337237143216?l=andymaleh.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://andymaleh.blogspot.com/feeds/1483705337237143216/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=32881756&amp;postID=1483705337237143216' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/32881756/posts/default/1483705337237143216'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/32881756/posts/default/1483705337237143216'/><link rel='alternate' type='text/html' href='http://andymaleh.blogspot.com/2011/02/presenting-at-mountainwest-magicruby.html' title='Presenting at MountainWest RubyConf 2011'/><author><name>Annas "Andy" Maleh</name><uri>http://www.blogger.com/profile/10268484073612495328</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/-f6UYG8WIYJI/Tpw6vYi2nTI/AAAAAAAAAPk/ICI9GDbAxh4/s1600/7312067a2015194b853856820711a178%253Fsize%253D200'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-32881756.post-8324748221016907830</id><published>2011-02-03T13:41:00.010-06:00</published><updated>2011-03-08T09:46:50.924-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Tools'/><title type='text'>Creating a locally tracked remote branch with Git</title><content type='html'>Git is a distributed source code control system that allows you to clone a remote repository locally, make commits to it on your machine, and then push them to the remote repository when done.&lt;br /&gt;&lt;br /&gt;It is often useful to create a remote branch for features that are experimental or will not be going out in the upcoming release as that allows you to work in isolation of the main code repository changes, thus not get blocked.&lt;br /&gt;&lt;br /&gt;In order to work with a Git remote branch, it has to be cloned locally, and there are multiple ways of doing it with different levels of complexity. Some have you create the local branch first. Others have you create the remote branch first.&lt;br /&gt;&lt;br /&gt;My intention for this blog post is to document the easiest way to date for creating a remote branch that is tracked locally.&lt;br /&gt;&lt;br /&gt;Here it goes (assuming origin is the default):&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;git branch new_branch_name&lt;br /&gt;git push origin new_branch_name&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Then you can checkout the local branch and work with it by typing:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;git checkout new_branch_name&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;The local branch automatically tracks the remote branch, so you do not have to worry about explicitly setting that up.&lt;br /&gt;&lt;br /&gt;Now, if you already have a remote branch created by someone else though, and you want to check it out locally, you can just run this command (assuming remote is origin):&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;git checkout -t -b branch_name origin/branch_name&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;A Google search turns out a dozen ways, many of which are over-complicated or out-dated, so I hope people find this blog post helpful for providing the simplest approach to date.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/32881756-8324748221016907830?l=andymaleh.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://andymaleh.blogspot.com/feeds/8324748221016907830/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=32881756&amp;postID=8324748221016907830' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/32881756/posts/default/8324748221016907830'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/32881756/posts/default/8324748221016907830'/><link rel='alternate' type='text/html' href='http://andymaleh.blogspot.com/2011/02/creating-localremote-branch-with-git.html' title='Creating a locally tracked remote branch with Git'/><author><name>Annas "Andy" Maleh</name><uri>http://www.blogger.com/profile/10268484073612495328</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/-f6UYG8WIYJI/Tpw6vYi2nTI/AAAAAAAAAPk/ICI9GDbAxh4/s1600/7312067a2015194b853856820711a178%253Fsize%253D200'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-32881756.post-6662265641668720869</id><published>2011-02-01T06:14:00.018-06:00</published><updated>2011-02-01T08:28:41.670-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Ruby'/><category scheme='http://www.blogger.com/atom/ns#' term='Rails'/><title type='text'>Setting non-nullable field defaults in Rails</title><content type='html'>Recently, I found myself following a pattern for setting non-nullable field defaults in a Rails model.&lt;br /&gt;&lt;br /&gt;Basically, instead of relying on the database schema:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;  create_table "user_queries", :force =&gt; true do |t|&lt;br /&gt;    ...&lt;br /&gt;    t.string   "sort_field", :default =&gt; "username", :nil =&gt; false&lt;br /&gt;  end&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;I add an after_initialize hook to the ActiveRecord model:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;  after_initialize :set_defaults&lt;br /&gt;&lt;br /&gt;  def set_defaults&lt;br /&gt;    self.sort_field = "username" if sort_field.nil?&lt;br /&gt;  end&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;The reason I do that is because of an issue I ran into when specifying the non-nullable default in the database schema. When the default value requirement changes (e.g. change default from "username" to "last_name"), I end up having to create a migration that modifies the column when using a database that supports column modification (e.g. MySQL), or worse yet for databases that do not support column modification (e.g. PostgreSQL), I create a migration that adds a new column, migrates older's column data to new column, and removes older column.&lt;br /&gt;&lt;br /&gt;By having the non-nullable default specified in ActiveRecord models instead, change becomes as easy as updating the model's test and the default value specified in the code. &lt;br /&gt;&lt;br /&gt;Of course, the disadvantage to this approach is it does not ensure that the default value is set when interacting with the database without ActiveRecord. But, it works if that is not a requirement in your client environment.&lt;br /&gt;&lt;br /&gt;Would be curious to know if others ran into the same problem and whether they addressed it in the same way.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/32881756-6662265641668720869?l=andymaleh.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://andymaleh.blogspot.com/feeds/6662265641668720869/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=32881756&amp;postID=6662265641668720869' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/32881756/posts/default/6662265641668720869'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/32881756/posts/default/6662265641668720869'/><link rel='alternate' type='text/html' href='http://andymaleh.blogspot.com/2011/02/setting-defaults-in-rails-activerecord.html' title='Setting non-nullable field defaults in Rails'/><author><name>Annas "Andy" Maleh</name><uri>http://www.blogger.com/profile/10268484073612495328</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/-f6UYG8WIYJI/Tpw6vYi2nTI/AAAAAAAAAPk/ICI9GDbAxh4/s1600/7312067a2015194b853856820711a178%253Fsize%253D200'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-32881756.post-5700631478404398230</id><published>2011-01-28T11:54:00.004-06:00</published><updated>2011-01-28T11:54:00.953-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Craftsmanship'/><title type='text'>On Continuous Learning</title><content type='html'>&lt;p&gt;So, a couple of Fridays ago I injured my right wrist snowboarding in Breckenridge, Colorado, and the doctor put a cast around my arm because I got a hairline fracture in the bone connecting to the wrist. Given that I do not have the dominant hand available for use anymore, I had to get by without it for the last two weeks, and will continue to do so for weeks to come. As a result, I had to learn how to do several things left-handed, and that got me thinking about &lt;a href="http://andymaleh.blogspot.com/2010/12/what-makes-developer-valuable-to-obtiva.html"&gt;Obtiva's culture&lt;/a&gt; of Continuous Learning and how it benefited the process.&lt;/p&gt;&lt;p&gt;Normally, I would have been discouraged and handicapped for weeks, probably using my injury as an excuse not to do some tasks and constantly complain. Given the new habits ingrained in me after being with &lt;a href="http://obtiva.com/"&gt;Obtiva&lt;/a&gt; for 5 years now, I surprised myself by having a totally different attitude:&lt;br /&gt;"Why should learning anything with my left hand be any different from learning a new language, library, or technology? Couldn't I follow the same process of gradual learning with &lt;a href="http://apprenticeship-patterns.labs.oreilly.com/ch02.html"&gt;"beginner's mind"&lt;/a&gt; (as mentioned in &lt;a href="http://redsquirrel.com/dave/"&gt;Dave Hoover&lt;/a&gt;'s book &lt;a href="http://oreilly.com/catalog/9780596518387"&gt;Apprenticeship Patterns&lt;/a&gt;)?"&lt;/p&gt;&lt;p&gt;And so I did, and as a result, I learned how to do quite a few things with my left hand that I could not do with it before:&lt;/p&gt;&lt;p&gt;Eating with chopsticks fast enough not to starve:&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_XQt1Vabxo5g/TUIEoo5joLI/AAAAAAAAANU/690sWUZGm-g/s1600/photo%2B%25282%2529.JPG"&gt;&lt;img style="cursor:pointer; cursor:hand;width: 400px; height: 299px;" src="http://2.bp.blogspot.com/_XQt1Vabxo5g/TUIEoo5joLI/AAAAAAAAANU/690sWUZGm-g/s400/photo%2B%25282%2529.JPG" border="0" alt=""id="BLOGGER_PHOTO_ID_5567017185603461298" /&gt;&lt;/a&gt;&lt;/p&gt;&lt;p&gt;Using a TrackPad comfortably:&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_XQt1Vabxo5g/TUIFV3vMtrI/AAAAAAAAANc/T1BJLCKqZ34/s1600/photo%2B%25283%2529.JPG"&gt;&lt;img style="cursor:pointer; cursor:hand;width: 400px; height: 299px;" src="http://4.bp.blogspot.com/_XQt1Vabxo5g/TUIFV3vMtrI/AAAAAAAAANc/T1BJLCKqZ34/s400/photo%2B%25283%2529.JPG" border="0" alt=""id="BLOGGER_PHOTO_ID_5567017962680661682" /&gt;&lt;/a&gt;&lt;/p&gt;&lt;p&gt;Diagraming and writing on a whiteboard quickly enough to effectively relay ideas to my coworkers:&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_XQt1Vabxo5g/TUIFyo7e6ZI/AAAAAAAAANk/brreRcwVzec/s1600/photo%2B%25284%2529.JPG"&gt;&lt;img style="cursor:pointer; cursor:hand;width: 400px; height: 299px;" src="http://1.bp.blogspot.com/_XQt1Vabxo5g/TUIFyo7e6ZI/AAAAAAAAANk/brreRcwVzec/s400/photo%2B%25284%2529.JPG" border="0" alt=""id="BLOGGER_PHOTO_ID_5567018456921860498" /&gt;&lt;/a&gt;&lt;/p&gt;&lt;p&gt;Drumming with one hand:&lt;br /&gt;&lt;iframe title="YouTube video player" class="youtube-player" type="text/html" width="640" height="390" src="http://www.youtube.com/embed/V51qvbJRNtc" frameborder="0" allowFullScreen&gt;&lt;/iframe&gt;&lt;/p&gt;I am very grateful to &lt;a href="http://obtiva.com/"&gt;Obtiva&lt;/a&gt; for instilling the Continuous Learning culture attitude in us, and would like to encourage everyone else to have that spirit instead of letting negativity pose as "being realistic" whenever you are learning something new, especially under difficult circumstances.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/32881756-5700631478404398230?l=andymaleh.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://andymaleh.blogspot.com/feeds/5700631478404398230/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=32881756&amp;postID=5700631478404398230' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/32881756/posts/default/5700631478404398230'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/32881756/posts/default/5700631478404398230'/><link rel='alternate' type='text/html' href='http://andymaleh.blogspot.com/2011/01/on-continuous-learning.html' title='On Continuous Learning'/><author><name>Annas "Andy" Maleh</name><uri>http://www.blogger.com/profile/10268484073612495328</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/-f6UYG8WIYJI/Tpw6vYi2nTI/AAAAAAAAAPk/ICI9GDbAxh4/s1600/7312067a2015194b853856820711a178%253Fsize%253D200'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/_XQt1Vabxo5g/TUIEoo5joLI/AAAAAAAAANU/690sWUZGm-g/s72-c/photo%2B%25282%2529.JPG' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-32881756.post-4968059647735151716</id><published>2011-01-27T15:10:00.008-06:00</published><updated>2011-01-27T15:51:11.129-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Ruby'/><category scheme='http://www.blogger.com/atom/ns#' term='Rails'/><title type='text'>Rails Dragonfly Image Upload With S3 and Test Faking with Fakeweb</title><content type='html'>&lt;p&gt;A while ago, I wrote a post titled &lt;a href="http://andymaleh.blogspot.com/2010/11/faking-paperclip-s3-calls-with-fakeweb.html"&gt;"Faking Paperclip S3 calls with Fakeweb"&lt;/a&gt;. Since then, while working with the Rails CMS &lt;a href="http://refinerycms.com/"&gt;Refinery&lt;/a&gt;, I discovered the delights of using the simpler Rack integrated &lt;a href="https://github.com/markevans/dragonfly"&gt;Dragonfly&lt;/a&gt; library for easy upload/processing of images in a Rails web application.&lt;br /&gt;&lt;br /&gt;Here is a guide on how to set Dragonfly up to work with S3, and how to fake its Cucumber integration test calls with Fakeweb.&lt;br /&gt;&lt;br /&gt;Assuming you already have Dragonfly configured for use by their &lt;a href="https://github.com/markevans/dragonfly"&gt;GitHub Instructions&lt;/a&gt;, edit the Dragonfly initializer and add the following line:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;app.configure_with(:heroku, ENV['S3_BUCKET'])&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Note that it is a bit quirky that we are referencing heroku here, but all what that Dragonfly config file does is configure S3 storage to read environment variables. There are other more verbose ways of doing this that are also easy, but using that one line is easiest. In the future, it is worth contributing a config file to Dragonfly that has a better name than heroku for configuring S3.&lt;br /&gt;&lt;br /&gt;Next, edit your Rails 3 application.rb file and add the following above your application module:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;ENV['S3_BUCKET'] = "APPLICATION_BUCKET_NAME_#{Rails.env}"&lt;br /&gt;ENV['S3_KEY'] = "S3_KEY"&lt;br /&gt;ENV['S3_SECRET'] = "S3_SECRET"&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Assuming you are using Bundler, edit Gemfile and add the following:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;gem 'rack-cache', '1.0.0', :require =&gt; 'rack/cache'&lt;br /&gt;gem 'dragonfly', '0.8.1'&lt;br /&gt;&lt;br /&gt;group :test do&lt;br /&gt;  gem 'fakeweb'&lt;br /&gt;  # other test gems go here&lt;br /&gt;end&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Now, add the following step to your general steps file:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;When /^(?:|I )attach the image "([^\"]*)" to "([^\"]*)"$/ do |file_path, field|&lt;br /&gt;  base_path = "http://s3.amazonaws.com/"&lt;br /&gt;&lt;br /&gt;  path = "^#{base_path}#{ENV['S3_BUCKET']}/([^/.]+/)*#{File.basename(file_path)}$"&lt;br /&gt;  FakeWeb.register_uri(:put, Regexp.new(path), :body =&gt; "OK")&lt;br /&gt;&lt;br /&gt;  body =&lt;&lt;-endstring&lt;br /&gt;  &amp;lt;?xml version=\"1.0\" encoding=\"UTF-8\"?&amp;gt;\n&amp;lt;ListAllMyBucketsResult xmlns=\"http://s3.amazonaws.com/doc/2006-03-01/\"&amp;gt;&amp;lt;Owner&amp;gt;&amp;lt;ID&amp;gt;cc51eabc6701f10ce998d1c4acce7e3b1dc5510ac392a24257c59922514c7baf&amp;lt;/ID&amp;gt;&amp;lt;DisplayName&amp;gt;S3_USER_NAME&amp;lt;/DisplayName&amp;gt;&amp;lt;/Owner&amp;gt;&amp;lt;Buckets&amp;gt;&amp;lt;Bucket&amp;gt;&amp;lt;Name&amp;gt;APPLICATION_BUCKET_NAME_test&amp;lt;/Name&amp;gt;&amp;lt;CreationDate&amp;gt;2011-01-20T21:42:56.000Z&amp;lt;/CreationDate&amp;gt;&amp;lt;/Bucket&amp;gt;&amp;lt;/Buckets&amp;gt;&amp;lt;/ListAllMyBucketsResult&amp;gt;&lt;br /&gt;  endstring&lt;br /&gt;  FakeWeb.register_uri(:get, base_path, :body =&gt; body)&lt;br /&gt;&lt;br /&gt;  When "I attach the file \"#{file_path}\" to \"#{field}\""&lt;br /&gt;end&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;The XML above provides Dragonfly with info about existing buckets in S3. This will ensure Dragonfly does not attempt to create the application bucket via a remote call. Make sure to replace APPLICATION_BUCKET_NAME_test with the right name for your test environment.&lt;br /&gt;&lt;br /&gt;Finally, use that step in your Cucumber feature files:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;    When I attach the image "features/support/sample_image.jpg" to "Logo"&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;That is assuming of course that you have a file called sample_image.jpg nested under your Cucumber support directory.&lt;br /&gt;&lt;br /&gt;Enjoy reaping the benefits of S3 usage with Dragonfly and test-driving it with Cucumber. &lt;br /&gt;&lt;br /&gt;p.s. Let me know in comments if I missed a detail or if you have any questions.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/32881756-4968059647735151716?l=andymaleh.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://andymaleh.blogspot.com/feeds/4968059647735151716/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=32881756&amp;postID=4968059647735151716' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/32881756/posts/default/4968059647735151716'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/32881756/posts/default/4968059647735151716'/><link rel='alternate' type='text/html' href='http://andymaleh.blogspot.com/2011/01/rails-dragonfly-image-upload-with-s3.html' title='Rails Dragonfly Image Upload With S3 and Test Faking with Fakeweb'/><author><name>Annas "Andy" Maleh</name><uri>http://www.blogger.com/profile/10268484073612495328</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/-f6UYG8WIYJI/Tpw6vYi2nTI/AAAAAAAAAPk/ICI9GDbAxh4/s1600/7312067a2015194b853856820711a178%253Fsize%253D200'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-32881756.post-8062973369135990935</id><published>2011-01-07T11:20:00.010-06:00</published><updated>2011-01-07T14:11:16.017-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Object Oriented Programming'/><category scheme='http://www.blogger.com/atom/ns#' term='Craftsmanship'/><title type='text'>How I Learned To Apply Design Patterns</title><content type='html'>&lt;p&gt;Video has been posted for my &lt;a href="http://www.obtiva.com/"&gt;Obtiva&lt;/a&gt; Lunch GeekFest talk this week:&lt;/p&gt;&lt;br /&gt;&lt;iframe src="http://player.vimeo.com/video/18446575" width="400" height="225" frameborder="0"&gt;&lt;/iframe&gt;&lt;p&gt;&lt;a href="http://vimeo.com/18446575"&gt;How I Learned to Apply Design Patterns Obtiva Geekfest&lt;/a&gt; from &lt;a href="http://vimeo.com/obtiva"&gt;Obtiva&lt;/a&gt; on &lt;a href="http://vimeo.com/"&gt;Vimeo&lt;/a&gt;.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;Here are the slides (with style change and some revisions): &lt;a href="http://www.slideshare.net/AndyMaleh/how-i-learned-to-apply-design-patterns" title="How I Learned To Apply Design Patterns"&gt;How I Learned To Apply Design Patterns&lt;/a&gt;&lt;/p&gt;&lt;br /&gt;&lt;p&gt;I would like to emphasize a few points that came up during the presentation from the audience:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="http://www.coreyhaines.com/"&gt;Corey Haines&lt;/a&gt; brought up the point that you can benefit from thinking about Design Patterns even if you do no implement them to the tee per the Gang of Four implementation (e.g. double dispatch for Visitor). &lt;/li&gt;&lt;li&gt;&lt;a href="http://squaremasher.blogspot.com/"&gt;Tyler Jennings&lt;/a&gt; brought up the point that you may sometimes need to split model responsibilities into a separate model responsible for performing the work, such as an OrderTransfer object for an Order. It becomes responsible for transaction-ability around product transfer between two orders.&lt;/li&gt;&lt;li&gt;&lt;a href="http://www.coreyhaines.com/"&gt;Corey Haines&lt;/a&gt; mentioned that not all developers tend to think of which Objects to assign responsibilities to up-front.   &lt;/li&gt;&lt;/ul&gt;&lt;p&gt;One thing that got left out of the presentation is explaining how to choose variations of a design pattern, such as State vs Strategy or Abstract Factory vs Factory Method depending on the situation. That leaves me room for a future blog post/presentation. :)&lt;/p&gt;&lt;p&gt;In the meantime, comments and questions are greatly encouraged.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/32881756-8062973369135990935?l=andymaleh.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://andymaleh.blogspot.com/feeds/8062973369135990935/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=32881756&amp;postID=8062973369135990935' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/32881756/posts/default/8062973369135990935'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/32881756/posts/default/8062973369135990935'/><link rel='alternate' type='text/html' href='http://andymaleh.blogspot.com/2011/01/how-i-learned-to-apply-design-patterns.html' title='How I Learned To Apply Design Patterns'/><author><name>Annas "Andy" Maleh</name><uri>http://www.blogger.com/profile/10268484073612495328</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/-f6UYG8WIYJI/Tpw6vYi2nTI/AAAAAAAAAPk/ICI9GDbAxh4/s1600/7312067a2015194b853856820711a178%253Fsize%253D200'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-32881756.post-1991799001799327583</id><published>2011-01-01T12:00:00.007-06:00</published><updated>2011-01-07T14:08:04.744-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Craftsmanship'/><title type='text'>Why Blog?</title><content type='html'>With the new year, it is good to re-evaluate certain habits to see if they still offer value, and one habit a I would like to re-evaluate here is why I blog:&lt;br /&gt;- Organize my thoughts and opinions&lt;br /&gt;- Solidify my knowledge&lt;br /&gt;- Bookmark my learning (virtual breadcrumb)&lt;br /&gt;- Validate my ideas&lt;br /&gt;- Provide others with valuable lessons&lt;br /&gt;- Connect with the community&lt;br /&gt;&lt;br /&gt;A lot of developers are intimidated by the idea of blogging due to different reasons, such as:&lt;br /&gt;- Do not have enough value to contribute&lt;br /&gt;- Cannot write well enough to impress (I am not Bob Martin or David Heinemeier Hansson)&lt;br /&gt;- Very time consuming&lt;br /&gt;&lt;br /&gt;Actually though, everybody brings a different perspective and in a way, it is selfish to hold back on sharing your experience when others could have benefited from the lessons you learned.&lt;br /&gt;&lt;br /&gt;About writing well, it is a learn-able skill, and in the Internet age where expressions like BTW and IMHO are common, it really does not matter as long as you get the idea across.&lt;br /&gt;&lt;br /&gt;Finally, regarding time spent, you can always limit the size of your blog posts or break longer blog posts into &lt;a href="http://andymaleh.blogspot.com/2007/10/restful-vs-soap-web-services-part-1.html"&gt;multiple parts&lt;/a&gt;, which as a side effect builds up more anticipation for your blog posts.&lt;br /&gt;&lt;br /&gt;I did not start blogging by writing an amazing article on software architecture or anything like that. I simply mentioned a good science fiction read, and here is my first blog post to prove it: &lt;a href="http://andymaleh.blogspot.com/2006/11/plunge-into-blogging-world.html"&gt;http://andymaleh.blogspot.com/2006/11/plunge-into-blogging-world.html&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Now if you have never blogged before, go write your first blog post now! It only takes 15 minutes or less and puts on you on a great path for sharing, organizing, and expanding your knowledge.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/32881756-1991799001799327583?l=andymaleh.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://andymaleh.blogspot.com/feeds/1991799001799327583/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=32881756&amp;postID=1991799001799327583' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/32881756/posts/default/1991799001799327583'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/32881756/posts/default/1991799001799327583'/><link rel='alternate' type='text/html' href='http://andymaleh.blogspot.com/2011/01/why-blog.html' title='Why Blog?'/><author><name>Annas "Andy" Maleh</name><uri>http://www.blogger.com/profile/10268484073612495328</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/-f6UYG8WIYJI/Tpw6vYi2nTI/AAAAAAAAAPk/ICI9GDbAxh4/s1600/7312067a2015194b853856820711a178%253Fsize%253D200'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-32881756.post-1969916405811116476</id><published>2010-12-19T18:58:00.009-06:00</published><updated>2010-12-20T09:42:38.360-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Miscellaneous'/><title type='text'>What makes a developer valuable to Obtiva?</title><content type='html'>I was recently asked by someone what makes a developer valuable to &lt;a href="http://obtiva.com"&gt;Obtiva&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;Here is the answer I gave:&lt;ol&gt;&lt;li&gt;The developer genuinely cares about the client needs: If the developer does not care about delivering something that serves the client needs, then no amount of work would help achieve success.&lt;/li&gt;&lt;li&gt;The developer strives as much as possible for effective communication with the client: After all, if the developer cannot communicate well with the client to understand their needs, then no amount of technical skill will help them deliver what the client needs.&lt;/li&gt;&lt;li&gt;The developer is always eager to learn something new: As long as the developer is motivated to learn, he will be able to overcome any shortcomings in his current technical skills.&lt;/li&gt;&lt;li&gt;The developer is willing to collaborate with others: A developer who does not play well with others will hamper the project velocity and productivity regardless of how superior his skills are compared to others'.&lt;/li&gt;&lt;/ol&gt;Notice how none of the points above mention anything about skills in programming languages, software processes, or frameworks and libraries. After all, experience has taught me that soft skills trump hard technical skills at getting to success.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/32881756-1969916405811116476?l=andymaleh.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://andymaleh.blogspot.com/feeds/1969916405811116476/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=32881756&amp;postID=1969916405811116476' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/32881756/posts/default/1969916405811116476'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/32881756/posts/default/1969916405811116476'/><link rel='alternate' type='text/html' href='http://andymaleh.blogspot.com/2010/12/what-makes-developer-valuable-to-obtiva.html' title='What makes a developer valuable to Obtiva?'/><author><name>Annas "Andy" Maleh</name><uri>http://www.blogger.com/profile/10268484073612495328</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/-f6UYG8WIYJI/Tpw6vYi2nTI/AAAAAAAAAPk/ICI9GDbAxh4/s1600/7312067a2015194b853856820711a178%253Fsize%253D200'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-32881756.post-2772372901227909137</id><published>2010-12-04T19:52:00.019-06:00</published><updated>2010-12-19T18:57:34.211-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Craftsmanship'/><title type='text'>To Reuse or To Rewrite?</title><content type='html'>It is amazing how many developers like to rewrite functionality from scratch instead of reusing a library when most common problems such as validating a zip code or parsing currency have been solved already countless of times. &lt;br /&gt;&lt;br /&gt;In a recent Ruby on Rails application I have been working on, I wanted to parse phone numbers in different formats, and figured why waste time re-inventing the wheel when I could use a library? I know it is easy to implement the parsing logic. I wrote such code in Java in the past. But, experience has taught me that thinking it is easy to rewrite when it is solved already is a &lt;a href="http://37signals.com/svn/posts/439-four-letter-words"&gt;trap&lt;/a&gt;. After all, so many hidden edge cases often lie in a seemingly simple problem that only reveal themselves after a long period of usage and testing. That makes it more than worthwhile to rely on a library than write things from scratch no matter how simplistic. Unfortunately, in the past, I did not have the foresight for it, and whenever I wrote things from scratch, I thought I delivered business value, and did not notice the cost sunk into fixing bugs for all the discovered edge cases over the course of using the application.&lt;br /&gt;&lt;br /&gt;I used to like rewriting code from scratch for problems already solved with libraries for several reasons:&lt;br /&gt;1- Seemed easy&lt;br /&gt;2- Gave a satisfying feeling of accomplishment at the end&lt;br /&gt;3- Seemed like more fun than learning the API of a library&lt;br /&gt;4- Prevented me from feeling dumb while attempting to learn a library&lt;br /&gt;5- Kept the code base simple&lt;br /&gt;&lt;br /&gt;What seemed easy often ended up having so many edge cases that it became a much more complex task than anticipated, especially when some edge cases were discovered by users in embarrassing bug reports. Now of course, libraries may still have undiscovered edge cases themselves, but taking probability into account (instead of thinking black and white), it is a lower chance to find a bug in a well-used library than code I just wrote.&lt;br /&gt;&lt;br /&gt;Regarding the feeling of accomplishment, it was a misleading reason as it could also be obtained from solving the main business problems instead of writing code for already solved lower level problems. &lt;br /&gt;&lt;br /&gt;About the fun aspect, while it is important to do something that I enjoy in order to stay motivated, it is also important that what I find fun is most useful to clients or else somebody else more focused on the client needs will do my work faster by reusing a library, rendering me a less valuable developer who selfishly spends time on rewriting code for the fun of it.&lt;br /&gt;&lt;br /&gt;One of my biggest fears in reusing a library was feeling dumb or overwhelmed by sheer complexity while learning it. Now, rationally speaking, if the highest goal is serving the client in the best way possible, then if it meant feeling dumb for a little while in order to implement a higher quality solution with a proven library instead of coding stuff from scratch, then so be it. Not being concerned with feeling dumb for the sake of serving a client shows both self security and humbleness. The opposite is simply selfish, insecure, and ineffective for the client. Still, if I can think of a simpler way of writing the library API, then it would be a good idea to write a facade on top of it or contribute the simpler API to the library directly.&lt;br /&gt;&lt;br /&gt;Finally as for keeping the code base simple, this really depends on the library being used. There are cases where writing code from scratch is more efficient than using an incredibly complex library. However, I have often generalized from one bad experience with some badly designed over-complicated library, avoiding libraries for a while and losing out on the benefits of many other better and simpler libraries for other problems. &lt;br /&gt;&lt;br /&gt;The way I think of it now is if a certain library that I am exploring seems to require me to write more complicated code than if I had written code from scratch, then I should be careful in considering the library a time waster as it may still save me time by handling edge cases I have not considered. Many times, when I wrote something from scratch for a solved problem that seemed simple, I ran into so many edge cases eventually that any productivity gained from not spending time on learning a library was offset completely with the problems encountered. And, as I stated before, I used to not notice that and think I was being productive without reusing a library, but experience taught me otherwise. My opinion now is a bit more strongly for reuse than &lt;a href="http://andymaleh.blogspot.com/2008/12/nih-syndrome-or-blowing-reuse-out-of.html"&gt;it was&lt;/a&gt; a couple of years ago.&lt;br /&gt;&lt;br /&gt;The only time I would solve a problem from scratch now is if no library out there solves it according to the quality standards required for my client. That is when it is a good opportunity to write my own library and open source it to let the community help test it and reveal edge cases quickly. &lt;br /&gt;&lt;br /&gt;Luckily, I found a library that parses phone numbers in Ruby called &lt;a href="https://github.com/midas/phone_number"&gt;phone_number&lt;/a&gt;. :)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/32881756-2772372901227909137?l=andymaleh.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://andymaleh.blogspot.com/feeds/2772372901227909137/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=32881756&amp;postID=2772372901227909137' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/32881756/posts/default/2772372901227909137'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/32881756/posts/default/2772372901227909137'/><link rel='alternate' type='text/html' href='http://andymaleh.blogspot.com/2010/12/to-reuse-or-to-rewrite.html' title='To Reuse or To Rewrite?'/><author><name>Annas "Andy" Maleh</name><uri>http://www.blogger.com/profile/10268484073612495328</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/-f6UYG8WIYJI/Tpw6vYi2nTI/AAAAAAAAAPk/ICI9GDbAxh4/s1600/7312067a2015194b853856820711a178%253Fsize%253D200'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-32881756.post-8329544490399257707</id><published>2010-11-24T09:38:00.013-06:00</published><updated>2010-11-24T13:32:39.092-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Craftsmanship'/><title type='text'>Can Business People Read Your Code?</title><content type='html'>Yesterday, I wrote a &lt;a href="http://andymaleh.blogspot.com/2010/11/generating-tests.html"&gt;blog post&lt;/a&gt; on how I refactored tests in Ruby to follow the "Data Generated Specs" pattern, making it easy to add specs and read the input and expected output values for the different cases.&lt;br /&gt;&lt;br /&gt;The surprising effect for that is being able to review the test cases with a non-technical client, and then the client liking the format so much and requesting a copy of the specs.&lt;br /&gt;&lt;br /&gt;I had another similar incident last week that also pleasantly surprised me.&lt;br /&gt;&lt;br /&gt;At one point, the client asked me about a detail in the business calculation to verify that I am handling it correctly, and I indicated that I followed the math formula she gave me. Then, to confirm, I had the client come over and look at my implementation in Ruby (changed a bit for IP protection):&lt;br /&gt;&lt;br /&gt;copay = benefit.includes_deductible? ? (value - deductible) : value&lt;br /&gt;12*rate + deductible + copay&lt;br /&gt;&lt;br /&gt;I made sure to explain the turnery operator while going over the implementation, and the client seemed to get it then cheerfully exclaim: "Great! Looks like you got it exactly the way I wrote it."&lt;br /&gt;&lt;br /&gt;I was very happy to hear that, and I wondered if this only became possible because I followed good clean code software development techniques such as TDD and refactoring. I mean, had I not refactored my code to extract the essence of the calculation in one tiny method with less than 5 lines of code, I would have probably confused the client by showing her too much code. &lt;br /&gt;&lt;br /&gt;How cleanly is your code written on average? Can business people read your code?&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/32881756-8329544490399257707?l=andymaleh.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://andymaleh.blogspot.com/feeds/8329544490399257707/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=32881756&amp;postID=8329544490399257707' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/32881756/posts/default/8329544490399257707'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/32881756/posts/default/8329544490399257707'/><link rel='alternate' type='text/html' href='http://andymaleh.blogspot.com/2010/11/can-business-people-read-your-code.html' title='Can Business People Read Your Code?'/><author><name>Annas "Andy" Maleh</name><uri>http://www.blogger.com/profile/10268484073612495328</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/-f6UYG8WIYJI/Tpw6vYi2nTI/AAAAAAAAAPk/ICI9GDbAxh4/s1600/7312067a2015194b853856820711a178%253Fsize%253D200'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-32881756.post-2224834939227889050</id><published>2010-11-23T15:01:00.015-06:00</published><updated>2010-11-23T17:24:20.810-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Ruby'/><category scheme='http://www.blogger.com/atom/ns#' term='Craftsmanship'/><title type='text'>Testing Pattern: Data Generated Specs</title><content type='html'>Just thought of sharing this DRY Ruby testing pattern that facilitates generating a lot of similar specs with different data.&lt;br /&gt;&lt;br /&gt;Recently, I wrote specs for a parsing engine that handled each test case with a context describing how the different attribute on a model (Benefit) would be evaluated:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt; context "Single: $10,000 Group: $20,000" do&lt;br /&gt;   describe "single_value" do&lt;br /&gt;     it "returns 10000 for Single: $10,000 Group: $20,000" do&lt;br /&gt;       benefit = Benefit.new(:value =&gt; "Single: $10,000 Group: $20,000")&lt;br /&gt;       benefit.single_value.should == 10000&lt;br /&gt;     end&lt;br /&gt;   end&lt;br /&gt;   describe "group_value" do&lt;br /&gt;     it "returns 10000 for Single: $10,000 Group: $20,000" do&lt;br /&gt;       benefit = Benefit.new(:value =&gt; "Single: $10,000 Group: $20,000")&lt;br /&gt;       benefit.group_value.should == 20000&lt;br /&gt;     end&lt;br /&gt;   end&lt;br /&gt;   describe "single_value_includes_deductible?" do&lt;br /&gt;     it "returns 10000 for Single: $10,000 Group: $20,000" do&lt;br /&gt;       benefit = Benefit.new(:value =&gt; "Single: $10,000 Group: $20,000")&lt;br /&gt;       benefit.single_value_includes_deductible?.should be_true&lt;br /&gt;     end&lt;br /&gt;   end&lt;br /&gt;   describe "group_value_includes_deductible?" do&lt;br /&gt;     it "returns 10000 for Single: $10,000 Group: $20,000" do&lt;br /&gt;       benefit = Benefit.new(:value =&gt; "Single: $10,000 Group: $20,000")&lt;br /&gt;       benefit.group_value_includes_deductible?.should be_true&lt;br /&gt;     end&lt;br /&gt;   end&lt;br /&gt;   describe "group_calculation_algorithm" do&lt;br /&gt;     it "returns 10000 for Single: $10,000 Group: $20,000" do&lt;br /&gt;       benefit = Benefit.new(:value =&gt; "Single: $10,000 Group: $20,000")&lt;br /&gt;       benefit.group_calculation_algorithm.should == :cap&lt;br /&gt;     end&lt;br /&gt;   end&lt;br /&gt; end&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;But, I kept getting more and more business rules for parsing the benefit string values, and I had to add a context block like the one above for every case, so you can imagine how this got out of control very fast and had a ridiculous amount of redundancy:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt; context "$10,000" do&lt;br /&gt;   describe "single_value" do&lt;br /&gt;     it "returns 10000 for $10,000" do&lt;br /&gt;       benefit = Benefit.new(:value =&gt; "Single: $10,000")&lt;br /&gt;       benefit.single_value.should == 10000&lt;br /&gt;     end&lt;br /&gt;   end&lt;br /&gt;   describe "group_value" do&lt;br /&gt;     it "returns 10000 for $10,000" do&lt;br /&gt;       benefit = Benefit.new(:value =&gt; "Single: $10,000")&lt;br /&gt;       benefit.group_value.should == 10000&lt;br /&gt;     end&lt;br /&gt;   end&lt;br /&gt;   describe "single_value_includes_deductible?" do&lt;br /&gt;     it "returns 10000 for $10,000" do&lt;br /&gt;       benefit = Benefit.new(:value =&gt; "$10,000")&lt;br /&gt;       benefit.single_value_includes_deductible?.should be_true&lt;br /&gt;     end&lt;br /&gt;   end&lt;br /&gt;   describe "group_value_includes_deductible?" do&lt;br /&gt;     it "returns 10000 for $10,000" do&lt;br /&gt;       benefit = Benefit.new(:value =&gt; "$10,000")&lt;br /&gt;       benefit.group_value_includes_deductible?.should be_true&lt;br /&gt;     end&lt;br /&gt;   end&lt;br /&gt;   describe "group_calculation_algorithm" do&lt;br /&gt;     it "returns 10000 for $10,000" do&lt;br /&gt;       benefit = Benefit.new(:value =&gt; "$10,000")&lt;br /&gt;       benefit.group_calculation_algorithm.should == :as_is&lt;br /&gt;     end&lt;br /&gt;   end&lt;br /&gt; end&lt;br /&gt;&lt;br /&gt; context "Single: $10,000 per Member" do&lt;br /&gt;   describe "single_value" do&lt;br /&gt;     it "returns 10000 for Single: $10,000 per Member" do&lt;br /&gt;       benefit = Benefit.new(:value =&gt; "Single: $10,000 per Member")&lt;br /&gt;       benefit.single_value.should == 10000&lt;br /&gt;     end&lt;br /&gt;   end&lt;br /&gt;   describe "group_value" do&lt;br /&gt;     it "returns 10000 for Single: $10,000 per Member" do&lt;br /&gt;       benefit = Benefit.new(:value =&gt; "Single: $10,000 per Member")&lt;br /&gt;       benefit.group_value.should == nil&lt;br /&gt;     end&lt;br /&gt;   end&lt;br /&gt;   describe "single_value_includes_deductible?" do&lt;br /&gt;     it "returns 10000 for Single: $10,000 per Member" do&lt;br /&gt;       benefit = Benefit.new(:value =&gt; "Single: $10,000 per Member")&lt;br /&gt;       benefit.single_value_includes_deductible?.should be_true&lt;br /&gt;     end&lt;br /&gt;   end&lt;br /&gt;   describe "group_value_includes_deductible?" do&lt;br /&gt;     it "returns 10000 for Single: $10,000 per Member" do&lt;br /&gt;       benefit = Benefit.new(:value =&gt; "Single: $10,000 per Member")&lt;br /&gt;       benefit.group_value_includes_deductible?.should be_true&lt;br /&gt;     end&lt;br /&gt;   end&lt;br /&gt;   describe "group_calculation_algorithm" do&lt;br /&gt;     it "returns 10000 for Single: $10,000 per Member" do&lt;br /&gt;       benefit = Benefit.new(:value =&gt; "Single: $10,000 per Member")&lt;br /&gt;       benefit.group_calculation_algorithm.should == :per_person&lt;br /&gt;     end&lt;br /&gt;   end&lt;br /&gt; end&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Finally, I refactored the specs applying what I am calling the "Data Generated Specs" pattern, by writing only one spec as a prototype and feeding in the input and expected output data dynamically through a hash:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;  {&lt;br /&gt;    "Single: $10,000 Group: $20,000" =&gt; {&lt;br /&gt;      "single_value" =&gt; 10000,&lt;br /&gt;      "group_value" =&gt; 20000,&lt;br /&gt;      "single_value_includes_deductible?" =&gt; true,&lt;br /&gt;      "group_value_includes_deductible?" =&gt; true,&lt;br /&gt;      "group_calculation_algorithm" =&gt; :cap,&lt;br /&gt;    },&lt;br /&gt;  }.each do |input_value, expected_value|&lt;br /&gt;    expected_value.keys.each do |attribute|&lt;br /&gt;      describe attribute do&lt;br /&gt;        it "returns #{expected_value[attribute]} for #{input_value}" do&lt;br /&gt;          benefit = Benefit.new(:value =&gt; input_value)&lt;br /&gt;          benefit.send(attribute).should == expected_value[attribute]&lt;br /&gt;        end&lt;br /&gt;      end&lt;br /&gt;    end&lt;br /&gt;  end&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Each test case became represented with a hash key/value block instead of a 30-line code context block, making it much easier to add test cases:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;  {&lt;br /&gt;    "Single: $10,000 Group: $20,000" =&gt; {&lt;br /&gt;      "single_value" =&gt; 10000,&lt;br /&gt;      "group_value" =&gt; 20000,&lt;br /&gt;      "single_value_includes_deductible?" =&gt; true,&lt;br /&gt;      "group_value_includes_deductible?" =&gt; true,&lt;br /&gt;      "group_calculation_algorithm" =&gt; :cap,&lt;br /&gt;    },&lt;br /&gt;    "$10,500" =&gt; {&lt;br /&gt;      "single_value" =&gt; 10500,&lt;br /&gt;      "group_value" =&gt; 10500,&lt;br /&gt;      "single_value_includes_deductible?" =&gt; true,&lt;br /&gt;      "group_value_includes_deductible?" =&gt; true,&lt;br /&gt;      "group_calculation_algorithm" =&gt; :as_is,&lt;br /&gt;    },&lt;br /&gt;    "Single: $10,500 per Member" =&gt; {&lt;br /&gt;      "single_value" =&gt; 10500,&lt;br /&gt;      "group_value" =&gt; nil,&lt;br /&gt;      "single_value_includes_deductible?" =&gt; true,&lt;br /&gt;      "group_value_includes_deductible?" =&gt; true,&lt;br /&gt;      "group_calculation_algorithm" =&gt; :per_person,&lt;br /&gt;    },&lt;br /&gt;    "Single: $10,500 per Member (Deductible not included)" =&gt; {&lt;br /&gt;      "single_value" =&gt; 10500,&lt;br /&gt;      "group_value" =&gt; nil,&lt;br /&gt;      "single_value_includes_deductible?" =&gt; false,&lt;br /&gt;      "group_value_includes_deductible?" =&gt; false,&lt;br /&gt;      "group_calculation_algorithm" =&gt; :per_person,&lt;br /&gt;    },&lt;br /&gt;    "See brochure for details" =&gt; {&lt;br /&gt;      "single_value" =&gt; nil,&lt;br /&gt;      "group_value" =&gt; nil,&lt;br /&gt;      "single_value_includes_deductible?" =&gt; false,&lt;br /&gt;      "group_value_includes_deductible?" =&gt; false,&lt;br /&gt;      "group_calculation_algorithm" =&gt; nil,&lt;br /&gt;    },&lt;br /&gt;  }.each do |input_value, expected_value|&lt;br /&gt;    expected_value.keys.each do |attribute|&lt;br /&gt;      describe attribute do&lt;br /&gt;        it "returns #{expected_value[attribute]} for #{input_value}" do&lt;br /&gt;          benefit = Benefit.new(:value =&gt; input_value)&lt;br /&gt;          benefit.send(attribute).should == expected_value[attribute]&lt;br /&gt;        end&lt;br /&gt;      end&lt;br /&gt;    end&lt;br /&gt;  end&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Since specs are generated with their titles, when they fail, you get a nice clear description for the failure that includes the attribute name as well as the input and output values:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;1) Benefit attribute single_value returns 0 for Single: $10,500 per Member&lt;br /&gt;  Failure/Error: benefit.send(attribute).should == expected_value[attribute]&lt;br /&gt;  expected: 10500,&lt;br /&gt;       got: 0 (using ==)&lt;br /&gt;  # ./spec/models/benefit_spec.rb:464&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;I generated about 1000+ tests with this technique. While reviewing some of the cases with a non-technical client, she liked reading the spec data so much that she requested a copy for herself to review and validate against the business rules. Specs as acceptance tests FTW!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/32881756-2224834939227889050?l=andymaleh.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://andymaleh.blogspot.com/feeds/2224834939227889050/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=32881756&amp;postID=2224834939227889050' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/32881756/posts/default/2224834939227889050'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/32881756/posts/default/2224834939227889050'/><link rel='alternate' type='text/html' href='http://andymaleh.blogspot.com/2010/11/generating-tests.html' title='Testing Pattern: Data Generated Specs'/><author><name>Annas "Andy" Maleh</name><uri>http://www.blogger.com/profile/10268484073612495328</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/-f6UYG8WIYJI/Tpw6vYi2nTI/AAAAAAAAAPk/ICI9GDbAxh4/s1600/7312067a2015194b853856820711a178%253Fsize%253D200'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-32881756.post-7748615073302598856</id><published>2010-11-22T09:15:00.007-06:00</published><updated>2010-11-29T12:26:03.688-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Ruby'/><category scheme='http://www.blogger.com/atom/ns#' term='Glimmer'/><title type='text'>MagicRuby: Whatever Happened to Desktop Development in Ruby?</title><content type='html'>I will be giving a talk at the upcoming &lt;a href="http://magic-ruby.com/"&gt;MagicRuby&lt;/a&gt; conference, which begins on Feb 4, 2011.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Title: &lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Whatever Happened to Desktop Development in Ruby?&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Abstract:&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;While web development is thriving in the Ruby world with Rails, Sinatra, and other frameworks, desktop development is still not very common as a lot of developers rely on Java technologies like Eclipse or straight .NET technologies such as Windows Forms.&lt;br /&gt;&lt;br /&gt;This talk will walk attendees through some Ruby desktop development frameworks/libraries, contrasting the pros and cons of each, and mentioning what is missing that discourages developers from relying on Ruby to build desktop applications. &lt;br /&gt;&lt;br /&gt;Frameworks/libraries covered will include MacRuby, Shoes, Limelight, and Glimmer.&lt;br /&gt;&lt;br /&gt;Attendees will walk out of the session with rudimentary knowledge on desktop development in Ruby as well as an idea of what to expect in the future.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/32881756-7748615073302598856?l=andymaleh.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://andymaleh.blogspot.com/feeds/7748615073302598856/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=32881756&amp;postID=7748615073302598856' title='5 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/32881756/posts/default/7748615073302598856'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/32881756/posts/default/7748615073302598856'/><link rel='alternate' type='text/html' href='http://andymaleh.blogspot.com/2010/11/magicruby-whatever-happened-to-desktop.html' title='MagicRuby: Whatever Happened to Desktop Development in Ruby?'/><author><name>Annas "Andy" Maleh</name><uri>http://www.blogger.com/profile/10268484073612495328</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/-f6UYG8WIYJI/Tpw6vYi2nTI/AAAAAAAAAPk/ICI9GDbAxh4/s1600/7312067a2015194b853856820711a178%253Fsize%253D200'/></author><thr:total>5</thr:total></entry><entry><id>tag:blogger.com,1999:blog-32881756.post-7867156290954642630</id><published>2010-11-19T08:57:00.013-06:00</published><updated>2010-12-02T13:52:20.074-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Craftsmanship'/><title type='text'>Should You Work Hard or Smart?</title><content type='html'>About five years ago, a senior developer I met recounted to me stories about how he aced interviews:&lt;br /&gt;"I always like to tell interviewers that some people work hard, and some people work smart, but I like to work HARD AND SMART!"&lt;br /&gt;&lt;br /&gt;It was certainly a nice sounding line that had a good ring to it, but is there such a thing as working hard and smart? Or does working hard automatically imply that you're not working as smart as you could be? Wouldn't you be working less hard if you had smarter ways of accomplishing your tasks? &lt;br /&gt;&lt;br /&gt;You are welcome to share your opinion in comments, but here is my perspective on the matter.&lt;br /&gt;&lt;br /&gt;It certainly depends on the definition of what is "hard" and what is "smart". &lt;br /&gt;&lt;br /&gt;If "hard" meant working 50-hour+ weeks, then on average, people get tired after say 8 or 9 hours of continuous work on a day, and their thinking capacity diminishes as a result, resulting in less "smart" work than say at the beginning of the day. So, in that case, working "hard" affects people's ability to work "smart" and the two do not quite go hand in hand.&lt;br /&gt;&lt;br /&gt;If "hard" meant working 35-40-hour weeks with extreme concentration, taking the rest of the days off to let the brain detangle itself and get ready for the next day, then on average, this facilitates performing work that is as "smart" as possible per people's thinking capacities. So, in that case, "hard" and "smart" do go together though people who work 60-hour weeks would not consider that "hard" enough, so it ends up just being "smart", and who doesn't like that?i&lt;br /&gt;&lt;br /&gt;Now in the software development world, if some developers find themselves working 60-hour weeks to meet a 3-month deadline for a business project, then they certainly are working "hard", but are they working as "smart" as they could be, or should they be ditching this old unproductive framework/library they are relying on and move on to a smarter technology/programming language that offers more productivity? After all, not only will that save them from over-extending themselves, yet also allow their work to be higher quality since it will be done in the majority of hours when their thinking capacity is near its fullest on average.&lt;br /&gt;&lt;br /&gt;Doing 12+ hour days is not necessarily bad every once in a while, especially when the developer has a sudden burst of creativity and motivation. However, if done regularly, it is important to be aware of the quality of work coming out of the long hours as sometimes it may give the &lt;a href="http://andymaleh.blogspot.com/2008/12/illusion-of-delivery.html"&gt;illusion of accomplishment&lt;/a&gt; when the work is actually taking a lot longer to finish with a tired less concentrated mind, and could have been done better when rested.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/32881756-7867156290954642630?l=andymaleh.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://andymaleh.blogspot.com/feeds/7867156290954642630/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=32881756&amp;postID=7867156290954642630' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/32881756/posts/default/7867156290954642630'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/32881756/posts/default/7867156290954642630'/><link rel='alternate' type='text/html' href='http://andymaleh.blogspot.com/2010/11/should-you-work-hard-or-smart.html' title='Should You Work Hard or Smart?'/><author><name>Annas "Andy" Maleh</name><uri>http://www.blogger.com/profile/10268484073612495328</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/-f6UYG8WIYJI/Tpw6vYi2nTI/AAAAAAAAAPk/ICI9GDbAxh4/s1600/7312067a2015194b853856820711a178%253Fsize%253D200'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-32881756.post-193978061425707696</id><published>2010-11-17T07:29:00.009-06:00</published><updated>2010-11-29T14:40:12.769-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Craftsmanship'/><category scheme='http://www.blogger.com/atom/ns#' term='Agile Methodologies'/><title type='text'>Pain Driven Development</title><content type='html'>One of the key things I learned from XP and the Agile movement in general is programming for today's requirements not tomorrow's predictions. And, every time you start writing implementation for requirements that may become valid in the future, the Agile folks would shout "&lt;a href="http://www.extremeplanner.com/blog/2006/12/yagni-revisited-waste-not-want-not.html"&gt;YAGNI&lt;/a&gt;" (You Aren't Gonna Need It). Applied to code architecture and design, Ward Cunningham summarizes this philosophy nicely with his famous quote "What's the simplest thing that could possibly work?".&lt;br /&gt;&lt;br /&gt;But, what happens when today's implementation no longer fulfills today's requirements? In other words, what happens when tomorrow becomes today and requirements grow or change? One example is when 100,000 more users are added to the system, making performance requirements much greater. Another example is when supporting one state is not enough anymore, and the business is now expanding nationally to cover all 50 states.&lt;br /&gt;&lt;br /&gt;That is where awareness of pain comes into play. I wrote a blog post about sensitivity to pain a few years back that talks about &lt;a href="http://andymaleh.blogspot.com/2007/09/pain-and-pleasure.html"&gt;pain and pleasure&lt;/a&gt; when it comes to writing and maintaining code. Developing that awareness of pain is highly important in detecting when to update today's implementation with a higher level of complexity that addresses today's requirements.&lt;br /&gt;&lt;br /&gt;Though people have different levels of tolerance to pain, it is a gift that they can feel it as it is often what pushes them toward action. And, in the case of software development, it can point out when today's implementation no longer serves today's requirements and needs to be revised either with a higher level of complexity, or sometimes with a lower level when some requirements are no longer needed.&lt;br /&gt;&lt;br /&gt;When I first heard of the YAGNI principle, I remember shuddering a bit and thinking "Isn't it kind of dumb to write code that I will revise in the future when I have to support more states when I could have added in multiple-state support to begin with?"&lt;br /&gt;&lt;br /&gt;Well, unfortunately, my thinking was shallow in certain ways. While the argument is logical at one level since following flexible design practices seems to make it easier to handle some future needs, it is much less trivial if I dig a level deeper and include more variables such as whether these future needs ever materialize in the next 2 years, or how much stepping around I am doing while adding new features, mostly because of complexity in code implemented for predicted needs that are not yet valid. &lt;br /&gt;&lt;br /&gt;And experience only confirms the concerns I raised above and shows that keeping the code as simple as possible, only addressing today's known business needs, seems to make it easiest to maintain the code and add more features as more needs come up. That is because the code always remains as simple as possible, yet adjusted in complexity only as pain is felt day-to-day. &lt;br /&gt;&lt;br /&gt;One example of this that I recently encountered is writing a web feature that relied on data from a web service. At first, the simplest thing that could possibly work was to have it request data from the service synchronously as users hit the site. Later, as requests for data got more complex and time-consuming to fulfill from the service, the implementation became painful to deal with as far as performance, so background caching of service data was added.  That is a very good example of what I like to call "Pain Driven Development" :)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/32881756-193978061425707696?l=andymaleh.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://andymaleh.blogspot.com/feeds/193978061425707696/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=32881756&amp;postID=193978061425707696' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/32881756/posts/default/193978061425707696'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/32881756/posts/default/193978061425707696'/><link rel='alternate' type='text/html' href='http://andymaleh.blogspot.com/2010/11/pain-driven-development.html' title='Pain Driven Development'/><author><name>Annas "Andy" Maleh</name><uri>http://www.blogger.com/profile/10268484073612495328</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/-f6UYG8WIYJI/Tpw6vYi2nTI/AAAAAAAAAPk/ICI9GDbAxh4/s1600/7312067a2015194b853856820711a178%253Fsize%253D200'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-32881756.post-936575041986864371</id><published>2010-11-16T09:41:00.007-06:00</published><updated>2011-01-27T15:43:18.030-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Ruby'/><category scheme='http://www.blogger.com/atom/ns#' term='Rails'/><title type='text'>Faking Paperclip S3 calls with Fakeweb</title><content type='html'>I recently wrote Cucumber acceptance tests for a project feature that involved uploading images to Amazon S3 via the Ruby Paperclip library. At first, I had them actually hit S3 for real to drive the implementation correctly without any mocking. Over time though, the tests became really slow and fragile because of their dependency on the web service, so I used Fakeweb to fake the upload requests to S3.&lt;br /&gt;&lt;br /&gt;Here is the Cucumber step I wrote for that:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;When /^(?:|I )attach the image "([^\"]*)" to "([^\"]*)" on S3$/ do |file_path, field|&lt;br /&gt;  definition = Image.attachment_definitions[:attachment]&lt;br /&gt;  path = "http://s3.amazonaws.com/#{definition[:bucket]}/#{definition[:path]}"&lt;br /&gt;  path.gsub!(':filename', File.basename(file_path))&lt;br /&gt;  path.gsub!(/:([^\/\.]+)/) do |match|&lt;br /&gt;    "([^\/\.]+)"&lt;br /&gt;  end&lt;br /&gt;  FakeWeb.register_uri(:put, Regexp.new(path), :body =&gt; "OK")&lt;br /&gt;  When "I attach the file \"#{file_path}\" to \"#{field}\""&lt;br /&gt;end&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;That prepares the environment for receiving an S3 request for upload, so when the test reaches the Cucumber step for uploading the image (And I press "Upload") the environment can receive the request from the Paperclip-enhanced class (Image) and fake a response for it.&lt;br /&gt;&lt;br /&gt;To make that step work, make sure to configure your project with the "fakeweb" gem.&lt;br /&gt;&lt;br /&gt;Here is how Paperclip was configured in the Image class:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;class Image &lt; Attachment&lt;br /&gt;  validates_attachment_content_type :attachment, :content_type =&gt; ["image/jpg", "image/jpeg", "image/png", "image/gif"], :if =&gt; :attachment_file_name&lt;br /&gt;  has_attached_file :attachment,&lt;br /&gt;    :storage =&gt; :s3,&lt;br /&gt;    :styles =&gt; {&lt;br /&gt;      :medium =&gt; "300x300&gt;"&lt;br /&gt;    },&lt;br /&gt;    :s3_credentials =&gt; "#{RAILS_ROOT}/config/environments/#{RAILS_ENV}/amazon_s3.yml",&lt;br /&gt;    :path =&gt; "#{RAILS_ENV}/images/:id/:style/:filename",&lt;br /&gt;    :bucket =&gt; "bucketname",&lt;br /&gt;    :url =&gt; ':s3_domain_url',&lt;br /&gt;    :whiny =&gt; false&lt;br /&gt;end&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Fakeweb ended up cutting about 30 seconds off the time to run all Cucumber tests. Good deal!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/32881756-936575041986864371?l=andymaleh.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://andymaleh.blogspot.com/feeds/936575041986864371/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=32881756&amp;postID=936575041986864371' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/32881756/posts/default/936575041986864371'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/32881756/posts/default/936575041986864371'/><link rel='alternate' type='text/html' href='http://andymaleh.blogspot.com/2010/11/faking-paperclip-s3-calls-with-fakeweb.html' title='Faking Paperclip S3 calls with Fakeweb'/><author><name>Annas "Andy" Maleh</name><uri>http://www.blogger.com/profile/10268484073612495328</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/-f6UYG8WIYJI/Tpw6vYi2nTI/AAAAAAAAAPk/ICI9GDbAxh4/s1600/7312067a2015194b853856820711a178%253Fsize%253D200'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-32881756.post-7880871408943939494</id><published>2010-11-15T09:19:00.026-06:00</published><updated>2010-11-19T09:35:42.687-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Craftsmanship'/><category scheme='http://www.blogger.com/atom/ns#' term='Agile Methodologies'/><title type='text'>What Continuous Integration Is Really About</title><content type='html'>Recently, I have been encountering a number of environments where developers work in multiple branches and do not integrate their code till the end of the iteration. They end up often spending hours fighting to merge the code in correctly, sometimes resulting in bugs or missed features.&lt;br /&gt;&lt;br /&gt;When I see that, I cannot help but remember the pains of integrations in 6-month-long Waterfall projects. I was a junior developer at an environment in the past where developers spent 6 months implementing features in isolation of each other, and then only integrating right before the project deadline. As a result, they would run into enormous integration issues and spend 3 additional months fixing all of them before finally delivering.&lt;br /&gt;&lt;br /&gt;Now, developers who integrate at the end of the iteration often end up with a similar result. They miss the deadline sometimes by a day or more, and end up with issues bleeding into the next iteration (e.g. missing features due to bad merge).&lt;br /&gt;&lt;br /&gt;When I encounter such environments, and hear that developers branch out at the beginning of every iteration before developing their own features, I shudder and point out that they are not following the Agile practice of Continuous Integration. They immediately shoot back saying something like "We have cruise control setup" or "We do not have the resources to setup a CI server", which only reveals ignorance about what Continuous Integration is really about. What I was actually saying is they are not integrating continuously into one common branch, and thus not resolving integration conflicts on an hourly or daily basis, yet letting them accumulate till the end of the iteration causing an integration snowball effect.&lt;br /&gt;&lt;br /&gt;It is an unfortunate matter of human nature to be lazy at acquiring knowledge. You always want the least amount of learning to get you to where you want to go, so often people fail to dig deeper than what they hear and miss out on the deepest essence of what they are learning. For example, a lot of developers learning MVC from frameworks like Struts or earlier editions of Rails know just enough of MVC to get by, but never spent time digging into the true essence of MVC from Smalltalk Applications (or desktop development in general), and thus fail to apply it correctly. You end up with bloated controllers, instead of splitting most of the non-control behavior into Models. In the same token, a lot of developers who hear of Continuous Integration from the marketing lingo of CI servers think that is what Continuous Integration is all about.&lt;br /&gt;&lt;br /&gt;Here is how &lt;a href="http://www.martinfowler.com/articles/continuousIntegration.html"&gt;Martin Fowler&lt;/a&gt; describes Continuous Integration:&lt;br /&gt;&lt;blockquote&gt;&lt;i&gt;Continuous Integration is a software development practice where members of a team integrate their work frequently, usually each person integrates at least daily - leading to multiple integrations per day. Each integration is verified by an automated build (including test) to detect integration errors as quickly as possible. Many teams find that this approach leads to significantly reduced integration problems and allows a team to develop cohesive software more rapidly.&lt;/i&gt;&lt;/blockquote&gt;&lt;br /&gt;&lt;br /&gt;Notice how the primary emphasis is on members integrating their work frequently; at least daily if not multiple times a day. Also, see how having the automated build is secondary and only there to support the primary goal. So, when developers work in their own branches and do not integrate till the end of their iteration, they are not fulfilling the primary goal of resolving conflicts often before they get big and hard to resolve, and having a CI server does not make them a team that is properly doing Continuous Integration. While a CI server certainly helps them when they integrate at the end of the iteration, they still have to deal with bigger integration issues than if they were integrating daily if not hourly.&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Now, working in branches certainly has its place. It is useful when doing a spike, building an experimental feature, performing big architectural changes, or even working on a separate release all together that would not go out till a few months later. Of course, in the case of a separate release, the code would probably not get merged back into master and can be thought of as a separate project (even if it branched off the original project's code base). And, in the case of big architectural changes, it is preferred if possible to have them done in small slices within iterations, and only relying on a branch as a last resort. &lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Local branches in source code control systems like Git and Mercurial have their place too. You can perform work in a local branch every day if you like as long as you integrate it back to the main branch at the end of the day or every few hours. Used that way, it would still be in line with the practice of Continuous Integration.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Takeaway? &lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Integrate early and often on the same branch (daily/hourly) and you will leverage the benefits of Continuous Integration on your Agile project by delivering more on time and avoiding big merge/conflict issues.&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/32881756-7880871408943939494?l=andymaleh.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://andymaleh.blogspot.com/feeds/7880871408943939494/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=32881756&amp;postID=7880871408943939494' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/32881756/posts/default/7880871408943939494'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/32881756/posts/default/7880871408943939494'/><link rel='alternate' type='text/html' href='http://andymaleh.blogspot.com/2010/11/what-continuous-integration-really-is.html' title='What Continuous Integration Is Really About'/><author><name>Annas "Andy" Maleh</name><uri>http://www.blogger.com/profile/10268484073612495328</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/-f6UYG8WIYJI/Tpw6vYi2nTI/AAAAAAAAAPk/ICI9GDbAxh4/s1600/7312067a2015194b853856820711a178%253Fsize%253D200'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-32881756.post-8734228011192353732</id><published>2010-11-02T08:27:00.006-05:00</published><updated>2010-11-02T13:29:23.311-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Conferences'/><category scheme='http://www.blogger.com/atom/ns#' term='Craftsmanship'/><title type='text'>SCNA 2010: How Drumming Reinvigorated My Passion For Mastery</title><content type='html'>The slides for my &lt;a href="http://andymaleh.blogspot.com/2010/10/scna-2010.html"&gt;SCNA 2010&lt;/a&gt; impromptu lightning talk "How Drumming Reinvigorated My Passion For Mastery" have been posted:&lt;br /&gt;&lt;div style="width:425px" id="__ss_5638200"&gt;&lt;strong style="display:block;margin:12px 0 4px"&gt;&lt;a href="http://www.slideshare.net/AndyMaleh/how-drumming-reinvigorated-my-passion-for-mastery-5638200" title="How drumming reinvigorated my passion for mastery"&gt;How drumming reinvigorated my passion for mastery&lt;/a&gt;&lt;/strong&gt;&lt;object id="__sse5638200" width="425" height="355"&gt;&lt;param name="movie" value="http://static.slidesharecdn.com/swf/ssplayer2.swf?doc=howdrummingreinvigoratedmypassionformastery-101101183052-phpapp02&amp;stripped_title=how-drumming-reinvigorated-my-passion-for-mastery-5638200&amp;userName=AndyMaleh" /&gt;&lt;param name="allowFullScreen" value="true"/&gt;&lt;param name="allowScriptAccess" value="always"/&gt;&lt;embed name="__sse5638200" src="http://static.slidesharecdn.com/swf/ssplayer2.swf?doc=howdrummingreinvigoratedmypassionformastery-101101183052-phpapp02&amp;stripped_title=how-drumming-reinvigorated-my-passion-for-mastery-5638200&amp;userName=AndyMaleh" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="425" height="355"&gt;&lt;/embed&gt;&lt;/object&gt;&lt;div style="padding:5px 0 12px"&gt;View more &lt;a href="http://www.slideshare.net/"&gt;presentations&lt;/a&gt; from &lt;a href="http://www.slideshare.net/AndyMaleh"&gt;AndyMaleh&lt;/a&gt;.&lt;/div&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;Direct Link:&lt;br /&gt;&lt;a href="http://slidesha.re/a7Su3m"&gt;http://slidesha.re/a7Su3m&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Cheers...&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/32881756-8734228011192353732?l=andymaleh.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://andymaleh.blogspot.com/feeds/8734228011192353732/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=32881756&amp;postID=8734228011192353732' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/32881756/posts/default/8734228011192353732'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/32881756/posts/default/8734228011192353732'/><link rel='alternate' type='text/html' href='http://andymaleh.blogspot.com/2010/11/scna-2010-how-drumming-reinvigorated-my.html' title='SCNA 2010: How Drumming Reinvigorated My Passion For Mastery'/><author><name>Annas "Andy" Maleh</name><uri>http://www.blogger.com/profile/10268484073612495328</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/-f6UYG8WIYJI/Tpw6vYi2nTI/AAAAAAAAAPk/ICI9GDbAxh4/s1600/7312067a2015194b853856820711a178%253Fsize%253D200'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-32881756.post-3167096508308558991</id><published>2010-10-22T12:32:00.003-05:00</published><updated>2010-10-22T12:34:54.168-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Ruby'/><category scheme='http://www.blogger.com/atom/ns#' term='Eclipse'/><category scheme='http://www.blogger.com/atom/ns#' term='Conferences'/><category scheme='http://www.blogger.com/atom/ns#' term='Agile Methodologies'/><category scheme='http://www.blogger.com/atom/ns#' term='Rails'/><title type='text'>Rails Tutorial Submission at EclipseCon 2011</title><content type='html'>&lt;p&gt;I submitted this tutorial proposal for EclipseCon 2011. If it catches your interest, please comment/vote for it by following the link at the bottom&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;h4&gt;Title: Behavior Driven Web Development with Rails, Aptana, and Cucumber&lt;/h4&gt;&lt;br /&gt;&lt;br /&gt;&lt;h4&gt;Abstract:&lt;/h4&gt;&lt;br /&gt;&lt;p&gt;If you have been waiting for a good excuse to finally plunge into the Ruby world and learn the wildly popular Rails web framework, this is the tutorial to attend at EclipseCon. Not only does it cover the basics of Ruby and Rails, yet also behavior/test driven development with Cucumber/RSpec. The Eclipse-based Aptana RadRails IDE will be the main tool used in this tutorial.&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;The tutorial will include:&lt;br /&gt;&lt;ul&gt;&lt;br /&gt;&lt;li&gt;Basics of Ruby including some basics in meta-programming&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Basics of Rails covering MVC and configuration&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Basics of Behavior Driven Development with Cucumber&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Basics of Test Driven Development with RSpec&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Basics of the Eclipse-based Aptana RadRails IDE for Ruby on Rails development&lt;/li&gt;&lt;br /&gt;&lt;li&gt;An example Ruby on Rails application that walks students through learning the different components of a Rails application&lt;/li&gt;&lt;br /&gt;&lt;/ul&gt;&lt;br /&gt;&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Most of the material of the tutorial will be inspired by the Rails training courses I have given at &lt;a href="http://obtiva.com"&gt;Obtiva&lt;/a&gt;, such as the &lt;a href="http://obtiva.com/trainings/3-ruby-on-rails-tdd-boot-camp"&gt;Rails TDD Bootcamp&lt;/a&gt; and the &lt;a href="http://obtiva.com/trainings/4-ruby-on-rails-evenings"&gt;Rails 10-week Evenings Course (self-authored)&lt;/a&gt;&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;h4&gt;Link:&lt;/h4&gt;&lt;br /&gt;&lt;a href="https://www.eclipsecon.org/submissions/2011/view_talk.php?id=1985&amp;search=difficulty%3D%22easiest%22"&gt;https://www.eclipsecon.org/submissions/2011/view_talk.php?id=1985&amp;search=difficulty%3D%22easiest%22&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/32881756-3167096508308558991?l=andymaleh.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://andymaleh.blogspot.com/feeds/3167096508308558991/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=32881756&amp;postID=3167096508308558991' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/32881756/posts/default/3167096508308558991'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/32881756/posts/default/3167096508308558991'/><link rel='alternate' type='text/html' href='http://andymaleh.blogspot.com/2010/10/rails-tutorial-submission-at-eclipsecon.html' title='Rails Tutorial Submission at EclipseCon 2011'/><author><name>Annas "Andy" Maleh</name><uri>http://www.blogger.com/profile/10268484073612495328</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/-f6UYG8WIYJI/Tpw6vYi2nTI/AAAAAAAAAPk/ICI9GDbAxh4/s1600/7312067a2015194b853856820711a178%253Fsize%253D200'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-32881756.post-3640082939404213978</id><published>2010-10-16T10:39:00.005-05:00</published><updated>2010-10-16T13:51:53.861-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Conferences'/><category scheme='http://www.blogger.com/atom/ns#' term='Craftsmanship'/><title type='text'>SCNA 2010: Day 2</title><content type='html'>Chad Fowler kicked off Day 2 of Software Craftsmanship North America with a talk on outsourcing simple tasks to cheaper labor with close supervision.&lt;br /&gt;&lt;br /&gt;The second talk, titled "Artist to Programmer", was about how a Computer Science degree approach did not work with Keavy McMinn who came from a fine arts background, so she ended up learning programming through online collaboration, and then finally joined the pragmatic programmers in the US and learned from them.&lt;br /&gt;&lt;br /&gt;Summary:&lt;br /&gt;-Embrace the unknown&lt;br /&gt;-respond to challenges&lt;br /&gt;-be a maker of stuff (enjoy it)&lt;br /&gt;-be open to change&lt;br /&gt;-consider your community&lt;br /&gt;&lt;br /&gt;Enrique Comba gave a talk about the Forsaken Value.&lt;br /&gt;&lt;br /&gt;I will be giving a lightning talk titled "How Drumming Re-Invigorated My Passion For Mastery"&lt;br /&gt;&lt;br /&gt;... in progress... will tidy up later.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/32881756-3640082939404213978?l=andymaleh.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://andymaleh.blogspot.com/feeds/3640082939404213978/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=32881756&amp;postID=3640082939404213978' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/32881756/posts/default/3640082939404213978'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/32881756/posts/default/3640082939404213978'/><link rel='alternate' type='text/html' href='http://andymaleh.blogspot.com/2010/10/scna-2010-day-2.html' title='SCNA 2010: Day 2'/><author><name>Annas "Andy" Maleh</name><uri>http://www.blogger.com/profile/10268484073612495328</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/-f6UYG8WIYJI/Tpw6vYi2nTI/AAAAAAAAAPk/ICI9GDbAxh4/s1600/7312067a2015194b853856820711a178%253Fsize%253D200'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-32881756.post-4378068472249026486</id><published>2010-10-15T11:03:00.024-05:00</published><updated>2010-10-16T11:07:00.174-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Conferences'/><category scheme='http://www.blogger.com/atom/ns#' term='Craftsmanship'/><title type='text'>SCNA 2010: Day 1</title><content type='html'>The &lt;a href="http://scna.softwarecraftsmanship.org/schedule"&gt;Software Craftsmanship North America&lt;/a&gt; conference started today with a keynote by &lt;a href="http://www.objectmentor.com/omTeam/martin_r.html"&gt;Bob Martin&lt;/a&gt; on the failure of state and rise of functional programming. The summary is that maintaining state is getting difficult with multi-core processors and software distribution, and functional programming provides a more disciplined generally less problematic approach to utilizing the extra concurrent/distributed processing power. Although functional programming was invented around 1957, it is finally feasible given the great amounts of memory and CPU cores available to us for cheap today. He ended the talk by mentioning the idea of thinking of everything as a function of time, including database transactions, thus potentially making relational databases obsolete as data is then stored as an initial state and a series of events across time. This prevents side effects as you never modify state, you just append a new data change event. So, to retrieve the state at any point in time, you just apply the change events up to that point, and have the required data as the output result of a function. The best example of that is source code management systems that developers rely on daily to protect their code, like Git.&lt;br /&gt;&lt;br /&gt;The next talk was given by Doug Bradbury about how developers are "made to make" software. It summed up to people liking to make things in collaboration with others, often people from different disciplines coming together in order to succeed and achieve their goal.&lt;br /&gt;&lt;br /&gt;The third talk is given by Doctor Norton (Michael Norton) titled "Training Software Professionals: Just what the doctor ordered."&lt;br /&gt;&lt;br /&gt;During lunch, I had a couple of very interesting conversations. &lt;br /&gt;&lt;br /&gt;One was about how the success of software development does not just depend on the developer skills with technology and process, yet also the soundness of the business plan, commitment of the team, openness of management for feedback, involvement of customer and users with requirements gathering and understanding, and other factors. However, people tend to forget all these factors and assume that if a project does not achieve success, then "Agile failed" or the team is not skilled instead of honestly looking holistically at all the factors involved and learning from them instead of blaming. &lt;br /&gt;&lt;br /&gt;The other conversation was about Closure, its uses, and whether it will ever be a mainstream front-end development platform or if it will be just a more optimized language for back-end development that takes advantage of multi-cores and distributed systems, while leaving OO languages for the front-end since they closely match the way people think about business domains. A reference was thrown about Deam Wampler mentioning this idea recently, and it seems to make sense, but I would have to gain more experience in functional programming before I can make my own conclusion.&lt;br /&gt;&lt;br /&gt;Dave lead an apprenticeship panel consisting of two apprentices from Obtiva (Nate and Ethan) and two from 8th Light (Eric and Colin). Each apprentice introduced themselves and then talked a bit about their apprenticeship. 8th light folks normally had a main mentor. Obtivians often rotated with multiple mentors. At 8th light, they used to have a 3-month limit apprenticeship, but now it's more open ended. At Obtiva, apprentices had to meet a checklist and check-points to graduate. &lt;br /&gt;&lt;br /&gt;Apprentices gave this advise to programmers:&lt;br /&gt;-Ask as many questions as possible&lt;br /&gt;-Pay attention to the answers&lt;br /&gt;-Do your homework after getting the answers&lt;br /&gt;-Learn theory and apply, don't just stick to one side&lt;br /&gt;-Pair with as many people as possible &lt;br /&gt;-Don't be afraid to suck while learning&lt;br /&gt;&lt;br /&gt;Colin has a background in music and compared the music ethic to the programming ethic as far as practicing hard and learning on the job (during performances with music).&lt;br /&gt;&lt;br /&gt;Someone from the audience asked if apprentices ever voiced disagreements of opinion and whether they stick to their opinion or not. One of the apprentices answered by saying he often holds back his opinion until he understood the opposite idea of the other person. Another said he voiced disagreements without pushing too hard as he cared about not tearing the team apart. In any case, all agreed that it is good to voice disagreements in a friendly way though for the benefit of both people in a pair.&lt;br /&gt;&lt;br /&gt;Apprentices tend to find themselves wanting to help others learn by learning themselves. They recommend pairing as a two-way learning technique, not just one way.&lt;br /&gt;&lt;br /&gt;It is important to balance teaching and learning, and it is a learning oriented exercise.&lt;br /&gt;&lt;br /&gt;Someone in the audience asked what's it worth to go through apprenticeship.&lt;br /&gt;&lt;br /&gt;One apprentice said he would trade his 6 months of apprenticeship for his 3 years and a half of college.&lt;br /&gt;&lt;br /&gt;A couple of people asked about co-op (interning) vs apprenticeship. The difference cited by apprentices was that apprenticeship has the expectation of getting a job afterward.&lt;br /&gt;&lt;br /&gt;Apprenticeship program recommendations mentioned were "Set expectations and give more feedback. "&lt;br /&gt;&lt;br /&gt;I gave a lightning talk, titled "Software Craftsmanship vs Software Engineering".&lt;br /&gt;&lt;br /&gt;Saw Randori with the stars, which was a pair-rotation session between a number of programming stars such as Bob Martin, Ken Auers, Corey Haines, and Chad Fowler. &lt;br /&gt;&lt;br /&gt;Ken Auers next gave a a great talk about entrepreneurship, "Lean Craftsmanship vs "Corporate" Craftsmanship"&lt;br /&gt;&lt;br /&gt;-It's all about getting/giving value&lt;br /&gt;-Tradeoff identification&lt;br /&gt;-Identify Exploration needs and constrain them&lt;br /&gt;&lt;br /&gt;Not a spec&lt;br /&gt;no fixed price contract&lt;br /&gt;not cheaper coders or designers&lt;br /&gt;&lt;br /&gt;Find the price first.&lt;br /&gt;&lt;br /&gt;What is your budget?&lt;br /&gt;&lt;br /&gt;Cost of communication is The biggest cost of a software project.&lt;br /&gt;&lt;br /&gt;Covering the cost:&lt;br /&gt;-get really good at dev&lt;br /&gt;-identify simple alternative&lt;br /&gt;-pay attention to what's working and what's nost&lt;br /&gt;-Have cheap people do easy things under CLOSE supervision of someone who knows the difference&lt;br /&gt;&lt;br /&gt;Quality Assurance:&lt;br /&gt;Test driven development?&lt;br /&gt;-as good as the tests&lt;br /&gt;-sometimes really hard&lt;br /&gt;Where is the risk?&lt;br /&gt;-how do you mitigate it?&lt;br /&gt;-build vs buy?&lt;br /&gt;&lt;br /&gt;Recommend book: The Principles of Beautiful Web Design.&lt;br /&gt;Know Compass.&lt;br /&gt;&lt;br /&gt;Need to learn something about system admin and ux.&lt;br /&gt;&lt;br /&gt;... in progress... will tidy up the post afterward.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/32881756-4378068472249026486?l=andymaleh.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://andymaleh.blogspot.com/feeds/4378068472249026486/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=32881756&amp;postID=4378068472249026486' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/32881756/posts/default/4378068472249026486'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/32881756/posts/default/4378068472249026486'/><link rel='alternate' type='text/html' href='http://andymaleh.blogspot.com/2010/10/scna-2010.html' title='SCNA 2010: Day 1'/><author><name>Annas "Andy" Maleh</name><uri>http://www.blogger.com/profile/10268484073612495328</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/-f6UYG8WIYJI/Tpw6vYi2nTI/AAAAAAAAAPk/ICI9GDbAxh4/s1600/7312067a2015194b853856820711a178%253Fsize%253D200'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-32881756.post-3482366136892603688</id><published>2010-09-13T08:03:00.002-05:00</published><updated>2010-09-13T08:10:03.288-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Object Oriented Programming'/><category scheme='http://www.blogger.com/atom/ns#' term='Ruby'/><title type='text'>Callbacks</title><content type='html'>I generally tend to find callbacks confusing when called callbacks in an Object Oriented context because they drop the level of abstraction too low. That tends to force developers to think about the low-level mechanism of calling back instead of the Object Oriented concept the callback is trying to achieve, so they end up with no abstract concept at which they could stop tracing through the code and take it for what its name says.&lt;br /&gt;&lt;br /&gt;For example, if the API says that the sort method takes a "callback" block of code in Ruby, that does not say anything about what that callback does, and makes it hard for the developer to guess what parameters it receives without reading the implementation code. On the other hand, if the API says the sort method takes a "comparator" block, it gives the developer much more  knowledge on what the block's responsibility is and what parameters to expect without having to read through the code.&lt;br /&gt;&lt;br /&gt;So, what are some examples of callbacks? Comparators, renderers, converters, translators, etc...&lt;br /&gt;&lt;br /&gt;The reason I bring this up is I often run into APIs in Ruby/Rails business projects that simply take a block without naming it, making it difficult to guess what the block does without digging through the implementation.&lt;br /&gt;&lt;br /&gt;For example, an API with print(data, &amp;block) or just print(data) does not tell me much about the passable block in the first case or if I could even pass a block in the second case (although the API accepts it). I would have to read through the implementation to find out. However, if the API was print(data, &amp;renderer), I would much more likely guess then that I can pass a renderer that receives the printable data for custom rendering before the actual printing occurs.&lt;br /&gt;&lt;br /&gt;So, give your callbacks better names, and you will help developers parse through and understand your APIs faster.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/32881756-3482366136892603688?l=andymaleh.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://andymaleh.blogspot.com/feeds/3482366136892603688/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=32881756&amp;postID=3482366136892603688' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/32881756/posts/default/3482366136892603688'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/32881756/posts/default/3482366136892603688'/><link rel='alternate' type='text/html' href='http://andymaleh.blogspot.com/2010/09/callbacks.html' title='Callbacks'/><author><name>Annas "Andy" Maleh</name><uri>http://www.blogger.com/profile/10268484073612495328</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/-f6UYG8WIYJI/Tpw6vYi2nTI/AAAAAAAAAPk/ICI9GDbAxh4/s1600/7312067a2015194b853856820711a178%253Fsize%253D200'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-32881756.post-4182366404020893491</id><published>2010-08-11T01:54:00.003-05:00</published><updated>2010-08-12T15:54:32.287-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Craftsmanship'/><title type='text'>Craftsmanship Swap with EdgeCase - Day Five</title><content type='html'>Here is my belated report on day five of the &lt;a href="http://andymaleh.blogspot.com/2010/08/craftsmanship-swap.html"&gt;craftsmanship swap&lt;/a&gt; with EdgeCase.&lt;br /&gt;&lt;br /&gt;I continued to pair with Mike, but on a different project. We decided to use Emacs that day.&lt;br /&gt;&lt;br /&gt;One feature that we were developing needed to be refactored and simplified, but we made the conscious decision of finishing it with the current code design first, and then diving into the refactoring afterward. That paid off greatly because the refactoring took very long and we did not have time to finish it by the end of day, yet we had a tested and functional version of the feature.&lt;br /&gt;&lt;br /&gt;Friday happened to be a day when employees wanted to grill hand-tossed Pizza outside. That was fun as it involved helping out in the process (think team building) as well as having interesting non-programming conversations.&lt;br /&gt;&lt;br /&gt;The day was ended in the music jamming area where Mark, Kevin, and I attempted playing metal, rock, and pop music. &lt;br /&gt;&lt;br /&gt;I would say the swap was very good overall since I got to experience tools I was not used to such as Rails.VIM and Emacs, new processes such as relying on Cucumber fully for integration testing without writing controller tests, and new cultural habits such as playing music and grilling pizza at work. :)&lt;br /&gt;&lt;br /&gt;In the future, if anyone is interested in doing a craftsmaship swap with Obtiva, visit our &lt;a href="http://obtiva.com"&gt;website&lt;/a&gt; to get the contact info (and mention this blog post).&lt;br /&gt;&lt;br /&gt;Thanks to EdgeCase for their hospitality and good luck to everyone on their craftsmanship journey.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/32881756-4182366404020893491?l=andymaleh.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://andymaleh.blogspot.com/feeds/4182366404020893491/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=32881756&amp;postID=4182366404020893491' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/32881756/posts/default/4182366404020893491'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/32881756/posts/default/4182366404020893491'/><link rel='alternate' type='text/html' href='http://andymaleh.blogspot.com/2010/08/craftsmanship-swap-with-edgecase-day_10.html' title='Craftsmanship Swap with EdgeCase - Day Five'/><author><name>Annas "Andy" Maleh</name><uri>http://www.blogger.com/profile/10268484073612495328</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/-f6UYG8WIYJI/Tpw6vYi2nTI/AAAAAAAAAPk/ICI9GDbAxh4/s1600/7312067a2015194b853856820711a178%253Fsize%253D200'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-32881756.post-5961678364157318767</id><published>2010-08-05T23:09:00.006-05:00</published><updated>2010-08-11T11:22:22.783-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Craftsmanship'/><title type='text'>Craftsmanship Swap with EdgeCase - Day Four</title><content type='html'>Here is a report of day four of the &lt;a href="http://andymaleh.blogspot.com/2010/08/craftsmanship-swap.html"&gt;craftsmanship swap&lt;/a&gt; with EdgeCase. &lt;p&gt;I continued pairing with Mike till we finished the story we were working on and another one we picked up in the morning. I got to learn plenty more VIM shortcuts in the process. &lt;p&gt;Also, I talked about the importance of presenting alternative UI designs to stakeholders when unsure about what to build instead of asking them to tell us what the design would be. Otherwise, you may find yourself committing to a suboptimal design by a non-designer. &lt;p&gt;Lunch was catered by Qdoba and Matt Yoho gave a talk on his Rails plugin BasicAssumption. It tries to improve on DecentExposure&amp;#39;s syntax and features. Both plugins help developers avoid abusing before filters in controllers to load models as their reliance on instance variables often leads to fragmented code that is difficult to trace. BasicAssumption provides a DSL for defining action-needed models, handling the memoization and definition of model retrieval helpers automatically. &lt;p&gt;After lunch, Mike and I moved to a different project and decided to use Emacs for a change. Had some interesting learning on jQuery, credit card processing with Braintree, and credit card security concerns. &lt;p&gt;Also, discussed issues with overuse of branches in source code control instead of the Agile practice of continuous integration on the main branch (as with the famous SVN Unstable Trunk strategy used with most open source projects). And, I emphasized the importance of having Staging be deployed off of the same branch from which Production is cut to perfectly simulate production instead of having Staging live in its own branch, thereby defeating its purpose. &lt;p&gt;After hours, I went to the music jamming area with Mark Peabody and we got to play some songs with him on guitar and me on drums. Mostly 90&amp;#39;s classics like In Bloom by Nirvana, and When I Come Around / Welcome To Paradise by Green Day. It was a blast. &lt;p&gt;Stay tuned for day five, the &lt;a href="http://andymaleh.blogspot.com/2010/08/craftsmanship-swap-with-edgecase-day_10.html"&gt;last day&lt;/a&gt; of the craftsmanship swap.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/32881756-5961678364157318767?l=andymaleh.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://andymaleh.blogspot.com/feeds/5961678364157318767/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=32881756&amp;postID=5961678364157318767' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/32881756/posts/default/5961678364157318767'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/32881756/posts/default/5961678364157318767'/><link rel='alternate' type='text/html' href='http://andymaleh.blogspot.com/2010/08/craftsmanship-swap-with-edgecase-day_05.html' title='Craftsmanship Swap with EdgeCase - Day Four'/><author><name>Annas "Andy" Maleh</name><uri>http://www.blogger.com/profile/10268484073612495328</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/-f6UYG8WIYJI/Tpw6vYi2nTI/AAAAAAAAAPk/ICI9GDbAxh4/s1600/7312067a2015194b853856820711a178%253Fsize%253D200'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-32881756.post-2567091626788471592</id><published>2010-08-04T22:24:00.005-05:00</published><updated>2010-08-11T11:23:10.420-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Craftsmanship'/><title type='text'>Craftsmanship Swap with EdgeCase - Day Three</title><content type='html'>Today was day three of the &lt;a href="http://andymaleh.blogspot.com/2010/08/craftsmanship-swap.html"&gt;craftsmanship swap&lt;/a&gt; with EdgeCase. &lt;p&gt;I got assigned to a new social networking Rails project where I would be pair programming with a new guy called Mike. &lt;/p&gt;&lt;p&gt;The first difference was that Mike's tool of choice was VIM, supercharged with the "Rails.VIM" plugin. Using it was quite a pleasurable experience compared to using a plain VIM as it provides a lot of IDE-like features that I get from RubyMine and Aptana, such as autocomplete, quick lookup of classes, and most importantly class/method instant navigation with support for going backward/forward like using a browser. &lt;/p&gt;&lt;p&gt;Also, I got to write tests in a more recent version of Cucumber with support for navigation in JavaScript driven UIs. &lt;/p&gt;&lt;p&gt;In addition to resolving a big, and performing a nice cleanup refactoring, we finished the first part of a new feature test-first, which we will continue tomorrow. &lt;/p&gt;&lt;p&gt;At the end of the day, we went to the music jamming area. My pair grabbed a guitar and I sat on the drums and we jammed briefly before Matt showed up and we all left to an evening outing at a nice bar/restaurant called Bodego near downtown Columbus, Ohio. We got joined by a couple of people from Relevance and had interesting conversations on software development, processes related to source code control strategies like SVN's famous Unstable Trunk, and the demise of Google Wave and older chat technologies like ICQ. &lt;/p&gt;&lt;p&gt;That's it for today. Stay tuned for &lt;a href="http://andymaleh.blogspot.com/2010/08/craftsmanship-swap-with-edgecase-day_05.html"&gt;day four&lt;/a&gt; of the swap tomorrow.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/32881756-2567091626788471592?l=andymaleh.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://andymaleh.blogspot.com/feeds/2567091626788471592/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=32881756&amp;postID=2567091626788471592' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/32881756/posts/default/2567091626788471592'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/32881756/posts/default/2567091626788471592'/><link rel='alternate' type='text/html' href='http://andymaleh.blogspot.com/2010/08/craftsmanship-swap-with-edgecase-day_04.html' title='Craftsmanship Swap with EdgeCase - Day Three'/><author><name>Annas "Andy" Maleh</name><uri>http://www.blogger.com/profile/10268484073612495328</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/-f6UYG8WIYJI/Tpw6vYi2nTI/AAAAAAAAAPk/ICI9GDbAxh4/s1600/7312067a2015194b853856820711a178%253Fsize%253D200'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-32881756.post-4014466163036805614</id><published>2010-08-03T17:02:00.014-05:00</published><updated>2010-08-11T11:24:13.150-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Craftsmanship'/><title type='text'>Craftsmanship Swap with EdgeCase - Day Two</title><content type='html'>Today was day two in the &lt;a href="http://andymaleh.blogspot.com/2010/08/craftsmanship-swap.html"&gt;craftsmanship swap&lt;/a&gt; with EdgeCase.&lt;br /&gt;&lt;br /&gt;The day was kicked off with a typical Agile stand-up meeting attended by local EdgeCase employees, employees in Scotland, and Ruby luminary &lt;a href="http://onestepback.org/"&gt;Jim Weirich&lt;/a&gt; from Cincinnati. &lt;br /&gt;&lt;br /&gt;Afterward, I got to pair with John on a new feature related to payment processing, which we finished by the end of the day. &lt;br /&gt;&lt;br /&gt;Highlights of my learning while pair-programming with John were:&lt;ul&gt;&lt;li&gt;Learned how to use let(:method_name) {value} in RSpec tests to write more expressive tests without relying on @ instance variables initialized in before :each blocks&lt;/li&gt;&lt;li&gt;Learned about the Emacs Yasnippet plugin that allows building expression expanding macros (e.g. typing do and then hitting tab expands it to a do end block with the cursor placed in between) Since I appreciated this feature quite a bit in Eclipse, it was nice to have it while pairing with John, and we even built our own snippet at one point&lt;/li&gt;&lt;li&gt;Learned how to use the Braintree payment processing library in Ruby, which makes it easy to accept credit card information securely&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;And, at the end of the day, I got to play on the drums in the music jamming area.&lt;br /&gt;&lt;br /&gt;Stay tuned for &lt;a href="http://andymaleh.blogspot.com/2010/08/craftsmanship-swap-with-edgecase-day_04.html"&gt;day three&lt;/a&gt; tomorrow.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/32881756-4014466163036805614?l=andymaleh.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://andymaleh.blogspot.com/feeds/4014466163036805614/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=32881756&amp;postID=4014466163036805614' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/32881756/posts/default/4014466163036805614'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/32881756/posts/default/4014466163036805614'/><link rel='alternate' type='text/html' href='http://andymaleh.blogspot.com/2010/08/craftsmanship-swap-with-edgecase-day_03.html' title='Craftsmanship Swap with EdgeCase - Day Two'/><author><name>Annas "Andy" Maleh</name><uri>http://www.blogger.com/profile/10268484073612495328</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/-f6UYG8WIYJI/Tpw6vYi2nTI/AAAAAAAAAPk/ICI9GDbAxh4/s1600/7312067a2015194b853856820711a178%253Fsize%253D200'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-32881756.post-7399126908738998485</id><published>2010-08-02T22:54:00.004-05:00</published><updated>2010-08-03T17:14:35.838-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Craftsmanship'/><title type='text'>Craftsmanship Swap with EdgeCase - Day One</title><content type='html'>Today was the first day of my &lt;a href="http://andymaleh.blogspot.com/2010/08/craftsmanship-swap.html"&gt;craftsmanship swap&lt;/a&gt; with EdgeCase. &lt;p&gt;The first thing I noticed when I got there was that their building is in an extremely green and tree surrounded location that makes it feel like you are programming in the forests. Beautiful scenery. &lt;p&gt;The second thing I noticed when I walked in is they have a room with music jamming equipment consisting of a few guitars and a drum kit. Since I have been recently wondering about the idea of a company having a jamming room for employees to release stress in, it was a pleasant surprise to see that implemented. &lt;p&gt;Now, regarding the work environment, it was a basic agile setup with big screens and dual keyboards to facilitate pair programming. &lt;p&gt;I started today by pairing with John on a Rails app that is deployed on Heroku, uses Amazon EC2 to run some background workers and scale automatically, and relies on RSpec, Haml, and other popular Rails libraries. &lt;p&gt;John prefers using Emacs, so I finally got a taste of using it practically on a Rails project, and I enjoyed learning new shortcuts and reaching some level of comfort with it by the end of the day. &lt;p&gt;John and I got to resolve an issue and make progress on a feature on Day One.&lt;p&gt;I am looking forward to more pairing at EdgeCase tomorrow, so stay tuned for my &lt;a href="http://andymaleh.blogspot.com/2010/08/craftsmanship-swap-with-edgecase-day_03.html"&gt;next blog post&lt;/a&gt; on the craftsmanship swap.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/32881756-7399126908738998485?l=andymaleh.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://andymaleh.blogspot.com/feeds/7399126908738998485/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=32881756&amp;postID=7399126908738998485' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/32881756/posts/default/7399126908738998485'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/32881756/posts/default/7399126908738998485'/><link rel='alternate' type='text/html' href='http://andymaleh.blogspot.com/2010/08/craftsmanship-swap-with-edgecase-day.html' title='Craftsmanship Swap with EdgeCase - Day One'/><author><name>Annas "Andy" Maleh</name><uri>http://www.blogger.com/profile/10268484073612495328</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/-f6UYG8WIYJI/Tpw6vYi2nTI/AAAAAAAAAPk/ICI9GDbAxh4/s1600/7312067a2015194b853856820711a178%253Fsize%253D200'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-32881756.post-1678416516159974636</id><published>2010-08-01T21:46:00.015-05:00</published><updated>2010-08-11T11:24:28.131-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Craftsmanship'/><title type='text'>Craftsmanship Swap with EdgeCase</title><content type='html'>Tomorrow will be &lt;a href="http://andymaleh.blogspot.com/2010/08/craftsmanship-swap-with-edgecase-day.html"&gt;the first day&lt;/a&gt; of my Obtiva Craftsmanship Swap with EdgeCase in Columbus, Ohio. &lt;p&gt;The swap will last till the end of the week, and I will be blogging every day about my experiences over at EdgeCase. My posts will cover technologies, practices, and culture. &lt;p&gt;In the meantime, Adam McCrea from EdgeCase will be hanging out at Obtiva for a week too as part of the week long swap. &lt;p&gt;I look forward to the knowledge exchange between Obtiva and EdgeCase. &lt;p&gt;Stay tuned for the upcoming blog posts this week.&lt;br /&gt;&lt;br /&gt;Update:&lt;br /&gt;&lt;a href="http://andymaleh.blogspot.com/2010/08/craftsmanship-swap-with-edgecase-day.html"&gt;Day One&lt;/a&gt; posted.&lt;br /&gt;&lt;a href="http://andymaleh.blogspot.com/2010/08/craftsmanship-swap-with-edgecase-day_03.html"&gt;Day Two&lt;/a&gt; posted.&lt;br /&gt;&lt;a href="http://andymaleh.blogspot.com/2010/08/craftsmanship-swap-with-edgecase-day_04.html"&gt;Day Three&lt;/a&gt; posted.&lt;br /&gt;&lt;a href="http://andymaleh.blogspot.com/2010/08/craftsmanship-swap-with-edgecase-day_05.html"&gt;Day Four&lt;/a&gt; posted.&lt;br /&gt;&lt;a href="http://andymaleh.blogspot.com/2010/08/craftsmanship-swap-with-edgecase-day_10.html"&gt;Day Five&lt;/a&gt; posted.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/32881756-1678416516159974636?l=andymaleh.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://andymaleh.blogspot.com/feeds/1678416516159974636/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=32881756&amp;postID=1678416516159974636' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/32881756/posts/default/1678416516159974636'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/32881756/posts/default/1678416516159974636'/><link rel='alternate' type='text/html' href='http://andymaleh.blogspot.com/2010/08/craftsmanship-swap.html' title='Craftsmanship Swap with EdgeCase'/><author><name>Annas "Andy" Maleh</name><uri>http://www.blogger.com/profile/10268484073612495328</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/-f6UYG8WIYJI/Tpw6vYi2nTI/AAAAAAAAAPk/ICI9GDbAxh4/s1600/7312067a2015194b853856820711a178%253Fsize%253D200'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-32881756.post-730020003422327529</id><published>2010-07-16T15:16:00.002-05:00</published><updated>2010-07-16T15:57:25.619-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Craftsmanship'/><title type='text'>How do you draw the line?</title><content type='html'>Never wrote a poem before, and though this may not be one, I could not think of another way to describe it.&lt;br /&gt;&lt;br /&gt;Enjoy!&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style:italic;"&gt;&lt;br /&gt;Are you disciplined or are you dogmatic? How do you draw the line? &lt;br /&gt;Are you pragmatic or are you lazy? How do you draw the line?&lt;br /&gt;Are you positive or just slap happy? How do you draw the line? &lt;br /&gt;Are you risk averting or negative? How do you draw the line?&lt;br /&gt;Are you open minded or always distracted with the latest and greatest? How do you draw the line?&lt;br /&gt;Are you cautious or are you closed minded? How do you draw the line? &lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Suggestions for expanding it or addressing the concerns it raises are welcome.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/32881756-730020003422327529?l=andymaleh.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://andymaleh.blogspot.com/feeds/730020003422327529/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=32881756&amp;postID=730020003422327529' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/32881756/posts/default/730020003422327529'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/32881756/posts/default/730020003422327529'/><link rel='alternate' type='text/html' href='http://andymaleh.blogspot.com/2010/07/how-do-you-draw-line.html' title='How do you draw the line?'/><author><name>Annas "Andy" Maleh</name><uri>http://www.blogger.com/profile/10268484073612495328</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/-f6UYG8WIYJI/Tpw6vYi2nTI/AAAAAAAAAPk/ICI9GDbAxh4/s1600/7312067a2015194b853856820711a178%253Fsize%253D200'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-32881756.post-8632897686747013506</id><published>2010-06-08T14:27:00.002-05:00</published><updated>2010-06-08T14:29:04.589-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Agile Methodologies'/><title type='text'>Agile Comes To You - Chicago - Slides</title><content type='html'>The slides for the Agile Comes To You seminar have been posted, including my keynote presentation:&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;a href="http://www.accurev.com/seminar/20100525-chicago-slides.html"&gt;http://www.accurev.com/seminar/20100525-chicago-slides.html&lt;/a&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/32881756-8632897686747013506?l=andymaleh.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://andymaleh.blogspot.com/feeds/8632897686747013506/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=32881756&amp;postID=8632897686747013506' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/32881756/posts/default/8632897686747013506'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/32881756/posts/default/8632897686747013506'/><link rel='alternate' type='text/html' href='http://andymaleh.blogspot.com/2010/06/agile-comes-to-you-chicago-slides.html' title='Agile Comes To You - Chicago - Slides'/><author><name>Annas "Andy" Maleh</name><uri>http://www.blogger.com/profile/10268484073612495328</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/-f6UYG8WIYJI/Tpw6vYi2nTI/AAAAAAAAAPk/ICI9GDbAxh4/s1600/7312067a2015194b853856820711a178%253Fsize%253D200'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-32881756.post-7979196781281471265</id><published>2010-05-30T13:25:00.010-05:00</published><updated>2010-06-01T08:48:54.431-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Craftsmanship'/><category scheme='http://www.blogger.com/atom/ns#' term='Agile Methodologies'/><title type='text'>Pair Programming in the Wild</title><content type='html'>Pair-programming is probably one of &lt;a href="http://www.extremeprogramming.org/"&gt;XP&lt;/a&gt;'s most controversial practices, and that may have been one of the reasons I initially got attracted to it about 5 years ago. After all, sticking only to practices that are mainstream, will end up with mainstream results, yet studying out-of-the-box practices that may potentially yield a world's difference in productivity and quality, is like discovering an O(1) algorithm in comparison to O(n): big difference!&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;So, what is pair programming about anyways?&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;In a keynote presentation that I gave at the &lt;a href="http://www.accurev.com/seminar/chicago20100525-4"&gt;Agile Comes To You Seminar&lt;/a&gt; last week, I defined it as:&lt;/div&gt;&lt;div&gt;&lt;i&gt;&lt;/i&gt;&lt;blockquote&gt;&lt;i&gt;Two  programmers  solve  problems  together  on  &lt;/i&gt;&lt;div&gt;&lt;i&gt;one  machine:  &lt;/i&gt;&lt;/div&gt;&lt;div&gt;&lt;ul&gt;&lt;li&gt;&lt;i&gt;The  driver (person on the keyboard)  focuses  on  writing  code &lt;/i&gt;&lt;/li&gt;&lt;li&gt;&lt;i&gt;The  navigator  focuses  on  strategic  direction&lt;/i&gt;&lt;/li&gt;&lt;/ul&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/blockquote&gt;&lt;div&gt;Notice the emphasis on how the programmers "solve problems together" as opposed to write code together. In other words, writing code is not the bottleneck, solving problems is.&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt; If writing code was indeed a bottleneck, then pair programming would have been a very different skill. It would have been about one programmer learning how to type on two keyboards at once instead of two programmers typing on one keyboard. It would have been about dedicating your left brain for one computer monitor and your right brain for another. It would have been about writing code that writes code for you. All of these things would have been interesting skills to master if writing code was the bottleneck.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;In reality though, writing code is just a tiny concern in comparison to solving big programming problems for business. And, here are just a few examples of the problems I am talking about:&lt;/div&gt;&lt;div&gt;&lt;ul&gt;&lt;li&gt;Where do I put the responsibilities for reporting on a collection of objects to make the code as maintainable as possible in the future?&lt;/li&gt;&lt;li&gt;What is the most efficient SQL query I can write to have the report run fast?&lt;/li&gt;&lt;li&gt;Do I need pagination or is the result set small enough?&lt;/li&gt;&lt;li&gt;Is it worth applying the State Pattern to this problem or are the state related actions few enough to warrant not applying the pattern?&lt;/li&gt;&lt;li&gt;Do I need a layer of presentation objects between the models and the view or would the code end up simpler without it?&lt;/li&gt;&lt;/ul&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;I cannot emphasize how often I have spent hours on such problems on my own, only to take a break and talk to another developer, and then get an immediate solution from their point of view.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;That made me curious about all the scenarios that benefit from pair programming: &lt;/div&gt;&lt;div&gt;&lt;ul&gt;&lt;li&gt;Decisions related to code aesthetics/API often get resolved quickly when validated against another developer's opinion, finishing faster, and with clearer code.&lt;/li&gt;&lt;li&gt;When deciding on one of multiple alternative solutions to a problem, a developer working alone may hesitate quite a bit about picking what is best for the team. Having a second developer present provides more confidence and speeds up the decision process.&lt;/li&gt;&lt;li&gt;&lt;a href="http://www.leaderu.com/cl-institute/habits/habit6.html"&gt;Synergy&lt;/a&gt; is the idea of 1 + 1 &gt; 2. This can help a lot in solving problems that involve creativity. Often developer A has one solution in mind that is not optimal and developer B has another solution that is not optimal. So, leaving one developer to implement his solution alone may yield mediocre results whereas having the two developers discuss their solutions first may yield a new solution that is much better than the two original ones.&lt;/li&gt;&lt;li&gt;When solving a problem that requires multiple skills (e.g. OO skills vs SQL querying skills), it is common that no one developer on the team is the best in all of them.  So, having two developers work on the problem will increase the chance of addressing all parts of the problem optimally, and at the same time cross pollinate the developer skills. For example, I have learned quite a bit from pairing with a developer who was proficient at SQL, while I helped him learn quite a bit about OO design.&lt;/li&gt;&lt;li&gt;When the driver spends too much time focusing on a problem that is of low priority, the navigator who has more of a bird's eye perspective will often notice that quickly and prevent the driver from getting derailed for a few hours unnecessarily.&lt;/li&gt;&lt;/ul&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Under the surface though, there are less apparent under-estimated benefits that improve developer skills and the development team quite a bit in the long term:&lt;/div&gt;&lt;div&gt;&lt;ul&gt;&lt;li&gt;Having developers socialize while programming on a daily basis increases team bonding and commitment toward the success of the project.&lt;/li&gt;&lt;li&gt;It can be quite fun, thus greatly motivational.&lt;/li&gt;&lt;li&gt;When developers of different experiences pair together, they cross pollinate their knowledge, learning quite a bit from each other, and getting stronger in the long term. One example of this is the number of shortcuts I learned while programming with the Eclipse IDE on Java projects. I got to a point where I can almost do anything by keyboard without ever wasting time reaching for the mouse. And, whenever I paired with new programmers, they would get surprised by the number of shortcuts I knew, and tell me that it intimidated them to learn that many shortcuts. I had to explain to them that it was like watering a plant: I learned all my shortcuts a few shortcuts a week over 12 months of pairing with different developers, thus expanding minimal yet consistent effort.&lt;/li&gt;&lt;/ul&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Given that I am clearly sold on pair programming, does that mean I do it all the time? Well, there are cases when I avoid it for practical reasons:&lt;/div&gt;&lt;div&gt;&lt;ul&gt;&lt;li&gt;I get exhausted from pairing for 5 hours straight. Yes, pairing can get exhausting, so it is important for a pair to realize the point at which they need to take a break from pairing.&lt;/li&gt;&lt;li&gt;I come to work tired from lack of sleep. I know I would not be effective pairing in that mode.&lt;/li&gt;&lt;li&gt;I have boiler plate work that is mind numbing such as data setup or the like. In this case, typing would indeed be the bottleneck, that can be a bad sign indicating lack of automation or having the wrong person do the job (developer doing the job of a data entry clerk).&lt;/li&gt;&lt;li&gt;I would like to work with a new technology on my own for a while in order to solidify my learning of it after having spent sometime pairing with someone on learning it.&lt;/li&gt;&lt;/ul&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;So to summarize, pair programming is about synergistically solving problems, not just having two developers typing on one machine. As a result, the benefits are:&lt;/div&gt;&lt;div&gt;&lt;ul&gt;&lt;li&gt;Increased productivity&lt;/li&gt;&lt;li&gt;Higher code quality, indirectly contributing to productivity in the long term.&lt;/li&gt;&lt;li&gt;Better solutions, indirectly contributing to customer satisfaction.&lt;/li&gt;&lt;li&gt;Increased team commitment&lt;/li&gt;&lt;li&gt;Continuous improvement to developer skills&lt;/li&gt;&lt;/ul&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Comments are welcome, especially to share personal experiences or ask questions about pair programming in the wild.&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/32881756-7979196781281471265?l=andymaleh.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://andymaleh.blogspot.com/feeds/7979196781281471265/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=32881756&amp;postID=7979196781281471265' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/32881756/posts/default/7979196781281471265'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/32881756/posts/default/7979196781281471265'/><link rel='alternate' type='text/html' href='http://andymaleh.blogspot.com/2010/05/pair-programming-in-wild.html' title='Pair Programming in the Wild'/><author><name>Annas "Andy" Maleh</name><uri>http://www.blogger.com/profile/10268484073612495328</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/-f6UYG8WIYJI/Tpw6vYi2nTI/AAAAAAAAAPk/ICI9GDbAxh4/s1600/7312067a2015194b853856820711a178%253Fsize%253D200'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-32881756.post-5880056451634406000</id><published>2010-05-24T08:08:00.047-05:00</published><updated>2010-06-14T14:02:19.821-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Craftsmanship'/><title type='text'>Writing good code is ALWAYS faster than writing bad code.</title><content type='html'>&lt;div&gt;"No matter who. No matter what. No matter when. Short term. Long term. Any term. Writing good code is ALWAYS faster than writing bad code." - &lt;a href="http://twitter.com/unclebobmartin/status/13745636909"&gt;Uncle Bob&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;That was a recent tweet by &lt;a href="http://www.objectmentor.com/omTeam/martin_r.html"&gt;Robert C. Martin&lt;/a&gt; who has been doing software development for more than 30 years and has written many books on the subject. &lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;I couldn't agree more. In one of the projects I was involved in, I encountered some code that developers rushed out the door quickly in two weeks without writing any tests or paying attention to how clean the code is because they felt pressured by the deadline. Needless to say, it had many bugs, so it took much longer to fix all of them and truly deliver the feature than the originally planned two weeks.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;The real irony of the matter though is I believe it would have taken no more than the two weeks originally planned if tests were written first. That is because without &lt;a href="http://www.agiledata.org/essays/tdd.html"&gt;test-driven design&lt;/a&gt;, the code was bloated and much more  complex than needed. When I later covered the code with tests and performed &lt;a href="http://en.wikipedia.org/wiki/Code_refactoring"&gt;refactorings&lt;/a&gt;, I discovered that the original code was more than double or even triple the amount of code needed with a simple clean design. In other words, it took longer to write the code without tests, and that is not counting the extra time spent tracing and fixing bugs.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Instead, developers had to get embarrassed by the large number of bugs reported, spend a long time tediously tracing through complex code to find the bugs, scramble to fix the bugs quickly, and be delayed by a few weeks in truly delivering the feature. It makes me wonder what gain they got out of not test-driving clean code in the first place given that it was an &lt;a href="http://en.wikipedia.org/wiki/Agile_software_development"&gt;Agile&lt;/a&gt; environment where everybody was already aware of the practice. &lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;I bet it was the convenience of not having to change their ways or ignorance to the true practical benefits of test-driven development. And, I have to admit, during my learning phase of test-driven development, it took me a while of swinging between doing it and abandoning it before I started seeing the futility of not doing it and truly appreciating how faster I got in developing software that way.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;To recap, I wholeheartedly agree with &lt;a href="http://www.objectmentor.com/omTeam/martin_r.html"&gt;Uncle Bob&lt;/a&gt;. Writing good code is ALWAYS faster than writing bad code.&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/32881756-5880056451634406000?l=andymaleh.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://andymaleh.blogspot.com/feeds/5880056451634406000/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=32881756&amp;postID=5880056451634406000' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/32881756/posts/default/5880056451634406000'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/32881756/posts/default/5880056451634406000'/><link rel='alternate' type='text/html' href='http://andymaleh.blogspot.com/2010/05/writing-good-code-is-always-faster-than.html' title='Writing good code is ALWAYS faster than writing bad code.'/><author><name>Annas "Andy" Maleh</name><uri>http://www.blogger.com/profile/10268484073612495328</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/-f6UYG8WIYJI/Tpw6vYi2nTI/AAAAAAAAAPk/ICI9GDbAxh4/s1600/7312067a2015194b853856820711a178%253Fsize%253D200'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-32881756.post-7167466447460248796</id><published>2010-04-16T11:58:00.007-05:00</published><updated>2010-05-14T13:52:01.035-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Tools'/><title type='text'>Unproductive developer habits</title><content type='html'>&lt;div&gt;&lt;b&gt;Updated: May 13, 2010&lt;/b&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;Ever since I switched from Java to Ruby and Windows to Mac, leaving away the powerful IDE support I had in Java (Eclipse) and the mnemonic shortcut support I had in Windows, I have been dissatisfied with the level of flow I have while writing code.&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;With Eclipse on Windows, I had the option of soaring mouse-less, not wasting an ounce of brain power on the interruption of switching to the command line, taking my hand off the keyboard to control the mouse,  or typing many characters to open a file when I could have done a quick project search with autocomplete and opened it in a breeze.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Unfortunately that is not the case on the Mac (no mnemonics) and many of the Ruby IDEs/Editors are unstable, require too much typing to perform common shortcuts, or simply miss many of the powerful navigation features I once had in Eclipse.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;What disheartens me the most though is that a lot of developers that I meet have incredibly unproductive habits and they are quite oblivious to them. Here are some examples:&lt;/div&gt;&lt;div&gt;&lt;ul&gt;&lt;li&gt;They use the mouse to do almost everything, including saving the file via a click on File and then Save (use the toolbar button at least!)&lt;/li&gt;&lt;li&gt;They have the mouse trackpad set to very slow making it further unproductive to use the mouse&lt;/li&gt;&lt;li&gt;Not knowing how to navigate or highlight with the arrow keys on the keyboard&lt;/li&gt;&lt;li&gt;Typing with two fingers only while looking at the keyboard&lt;/li&gt;&lt;li&gt;Navigating the folder structure with the mouse to open a file when they could have typed a few letters and relied on autocomplete to find it instantaneously&lt;/li&gt;&lt;li&gt;Not knowing about the jump to file shortcut for opening a highlighted class or method instantly&lt;/li&gt;&lt;li&gt;Switching tabs with the mouse instead of knowing the keyboard shortcut (CTRL+PGDN on Windows)&lt;/li&gt;&lt;li&gt;Doing find and replace with reliance on the mouse instead of a quick replace or replace all shortcut&lt;/li&gt;&lt;li&gt;Not knowing about alt mnemonics in Windows and Linux (Macs suck for not having that feature) and thus using the mouse for a lot of tasks that could have been performed with a few keyboard strokes&lt;/li&gt;&lt;li&gt;Moving files by typing extremely long commands on the command line to move a file when they could have benefited positively from the mouse for once to do quicker drag and drop&lt;/li&gt;&lt;/ul&gt;&lt;div&gt;And these are just a few that I could think of right now. &lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Yes, I've tried the Eclipse Ruby plugin, Aptana RadRails, Sun NetBeans, and IntelliJ RubyMine. Each has its own pros and cons. None brings back the holy grail days of mouse-less Java development with Eclipse. &lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;And, I am not talking about the loss of features that are achievable only with static typing. I am fine without those.What I am missing is just interruption-free navigation with the keyboard with as few strokes as possible.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;What then? Write my own Ruby editor for the Mac? Write my own plugins for VIM? Both ideas seem worthy of consideration.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;b&gt;Further Comments (May 13, 2010): &lt;/b&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Some people I talked to tried to simplify the interpretation of this blog post into blaming Ruby dynamic typing for not being productive (not true), IDEs for being bloated and making you use the mouse (not always true), or even the Mac not being shortcut friendly (not fully true either).&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;I would like to clarify that like any real situation no one thing is the sole factor to blame and none of it is black and white. This is about a combination of a lacking shortcut support in some editors/IDEs, lack of mnemonic support on the Mac (though compensating with great shell support), and lack of care about the situation by a lot of developers who are content to continue use the mouse or use inefficient shortcuts that require many keystrokes.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Also, I would like to clarify that despite all of this, I find myself much more productive in Ruby given how much less code I write (compensating for less productivity with certain things like massive refactorings). That was one of the biggest paradoxes that I encountered after I was half a dozen months down the road of programming in Ruby, which prevented me from switching back to Java. Of course, that is only given the fact that I am ruthless with test-driven development whether in Java or Ruby.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;p.s. here is a blog post on useful Eclipse shortcuts for the curious:&lt;/div&gt;&lt;div&gt;&lt;a href="http://andymaleh.blogspot.com/2009/07/mouse-less-eclipse.html"&gt;http://andymaleh.blogspot.com/2009/07/mouse-less-eclipse.html&lt;/a&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/32881756-7167466447460248796?l=andymaleh.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://andymaleh.blogspot.com/feeds/7167466447460248796/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=32881756&amp;postID=7167466447460248796' title='6 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/32881756/posts/default/7167466447460248796'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/32881756/posts/default/7167466447460248796'/><link rel='alternate' type='text/html' href='http://andymaleh.blogspot.com/2010/04/unproductive-developer-habits.html' title='Unproductive developer habits'/><author><name>Annas "Andy" Maleh</name><uri>http://www.blogger.com/profile/10268484073612495328</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/-f6UYG8WIYJI/Tpw6vYi2nTI/AAAAAAAAAPk/ICI9GDbAxh4/s1600/7312067a2015194b853856820711a178%253Fsize%253D200'/></author><thr:total>6</thr:total></entry><entry><id>tag:blogger.com,1999:blog-32881756.post-1058740343217641654</id><published>2010-03-07T12:49:00.035-06:00</published><updated>2010-03-07T13:33:54.505-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Craftsmanship'/><title type='text'>Revisiting Software Craftsmanship vs Engineering</title><content type='html'>&lt;div&gt;With the emerging software craftsmanship movement, I have been noticing a lot of confusion out there as to what it is, whether it has any value at all or is just another fad, and whether it is the new silver bullet that trumps the older ways. &lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;To help sort some of the confusion out, I wrote a blog post last year titled: &lt;a href="http://andymaleh.blogspot.com/2008/12/software-craftsmanship-vs-software.html"&gt;Software Craftsmanship vs Software Engineering&lt;/a&gt;.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Did my opinion change since that blog post?&lt;/div&gt;&lt;br /&gt;So much has changed in the craftsmanship world since then, especially given that &lt;a href="http://obtiva.com/"&gt;Obtiva&lt;/a&gt;, the Chicago agile consulting company I work with, hosted the first Software Craftsmanship conference here in Chicago, which ran at the same time as the Agile 2009 conference. And as a result, I certainly learned a few new things about the differences and similarities between software craftsmanship and engineering.&lt;div&gt;&lt;br /&gt;Let's start with the summary of last year's blog post:&lt;br /&gt;&lt;blockquote&gt;&lt;span style="font-style:italic;"&gt;... Software Engineering is not about over-engineering or heavy-weight processes like Waterfall; it is about delivering economical software that is reliable and efficient. Software Craftsmanship is therefore not in conflict with Software Engineering, yet in fact in harmony with it as it helps accomplish its goal through practical learning of software development with the guidance of experienced developers.&lt;/span&gt;&lt;/blockquote&gt;Since that conclusion, a few more differences have emerged:&lt;ul&gt;&lt;li&gt;Engineers often seem to believe that they can completely streamline the process of building software, with complete control and predictability. And, this belief seems to be process independent. In other words, even engineers who are strong advocates of agile often believe that if you do a, b, and c, you will get the results you want.&lt;/li&gt;&lt;li&gt;Engineers often think that one has to learn all, most, or many best practices before successfully building software.&lt;/li&gt;&lt;li&gt;Some engineers seem to think that best practices apply everywhere or in every situation. More experienced engineers are aware that different contexts require different best practices though.&lt;/li&gt;&lt;/ul&gt;On the other hand, here are some observations I made from observing developers who have not had much software engineering background and thus have a bit more laissez-faire attitude that leans towards learning your skills through craftsmanship as opposed to a systematic study of best practices:&lt;ul&gt;&lt;li&gt;Craftsmen see software development more as an art that emerges and less as a science that can be controlled, so they let time and experience shape up their skills in successfully completing software projects.&lt;/li&gt;&lt;li&gt;Craftsmen often discover their own best practices from their experiences, which often better fit their situations.&lt;/li&gt;&lt;li&gt;Craftsmen do not religiously follow even their own best practices, often transcending them when they do not make sense in a new situation anymore. They thus rely more on their intuition and gut feelings to succeed.&lt;/li&gt;&lt;/ul&gt;&lt;/div&gt;&lt;div&gt;It was not easy for me to spot these differences. They only started to become apparent after observing the way our top craftsmen at Obtiva have worked over the last year. After all, they often relied more on common sense and experienced intuition than industry best practices, and yet still succeeded at delivery as demonstrated by Mad Mimi (http://www.madmimi.com) for example.&lt;br /&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;Even Tom DeMarco, one of the early key figures in the software engineering world, famous for the quote "You cannot control what you cannot measure", recently renounced the controlled development approach in an &lt;a href="http://www.computer.org/portal/web/computingnow/0709/whatsnew/software-r"&gt;article&lt;/a&gt; posted by the IEEE, titled &lt;a href="http://www.computer.org/portal/web/computingnow/0709/whatsnew/software-r"&gt;"Software Engineering: An Idea Whose Time Has Come and Gone?"&lt;/a&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;Although I noticed these differences, let me clarify that nothing in software engineering's original definition or goals necessarily states that you must follow certain best practices or processes to succeed. It just happened that people who adopted the software engineering approach tended to gravitate more towards a controlled measured fashion to software development.&lt;br /&gt;&lt;br /&gt;For example, one of the common practices in &lt;a href="http://www.extremeprogramming.org/"&gt;eXtreme Programming&lt;/a&gt; is to develop features within iterations and then measure the velocity at the end of each iteration in order to determine your velocity and have a better estimate for your stakeholders. Software engineers following that process would often take that practice as gospel and believe that you will not succeed unless you build your software iteratively and measure velocity consistently. I know I have made that assumption in the past, and did not change my mind till I saw projects that succeeded without any iterative scheduling or measuring.&lt;br /&gt;&lt;br /&gt;As a software engineer who likes to question everything, I definitely wondered why. If I were to solve this following the software engineering discipline, I may ask what is the cost of iterative planning and what are the benefits offered by it? Then, I would check our current environment and see if it fits the cost/benefit of iterative planning. Though this is an important software engineering practice, many engineers often forget about it and just follow a process blindly out of comfort and past experience with it.&lt;br /&gt;&lt;br /&gt;To bring it back to my example, if the project is in the maintenance phase and all what the stakeholders want is bug fixes and tiny feature additions here and there, then why would they need to know the team velocity or do iterative development at all? The &lt;a href="http://agileproductdesign.com/blog/2009/kanban_over_simplified.html"&gt;Kanban&lt;/a&gt; approach, which loses them the benefit of more accurate estimation, may fit them better since most software changes at that point would take no longer than two weeks anyways if not just a couple of days.&lt;br /&gt;&lt;br /&gt;However, as you notice, I was able to figure that out by applying software engineering disciplines only without having craftsmanship come into play. So, how does software craftsmanship fit into the story?&lt;br /&gt;&lt;br /&gt;Well, as stated before, software craftsmen often learn their best practices from their environment, their personal experiences, and their mentor's experiences. So, if an apprentice worked in some environment where most projects were in maintenance mode and far-term planning was rarely necessary, they would naturally succeed without any iterative development or velocity measuring, which may potentially baffle even some of the most experienced software engineers. However, the moment they hit a green field project, they will realize that their older methods are not working anymore because the stakeholders now need to know how long the next 20+ features will take for budget reasons. That is when they are forced to learn a new estimation approach, such as iterative velocity-based estimation.&lt;br /&gt;&lt;br /&gt;So whereas software engineering teaches you to learn as many best practices as available out there and gain the skill of analyzing any situation objectively to prescriptively apply the best practice that fits, software craftsmanship actually encourages you to learn best practices gradually out of your own experiences and mentor experiences, and thus naturally apply the best practices that fit without much analysis.&lt;br /&gt;&lt;br /&gt;So, what are the trade-offs between these two approaches?&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;With software engineering, you have to work really hard at learning processes, best practices, and analysis techniques, and then spend quite some time gaining applied experience, before you can be a good software engineer. However, once you have gone through that hump, you have a very wide perspective on how software can be developed, which will make your opinion quite valuable to your team.&lt;/li&gt;&lt;li&gt;On the other hand, with software craftsmanship, you can start developing production quality software much quicker by apprenticing with a few experienced craftsmen and learning the ways that worked for them and their projects. That will keep you motivated to keep learning and thus widening your perspective gradually to the different software development methods out there. The trade-off though is you may end up having to fail really hard at applying a practice that does not work anymore in a new situation before you learn another way. That happens even though the better way may have been discovered 15 years ago by other people who have faced the same situation long ago.&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;In any case, one of the things that experience has taught me over the years is to try to stay as unbiased and detached as possible from any approach instead of defining myself through one. So although I have a master degree in software engineering, that does not stop me from learning the ways of software craftsmanship or becoming a software craftsman myself. And, I encourage you to do the same.&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/32881756-1058740343217641654?l=andymaleh.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://andymaleh.blogspot.com/feeds/1058740343217641654/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=32881756&amp;postID=1058740343217641654' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/32881756/posts/default/1058740343217641654'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/32881756/posts/default/1058740343217641654'/><link rel='alternate' type='text/html' href='http://andymaleh.blogspot.com/2010/03/revisiting-software-craftsmanship-vs.html' title='Revisiting Software Craftsmanship vs Engineering'/><author><name>Annas "Andy" Maleh</name><uri>http://www.blogger.com/profile/10268484073612495328</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/-f6UYG8WIYJI/Tpw6vYi2nTI/AAAAAAAAAPk/ICI9GDbAxh4/s1600/7312067a2015194b853856820711a178%253Fsize%253D200'/></author><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-32881756.post-4665834349700936414</id><published>2009-11-27T11:55:00.010-06:00</published><updated>2009-11-27T12:28:48.153-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Ruby'/><category scheme='http://www.blogger.com/atom/ns#' term='Eclipse'/><category scheme='http://www.blogger.com/atom/ns#' term='Glimmer'/><title type='text'>Invoking Glimmer Tests and Specs via Rake</title><content type='html'>As part of implementing the &lt;a href="http://andymaleh.blogspot.com/2009/11/conways-game-of-life-glimmer-edition.html"&gt;Game of Life UI in Glimmer&lt;/a&gt;, I actually updated Glimmer's Rakefile to invoke all tests successfully. Since the Game of Life domain logic was test-driven with RSpec, I also had Rakefile invoke both specs and regular unit-tests with the default command: jrake (the j is needed because Glimmer runs on jRuby instead of Ruby)&lt;br /&gt;&lt;br /&gt;"jrake spec" invokes specs alone.&lt;br /&gt;"jrake test" invokes unit-tests alone.&lt;br /&gt;&lt;br /&gt;More improvement and changes are coming Glimmer's way including an attractive image on &lt;a href="http://www.eclipse.org/glimmer/"&gt;the landing page&lt;/a&gt;:&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_XQt1Vabxo5g/SxAaVySVQ0I/AAAAAAAAAMg/EPsJt_NkuPc/s1600/Bitter-sweet.jpg"&gt;&lt;img style="cursor:pointer; cursor:hand;width: 400px; height: 400px;" src="http://3.bp.blogspot.com/_XQt1Vabxo5g/SxAaVySVQ0I/AAAAAAAAAMg/EPsJt_NkuPc/s400/Bitter-sweet.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5408852114050204482" /&gt;&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/32881756-4665834349700936414?l=andymaleh.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://andymaleh.blogspot.com/feeds/4665834349700936414/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=32881756&amp;postID=4665834349700936414' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/32881756/posts/default/4665834349700936414'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/32881756/posts/default/4665834349700936414'/><link rel='alternate' type='text/html' href='http://andymaleh.blogspot.com/2009/11/invoking-glimmer-tests-and-specs-via.html' title='Invoking Glimmer Tests and Specs via Rake'/><author><name>Annas "Andy" Maleh</name><uri>http://www.blogger.com/profile/10268484073612495328</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/-f6UYG8WIYJI/Tpw6vYi2nTI/AAAAAAAAAPk/ICI9GDbAxh4/s1600/7312067a2015194b853856820711a178%253Fsize%253D200'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/_XQt1Vabxo5g/SxAaVySVQ0I/AAAAAAAAAMg/EPsJt_NkuPc/s72-c/Bitter-sweet.jpg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-32881756.post-217608276567458809</id><published>2009-11-26T15:00:00.000-06:00</published><updated>2009-11-26T15:14:07.374-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Ruby'/><category scheme='http://www.blogger.com/atom/ns#' term='Eclipse'/><category scheme='http://www.blogger.com/atom/ns#' term='Glimmer'/><title type='text'>Conway's Game of Life - Glimmer Edition</title><content type='html'>I recently attended a Chicago Ruby group meeting where everybody paired up on implementing a version of Conway's Game of Life in Ruby. At the end of the meeting, the logic of the game was completely test-driven and ready for use, so I decided to slap on a Glimmer UI on top of it afterward:&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_XQt1Vabxo5g/Sw7tGh03HRI/AAAAAAAAAMY/SMISf4ZqoYA/s1600/Picture+7.png"&gt;&lt;img style="cursor:pointer; cursor:hand;width: 400px; height: 386px;" src="http://2.bp.blogspot.com/_XQt1Vabxo5g/Sw7tGh03HRI/AAAAAAAAAMY/SMISf4ZqoYA/s400/Picture+7.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5408520898933628178" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Here is Glimmer's repository:&lt;br /&gt;&lt;a href="http://dev.eclipse.org/svnroot/technology/org.eclipse.glimmer.core/"&gt;http://dev.eclipse.org/svnroot/technology/org.eclipse.glimmer.core/&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Here are the tests written with RSpec:&lt;br /&gt;&lt;a href="http://dev.eclipse.org/svnroot/technology/org.eclipse.glimmer.core/spec/samples/game_of_life/"&gt;http://dev.eclipse.org/svnroot/technology/org.eclipse.glimmer.core/spec/samples/game_of_life/&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;And, here is the implementation:&lt;br /&gt;&lt;a href="http://dev.eclipse.org/svnroot/technology/org.eclipse.glimmer.core/samples/game_of_life/"&gt;http://dev.eclipse.org/svnroot/technology/org.eclipse.glimmer.core/samples/game_of_life/&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;The game logic is in grid.rb and cell.rb whereas the UI code is in game_of_life.rb. cell_presenter.rb provides the presenter needed for &lt;a href="http://andymaleh.blogspot.com/2008/02/table-data-binding-and-mvp-in-glimmer.html"&gt;data-binding with the MVP pattern&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;Here is how the Glimmer UI code looks like:&lt;br /&gt;&lt;br /&gt;width = 7&lt;br /&gt;height = 7&lt;br /&gt;grid = Grid.new(width, height)&lt;br /&gt;shell {&lt;br /&gt;&amp;nbsp;&amp;nbsp;text "Conway's Game of Life (Glimmer Edition)"&lt;br /&gt;&amp;nbsp;&amp;nbsp;composite {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;layout GridLayout.new(width,true) &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;(0...width).each { |x|&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;(0...height).each { |y|&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;button {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;layout_data GridData.new(fill, fill, true, true)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;text        bind(CellPresenter.new(grid, x, y), :alive)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;on_widget_selected {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;grid.toggle_aliveness!(x, y)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;button {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;text "Step"&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;on_widget_selected {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;grid.step!&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}&lt;br /&gt;&amp;nbsp;&amp;nbsp;}&lt;br /&gt;}.open&lt;br /&gt;&lt;br /&gt;It simply iterates over the Game of Life grid cells, wrapping each with a presenter and binding it to a button in the UI:&lt;br /&gt;text        bind(CellPresenter.new(grid, x, y), :alive)&lt;br /&gt;&lt;br /&gt;When a button is clicked, the cell aliveness is toggled to "alive" (showing 'o') or "dead". This enables player to lay out the grid of cells:&lt;br /&gt;on_widget_selected {&lt;br /&gt;&amp;nbsp;&amp;nbsp;grid.toggle_aliveness!(x, y)&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;Finally, to step the game, there is a "Step" button that steps the grid into the next generation, resulting in cells that die, new cells born, and cells that simply continue to be alive:&lt;br /&gt;button {&lt;br /&gt;&amp;nbsp;&amp;nbsp;text "Step"&lt;br /&gt;&amp;nbsp;&amp;nbsp;on_widget_selected {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;grid.step!&lt;br /&gt;&amp;nbsp;&amp;nbsp;}&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;One thing that is noteworthy is that Glimmer's support for data-binding greatly facilitated the decoupling of the UI from the domain logic enabling us to write our domain code in full isolation of the UI, and later adding the UI and its related presentation logic via the Glimmer UI DSL and the presenter.&lt;br /&gt;&lt;br /&gt;Hit me up with comments or an email if you have any questions. &lt;br /&gt;&lt;br /&gt;Happy thanksgiving!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/32881756-217608276567458809?l=andymaleh.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://andymaleh.blogspot.com/feeds/217608276567458809/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=32881756&amp;postID=217608276567458809' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/32881756/posts/default/217608276567458809'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/32881756/posts/default/217608276567458809'/><link rel='alternate' type='text/html' href='http://andymaleh.blogspot.com/2009/11/conways-game-of-life-glimmer-edition.html' title='Conway&apos;s Game of Life - Glimmer Edition'/><author><name>Annas "Andy" Maleh</name><uri>http://www.blogger.com/profile/10268484073612495328</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/-f6UYG8WIYJI/Tpw6vYi2nTI/AAAAAAAAAPk/ICI9GDbAxh4/s1600/7312067a2015194b853856820711a178%253Fsize%253D200'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/_XQt1Vabxo5g/Sw7tGh03HRI/AAAAAAAAAMY/SMISf4ZqoYA/s72-c/Picture+7.png' height='72' width='72'/><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-32881756.post-6279343052288738708</id><published>2009-11-24T18:56:00.012-06:00</published><updated>2009-11-24T19:30:35.140-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Ruby'/><category scheme='http://www.blogger.com/atom/ns#' term='Craftsmanship'/><category scheme='http://www.blogger.com/atom/ns#' term='Agile Methodologies'/><title type='text'>Conditionals in Unit Tests</title><content type='html'>One of the questions newcomers to TDD (Test-Driven Development) often ask is: &lt;i&gt;how can I trust test code to be correct?&lt;/i&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Well, the reality is that it is not black and white. Not every instance of implementation code is prone to bugs (think getters and setters) and not every instance of test code is perfectly free of bugs. However, as software engineers, we are more concerned with the practical aspects of software development, and experience seems to indicate that if you write your test code in a linear fashion without using conditionals, then it is less prone to having bugs, and thus can serve as a useful tool in driving reliable implementation code as per the requirements specified.&lt;/div&gt; &lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Back to the question: &lt;i&gt;how can I trust test code to be correct?&lt;/i&gt;&lt;/div&gt;&lt;div&gt;&lt;i&gt;&lt;br /&gt;&lt;/i&gt;&lt;/div&gt;&lt;div&gt;Test code often follows this structure:&lt;/div&gt;&lt;div&gt;&lt;ul&gt;&lt;li&gt;Pre-conditions setup&lt;/li&gt;&lt;li&gt;Action being tested&lt;/li&gt;  &lt;li&gt;Post-condition verification&lt;/li&gt;&lt;/ul&gt;&lt;div&gt;For example (in Ruby):&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;# pre-conditions&lt;/div&gt;&lt;div&gt;time = Time.new&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;# action&lt;/div&gt;&lt;div&gt;hours = time.hours_between(9am, 2pm)&lt;/div&gt; &lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;# post-conditions (specified with &lt;a href="http://rspec.info/"&gt;RSpec&lt;/a&gt;)&lt;/div&gt;&lt;div&gt;hours.should == [9am, 10am, 11am, 12pm, 1pm, 2pm]&lt;br /&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Since that code is linear and free of conditionals, if it parses successfully, it generally expresses what it says without much ambiguity and thus has very little chance for error. &lt;/div&gt;  &lt;div&gt;&lt;br /&gt;Now, let's look at a version of the implementation after a few tests have been written:&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;def hours_between(start_time, end_time)&lt;/div&gt;&lt;div&gt;&amp;nbsp;&amp;nbsp;(numeric_time(start_time) .. numeric_time(end_time)).map do |numeric_time|&lt;/div&gt; &lt;div&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;textual_time(numeric_time)&lt;/div&gt;&lt;div&gt;&amp;nbsp;&amp;nbsp;end&lt;/div&gt;&lt;div&gt;end&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;def numeric_time(time)&lt;/div&gt;&lt;div&gt;&amp;nbsp;&amp;nbsp;meridian_indicator = time[-2..-1]&lt;/div&gt;&lt;div&gt;&amp;nbsp;&amp;nbsp;numeric_time = time.delete(meridian_indicator).to_i&lt;/div&gt; &lt;div&gt;&amp;nbsp;&amp;nbsp;numeric_time = meridian_indicator == "am" ? numeric_time : numeric_time + 12&lt;/div&gt;&lt;div&gt;&amp;nbsp;&amp;nbsp;numeric_time = 0 if numeric_time == 24&lt;/div&gt;&lt;div&gt;&amp;nbsp;&amp;nbsp;numeric_time&lt;/div&gt;&lt;div&gt;end&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;def textual_time(numeric_time)&lt;/div&gt; &lt;div&gt;&amp;nbsp;&amp;nbsp;meridian_indicator = numeric_time &amp;lt; 12 ? "am" : "pm"&lt;/div&gt;&lt;div&gt;&amp;nbsp;&amp;nbsp;textual_time= numeric_time &amp;lt; 12 ? numeric_time.to_s : (numeric_time - 12).to_s&lt;/div&gt;&lt;div&gt;&amp;nbsp;&amp;nbsp;textual_time= "12am" if textual_time == "0am"&lt;/div&gt; &lt;div&gt;&amp;nbsp;&amp;nbsp;textual_time+ meridian_indicator&lt;/div&gt;&lt;div&gt;end&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Do you notice how much complexity there is with reading statements that involve conditionals. It's doable, but definitely takes work despite how factored the code is. &lt;/div&gt; &lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Note that the implemented functionality is not entirely correct as it only works if the range specified is between 1am and 11pm. More tests need to be written to drive the rest of the implementation. However, given that tests do not have any conditionals, they provide us with an automated way of testing that our implementation works according to plan.&lt;/div&gt; &lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;So, avoid conditionals in unit tests, and you will benefit from them in implementing more reliable code.&lt;/div&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/32881756-6279343052288738708?l=andymaleh.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://andymaleh.blogspot.com/feeds/6279343052288738708/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=32881756&amp;postID=6279343052288738708' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/32881756/posts/default/6279343052288738708'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/32881756/posts/default/6279343052288738708'/><link rel='alternate' type='text/html' href='http://andymaleh.blogspot.com/2009/11/conditionals-in-unit-tests.html' title='Conditionals in Unit Tests'/><author><name>Annas "Andy" Maleh</name><uri>http://www.blogger.com/profile/10268484073612495328</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/-f6UYG8WIYJI/Tpw6vYi2nTI/AAAAAAAAAPk/ICI9GDbAxh4/s1600/7312067a2015194b853856820711a178%253Fsize%253D200'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-32881756.post-8995853171199971390</id><published>2009-11-06T10:16:00.007-06:00</published><updated>2009-11-08T13:07:48.536-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='User Experience'/><category scheme='http://www.blogger.com/atom/ns#' term='Conferences'/><title type='text'>Social Dev Camp - Iterative Prototyping: Discover Your Interface Sooner!</title><content type='html'>&lt;span style="font-weight:bold;"&gt;Updated Nov 8, 2009&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;I'm giving a presentation at &lt;a href="http://barcamp.pbworks.com/SocialDevCampChicago"&gt;Social Dev Camp / Chicago&lt;/a&gt; this Sunday at 2:30PM.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Title:&lt;/span&gt; &lt;br /&gt;&lt;br /&gt;Iterative Prototyping: &lt;span style="font-style:italic;"&gt;Discover Your Interface Sooner!&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Abstract:&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Iterative incremental design of software is great as it helps developers discover how to build their applications gradually with small low-risk steps followed by user acceptance testing. However, why limit this agile approach to writing code? This same technique can be applied to user interfaces too during the early conceptual stages of design, enabling ability to make changes in hours instead of weeks since it is done to paper instead of code. For example, can you think how much more time it would take to redesign each page in MySpace to look more like Facebook if it is already coded vs when it was still on paper? Come to this talk to learn the basics of Iterative Prototyping and how you can apply this valuable tool to achieve better user experience.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/32881756-8995853171199971390?l=andymaleh.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://andymaleh.blogspot.com/feeds/8995853171199971390/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=32881756&amp;postID=8995853171199971390' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/32881756/posts/default/8995853171199971390'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/32881756/posts/default/8995853171199971390'/><link rel='alternate' type='text/html' href='http://andymaleh.blogspot.com/2009/11/social-dev-camp-paper-prototyping.html' title='Social Dev Camp - Iterative Prototyping: Discover Your Interface Sooner!'/><author><name>Annas "Andy" Maleh</name><uri>http://www.blogger.com/profile/10268484073612495328</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/-f6UYG8WIYJI/Tpw6vYi2nTI/AAAAAAAAAPk/ICI9GDbAxh4/s1600/7312067a2015194b853856820711a178%253Fsize%253D200'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-32881756.post-6010188822026410528</id><published>2009-10-19T14:15:00.002-05:00</published><updated>2009-10-19T14:17:59.659-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Craftsmanship'/><title type='text'>Polyglot Programmers: Hello, and Beyond.</title><content type='html'>This might be of interest to developers in the Chicago area who are always&lt;br /&gt;checking out new languages and technologies.&lt;br /&gt;&lt;br /&gt;The Polyglot Programmers of Chicago are meeting this Thursday at 6PM&lt;br /&gt;to see a talk by Clyde Forrester titled "Hello, and Beyond".&lt;br /&gt;&lt;br /&gt;Abstract:&lt;br /&gt;&lt;br /&gt;"When learning a new programming language or testing a new&lt;br /&gt;environment, one commonly runs the "Hello" program, which simply puts&lt;br /&gt;"Hello" on the screen. Some, like me, do not progress beyond that in&lt;br /&gt;great leaps, but must define deliberate small steps to understand new&lt;br /&gt;languages and additional functionality. To help with this, I am&lt;br /&gt;gradually building a set of exercises and implementations in many&lt;br /&gt;computer languages. I will present what I have so far, as well as the&lt;br /&gt;significant problems I have encountered, and some lessons learned."&lt;br /&gt;&lt;br /&gt;When: Thursday, October 22, 2009, 6:00-8:00&lt;br /&gt;Where: Obtiva, 566 W. Adams St., Suite 400, Chicago, IL&lt;br /&gt;Eating: Giordano's Pizza&lt;br /&gt;&lt;br /&gt;Link: &lt;a href="http://polyglotprogrammers.com/usa/illinois/chicago/200910.html"&gt; http://polyglotprogrammers.com/usa/illinois/chicago/200910.html&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/32881756-6010188822026410528?l=andymaleh.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://andymaleh.blogspot.com/feeds/6010188822026410528/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=32881756&amp;postID=6010188822026410528' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/32881756/posts/default/6010188822026410528'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/32881756/posts/default/6010188822026410528'/><link rel='alternate' type='text/html' href='http://andymaleh.blogspot.com/2009/10/polyglot-programmers-hello-and-beyond.html' title='Polyglot Programmers: Hello, and Beyond.'/><author><name>Annas "Andy" Maleh</name><uri>http://www.blogger.com/profile/10268484073612495328</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/-f6UYG8WIYJI/Tpw6vYi2nTI/AAAAAAAAAPk/ICI9GDbAxh4/s1600/7312067a2015194b853856820711a178%253Fsize%253D200'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-32881756.post-3532384418371239397</id><published>2009-09-23T14:20:00.001-05:00</published><updated>2009-09-23T14:22:16.666-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Ruby'/><category scheme='http://www.blogger.com/atom/ns#' term='Eclipse'/><category scheme='http://www.blogger.com/atom/ns#' term='Glimmer'/><title type='text'>Glimmer Webinar Video</title><content type='html'>Here is a video of the Glimmer Webinar I gave today:&lt;br /&gt;&lt;a href="http://live.eclipse.org/node/792"&gt;http://live.eclipse.org/node/792&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Enjoy!&lt;br /&gt;&lt;br /&gt;And, email me any questions you have.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/32881756-3532384418371239397?l=andymaleh.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://andymaleh.blogspot.com/feeds/3532384418371239397/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=32881756&amp;postID=3532384418371239397' title='6 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/32881756/posts/default/3532384418371239397'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/32881756/posts/default/3532384418371239397'/><link rel='alternate' type='text/html' href='http://andymaleh.blogspot.com/2009/09/glimmer-webinar-video.html' title='Glimmer Webinar Video'/><author><name>Annas "Andy" Maleh</name><uri>http://www.blogger.com/profile/10268484073612495328</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/-f6UYG8WIYJI/Tpw6vYi2nTI/AAAAAAAAAPk/ICI9GDbAxh4/s1600/7312067a2015194b853856820711a178%253Fsize%253D200'/></author><thr:total>6</thr:total></entry><entry><id>tag:blogger.com,1999:blog-32881756.post-5091233811302612999</id><published>2009-09-22T09:13:00.004-05:00</published><updated>2009-09-22T09:18:00.729-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Ruby'/><category scheme='http://www.blogger.com/atom/ns#' term='Eclipse'/><category scheme='http://www.blogger.com/atom/ns#' term='Glimmer'/><title type='text'>Webinar: Simplifying Desktop Development with Glimmer</title><content type='html'>&lt;span style="font-weight: bold;"&gt;Webinar:&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Simplifying Desktop Development with Glimmer&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Link:&lt;/span&gt;&lt;br /&gt;&lt;a href="http://live.eclipse.org/node/792"&gt;&lt;br /&gt;http://live.eclipse.org/node/792&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;" class="field-label"&gt;Abstract:&lt;br /&gt;&lt;/span&gt; &lt;span class="field-item"&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;Programming SWT/JFace user-interfaces in Java often involves a lot of repetitive boiler-plate code that is overly verbose and hard to map to the user-interface visually. This can significantly hinder maintainability and productivity for Eclipse RCP projects.&lt;/p&gt;  &lt;p&gt;Enter Glimmer; a JRuby API for SWT that takes advantage of the expressive Ruby language to provide a simple user-interface DSL (domain-specific language). Developers can rely on Glimmer to build the presentation layer of desktop applications in Ruby while keeping the business logic in Java, or alternatively do complete desktop application development in Ruby. Glimmer comes with built-in data-binding support to greatly facilitate writing maintainable and testable desktop application code.&lt;/p&gt;   &lt;p&gt;In this webinar, I will introduce Glimmer, demo the latest features by contrasting the code of an application written in both Glimmer and classic SWT, provide a quick update on the status of the project and finally, have a Q&amp;amp;A and feedback session.&lt;/p&gt;  &lt;p&gt;Total running time will be approximately 1 hour&lt;/p&gt;  &lt;p&gt;9:00 am PDT / 12:00 pm EDT / 4:00 pm GMT - &lt;a href="http://www.timeanddate.com/worldclock/fixedtime.html?month=9&amp;amp;day=23&amp;amp;year=2009&amp;amp;hour=16&amp;amp;min=0&amp;amp;sec=0&amp;amp;p1=0" target="”blank”"&gt;Convert to other time zones&lt;/a&gt;&lt;/p&gt;&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/32881756-5091233811302612999?l=andymaleh.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://andymaleh.blogspot.com/feeds/5091233811302612999/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=32881756&amp;postID=5091233811302612999' title='5 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/32881756/posts/default/5091233811302612999'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/32881756/posts/default/5091233811302612999'/><link rel='alternate' type='text/html' href='http://andymaleh.blogspot.com/2009/09/webinar-simplifying-desktop-development.html' title='Webinar: Simplifying Desktop Development with Glimmer'/><author><name>Annas "Andy" Maleh</name><uri>http://www.blogger.com/profile/10268484073612495328</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/-f6UYG8WIYJI/Tpw6vYi2nTI/AAAAAAAAAPk/ICI9GDbAxh4/s1600/7312067a2015194b853856820711a178%253Fsize%253D200'/></author><thr:total>5</thr:total></entry><entry><id>tag:blogger.com,1999:blog-32881756.post-1132873335244888012</id><published>2009-09-01T12:35:00.013-05:00</published><updated>2009-09-01T14:49:14.429-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Mobile'/><category scheme='http://www.blogger.com/atom/ns#' term='Technologies'/><title type='text'>Palm webOS Development First Impression</title><content type='html'>Yesterday, I got a chance to pair-program on a &lt;a href="http://www.palm.com/us/products/phones/pre/"&gt;Palm Pre&lt;/a&gt; application with my colleague Roy Kolak, author of the iPhone music bookmarking application &lt;a href="http://www.vimeo.com/5701304"&gt;NoteWorthy&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;The application being built connects to a web service in order to list media offerings available for playback on the device.&lt;br /&gt;&lt;br /&gt;Given my non-existent experience with development on the Palm Pre or any mobile device for that matter, I was a little worried about the learning curve, but I was delightfully surprised by how productive I was in helping Roy with the application.&lt;br /&gt;&lt;br /&gt;While a part of the reason is Roy's good &lt;a href="http://andymaleh.blogspot.com/2009/03/agile-2009-talk-pairing-parody.html"&gt;pairing skills&lt;/a&gt;, like explaining things before jumping into code, listening to all questions and suggestions openly, and taking turns driving with the keyboard, another big factor was certainly the &lt;a href="http://developer.palm.com/"&gt;Mojo SDK&lt;/a&gt;, which enabled me to leverage my existing Javascript/XHTML/CSS web development skills to write code for the Palm webOS without having to learn any new languages.&lt;br /&gt;&lt;br /&gt;Additionally, Roy factored the code in such a way that maximizes separation of business logic from the view, enabling us to do true test-driven development with &lt;a href="http://jania.pe.kr/aw/moin.cgi/JSSpec"&gt;JSSpec&lt;/a&gt; (a Javascript spin-off of Ruby's famous &lt;a href="http://rspec.info/"&gt;rspec&lt;/a&gt;). In fact, the Mojo SDK encourages code structure that follows a variation of the familiar MVC pattern.&lt;br /&gt;&lt;br /&gt;I asked Roy what he thought of development on the webOS in comparison to the iPhone OS. His response was that it took him several months to truly get how things worked with iPhone development whereas it took him less than a month to figure out Palm webOS development.&lt;br /&gt;&lt;br /&gt;Palm sure has a lot of inertia to go against with its platform as the iPhone is a lot more mature and has a very big following. But, given that development on the webOS takes a fraction of the time of that on the iPhone OS, will the platform pay off for Palm in the long term? Only time will tell.&lt;br /&gt;&lt;br /&gt;In any case, thanks to Palm's engineers for building such an elegant platform for us developers to quickly deliver value to consumers.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/32881756-1132873335244888012?l=andymaleh.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://andymaleh.blogspot.com/feeds/1132873335244888012/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=32881756&amp;postID=1132873335244888012' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/32881756/posts/default/1132873335244888012'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/32881756/posts/default/1132873335244888012'/><link rel='alternate' type='text/html' href='http://andymaleh.blogspot.com/2009/09/palm-pre-webos-development-first.html' title='Palm webOS Development First Impression'/><author><name>Annas "Andy" Maleh</name><uri>http://www.blogger.com/profile/10268484073612495328</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/-f6UYG8WIYJI/Tpw6vYi2nTI/AAAAAAAAAPk/ICI9GDbAxh4/s1600/7312067a2015194b853856820711a178%253Fsize%253D200'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-32881756.post-1888242233866139752</id><published>2009-08-26T10:35:00.023-05:00</published><updated>2009-08-26T17:42:52.868-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Conferences'/><category scheme='http://www.blogger.com/atom/ns#' term='Craftsmanship'/><title type='text'>Software Craftsmanship North America Conference Coverage</title><content type='html'>Last updated at 5:42PM&lt;br /&gt;&lt;br /&gt;I am at the &lt;a href="http://scna.softwarecraftsmanship.org/schedule"&gt;Software Craftsmanship North America conference&lt;/a&gt; in Chicago, USA.&lt;br /&gt;&lt;br /&gt;I will be doing live coverage of the conference in this blog post, so do not be jarred if the content gets updated often.&lt;br /&gt;&lt;br /&gt;Here is a twitter stream about it too:&lt;br /&gt;&lt;a href="http://twitter.com/#search?q=%23scna%20AndyMaleh"&gt;http://twitter.com/#search?q=%23scna%20AndyMaleh&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Ken Auer kicked off the conference with a spectacular story about his upbringing both in and out of the software industry. He then proceeded to transition it to software craftsmanship and how he concluded that it is his favorite model for excelling in improving software development skills.&lt;br /&gt;&lt;br /&gt;The first talk I attended was "There and Back Again" by Dave Astels, who recently left Google to join EngineYard, a very promising Rails hosting enterprise. His talk kicked off with a Software Craftsmanship version of the Star Wars rolling movie intro. The main emphasis of the talk is for developers to stick with technical work no matter how many ranks they ascend. Those who turn into complete managers cross to the dark side. In fact, that was partially why Dave left Google himself. He did not want to lose touch with the industry so he seeked more technical software work.&lt;br /&gt;&lt;br /&gt;Next, I attended "Demonstrating Responsibility: The Mindset of Craftsmanship" by Christopher Avery. This was a talk on how taking responsibility is a key factor in succeeding with software development projects. Whether the process is agile or whatever new buzzword is out there. If team members are not taking responsibility, the chance of excelling and delivering is much lower.&lt;br /&gt;&lt;br /&gt;Christopher mentioned the different emotional states people pass through when confronted with problems (sometimes skipping some) as a coping mechanism:&lt;br /&gt;&lt;br /&gt;Denial &gt; Lay Blame &gt; Justify &gt; Shame &gt; Obligation&lt;br /&gt;&lt;br /&gt;These states get in the way of being responsible, which gets in the way of solving problems and learning. In order to get through the states quickly towards responsibility, Christopher recommended adopting these attitudes:&lt;br /&gt;Intention - The Winning Key: intending to recognize current emotional state and get beyond it&lt;br /&gt;Awareness - The Change Key: being aware of current emotional state&lt;br /&gt;Confront - The Truth Key: confronting current emotional state&lt;br /&gt;&lt;br /&gt;Afterwards, I went to Jim Weirich's talk "Grand Unified Theory of Software Design". After quizzing the audience on common software design best practices such as DRY, SOLID, Law of Demeter, etc..., he proceeds to compare these practices to the early upbringing of physics and how there were many different theories in it before they were recently unified (partially) under M-Theory and Super-String Theory. He was wondering if he could do the same with software design principles, and his conclusion was that all principles seem to step from wanting to minimize &lt;span class="status-body"&gt;&lt;span id="msgtxt3559746411" class="msgtxt en"&gt;connascence.&lt;br /&gt;&lt;br /&gt;Connascence is a variation on the idea of software coupling, which is defined as follows:&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="status-body"&gt;&lt;span id="msgtxt3559746411" class="msgtxt en"&gt;"Two pieces of software share connascence when a change in one requires a corresponding change in the other&lt;/span&gt;&lt;/span&gt;."&lt;br /&gt;&lt;br /&gt;Here are the different types of connascence he went through (C stands for Connascence):&lt;br /&gt;CoName, CoPosition, CoMeaning, ContraC, CoAlgorithm, CoTiming, CoExecution, CoIdentity, CoValue, CoType.&lt;br /&gt;&lt;br /&gt;Ward Cunningham talked next about how he designed computers with a completely different paradigm following the way bacteria communicates. In fact, the title of the talk was "&lt;a href="http://scna.softwarecraftsmanship.org/schedule#ward_cunningham"&gt;What If Bacteria Designed Computers&lt;/a&gt;"&lt;br /&gt;&lt;br /&gt;Next, I helped moderate a talk/panel given by Kevin Tayler, Micah Martin, and Carl Erickson titled "The Business of Craftsmanship." The audience asked quite a few interesting questions, such as, "How do you sell clients on apprentices working on their projects?", "How often does apprenticeship not work out?", "What happens if apprentices leave after investing in them?"&lt;br /&gt;&lt;br /&gt;The last talk I saw before the final keynote was "&lt;a href="http://scna.softwarecraftsmanship.org/schedule#cory_foy"&gt;Selling Craftsmanship in the Enterprise&lt;/a&gt;" by Cory Foy. One of the key points he made in it was: "&lt;span class="status-body"&gt;&lt;span id="msgtxt3564784512" class="msgtxt en"&gt;The core of this movement [craftsmanship] is developers taking responsibility for their own careers.&lt;/span&gt;&lt;/span&gt;"&lt;br /&gt;&lt;br /&gt;Last but not least, I attended Bob Martin's incredibly dynamic keynote: "Craftsmanship Under Pressure".&lt;br /&gt;&lt;br /&gt;Here are some traits he listed on what it means to be a professional:&lt;br /&gt;- Can stay cool under pressure&lt;br /&gt;- Under-commit but over-deliver&lt;br /&gt;- Can have difficult conversations with the customer, like delaying the deadline.&lt;br /&gt;- Know their field&lt;br /&gt;- Live to learn. Love to Learn.&lt;br /&gt;&lt;br /&gt;Great conference overall. It has been filmed, and you can find the sessions once announced on the @scna twitter feed.&lt;br /&gt;&lt;br /&gt;That's all folks. Maybe we'll meet next year at this conference.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/32881756-1888242233866139752?l=andymaleh.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://andymaleh.blogspot.com/feeds/1888242233866139752/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=32881756&amp;postID=1888242233866139752' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/32881756/posts/default/1888242233866139752'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/32881756/posts/default/1888242233866139752'/><link rel='alternate' type='text/html' href='http://andymaleh.blogspot.com/2009/08/software-craftsmanship-north-america.html' title='Software Craftsmanship North America Conference Coverage'/><author><name>Annas "Andy" Maleh</name><uri>http://www.blogger.com/profile/10268484073612495328</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/-f6UYG8WIYJI/Tpw6vYi2nTI/AAAAAAAAAPk/ICI9GDbAxh4/s1600/7312067a2015194b853856820711a178%253Fsize%253D200'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-32881756.post-989834390069843600</id><published>2009-08-13T21:48:00.013-05:00</published><updated>2009-09-04T09:34:55.282-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Craftsmanship'/><title type='text'>Taking the Status Quo for Granted</title><content type='html'>Software developers often take the status quo of the software industry for granted, aiming no higher in their solutions than the standards set by their community.&lt;br /&gt;&lt;br /&gt;Let's take web programming as an example. In order to build web applications for clients or companies, most developers out there strive to master the standard web technologies: XHTML, CSS, Javascript as well as a back-end programming language+framework such as Java+Spring or Ruby on Rails.&lt;br /&gt;&lt;br /&gt;However, once developers are comfortable enough with building web applications, they often seek ways to increase productivity and quality of work (performance, reliability, security, ...) through changes in software development processes and/or technologies.&lt;br /&gt;&lt;br /&gt;As far as software technologies though, I've observed that developers too often only think of improvements that are incremental and within the box of what they normally do as opposed to outside the box.&lt;br /&gt;&lt;br /&gt;What are some examples of in-the-box thinking?&lt;br /&gt;&lt;ul&gt;&lt;br /&gt;&lt;li&gt;You have to program in two languages, one on the server and one on the client, in order to build a web application successfully.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Despite your best efforts in adhering to &lt;a href="http://eisabainyo.net/weblog/web-standards/"&gt;web standards&lt;/a&gt;, you ought to spend time dealing with many browser-dependent issues while in the midst of building business web applications.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;You have to think about the low-level HTTP protocol details every time you build new business features in order to map them into service requests according to the web &lt;a href="http://en.wikipedia.org/wiki/Resource_oriented_architecture"&gt;resource-oriented architecture&lt;/a&gt;.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;You have to code URL history management for Ajax calls yourself (with the aid of some library like &lt;a href="http://developer.yahoo.com/yui/history/"&gt;YUI Browser History Manager&lt;/a&gt; or &lt;a href="http://www.javascriptplugins.com/framework/jquery/really-simple-history/"&gt;Really Simple History&lt;/a&gt;) to ensure that the back button and bookmark-ability are not broken in your shiny Web 2.0 application.&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;Having listed a few examples of in-the-box thinking, one may wonder "What is the box exactly made of?"&lt;br /&gt;&lt;br /&gt;The box is made of all the currently assumed constraints that seem unchangeable, such as available development technologies, team values, and quality standards set by the client.&lt;br /&gt;&lt;br /&gt;How do you think outside the box?&lt;br /&gt;&lt;br /&gt;Thinking outside the box is an exercise in which people temporarily drop some (or all) of the assumed constraints and imagine how things would go about instead in that alternate reality. It is an exercise in creativity and imagination, and while it may yield some ideas that are not feasible in reality, it often yields other ideas that make people realize some of the assumed constraints are indeed changeable.&lt;br /&gt;&lt;br /&gt;This is in fact what some luminaries in the Java world, such as &lt;a href="http://blog.springframework.com/rod/"&gt;Rod Johnson,&lt;/a&gt; did when they envisioned successful enterprise development without the constraints of EJBs (Enterprise JavaBeans). That's what &lt;a href="http://www.loudthinking.com/"&gt;DHH (David Heinemeier Hansson)&lt;/a&gt; did when he envisioned simplified web development relying on conventions instead of endless configuration files. That's what Google did when they built &lt;a href="http://code.google.com/webtoolkit/"&gt;GWT (Google Web Toolkit)&lt;/a&gt;, a framework that abstracts all the web low level details from developers.&lt;br /&gt;&lt;br /&gt;In any case, often developers reject out-of-the-box solutions because they are not mature enough yet. For example, I know quite a few developers that are not very fond of GWT despite the fact that it offers these benefits:&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Simplifies the problem of web development by abstracting it to its essence: programming on the server and programming on the client with data passed back and forth in between. This has been successfully solved for desktop applications in the 90s with one programming language, so why have developers deal now with co-incidental technologies like XHTML, CSS, and Javascript?&lt;/li&gt;&lt;li&gt;Unified debugging interaction for client and server making it very easy to trace data moving between them without having to context switch between many different syntaxes and technologies&lt;/li&gt;&lt;li&gt;Abstracted all browser-related variations saving the developers from a huge burden in web development. Isn't that the premise of abstraction in software after all?&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;The reasons GWT is not considered a mature solution by some developers though are:&lt;/p&gt;&lt;ul&gt;&lt;br /&gt;&lt;li&gt;Does not render &lt;a href="http://eisabainyo.net/weblog/web-standards/"&gt;web-standards&lt;/a&gt; compliant XHTML/CSS as it relies on the frowned up abuse of HTML tables to do layout&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Relies on the imperative Swing-like Java syntax to layout widgets, which is considered archaic nowadays compared to using DSLs that map closely to the visual layout, like &lt;a href="http://groovy.codehaus.org/Swing+Builder"&gt;Groovy SwingBuilder&lt;/a&gt; and &lt;a href="http://www.swixml.org/"&gt;SWIXML&lt;/a&gt; (or even good old XHTML)&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Of course, there is the learning curve and the fact that developers would have to remember to debug through an IDE instead of a browser debugger like &lt;a href="http://getfirebug.com/"&gt;Firebug&lt;/a&gt;. So, traditional web developers are kinda out of luck until they learn the new ways, but veteran desktop developers would be fine.&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;Still, the reason I bring this example up is because often when people get frustrated with a technology like GWT, they go back to accepting the status quo and working with solutions that are in-the-box as opposed to fixing the problems with the new out-of-the-box solutions.&lt;/p&gt;&lt;p&gt;The few that do persist and go beyond the box though end up with solutions that completely shatter existing expectations. For example, the Java language in its early days was considered by many developers as outlandish and impractical in comparison to writing code with a language that hits memory directly and works close to the hardware, like C/C++.&lt;br /&gt;&lt;/p&gt;&lt;p&gt;Who's making all the money now? :)&lt;br /&gt;&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/32881756-989834390069843600?l=andymaleh.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://andymaleh.blogspot.com/feeds/989834390069843600/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=32881756&amp;postID=989834390069843600' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/32881756/posts/default/989834390069843600'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/32881756/posts/default/989834390069843600'/><link rel='alternate' type='text/html' href='http://andymaleh.blogspot.com/2009/08/taking-status-quoue-for-granted.html' title='Taking the Status Quo for Granted'/><author><name>Annas "Andy" Maleh</name><uri>http://www.blogger.com/profile/10268484073612495328</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/-f6UYG8WIYJI/Tpw6vYi2nTI/AAAAAAAAAPk/ICI9GDbAxh4/s1600/7312067a2015194b853856820711a178%253Fsize%253D200'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-32881756.post-1132202260171969120</id><published>2009-07-30T11:32:00.014-05:00</published><updated>2009-07-30T12:25:58.433-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Craftsmanship'/><title type='text'>TODO or not TODO</title><content type='html'>In the spirit of continuous improvement and XP's recommendation to always keep the code pristine clean (&lt;a href="http://www.extremeprogramming.org/rules/refactor.html"&gt;Refactor Mercilessly&lt;/a&gt;), I often perform a lot of refactorings to simplify the code as much as possible as the accumulated debts over the many months of a project can otherwise make working with the code intolerable a few years down the road.&lt;br /&gt;&lt;br /&gt;The way I look at refactoring is it's like maintaining your car or cleaning your room. Do it continuously and you'll enjoy driving around or relaxing in your room. Ignore it, and a year later your car is not working as it should anymore and your room is completely intolerable except for running in to sleep and then run out again.&lt;br /&gt;&lt;br /&gt;Unfortunately though, while I get insights for many refactorings that can make a significant dent on code simplicity, I often don't seem to find time to perform all of them when approaching a deadline. Should I ignore them and hope for the best? What if I ignore them, and after the deadline, I don't remember them anymore?&lt;br /&gt;&lt;br /&gt;The best solution I personally found is to add a TODO in the place where the pending refactoring is useful.&lt;br /&gt;&lt;br /&gt;But some developers from the agile community would immediately flinch and say: &lt;span style="font-style: italic;"&gt;If you put off refactorings by adding TODO statements, you'll never get to do them and your code will be littered with them.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;I used to have that fear myself till I gave that approach a try a few years ago.&lt;br /&gt;&lt;br /&gt;Turned out that since continuous merciless refactoring is in my blood, I never find myself ignoring refactorings and letting the code rot. Quite the opposite, I sometimes almost miss deadlines to ensure that the code is in pristine condition.&lt;br /&gt;&lt;br /&gt;Nonetheless, given that I have to let go of some refactorings to meet deadlines, I often forget them afterwards. One approach I tried to remedy that is to add reminder tasks about the refactorings in my task management app. Unfortunately, these often get ignored when the list grows too big.&lt;br /&gt;&lt;br /&gt;So, I finally resorted to adding TODOs within the code, and I found a number of benefits as a result:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Refactoring ideas are preserved next to the code that needs them, thus maintaining context&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Other developers see them and get an opportunity to perform the refactorings in the process of fixing a bug or adding a new feature&lt;/li&gt;&lt;li&gt;Developers are constantly reminded about them whenever they see the code that can benefit from refactoring&lt;/li&gt;&lt;/ul&gt;Therefore, TODOs are not used as a crutch to avoid performing refactorings when working in the code, they are used instead as reminders for refactorings that there was absolutely no time to perform before some deadline. They are placed right next to the code that needs them, thus constantly reminding developers of them and becoming available for all developers on the team to see as opposed to only the original developer who spotted their need.&lt;br /&gt;&lt;br /&gt;I'd be curious to hear the opinions and experiences of other developers on the matter. Feel free to post a comment about it.&lt;br /&gt;&lt;br /&gt;p.s. if you're using the Eclipse IDE, there is a view you can bring up called the Tasks view, which aggregates all TODO tasks from your project files (or a selected subset). That can help keep TODOs at the back of your mind at all times. Of course, if you're a command line zealot, you can simply grep or rak the TODOs instead.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/32881756-1132202260171969120?l=andymaleh.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://andymaleh.blogspot.com/feeds/1132202260171969120/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=32881756&amp;postID=1132202260171969120' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/32881756/posts/default/1132202260171969120'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/32881756/posts/default/1132202260171969120'/><link rel='alternate' type='text/html' href='http://andymaleh.blogspot.com/2009/07/todo-or-not-todo.html' title='TODO or not TODO'/><author><name>Annas "Andy" Maleh</name><uri>http://www.blogger.com/profile/10268484073612495328</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/-f6UYG8WIYJI/Tpw6vYi2nTI/AAAAAAAAAPk/ICI9GDbAxh4/s1600/7312067a2015194b853856820711a178%253Fsize%253D200'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-32881756.post-3194985267292681439</id><published>2009-07-27T20:03:00.019-05:00</published><updated>2011-02-24T12:45:02.968-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Eclipse'/><category scheme='http://www.blogger.com/atom/ns#' term='Craftsmanship'/><title type='text'>Mouse-less Eclipse</title><content type='html'>&lt;span style="font-style: italic;"&gt;Last updated on July 29, 2009&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;A fellow blog reader &lt;a href="https://www.blogger.com/comment.g?blogID=32881756&amp;amp;postID=5323123261837242469"&gt;commented&lt;/a&gt; on a post I made last month titled &lt;a href="http://andymaleh.blogspot.com/2009/06/ide-vs-editor-war-in-ruby-world.html"&gt;The IDE vs Editor War in the Ruby World&lt;/a&gt;, asking how I actually use Eclipse in a mouse-less way. So, I decided to post a list of all Eclipse shortcuts that I find practical enough to use in my day-to-day work. Note that my focus will be mostly on text editing shortcuts as opposed to language specific shortcuts.&lt;br /&gt;&lt;span style="font-size:130%;"&gt;&lt;b&gt;&lt;br /&gt;Mouse-less Eclipse Keyboard Shortcuts:&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;span style="font-weight: bold;"&gt;&lt;span class="Apple-style-span" style="font-weight: normal; "&gt;&lt;span style="font-weight: bold; "&gt;CTRL+SHIFT+L:&lt;/span&gt; lists all available shortcuts (useful for learning)&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="font-weight: bold;"&gt;&lt;span class="Apple-style-span" style="font-weight: normal; "&gt;&lt;/span&gt;CTRL+SHIFT+R:&lt;/span&gt; lookup up a resource (e.g. html, xml, rb, erb, properties, etc...)&lt;/li&gt;&lt;li&gt;&lt;span style="font-weight: bold;"&gt;CTRL+SHIFT+T:&lt;/span&gt; lookup a class name (e.g. String or Customer)&lt;/li&gt;&lt;li&gt;&lt;span style="font-weight: bold;"&gt;CTRL+F6: &lt;/span&gt;quickly jump between open files&lt;/li&gt;&lt;li&gt;&lt;span style="font-weight: bold;"&gt;CTRL+E: &lt;/span&gt;jump between open files using a filename filter or navigation keys&lt;/li&gt;&lt;li&gt;&lt;span style="font-weight: bold;"&gt;ALT+LEFT and ALT+RIGHT: &lt;/span&gt;navigate back and forth in the history of the files I opened. I rely on this one a lot to avoid using the mouse when navigating back and forth between different classes that collaborate to get a user interaction handled.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="font-weight: bold;"&gt;CTRL+O:&lt;/span&gt; lookup a method (thanks Kristian for reminding me)&lt;/li&gt;&lt;li&gt;&lt;span style="font-weight: bold;"&gt;F3:&lt;/span&gt; jump to method, class, or variable declaration.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="font-weight: bold;"&gt;CTRL+J keyword:&lt;/span&gt; instant search of a keyword within a file&lt;/li&gt;&lt;li&gt;&lt;span style="font-weight: bold;"&gt;CTRL+F keyword then ENTER: &lt;/span&gt;regular search.&lt;/li&gt;&lt;li&gt;&lt;span style="font-weight: bold;"&gt;CTRL+K and CTRL+SHIFT+K: &lt;/span&gt;find next and find previous repeating search for the last keyword&lt;/li&gt;&lt;li&gt;&lt;span style="font-weight: bold;"&gt;Highlight text to find other occurrances of a keyword and then CTRL+K:&lt;/span&gt; lets you find a keyword without even typing it if you see one occurrence already in the file (for example, you see a use of the slow performing method "reindex" and you wonder where else it's used in the file)&lt;/li&gt;&lt;li&gt;&lt;span style="font-weight: bold;"&gt;CTRL+H:&lt;/span&gt; project-wide search for a keyword. You can also specify file patterns. Make sure to tab into fields or use mnemonics and hit ENTER instead of using the mouse. Once the search completes, pick the result you want using the up/down arrows and then hit enter to open the file.&lt;/li&gt;&lt;li&gt;&lt;span style="font-weight: bold;"&gt;HOME/END/PGUP/PGDN:&lt;/span&gt; for navigation of course. I've been surprised many times by how very few developers rely on these buttons to navigate a file efficiently without using the mouse.&lt;/li&gt;&lt;li&gt;&lt;span style="font-weight: bold;"&gt;CTRL+LEFT and CTRL+RIGHT&lt;/span&gt;: jump between words for quicker navigation in a line without taking hand off keyboard to use the mouse.&lt;/li&gt;&lt;li&gt;&lt;span style="font-weight: bold;"&gt;CTRL+SHIFT+LEFT and CTRL+SHIFT+RIGHT: &lt;/span&gt;quick highlighting of words without taking hand off keyboard to use the mouse.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="font-weight: bold;"&gt;CTRL+L:&lt;/span&gt; jump to a particular line number. I keep line numbers visible to quickly locate stack trace errors. This one is invaluable in saving me from paging through a file or using the mouse.&lt;/li&gt;&lt;li&gt;&lt;span style="font-weight: bold;"&gt;CTRL+ALT+DOWN (or UP):&lt;/span&gt; clones a line downwards. It's like copy/paste without using the clipboard, which I use often to avoid emptying the clipboard from something I've copied that I'd like to paste somewhere. This is most useful with the CTRL+UP/DOWN shortcuts.&lt;/li&gt;&lt;li&gt;&lt;span style="font-weight: bold;"&gt;CTRL+UP and CTRL+DOWN: &lt;/span&gt;moves a line up or down quickly. I often start by cloning a line, and then I move the cloned line down or up to the place I want it to be at.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="font-weight: bold;"&gt;CTRL+SHIFT+F: &lt;/span&gt;format content (makes sure everything is indented nicely)&lt;/li&gt;&lt;li&gt;&lt;span style="font-weight: bold;"&gt;ALT+SHIFT+UP:&lt;/span&gt; highlights an entire variable name even if it had underscores and multiple words&lt;/li&gt;&lt;li&gt;&lt;span style="font-weight: bold;"&gt;ALT+W P: &lt;/span&gt;access preferences via ALT+character mnemonics&lt;/li&gt;&lt;li&gt;&lt;span style="font-weight: bold;"&gt;ALT+character mnemonics in general: &lt;/span&gt;useful to do all upper menu navigation instantly without a mouse if you're on Linux or Windows (sorry Mac people). Over time, your nervous system ends up memorizing a lot of the character sequences, saving you from having to even read the menu items, let alone pointing at them with a mouse and clicking them.&lt;/li&gt;&lt;/ul&gt;Additionally, there are many shortcuts for refactoring and source generation, which I will leave for the readers to discover on their own through the menus of Eclipse.&lt;br /&gt;&lt;br /&gt;If I remember more shortcuts over the next few days, I will make sure to update the list above. Although anyone can look up shortcuts in the Eclipse keys preferences page, not all shortcuts are practical, so I am only highlighting the ones that I consistently use to increase productivity and flow. Of course, there may be shortcuts that I have not learned to appreciate yet, so feel free to contribute in the comments the shortcuts you normally like to use.&lt;br /&gt;&lt;br /&gt;How do I know about all these shortcuts? Did I learn them all from a reference? How can I keep learning more shortcuts in my day-to-day job? I'll leave the answers to these questions to a future blog post.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/32881756-3194985267292681439?l=andymaleh.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://andymaleh.blogspot.com/feeds/3194985267292681439/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=32881756&amp;postID=3194985267292681439' title='12 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/32881756/posts/default/3194985267292681439'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/32881756/posts/default/3194985267292681439'/><link rel='alternate' type='text/html' href='http://andymaleh.blogspot.com/2009/07/mouse-less-eclipse.html' title='Mouse-less Eclipse'/><author><name>Annas "Andy" Maleh</name><uri>http://www.blogger.com/profile/10268484073612495328</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/-f6UYG8WIYJI/Tpw6vYi2nTI/AAAAAAAAAPk/ICI9GDbAxh4/s1600/7312067a2015194b853856820711a178%253Fsize%253D200'/></author><thr:total>12</thr:total></entry><entry><id>tag:blogger.com,1999:blog-32881756.post-2389861015190830863</id><published>2009-06-24T10:28:00.005-05:00</published><updated>2009-06-24T10:37:57.834-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Conferences'/><category scheme='http://www.blogger.com/atom/ns#' term='Craftsmanship'/><title type='text'>Software Craftsmanship North America</title><content type='html'>Dave Hoover, one of my fellow colleagues at Obtiva, is collaborating with the people at 8th Light to bring us one of the first conferences focused on software craftsmanship (Software Craftsmanship North America):&lt;br /&gt;&lt;a href="http://scna.softwarecraftsmanship.com/"&gt;http://scna.softwarecraftsmanship.com/&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;I originally got introduced to the idea of Software Craftsmanship while reading the Pragmatic Programmer by Andrew Hunt and Dave Thomas, and later learned more about it through the book titled Software Craftsmanship by Pete-McBreen.&lt;br /&gt;&lt;br /&gt;I even blogged about Software Craftsmanship contrasting it with Software Engineering over here:&lt;br /&gt;&lt;a href="http://andymaleh.blogspot.com/2008/12/software-craftsmanship-vs-software.html"&gt;http://andymaleh.blogspot.com/2008/12/software-craftsmanship-vs-software.html&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Well, if you want to learn more about it, InfoQ recently posted an interview with Dave Hoover clarifying the purpose and goals behind the conference:&lt;br /&gt;&lt;a href="http://www.infoq.com/news/2009/06/software-craftsmanship-conf"&gt;http://www.infoq.com/news/2009/06/software-craftsmanship-conf&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Feel free to post a comment if you have any questions about it&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/32881756-2389861015190830863?l=andymaleh.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://andymaleh.blogspot.com/feeds/2389861015190830863/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=32881756&amp;postID=2389861015190830863' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/32881756/posts/default/2389861015190830863'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/32881756/posts/default/2389861015190830863'/><link rel='alternate' type='text/html' href='http://andymaleh.blogspot.com/2009/06/software-craftsmanship-north-america.html' title='Software Craftsmanship North America'/><author><name>Annas "Andy" Maleh</name><uri>http://www.blogger.com/profile/10268484073612495328</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/-f6UYG8WIYJI/Tpw6vYi2nTI/AAAAAAAAAPk/ICI9GDbAxh4/s1600/7312067a2015194b853856820711a178%253Fsize%253D200'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-32881756.post-5323123261837242469</id><published>2009-06-02T21:24:00.010-05:00</published><updated>2009-06-02T22:19:17.395-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Tools'/><category scheme='http://www.blogger.com/atom/ns#' term='Ruby'/><category scheme='http://www.blogger.com/atom/ns#' term='Eclipse'/><title type='text'>The IDE vs Editor War in the Ruby World</title><content type='html'>Ever since I switched to Ruby programming last September to develop Rails web applications, I've been fighting an up-hill battle to convince other developers of the value of using Eclipse or IDEs in general.&lt;br /&gt;&lt;br /&gt;Since Ruby is an interpreted language (with a transparent compilation step for optimizations purposes only), developers mainly rely on test-driven development to produce reliable code. Auto-compilation and verification of code is thus rendered for the most part unnecessary. &lt;br /&gt;&lt;br /&gt;Additionally, given Ruby's support for attributes (via attr* methods) and no need to declare class variables, many of the source code generators used in Java are not needed in Ruby. After all, Ruby's philosophy is about producting the tersest most abstract code, free of boiler-plate repetitive code.&lt;br /&gt;&lt;br /&gt;Refactoring with Ruby is often done manually, but given that there isn't usually a lot of code with proper abstraction, and given Ruby's method aliasing support, huge refactorings of the nature that ripples through the whole system are rare, and thus refactoring is quite easy to perform manually especially given the protection of the Ruby must-have unit tests. &lt;br /&gt;&lt;br /&gt;So, what does that leave as far as tooling needs? Color coding, syntax highlighting, file lookup, search and replace, and possibly some autocompletion capabilities.&lt;br /&gt;&lt;br /&gt;Well, these limited needs brought back the popularity of simple editors that support just these features. By simple editors, I do actually mean good old VIM and emacs as well as the new extremely popular Mac editor, TextMate.&lt;br /&gt;&lt;br /&gt;After 10 months of pair-programming with different Ruby developers with varying habits and backgrounds, I got to do a pilgrimage through most Ruby editors and IDEs. So far, I've gone through TextMate, VIM, Aptana RadRails, Eclipse DLTK, NetBeans, and IntelliJ RubyMine. &lt;br /&gt;&lt;br /&gt;Yes, I'm a shortcut freak, and I used to write Java programs in Eclipse mouse-less!!! So, how did other editors and IDEs measure in comparison as far as shortcuts and productivity? &lt;br /&gt;&lt;br /&gt;I'll leave that to another post. &lt;br /&gt;&lt;br /&gt;In the meantime, what is your opinion of the matter? Do any of you prefer editors over IDEs? If so what's your editor/IDE of choice and what are the reasons you like it? Feel free to mention different ones for different programming languages.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/32881756-5323123261837242469?l=andymaleh.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://andymaleh.blogspot.com/feeds/5323123261837242469/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=32881756&amp;postID=5323123261837242469' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/32881756/posts/default/5323123261837242469'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/32881756/posts/default/5323123261837242469'/><link rel='alternate' type='text/html' href='http://andymaleh.blogspot.com/2009/06/ide-vs-editor-war-in-ruby-world.html' title='The IDE vs Editor War in the Ruby World'/><author><name>Annas "Andy" Maleh</name><uri>http://www.blogger.com/profile/10268484073612495328</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/-f6UYG8WIYJI/Tpw6vYi2nTI/AAAAAAAAAPk/ICI9GDbAxh4/s1600/7312067a2015194b853856820711a178%253Fsize%253D200'/></author><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-32881756.post-6313786885702483549</id><published>2009-05-18T09:43:00.002-05:00</published><updated>2009-05-18T09:54:49.264-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Mobile'/><title type='text'>iMeow</title><content type='html'>Some of my colleagues at work built a new iPhone app called iMeow &lt;a href="http://itunes.apple.com/WebObjects/MZStore.woa/wa/viewSoftware?id=314851507&amp;mt=8"&gt;(iTunes link)&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;The instructions for using iMeow are actually encoded in a poem included with the app:&lt;br /&gt;&lt;br /&gt;"I like to have my ears and belly rubbed. &lt;br /&gt;But, please don't step on my toes or pull my tail!!!&lt;br /&gt;I'll cry for food if I'm hungry.&lt;br /&gt;And whatever you do. Do. Not. Shake. Me."&lt;br /&gt;&lt;br /&gt;Since I have a coffee-colored cat called Java, I decided to try out iMeow with her. &lt;br /&gt;&lt;br /&gt;When I pressed the mouth of the iMeow cat to make it meow, my cat suddenly became alert and still. I did it a few times and then tossed the phone away. My cat started moving slowly towards the phone and then went and sniffed it.&lt;br /&gt;&lt;br /&gt;Next experiment was to pull the iMeow's cat tail or step on its toes. The shrieks that came out of that sent chills down my cat's spine!!!&lt;br /&gt;&lt;br /&gt;Finally, I shook the iPhone forcing the iMeow cat to give an aggressive fighting shriek and exhale (the one cats do right before clawing you). That freaked my cat out, but it was fast enough that my cat was able to get over it quickly.&lt;br /&gt;&lt;br /&gt;In any case, I expect the app to get a number of updates in the future, so if you have a cat and you would like to test how it would react to another cat, give iMeow a spin.&lt;br /&gt;&lt;br /&gt;My next experiment will be to test iMeow in the wild, either in a pet store, or at a public place to see how everyone will react. ;)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/32881756-6313786885702483549?l=andymaleh.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://andymaleh.blogspot.com/feeds/6313786885702483549/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=32881756&amp;postID=6313786885702483549' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/32881756/posts/default/6313786885702483549'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/32881756/posts/default/6313786885702483549'/><link rel='alternate' type='text/html' href='http://andymaleh.blogspot.com/2009/05/imeow.html' title='iMeow'/><author><name>Annas "Andy" Maleh</name><uri>http://www.blogger.com/profile/10268484073612495328</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/-f6UYG8WIYJI/Tpw6vYi2nTI/AAAAAAAAAPk/ICI9GDbAxh4/s1600/7312067a2015194b853856820711a178%253Fsize%253D200'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-32881756.post-407552550158407914</id><published>2009-03-25T23:47:00.009-05:00</published><updated>2009-03-27T10:57:39.911-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Eclipse'/><category scheme='http://www.blogger.com/atom/ns#' term='Conferences'/><category scheme='http://www.blogger.com/atom/ns#' term='Glimmer'/><category scheme='http://www.blogger.com/atom/ns#' term='Agile Methodologies'/><title type='text'>XP West Michigan and EclipseCon 2009</title><content type='html'>Tyler Jennings, Jake Scruggs, and I went on a road trip to Grand Rapids, Michigan yesterday and gave two presentations at the &lt;a href="http://www.xpwestmichigan.org/"&gt;XP West Michigan&lt;/a&gt; user group. Jake presented "What’s the right level of testing?", and Tyler and I presented "&lt;a href="http://andymaleh.blogspot.com/2009/03/agile-2009-talk-pairing-parody.html"&gt;Pairing Parody&lt;/a&gt;". Atomic Object hosted us and gave us a tour around their office. They had a nice open environment for pair-programming and a street light that signals the state of project builds (red for failure, green for success, and yellow for build in progress). The experience was very hospitable overall thanks to Michael Swieton.&lt;br /&gt;&lt;br /&gt;Today, I flew to the Silicon Valley area around San Jose, California to present at EclipseCon 2009 tomorrow. I will be giving a short talk about &lt;a href="http://www.eclipse.org/glimmer"&gt;Glimmer&lt;/a&gt; and the current state of the project.&lt;br /&gt;&lt;br /&gt;If you have any specific questions about the project, feel free to list them here in the comments, and I will try to cover them in the talk.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/32881756-407552550158407914?l=andymaleh.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://andymaleh.blogspot.com/feeds/407552550158407914/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=32881756&amp;postID=407552550158407914' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/32881756/posts/default/407552550158407914'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/32881756/posts/default/407552550158407914'/><link rel='alternate' type='text/html' href='http://andymaleh.blogspot.com/2009/03/xp-west-michigan-and-eclipsecon-2009.html' title='XP West Michigan and EclipseCon 2009'/><author><name>Annas "Andy" Maleh</name><uri>http://www.blogger.com/profile/10268484073612495328</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/-f6UYG8WIYJI/Tpw6vYi2nTI/AAAAAAAAAPk/ICI9GDbAxh4/s1600/7312067a2015194b853856820711a178%253Fsize%253D200'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-32881756.post-2616584571353988344</id><published>2009-03-09T12:45:00.003-05:00</published><updated>2009-03-09T12:50:27.960-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Conferences'/><category scheme='http://www.blogger.com/atom/ns#' term='Agile Methodologies'/><title type='text'>Agile 2009 Workshop: TDD Ping Pong Match!</title><content type='html'>By the way, &lt;a href="http://nuts.redsquirrel.com/"&gt;Dave Hoover&lt;/a&gt; and I proposed a workshop for Agile 2009 titled: &lt;a href="http://agile2009.agilealliance.org/node/2371"&gt;TDD Ping Pong Match!&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;It's a new and improved version of the same workshop conducted in Toronto last year at Agile 2008.&lt;br /&gt;&lt;br /&gt;Abstract:&lt;br /&gt;&lt;br /&gt;Attendees will be entered into a competition where they will pair-program on implementing small software application features following the TDD Ping Pong game rules. Each game will last for a few minutes, and the programmer with the least time driving (i.e. doing the simplest thing that works and coming up with the most tests) will be declared winner. This game is a great opportunity to learn TDD and Pair-Programming effectively and pragmatically. Winners will receive prizes, so sharpen your TDD Ping Pong skills and get ready for Andy and Dave’s challenge!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/32881756-2616584571353988344?l=andymaleh.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://andymaleh.blogspot.com/feeds/2616584571353988344/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=32881756&amp;postID=2616584571353988344' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/32881756/posts/default/2616584571353988344'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/32881756/posts/default/2616584571353988344'/><link rel='alternate' type='text/html' href='http://andymaleh.blogspot.com/2009/03/agile-2009-talk-tdd-ping-pong-match.html' title='Agile 2009 Workshop: TDD Ping Pong Match!'/><author><name>Annas "Andy" Maleh</name><uri>http://www.blogger.com/profile/10268484073612495328</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/-f6UYG8WIYJI/Tpw6vYi2nTI/AAAAAAAAAPk/ICI9GDbAxh4/s1600/7312067a2015194b853856820711a178%253Fsize%253D200'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-32881756.post-8088458943812792708</id><published>2009-03-03T14:02:00.002-06:00</published><updated>2009-03-03T14:04:31.585-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Conferences'/><category scheme='http://www.blogger.com/atom/ns#' term='Agile Methodologies'/><title type='text'>Agile 2009 Talk: Pairing Parody</title><content type='html'>I submitted a proposal for this talk with Tyler Jennings:&lt;br /&gt;&lt;a href="http://agile2009.agilealliance.org/node/2370"&gt;http://agile2009.agilealliance.org/node/2370&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Comments are welcome.&lt;br /&gt;&lt;br /&gt;Abstract&lt;br /&gt;&lt;br /&gt;Pair programming requires a certain level of social interaction (Yikes!!!) that quite a few developers are not accustomed to - even with their peers. Learning to work effectively with people of different personalities and skills (or even Jedi powers) can sometimes seem daunting compared to the typical habit of working alone in a dark corner. We’ve seen pairing work wonderfully, we’ve seen it be an abysmal failure that involved some shouting and storming away, and we’re going to bring our best-of moments to you in comedic fashion.&lt;br /&gt;Process/Mechanics&lt;br /&gt;&lt;br /&gt;First we’ll cover the basics for anyone who isn’t familiar with the drama that often accompanies pair programming. Afterward, Andy and I will be acting out various skits, demonstrating both effective and dysfunctional pairing scenarios. Discussions (and laughter or cries of terror) are highly encouraged at the end of each skit.&lt;br /&gt;&lt;br /&gt;Basic Patterns&lt;br /&gt;&lt;br /&gt;    * Be Verbose&lt;br /&gt;    * Questions Not Demands&lt;br /&gt;    * Pair Negotiation&lt;br /&gt;    * Ping Pong Programming&lt;br /&gt;    * 2 x 2 Pairing&lt;br /&gt;    * Independent Research / Spikes&lt;br /&gt;&lt;br /&gt;Mentoring Patterns&lt;br /&gt;&lt;br /&gt;    * Let the student drive&lt;br /&gt;    * Let the student fail&lt;br /&gt;    * The third wheel&lt;br /&gt;    * Test Mentor&lt;br /&gt;&lt;br /&gt;Anti-Patterns&lt;br /&gt;&lt;br /&gt;    * The Prima Donna Programmer&lt;br /&gt;    * The Apathetic Programmer&lt;br /&gt;    * The Human Compiler&lt;br /&gt;    * Worshipping The Hero&lt;br /&gt;    * The Professional Driver&lt;br /&gt;&lt;br /&gt;Learning outcomes&lt;br /&gt;&lt;br /&gt;    * Recognizing a dysfunctional pairing session&lt;br /&gt;    * Patterns for pairing effectively with various personality types and skill levels&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/32881756-8088458943812792708?l=andymaleh.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://andymaleh.blogspot.com/feeds/8088458943812792708/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=32881756&amp;postID=8088458943812792708' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/32881756/posts/default/8088458943812792708'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/32881756/posts/default/8088458943812792708'/><link rel='alternate' type='text/html' href='http://andymaleh.blogspot.com/2009/03/agile-2009-talk-pairing-parody.html' title='Agile 2009 Talk: Pairing Parody'/><author><name>Annas "Andy" Maleh</name><uri>http://www.blogger.com/profile/10268484073612495328</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/-f6UYG8WIYJI/Tpw6vYi2nTI/AAAAAAAAAPk/ICI9GDbAxh4/s1600/7312067a2015194b853856820711a178%253Fsize%253D200'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-32881756.post-6435504790453707624</id><published>2009-02-03T13:47:00.012-06:00</published><updated>2009-02-04T13:36:21.351-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Ruby'/><category scheme='http://www.blogger.com/atom/ns#' term='Eclipse'/><category scheme='http://www.blogger.com/atom/ns#' term='Glimmer'/><category scheme='http://www.blogger.com/atom/ns#' term='Agile Methodologies'/><title type='text'>Obtiva HackFest and Glimmer Tree Data Binding in Progress</title><content type='html'>Today, instead of having our weekly GeekFest meeting at &lt;a href="http://obtiva.com"&gt;Obtiva&lt;/a&gt;, &lt;a href="http://redsquirrel.com/dave/"&gt;Dave&lt;/a&gt; organized a HackFest instead.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://aberant.tumblr.com/"&gt;Colin&lt;/a&gt;, &lt;a href="http://redsquirrel.com/cgi-bin/dave"&gt;Dave&lt;/a&gt;, Roy, and &lt;a href="http://natejackson.blogspot.com"&gt;Nate&lt;/a&gt; worked on &lt;br /&gt;&lt;a href="http://aberant.tumblr.com/"&gt;Colin&lt;/a&gt;'s ultimate midi controller project. Tom, &lt;a href="http://softwareapprenticetips.blogspot.com/"&gt;Leah&lt;/a&gt;, and &lt;a href="http://jakescruggs.blogspot.com/"&gt;Jake&lt;/a&gt; worked on the &lt;a href="http://metric-fu.rubyforge.org/"&gt;Metric Fu&lt;/a&gt; Aggregator. And, &lt;a href="http://squaremasher.blogspot.com/"&gt;Tyler&lt;/a&gt;, &lt;a href="http://crimsonknight78.blogspot.com/"&gt;Turner&lt;/a&gt;, and I worked on implementing Tree Data-Binding support for &lt;a href="http://www.eclipse.org/glimmer"&gt;Glimmer&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;In one hour, we made as much progress as we could, which amounted to coming up with a design for the &lt;a href="http://andymaleh.blogspot.com/2007/12/glimmers-built-in-data-binding-syntax.html"&gt;data-binding&lt;/a&gt; syntax in this unit test:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;  module Node&lt;br /&gt;    attr_accessor :parent, :children&lt;br /&gt;  end&lt;br /&gt;  &lt;br /&gt;  class Person &lt;br /&gt;    include Node&lt;br /&gt;    attr_accessor :name, :age, :adult&lt;br /&gt;  end&lt;br /&gt;  &lt;br /&gt;  def test_root_node_only&lt;br /&gt;    adam = Person.new&lt;br /&gt;    adam.name = "Adam"&lt;br /&gt;    &lt;br /&gt;    @target = shell {&lt;br /&gt;      @tree = tree {&lt;br /&gt;        items bind(adam, :name)&lt;br /&gt;      }&lt;br /&gt;    }&lt;br /&gt;    &lt;br /&gt;    assert_equal 1, @tree.widget.getItems.size&lt;br /&gt;    assert_equal adam, @tree.widget.getItems.first&lt;br /&gt;  end&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;To bind SWT Tree items to a model node hierarchy, you pass two parameters to the bind command: the root model node and the name of the attribute to be used for displaying text in the tree.&lt;br /&gt;&lt;br /&gt;More tests will eventually be written to test data-binding a root model with children.&lt;br /&gt;&lt;br /&gt;In the future, this will probably grow in other directions to handle tree node images and selection. &lt;br /&gt;&lt;br /&gt;&lt;a href="http://www.agiledata.org/essays/tdd.html"&gt;Test-driven design&lt;/a&gt; is a common practice at Obtiva as it gets many birds with one stone: ease of exploration of ideas, test-coverage, clean code design, and higher productivity due to incremental development preventing endless hours of debugging.&lt;br /&gt;&lt;br /&gt;Stay tuned for more on Tree Data-Binding support in Glimmer in the future.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/32881756-6435504790453707624?l=andymaleh.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://andymaleh.blogspot.com/feeds/6435504790453707624/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=32881756&amp;postID=6435504790453707624' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/32881756/posts/default/6435504790453707624'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/32881756/posts/default/6435504790453707624'/><link rel='alternate' type='text/html' href='http://andymaleh.blogspot.com/2009/02/obtiva-hackfest-and-glimmer-tree-data.html' title='Obtiva HackFest and Glimmer Tree Data Binding in Progress'/><author><name>Annas "Andy" Maleh</name><uri>http://www.blogger.com/profile/10268484073612495328</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/-f6UYG8WIYJI/Tpw6vYi2nTI/AAAAAAAAAPk/ICI9GDbAxh4/s1600/7312067a2015194b853856820711a178%253Fsize%253D200'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-32881756.post-403889723818572623</id><published>2009-01-29T16:39:00.002-06:00</published><updated>2009-01-29T19:16:40.492-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Ruby'/><category scheme='http://www.blogger.com/atom/ns#' term='Eclipse'/><category scheme='http://www.blogger.com/atom/ns#' term='Glimmer'/><title type='text'>Sudoku Solver in Glimmer</title><content type='html'>&lt;a href="http://redsquirrel.com/dave/"&gt;Dave Hoover&lt;/a&gt; recently experimented with writing a &lt;a href="http://github.com/redsquirrel/nest/tree/master/sudoku"&gt;Sudoku solver&lt;/a&gt; in Ruby, so Joseph Leddy and I decided to slap a &lt;a href="http://www.eclipse.org/glimmer"&gt;Glimmer&lt;/a&gt; cover on top of it. We pair-programmed on writing it test-first following the &lt;a href="http://andymaleh.blogspot.com/2008/02/table-data-binding-and-mvp-in-glimmer.html"&gt;Model View Presenter&lt;/a&gt; pattern.&lt;br /&gt;&lt;br /&gt;Here is how the user-interface looks like:&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_XQt1Vabxo5g/SYEZ8R0EwpI/AAAAAAAAAKE/O7DutPqFvzg/s1600-h/Picture+17.png"&gt;&lt;img style="cursor:pointer; cursor:hand;width: 400px; height: 342px;" src="http://1.bp.blogspot.com/_XQt1Vabxo5g/SYEZ8R0EwpI/AAAAAAAAAKE/O7DutPqFvzg/s400/Picture+17.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5296543160129077906" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;I'll provide more details once I've committed the code to the &lt;a href="http://www.eclipse.org/glimmer"&gt;Glimmer&lt;/a&gt; &lt;a href="http://dev.eclipse.org/viewcvs/index.cgi/?root=Technology_GLIMMER"&gt;repository&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/32881756-403889723818572623?l=andymaleh.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://andymaleh.blogspot.com/feeds/403889723818572623/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=32881756&amp;postID=403889723818572623' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/32881756/posts/default/403889723818572623'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/32881756/posts/default/403889723818572623'/><link rel='alternate' type='text/html' href='http://andymaleh.blogspot.com/2009/01/sudoku-solver-in-glimmer.html' title='Sudoku Solver in Glimmer'/><author><name>Annas "Andy" Maleh</name><uri>http://www.blogger.com/profile/10268484073612495328</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/-f6UYG8WIYJI/Tpw6vYi2nTI/AAAAAAAAAPk/ICI9GDbAxh4/s1600/7312067a2015194b853856820711a178%253Fsize%253D200'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/_XQt1Vabxo5g/SYEZ8R0EwpI/AAAAAAAAAKE/O7DutPqFvzg/s72-c/Picture+17.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-32881756.post-4969381918782958540</id><published>2009-01-28T20:43:00.005-06:00</published><updated>2009-01-28T23:35:13.104-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Miscellaneous'/><title type='text'>About My 2008/2009 Vacation</title><content type='html'>I've been wanting to blog about this for a while, so here it goes.&lt;br /&gt;&lt;br /&gt;I spent my Christmas vacation this year in Dubai, and I got to see a lot of interesting things, such as the world's new highest tower (higher than CN), one of the world's largest malls (slightly larger than Edmonton's), a 7-star hotel that looks like a sail, an indoor skiing/snowboarding hill, palm artificial islands, and a hotel that is partially underwater and has a massive aquarium.&lt;br /&gt;&lt;br /&gt;Best of all, through a friend of mine who works in technology in Dubai, I got to go to a programming user group meeting that had Matt Mullenweg from WordPress/Automattic. &lt;br /&gt;&lt;br /&gt;Here are some photos from the trip:&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_XQt1Vabxo5g/SX_m1rAfGbI/AAAAAAAAAJk/MzGG1bZCEbs/s1600-h/IMG_0981.JPG"&gt;&lt;img style="cursor:pointer; cursor:hand;width: 240px; height: 320px;" src="http://3.bp.blogspot.com/_XQt1Vabxo5g/SX_m1rAfGbI/AAAAAAAAAJk/MzGG1bZCEbs/s320/IMG_0981.JPG" border="0" alt=""id="BLOGGER_PHOTO_ID_5296205496563210674" /&gt;&lt;/a&gt;&lt;br /&gt;Highest tower in the world (Burj Dubai)&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_XQt1Vabxo5g/SYEWbzVoSwI/AAAAAAAAAJs/6bJQtrrApdo/s1600-h/IMG_0788.JPG"&gt;&lt;img style="cursor:pointer; cursor:hand;width: 320px; height: 240px;" src="http://3.bp.blogspot.com/_XQt1Vabxo5g/SYEWbzVoSwI/AAAAAAAAAJs/6bJQtrrApdo/s320/IMG_0788.JPG" border="0" alt=""id="BLOGGER_PHOTO_ID_5296539303657622274" /&gt;&lt;/a&gt;&lt;br /&gt;Atlantis Hotel partially underwater at the head of the palm artificial islands&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_XQt1Vabxo5g/SYEW5pPC_uI/AAAAAAAAAJ0/4xIJPQPMF6A/s1600-h/IMG_0693.JPG"&gt;&lt;img style="cursor:pointer; cursor:hand;width: 240px; height: 320px;" src="http://4.bp.blogspot.com/_XQt1Vabxo5g/SYEW5pPC_uI/AAAAAAAAAJ0/4xIJPQPMF6A/s320/IMG_0693.JPG" border="0" alt=""id="BLOGGER_PHOTO_ID_5296539816341733090" /&gt;&lt;/a&gt;&lt;br /&gt;7-star hotel that looks like a sail (Burj al Arab)&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_XQt1Vabxo5g/SX_mmT9k_QI/AAAAAAAAAJY/xeJ2_VYVG90/s1600-h/IMG_1131.JPG"&gt;&lt;img style="cursor:pointer; cursor:hand;width: 240px; height: 320px;" src="http://3.bp.blogspot.com/_XQt1Vabxo5g/SX_mmT9k_QI/AAAAAAAAAJY/xeJ2_VYVG90/s320/IMG_1131.JPG" border="0" alt=""id="BLOGGER_PHOTO_ID_5296205232678960386" /&gt;&lt;/a&gt;&lt;br /&gt;Foggy skyscrapers&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_XQt1Vabxo5g/SYEXn1QMMHI/AAAAAAAAAJ8/5R1ASHbjJag/s1600-h/IMG_0915.JPG"&gt;&lt;img style="cursor:pointer; cursor:hand;width: 320px; height: 240px;" src="http://3.bp.blogspot.com/_XQt1Vabxo5g/SYEXn1QMMHI/AAAAAAAAAJ8/5R1ASHbjJag/s320/IMG_0915.JPG" border="0" alt=""id="BLOGGER_PHOTO_ID_5296540609841737842" /&gt;&lt;/a&gt;&lt;br /&gt;Indoor skiing/snowboarding hill&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_XQt1Vabxo5g/SYE_cmTlXzI/AAAAAAAAAKM/rb1VwxLmVTc/s1600-h/IMG_0930.JPG"&gt;&lt;img style="cursor:pointer; cursor:hand;width: 400px; height: 300px;" src="http://3.bp.blogspot.com/_XQt1Vabxo5g/SYE_cmTlXzI/AAAAAAAAAKM/rb1VwxLmVTc/s400/IMG_0930.JPG" border="0" alt=""id="BLOGGER_PHOTO_ID_5296584397315989298" /&gt;&lt;/a&gt;&lt;br /&gt;Me and a snowboard on the indoor hill&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_XQt1Vabxo5g/SX_l_gaJDVI/AAAAAAAAAI4/gYeP3DRpsxA/s1600-h/IMG_1235.JPG"&gt;&lt;img style="cursor:pointer; cursor:hand;width: 320px; height: 240px;" src="http://1.bp.blogspot.com/_XQt1Vabxo5g/SX_l_gaJDVI/AAAAAAAAAI4/gYeP3DRpsxA/s320/IMG_1235.JPG" border="0" alt=""id="BLOGGER_PHOTO_ID_5296204566005091666" /&gt;&lt;/a&gt;&lt;br /&gt;User group meeting with Matt from WordPress&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/32881756-4969381918782958540?l=andymaleh.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://andymaleh.blogspot.com/feeds/4969381918782958540/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=32881756&amp;postID=4969381918782958540' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/32881756/posts/default/4969381918782958540'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/32881756/posts/default/4969381918782958540'/><link rel='alternate' type='text/html' href='http://andymaleh.blogspot.com/2009/01/about-my-20082009-vacation.html' title='About My 2008/2009 Vacation'/><author><name>Annas "Andy" Maleh</name><uri>http://www.blogger.com/profile/10268484073612495328</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/-f6UYG8WIYJI/Tpw6vYi2nTI/AAAAAAAAAPk/ICI9GDbAxh4/s1600/7312067a2015194b853856820711a178%253Fsize%253D200'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/_XQt1Vabxo5g/SX_m1rAfGbI/AAAAAAAAAJk/MzGG1bZCEbs/s72-c/IMG_0981.JPG' height='72' width='72'/><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-32881756.post-1568991420491787977</id><published>2009-01-14T21:09:00.013-06:00</published><updated>2009-01-14T21:25:07.476-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Ruby'/><title type='text'>Easily Typable</title><content type='html'>For the Rubyists of us, I created a new mixin module called EasilyTypable:&lt;br /&gt;&lt;br /&gt;&lt;a href="http://github.com/AndyObtiva/easilytypable/tree/master"&gt;http://github.com/AndyObtiva/easilytypable/tree/master&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;I am pasting the README for it over here:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;Easily Typable&lt;br /&gt;==============&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Introduction:&lt;br /&gt;-------------&lt;br /&gt;&lt;br /&gt;Often when working with models that belong to an inheritance hierarchy, &lt;br /&gt;it is useful to verify if a particular model is of a certain type to &lt;br /&gt;perform some behavior specific to it. For example, this is needed when &lt;br /&gt;the view needs to handle a special rendering case when encountering a&lt;br /&gt;certain type.&lt;br /&gt;&lt;br /&gt;The call typically made to accomplish the task is: &lt;br /&gt;model.is_a?(CertainType)&lt;br /&gt;&lt;br /&gt;Often, to do so in a more readable fashion, developers add a more &lt;br /&gt;English-like method that hides the details of type checking: &lt;br /&gt;model.certain_type? &lt;br /&gt;&lt;br /&gt;Writing such methods gets repetitive after a while, so an easier way &lt;br /&gt;to get these methods automatically is to mixin the EasilyTypable &lt;br /&gt;module.&lt;br /&gt;&lt;br /&gt;When mixed into classes in an inheritance hierarchy, each class gets &lt;br /&gt;"certain_type?" methods for its type and all of its subclass types.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Example:&lt;br /&gt;--------&lt;br /&gt;&lt;br /&gt;require 'rubygems'&lt;br /&gt;require 'spec'&lt;br /&gt;require File.dirname(__FILE__) + '/../lib/easily_typable'&lt;br /&gt;&lt;br /&gt;class TypeA&lt;br /&gt;  include Obtiva::EasilyTypable&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;class TypeB &lt; TypeA&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;class TypeC &lt; TypeB&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;describe "Obtiva::EasilyTypable" do&lt;br /&gt;  it "should add type_a? method to TypeA object" do&lt;br /&gt;    TypeA.new.type_a?.should be_true&lt;br /&gt;  end&lt;br /&gt;  it "should add type_b? method to TypeB object" do&lt;br /&gt;    TypeB.new.type_b?.should be_true&lt;br /&gt;  end&lt;br /&gt;  it "should add type_b? method to TypeA object" do&lt;br /&gt;    TypeA.new.type_b?.should be_false&lt;br /&gt;  end&lt;br /&gt;  it "should add type_c? method to TypeC object" do&lt;br /&gt;    TypeC.new.type_c?.should be_true&lt;br /&gt;  end&lt;br /&gt;  it "should add type_c? method to TypeA object" do&lt;br /&gt;    TypeA.new.type_c?.should be_false&lt;br /&gt;  end&lt;br /&gt;  it "should add type_c? method to TypeB object" do&lt;br /&gt;    TypeB.new.type_c?.should be_false&lt;br /&gt;  end&lt;br /&gt;end&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Keep in mind that this is no substitute for good Object-Oriented design and is not an excuse to type-check everything in your code instead of letting behavior live in the models or rely on patterns like Strategy and State.&lt;br /&gt;&lt;br /&gt;The type checking methods are simply useful in cases where type-related behavior really should not live on the model to maintain its cohesion and avoid strong coupling. An example of that is View logic that depends on the type of the model, but should not live in the model.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/32881756-1568991420491787977?l=andymaleh.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://andymaleh.blogspot.com/feeds/1568991420491787977/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=32881756&amp;postID=1568991420491787977' title='11 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/32881756/posts/default/1568991420491787977'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/32881756/posts/default/1568991420491787977'/><link rel='alternate' type='text/html' href='http://andymaleh.blogspot.com/2009/01/easily-typable.html' title='Easily Typable'/><author><name>Annas "Andy" Maleh</name><uri>http://www.blogger.com/profile/10268484073612495328</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/-f6UYG8WIYJI/Tpw6vYi2nTI/AAAAAAAAAPk/ICI9GDbAxh4/s1600/7312067a2015194b853856820711a178%253Fsize%253D200'/></author><thr:total>11</thr:total></entry><entry><id>tag:blogger.com,1999:blog-32881756.post-2291443617408276893</id><published>2008-12-22T08:33:00.004-06:00</published><updated>2008-12-22T08:40:04.672-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Eclipse'/><category scheme='http://www.blogger.com/atom/ns#' term='Conferences'/><category scheme='http://www.blogger.com/atom/ns#' term='Glimmer'/><title type='text'>Glimmer Short Talk Description Change for EclipseCon 2009</title><content type='html'>I reported a few days ago that I will be presenting Glimmer at EclipseCon 2009:&lt;br /&gt;&lt;a href="http://andymaleh.blogspot.com/2008/12/eclipsecon-2009-here-i-come.html"&gt;http://andymaleh.blogspot.com/2008/12/eclipsecon-2009-here-i-come.html&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;I just wanted to mention that I updated the description to provide more value to attendees in the 10-minute talk that I will be giving in 2009. Last year, I provided a quick introduction to what Glimmer is about. This year, I will expand by demonstrating the latest features added to Glimmer.&lt;br /&gt;&lt;br /&gt;Here is the part I specifically changed in the talk's description:&lt;br /&gt;&lt;blockquote style="font-style: italic;"&gt;In this presentation, I will introduce Glimmer, demo the latest features by contrasting the code of an application written in both Glimmer and classic SWT, and finally provide a quick update on the status of the project.&lt;/blockquote&gt;Looking forward to seeing everyone at the conference.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/32881756-2291443617408276893?l=andymaleh.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://andymaleh.blogspot.com/feeds/2291443617408276893/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=32881756&amp;postID=2291443617408276893' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/32881756/posts/default/2291443617408276893'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/32881756/posts/default/2291443617408276893'/><link rel='alternate' type='text/html' href='http://andymaleh.blogspot.com/2008/12/glimmer-short-talk-description-change.html' title='Glimmer Short Talk Description Change for EclipseCon 2009'/><author><name>Annas "Andy" Maleh</name><uri>http://www.blogger.com/profile/10268484073612495328</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/-f6UYG8WIYJI/Tpw6vYi2nTI/AAAAAAAAAPk/ICI9GDbAxh4/s1600/7312067a2015194b853856820711a178%253Fsize%253D200'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-32881756.post-3256547103309603755</id><published>2008-12-21T22:22:00.005-06:00</published><updated>2008-12-21T22:46:58.204-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Consulting'/><category scheme='http://www.blogger.com/atom/ns#' term='Craftsmanship'/><category scheme='http://www.blogger.com/atom/ns#' term='Agile Methodologies'/><title type='text'>Black Box vs Invisible Box of Professional Practices</title><content type='html'>When a non-technical client requests software development services from a consulting shop, and they agree about the development of a certain application (the what,) is it a good idea to discuss the practices that will be followed in order to get the job done (the how,) or would mentioning the practices be irrelevant to a client who is not technical and has no expertise with software development?&lt;br /&gt;&lt;br /&gt;For example, a certain consulting shop may choose to build the client's application following XP practices because from experience, developers at that shop have found that they finish developing features faster and with higher quality when following the XP process.&lt;br /&gt;&lt;br /&gt;Is it relevant at all to mention these practices to a client who knows nothing about XP  without being asked first? Or is it initially better to provide the client with the minimum amount of information needed, such as the number of developers, hourly-rate, estimated development time, etc...?&lt;br /&gt;&lt;br /&gt;If the client was curious to know how the application is being developed, the details can always be provided when asked, but the reason I am asking the questions above is because often, mentioning these details too early can muddy the water and give the client authority over practices they do not have the qualifications to decide on.&lt;br /&gt;&lt;br /&gt;For example, mentioning radical practices such as test-driven development and pair-programming sometimes stirs up discomfort and confusion about how these practices work due to lack of experience with them (like the classical misconception that the two practices aforementioned reduce productivity instead of increasing it.) The client then may demand removal/adjustment of the practices when in fact, the main reason the practices are followed is to serve the client in the most professional and productive way possible. That leads to the often frowned upon micro-management of practices, thus hindering creativity and productivity.&lt;br /&gt;&lt;br /&gt;Without micro-management on the other hand, when the client is told he is sold the work hours of four developers with a certain estimate for application release, the developers can choose any way they desire to accomplish the client's goals. If they decide that it's more productive to pair on certain tasks and always write tests first, that is their decision. Trusting them with that freedom can often result in higher creativity and productivity in the long run, freeing the client from focusing on practices (the how) in order to focus on coming up with the best product to build (the what.)&lt;br /&gt;&lt;br /&gt;After all, when I request from a company to build me a house, I do not want to be bored with all the technical details about how it is going to be built. I just want a quality home built by a certain date. If I get interested enough to know about the practices followed, I will ask, but I do not want to waste my time hearing about them before the beginning of the project if they do not affect my involvement with it.&lt;br /&gt;&lt;br /&gt;In either case, clients still need to hear about the practices that directly affect their involvement with the development of the product. For example, stand-up meetings and iterative planning are two XP practices that need to be agreed on with the client before beginning the project in order to get the client's commitment and effectively apply them.&lt;br /&gt;&lt;br /&gt;How would you answer the questions asked above? Are you in favor of having a black box or an invisible box around the professional practices that do not directly affect the client? Keep in mind that in either case, the box is transparent. It's just that with the black box, the client has to look closely to see them (like looking at tinted glass) whereas with the invisible box, all the details are being shown even before asking for them.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/32881756-3256547103309603755?l=andymaleh.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://andymaleh.blogspot.com/feeds/3256547103309603755/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=32881756&amp;postID=3256547103309603755' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/32881756/posts/default/3256547103309603755'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/32881756/posts/default/3256547103309603755'/><link rel='alternate' type='text/html' href='http://andymaleh.blogspot.com/2008/12/black-box-vs-invisible-box-of.html' title='Black Box vs Invisible Box of Professional Practices'/><author><name>Annas "Andy" Maleh</name><uri>http://www.blogger.com/profile/10268484073612495328</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/-f6UYG8WIYJI/Tpw6vYi2nTI/AAAAAAAAAPk/ICI9GDbAxh4/s1600/7312067a2015194b853856820711a178%253Fsize%253D200'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-32881756.post-3393008735323905231</id><published>2008-12-20T17:31:00.002-06:00</published><updated>2008-12-21T15:21:19.218-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Craftsmanship'/><title type='text'>The Attitudes for Excelling in a Team</title><content type='html'>Programmers working on a team often fall into the trap of comparing their skills to their coworkers and feeling negative about it. They often forget that people have different strengths and weaknesses, and having different perspectives and styles of work actually improves synergy and output rather than hinder it.&lt;br /&gt;&lt;br /&gt;What are some attitudes that can help a team be more effective though?&lt;br /&gt;&lt;br /&gt;Here is a list I just brainstormed quickly:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Motivation, enthusiasm, and excitement&lt;/li&gt;&lt;li&gt;Positive attitude and optimism&lt;/li&gt;&lt;li&gt;Respect and patience&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Humbleness&lt;/li&gt;&lt;li&gt;Belief in the value of others&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Love for learning&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;Could you think of other attitudes or traits that would help a team be more effective?&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/32881756-3393008735323905231?l=andymaleh.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://andymaleh.blogspot.com/feeds/3393008735323905231/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=32881756&amp;postID=3393008735323905231' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/32881756/posts/default/3393008735323905231'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/32881756/posts/default/3393008735323905231'/><link rel='alternate' type='text/html' href='http://andymaleh.blogspot.com/2008/12/attitudes-for-excelling-as-team.html' title='The Attitudes for Excelling in a Team'/><author><name>Annas "Andy" Maleh</name><uri>http://www.blogger.com/profile/10268484073612495328</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/-f6UYG8WIYJI/Tpw6vYi2nTI/AAAAAAAAAPk/ICI9GDbAxh4/s1600/7312067a2015194b853856820711a178%253Fsize%253D200'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-32881756.post-4169552422939852906</id><published>2008-12-19T07:40:00.008-06:00</published><updated>2008-12-19T08:11:41.324-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Craftsmanship'/><title type='text'>Contributing Value as a Junior Developer</title><content type='html'>When I was still a junior software developer in the enterprise, I often felt like my opinion did not count. I had the typical shyness many junior developers have at their first job out of college. Whenever I was in the presence of senior developers, I worried about whether what I said would sound dumb and attempted as much as possible to be right to avoid embarrassing myself.&lt;br /&gt;&lt;br /&gt;What was the net result of that?&lt;br /&gt;&lt;br /&gt;I shared my opinion less and less, holding back on any ideas I had, and feeling frustrated with myself being junior. I had the illusion that if I gain enough experience and knowledge, I would finally speak intelligently and assert myself. &lt;br /&gt;&lt;br /&gt;Also, whenever I was sure of something I said to someone more senior, and he was not convinced of it, I would get really angry.&lt;br /&gt;&lt;br /&gt;That attitude finally changed after I learned two things:&lt;br /&gt;&lt;ol&gt;&lt;li&gt;Even the most senior and experienced of developers are sometimes wrong and they often humbly admit it because to them, finding the truth and serving the customer is much more important than others' perception of them.&lt;/li&gt;&lt;li&gt;When working with other people, our brains are not directly connected to theirs, so communication is not instantanious or perfect, often requiring a lot of patience and many attempts from both the speaker and listener before the message is communicated successfully.&lt;/li&gt;&lt;/ol&gt;&lt;br /&gt;Once my attitude changed, my behavior changed too as a consequence. &lt;br /&gt;&lt;br /&gt;For example, now whenever I have an idea I would like to share, I speak up about it despite knowing that the team may resist it or the idea may simply be bad. Why? Because that's why we work as a team; to get different ideas, different perspectives, and different thoughts. Every opinion matters whether it's from a senior developer or a junior developer. Having a different mind thinking about the problem is very valuable. And, if the idea is not good for some reason, so what? I learn something new and I feel good about stimulating others' thoughts with my suggestion, possibly helping them come up with a different more effective idea.&lt;br /&gt;&lt;br /&gt;Also, whenever someone would not see my point of view or not be convinced of something I said, I would take a deep breath and try to communicate it a different way by drawing on the whiteboard, telling a story or scenario, giving a concrete example, or asking the person questions that point him to the message I was trying to communicate. At least, when communication fails, I don't take it personally and appreciate the fact that other people have different points of view and paradigms of thinking, which could make it challenging to communicate a point sometimes. But, if the point does get communicated, the synergistic value of co-operation is priceless!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/32881756-4169552422939852906?l=andymaleh.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://andymaleh.blogspot.com/feeds/4169552422939852906/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=32881756&amp;postID=4169552422939852906' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/32881756/posts/default/4169552422939852906'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/32881756/posts/default/4169552422939852906'/><link rel='alternate' type='text/html' href='http://andymaleh.blogspot.com/2008/12/contributing-value-as-junior-developer.html' title='Contributing Value as a Junior Developer'/><author><name>Annas "Andy" Maleh</name><uri>http://www.blogger.com/profile/10268484073612495328</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/-f6UYG8WIYJI/Tpw6vYi2nTI/AAAAAAAAAPk/ICI9GDbAxh4/s1600/7312067a2015194b853856820711a178%253Fsize%253D200'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-32881756.post-7594139686936609353</id><published>2008-12-18T08:51:00.002-06:00</published><updated>2008-12-18T08:51:00.296-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Craftsmanship'/><title type='text'>Ridiculous or Outside the Box?</title><content type='html'>Ever heard someone call your idea about something ridiculous? &lt;br /&gt;&lt;br /&gt;Well, that may be a good sign about the idea. &lt;br /&gt;&lt;br /&gt;Usually, when people call something ridiculous it is not because they objectively thought about it and found it ridiculous. It is because it triggered a feeling in their body that it's ridiculous. If they had thought about it objectively, they would have pointed out why they don't believe the idea is good and/or listened to you actively to figure out why you believe the idea is useful.&lt;br /&gt;&lt;br /&gt;But, when someone utters a statement like that, it means the idea completely shattered their first level of habituated thinking and triggered a feeling of discomfort in their body. It means the idea pierced through their current paradigms of thinking. It means the idea is fresh and has potential.&lt;br /&gt;&lt;br /&gt;So, the next time you hear the word ridiculous about an idea you mentioned, don't immediately flinch and take that personally. Instead, re-evaluate the idea objectively to verify that it is sound, and calmly present the pros and cons of implementing it versus the status quo or other ideas presented. &lt;br /&gt;&lt;br /&gt;After all, is the idea presented really ridiculous or is it simply outside the box?&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/32881756-7594139686936609353?l=andymaleh.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://andymaleh.blogspot.com/feeds/7594139686936609353/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=32881756&amp;postID=7594139686936609353' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/32881756/posts/default/7594139686936609353'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/32881756/posts/default/7594139686936609353'/><link rel='alternate' type='text/html' href='http://andymaleh.blogspot.com/2008/12/ridiculous-or-outside-box.html' title='Ridiculous or Outside the Box?'/><author><name>Annas "Andy" Maleh</name><uri>http://www.blogger.com/profile/10268484073612495328</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/-f6UYG8WIYJI/Tpw6vYi2nTI/AAAAAAAAAPk/ICI9GDbAxh4/s1600/7312067a2015194b853856820711a178%253Fsize%253D200'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-32881756.post-2241505018148552474</id><published>2008-12-17T10:18:00.011-06:00</published><updated>2008-12-17T16:52:15.860-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Eclipse'/><category scheme='http://www.blogger.com/atom/ns#' term='Conferences'/><category scheme='http://www.blogger.com/atom/ns#' term='Glimmer'/><title type='text'>EclipseCon 2009 Here I Come</title><content type='html'>&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="https://www.eclipsecon.org/submissions/2009/view_talk.php?id=367"&gt;&lt;img style="cursor: pointer; width: 100px; height: 100px;" src="http://www.eclipsecon.org/2009/static/image/100x100_speaking.gif" alt="I'm speaking at EclipseCon 2009" border="1" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;My Glimmer talk proposed for EclipseCon 2009 has been accepted:&lt;br /&gt;&lt;a href="https://www.eclipsecon.org/submissions/2009/view_talk.php?id=367"&gt;https://www.eclipsecon.org/submissions/2009/view_talk.php?id=367&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Looking forward to being at Santa Clara, California during Mar 23-26 2009.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/32881756-2241505018148552474?l=andymaleh.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://andymaleh.blogspot.com/feeds/2241505018148552474/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=32881756&amp;postID=2241505018148552474' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/32881756/posts/default/2241505018148552474'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/32881756/posts/default/2241505018148552474'/><link rel='alternate' type='text/html' href='http://andymaleh.blogspot.com/2008/12/eclipsecon-2009-here-i-come.html' title='EclipseCon 2009 Here I Come'/><author><name>Annas "Andy" Maleh</name><uri>http://www.blogger.com/profile/10268484073612495328</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/-f6UYG8WIYJI/Tpw6vYi2nTI/AAAAAAAAAPk/ICI9GDbAxh4/s1600/7312067a2015194b853856820711a178%253Fsize%253D200'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-32881756.post-8145807602704827140</id><published>2008-12-16T23:03:00.005-06:00</published><updated>2008-12-19T08:13:57.686-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Craftsmanship'/><category scheme='http://www.blogger.com/atom/ns#' term='Agile Methodologies'/><title type='text'>Pair Programming Tour</title><content type='html'>Corey Haines is a journeyman craftsman who's actually on a pair-programming tour.&lt;br /&gt;&lt;br /&gt;He visited us at the Obtiva studio in Chicago on Dec 5 and pair-programmed with my colleagues Joseph Leddy and Turner King:&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_XQt1Vabxo5g/SUiKUkIExWI/AAAAAAAAAHI/xab50LtreMM/s1600-h/IMG_0501.JPG"&gt;&lt;img style="cursor: pointer; width: 320px; height: 240px;" src="http://1.bp.blogspot.com/_XQt1Vabxo5g/SUiKUkIExWI/AAAAAAAAAHI/xab50LtreMM/s320/IMG_0501.JPG" alt="" id="BLOGGER_PHOTO_ID_5280622648991466850" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Here is a video of an interview he also conducted with our Chief Craftsman Dave Hoover:&lt;br /&gt;&lt;a href="http://programmingtour.blogspot.com/2008/12/talk-with-dave-hoover.html"&gt;&lt;embed allowscriptaccess="always" allowfullscreen="true" type="application/x-shockwave-flash" src="http://vimeo.com/moogaloop.swf?clip_id=2450782&amp;amp;server=vimeo.com&amp;amp;show_title=1&amp;amp;show_byline=1&amp;amp;show_portrait=0&amp;amp;color=&amp;amp;fullscreen=1" height="300" width="400"&gt;&lt;/embed&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;His tour blog is interesting in general as it includes interviews with a number of software craftsmen such as Uncle Bob, Brian Marick, David Chelimsky, and Micah Martin. Check it out here:&lt;br /&gt;&lt;a href="http://programmingtour.blogspot.com/"&gt;http://programmingtour.blogspot.com&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/32881756-8145807602704827140?l=andymaleh.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://andymaleh.blogspot.com/feeds/8145807602704827140/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=32881756&amp;postID=8145807602704827140' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/32881756/posts/default/8145807602704827140'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/32881756/posts/default/8145807602704827140'/><link rel='alternate' type='text/html' href='http://andymaleh.blogspot.com/2008/12/pair-programming-tour.html' title='Pair Programming Tour'/><author><name>Annas "Andy" Maleh</name><uri>http://www.blogger.com/profile/10268484073612495328</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/-f6UYG8WIYJI/Tpw6vYi2nTI/AAAAAAAAAPk/ICI9GDbAxh4/s1600/7312067a2015194b853856820711a178%253Fsize%253D200'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/_XQt1Vabxo5g/SUiKUkIExWI/AAAAAAAAAHI/xab50LtreMM/s72-c/IMG_0501.JPG' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-32881756.post-1229483968178456198</id><published>2008-12-15T10:07:00.001-06:00</published><updated>2008-12-15T11:07:46.720-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Craftsmanship'/><category scheme='http://www.blogger.com/atom/ns#' term='Agile Methodologies'/><title type='text'>Dynamic Languages Replacing Static Ones?</title><content type='html'>A number of years ago, Uncle Bob (&lt;a href="http://www.objectmentor.com/omTeam/martin_r.html"&gt;Robert C. Martin&lt;/a&gt;) wondered if dynamic languages would replace static languages for mainstream software development.&lt;br /&gt;&lt;br /&gt;Here is a summary of an article he wrote in 2003 titled &lt;a href="http://www.artima.com/weblogs/viewpost.jsp?thread=4639"&gt;"Are Dynamic Languages Going to Replace Static Languages?"&lt;/a&gt;:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;For many years we've been using statically typed languages for the safety they offer. But now, as we all gradually adopt Test Driven Development, are we going to find that safety redundant? Will we therefore decide that the flexibility of dynamically typed languages is desirable?&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;The static languages being referred to by the article are typical mainstream static languages such as Java and C++ by the way, not languages like Haskell or Objective Caml.&lt;br /&gt;&lt;br /&gt;When writing all code test-first with 100% test coverage for the implementation, one seriously begins to wonder if the static typing is helping or in fact hindering design flexibility in comparison to dynamic typing.&lt;br /&gt;&lt;br /&gt;Here is a metaphor that may help us understand this better.&lt;br /&gt;&lt;br /&gt;Static typing is like choreographing circus stunts with safety built into the moves. The circus people can only practice moves that are safe and would not result in them crashing down in front of the audience. While such moves will still look good due to the great practice put into them, they are generally conservative due to safety consciousness.&lt;br /&gt;&lt;br /&gt;On the other hand, dynamic typing is like choreographing wild circus stunts, attempting such wild moves that if successful completely wow the audience.&lt;br /&gt;&lt;br /&gt;Traditionally, performers would get into horrible accidents while practicing such wild moves, which is the reason why static typing became the norm in software development for a while. It was after all, the only way to achieve reliable business software delivery.&lt;br /&gt;&lt;br /&gt;However, when the concept of a circus safety harness was introduced, performs were able to practice the wildest move and still be safe from injury. This is similar to having a unit-test suite acting as a safety harness for all the dynamically typed code you write. It lets you go wild with your software design, achieving unmatched productivity and flexibility with your code while remaining safely covered with your tests.&lt;br /&gt;&lt;br /&gt;So, did test-driven development change the playing ground enough to enable developers to leverage dynamic languages in favor of static ones without the traditional fears that encouraged static typing in the first place?&lt;br /&gt;&lt;a href="http://syntatic.wordpress.com/2008/11/25/the-closet-jrubyists/"&gt;&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/32881756-1229483968178456198?l=andymaleh.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://andymaleh.blogspot.com/feeds/1229483968178456198/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=32881756&amp;postID=1229483968178456198' title='5 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/32881756/posts/default/1229483968178456198'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/32881756/posts/default/1229483968178456198'/><link rel='alternate' type='text/html' href='http://andymaleh.blogspot.com/2008/12/dynamic-languages-replacing-static-ones.html' title='Dynamic Languages Replacing Static Ones?'/><author><name>Annas "Andy" Maleh</name><uri>http://www.blogger.com/profile/10268484073612495328</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/-f6UYG8WIYJI/Tpw6vYi2nTI/AAAAAAAAAPk/ICI9GDbAxh4/s1600/7312067a2015194b853856820711a178%253Fsize%253D200'/></author><thr:total>5</thr:total></entry><entry><id>tag:blogger.com,1999:blog-32881756.post-4000094226540917791</id><published>2008-12-14T23:15:00.001-06:00</published><updated>2008-12-14T23:36:15.552-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Ruby'/><category scheme='http://www.blogger.com/atom/ns#' term='Eclipse'/><category scheme='http://www.blogger.com/atom/ns#' term='Glimmer'/><title type='text'>First Code Example of Glimmer RSpec/SWTBot Testing</title><content type='html'>So, I mentioned in this &gt;&gt;&lt;a href="http://andymaleh.blogspot.com/2008/12/glimmers-got-bdd-through-rspec-and.html"&gt;blog post&lt;/a&gt;&lt;&lt; that Glimmer's now got Behavior-Driven Development support through &lt;a href="http://www.google.com/search?q=rspec+&amp;ie=utf-8&amp;oe=utf-8&amp;aq=t&amp;rls=org.mozilla:en-US:official&amp;client=firefox-a"&gt;RSpec&lt;/a&gt; and &lt;a href="http://swtbot.sourceforge.net/download.html"&gt;SWTBot&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;In this post, I'll go over some of the technical aspects of how that works.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://www.google.com/search?q=rspec+&amp;ie=utf-8&amp;oe=utf-8&amp;aq=t&amp;rls=org.mozilla:en-US:official&amp;client=firefox-a"&gt;RSpec&lt;/a&gt; Cucumber is an engine that lets you map English statements (or any language actually) to executable code in order to validate software specifications written as scenarios with the code written to fulfill them. This is pretty much what &lt;a href="http://www.extremeprogramming.org/rules/functionaltests.html"&gt;Acceptance Tests&lt;/a&gt; in the XP process are.&lt;br /&gt;&lt;br /&gt;Here is an RSpec Cucumber login.feature file that I wrote to test a Login (Glimmer) sample application:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;Feature: Login feature&lt;br /&gt;  In order to keep user data secure&lt;br /&gt;  As a user&lt;br /&gt;  I would like to be authenticated before I can access my data&lt;br /&gt;  &lt;br /&gt;  Scenario: Login&lt;br /&gt;    Given I fill in "User" for "Username"&lt;br /&gt;    And I fill in "Pass" for "Password"&lt;br /&gt;    When I "Login"&lt;br /&gt;    Then my status should be "Logged In"&lt;br /&gt;&lt;br /&gt;  Scenario: Logout&lt;br /&gt;    GivenScenario Login&lt;br /&gt;    When I "Logout"&lt;br /&gt;    Then my status should be "Logged Out"&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;The top 3 lines after the feature heading describe the user story being developed in the stakeholder language. Those lines are not executable.&lt;br /&gt;&lt;br /&gt;The scenarios that follow however, which demonstrate the feature functionality, are written in the Given/When/Then format and executed to validate that the implementation satisfies the specification. &lt;br /&gt;&lt;br /&gt;In order to execute these scenarios, you need to have code that can execute each step (statement on a line) in every scenario. Such code is arranged in *_steps.rb files. Here is how such code is written:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;When /I fill in "(.*)" for "(.*)"/ do |text, label|&lt;br /&gt;&amp;nbsp;&amp;nbsp;@bot.text_with_label(label).text = text&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;When /I "(.*)"/ do |button|&lt;br /&gt;&amp;nbsp;&amp;nbsp;@bot.button(button).click&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;Then /my status should be "(.*)"/ do |text|&lt;br /&gt;&amp;nbsp;&amp;nbsp;@bot.label(text).should_not be_nil&lt;br /&gt;end&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;The @bot object is actually an instance of the SWTBot class. This is an SWT driver that enables you to poke at an SWT desktop application by simulating a user filling in fields and initiating events like clicking a button.&lt;br /&gt;&lt;br /&gt;Let's go through the steps one by one.&lt;br /&gt;&lt;br /&gt;The following statement grabs a text box with the specified label, and sets its text property to whatever the text mentioned in the step is:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;When /I fill in "(.*)" for "(.*)"/ do |text, label|&lt;br /&gt;&amp;nbsp;&amp;nbsp;@bot.text_with_label(label).text = text&lt;br /&gt;end&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;This following statement on the other hand grabs a button based on the text that is displayed on it, and simulates a user click on it:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;When /I "(.*)"/ do |button|&lt;br /&gt;&amp;nbsp;&amp;nbsp;@bot.button(button).click&lt;br /&gt;end&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Finally, this following statement looks for a label with the specified text and says that it should not be nil (null.) The should_not method is a method from RSpec that lets you write assertions using English-like statements as opposed to using the assert_equals method with two parameters:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;Then /my status should be "(.*)"/ do |text|&lt;br /&gt;&amp;nbsp;&amp;nbsp;@bot.label(text).should_not be_nil&lt;br /&gt;end&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;My code samples are still experimental and not ready to share yet. Once I have them in a good-enough state, I will commit them to the repository and blog about them in order to give people the opportunity to play with them.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/32881756-4000094226540917791?l=andymaleh.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://andymaleh.blogspot.com/feeds/4000094226540917791/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=32881756&amp;postID=4000094226540917791' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/32881756/posts/default/4000094226540917791'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/32881756/posts/default/4000094226540917791'/><link rel='alternate' type='text/html' href='http://andymaleh.blogspot.com/2008/12/first-example-of-glimmer-rspecswtbot.html' title='First Code Example of Glimmer RSpec/SWTBot Testing'/><author><name>Annas "Andy" Maleh</name><uri>http://www.blogger.com/profile/10268484073612495328</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/-f6UYG8WIYJI/Tpw6vYi2nTI/AAAAAAAAAPk/ICI9GDbAxh4/s1600/7312067a2015194b853856820711a178%253Fsize%253D200'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-32881756.post-8617404250446533631</id><published>2008-12-13T09:53:00.002-06:00</published><updated>2008-12-13T09:53:00.289-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Eclipse'/><title type='text'>Friend of Eclipse 2009</title><content type='html'>Just wanted to share that I renewed my friendship with Eclipse.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://www.eclipse.org/donate/"&gt;&lt;img src="http://www.eclipse.org/donate/images/friendslogo.jpg"/&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;If you want to become a friend too or just renew your friendship, click on the image above for more details.&lt;br /&gt;&lt;br /&gt;I do it because I am very appreciative of all the work that went into Eclipse, RCP, SWT, and the ecosystem in general.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/32881756-8617404250446533631?l=andymaleh.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://andymaleh.blogspot.com/feeds/8617404250446533631/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=32881756&amp;postID=8617404250446533631' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/32881756/posts/default/8617404250446533631'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/32881756/posts/default/8617404250446533631'/><link rel='alternate' type='text/html' href='http://andymaleh.blogspot.com/2008/12/friend-of-eclipse-2009.html' title='Friend of Eclipse 2009'/><author><name>Annas "Andy" Maleh</name><uri>http://www.blogger.com/profile/10268484073612495328</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/-f6UYG8WIYJI/Tpw6vYi2nTI/AAAAAAAAAPk/ICI9GDbAxh4/s1600/7312067a2015194b853856820711a178%253Fsize%253D200'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-32881756.post-8283989999769975829</id><published>2008-12-12T08:02:00.002-06:00</published><updated>2008-12-12T08:02:00.440-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Craftsmanship'/><category scheme='http://www.blogger.com/atom/ns#' term='Agile Methodologies'/><title type='text'>Writing More Code Is Easier!?!</title><content type='html'>The statement in the title may sound like an oxymoron, but some developers I met seem to believe it. &lt;br /&gt;&lt;br /&gt;A developer came to me one time asking me for help with a problem he struggled with for hours. The first question I asked, as I usually do: "Are the tests passing?" His response was that he was under a lot of pressure, and he had to deliver a feature very quickly for the manager. In other words, no tests were written, and the developer was planning to write them after he had verified through the web browser user-interface that the feature is fully functional. &lt;br /&gt;&lt;br /&gt;I took a look at the code and saw that it consisted of more than 50 lines of heavy logic packed into one gigantic method. It was difficult to read and decipher, but after I got a grasp on what the developer was attempting to do, I realized that most of the logic could have been done with one line of code using one of the 3rd party libraries used heavily on the project. &lt;br /&gt;&lt;br /&gt;I asked the developer if he thought of checking whether that feature was in the library first before writing it from scratch, and he said he was so much in a hurry, he did not want to spend the time on that kind of research. &lt;br /&gt;&lt;br /&gt;Well, I ended up writing a test as if the method never existed (keeping with the test first philosophy,) commented the method code out, ran the test and got it failing, added a few lines of code to pass the test, wrote another test, wrote some more code including the one line needed from the 3rd party library, and voila. A method with no more than 7 lines of code was working perfectly according to the tests that specified the behavior.&lt;br /&gt;&lt;br /&gt;So, while it may seem like writing more code is easier than doing the hard work of &lt;a href="http://en.wikipedia.org/wiki/Don%27t_repeat_yourself"&gt;DRY&lt;/a&gt;ing it up, applying design patterns, and reusing libraries that can help, more code means more code to maintain and more potential bugs to deal with. In other words, more work in the future that becomes a lot harder to deal with than writing less code that is simpler and more reliable.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/32881756-8283989999769975829?l=andymaleh.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://andymaleh.blogspot.com/feeds/8283989999769975829/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=32881756&amp;postID=8283989999769975829' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/32881756/posts/default/8283989999769975829'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/32881756/posts/default/8283989999769975829'/><link rel='alternate' type='text/html' href='http://andymaleh.blogspot.com/2008/12/writing-more-code-is-easier.html' title='Writing More Code Is Easier!?!'/><author><name>Annas "Andy" Maleh</name><uri>http://www.blogger.com/profile/10268484073612495328</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/-f6UYG8WIYJI/Tpw6vYi2nTI/AAAAAAAAAPk/ICI9GDbAxh4/s1600/7312067a2015194b853856820711a178%253Fsize%253D200'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-32881756.post-5723541114306490373</id><published>2008-12-11T10:08:00.008-06:00</published><updated>2008-12-12T00:37:51.334-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Ruby'/><category scheme='http://www.blogger.com/atom/ns#' term='Eclipse'/><category scheme='http://www.blogger.com/atom/ns#' term='Glimmer'/><title type='text'>Glimmer's Got BDD through RSpec and SWTBot</title><content type='html'>I got an &lt;a href="http://rspec.info/"&gt;RSpec&lt;/a&gt; Story Runner (&lt;a href="http://github.com/aslakhellesoy/cucumber/tree/master"&gt;Cucumber&lt;/a&gt;) test passing with &lt;a href="http://www.eclipse.org/glimmer/"&gt;Glimmer&lt;/a&gt; code that tests whether a user logs in successfully. &lt;br /&gt;&lt;br /&gt;&lt;a href="http://rspec.info/"&gt;RSpec&lt;/a&gt; is a Ruby library that encourages BDD (&lt;a href="http://en.wikipedia.org/wiki/Behavior_Driven_Development"&gt;Behavior Driven Development&lt;/a&gt;,) enabling you to drive the functionality of your application from the outside in by specifying the external behavior from the user's point of view and in the user's language.&lt;br /&gt;&lt;br /&gt;Here is the test I got passing with &lt;a href="http://www.eclipse.org/glimmer/"&gt;Glimmer&lt;/a&gt;:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;Feature: Login feature&lt;br /&gt;  In order to keep user data secure&lt;br /&gt;  As a user&lt;br /&gt;  I would like to be authenticated before I can access my data&lt;br /&gt;  &lt;br /&gt;  Scenario: Login&lt;br /&gt;    Given I fill in "User" for "Username"&lt;br /&gt;    And I fill in "Pass" for "Password"&lt;br /&gt;    When I "Login"&lt;br /&gt;    Then my status should become "Logged In"&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;It uses &lt;a href="http://www.eclipse.org/swtbot/"&gt;SWTBot&lt;/a&gt; behind the scenes to execute the scenario steps, such as filling in text fields and pressing the login button.&lt;br /&gt;&lt;br /&gt;Here is the user-interface:&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_XQt1Vabxo5g/SUE6iD2TErI/AAAAAAAAAHA/xmBAoIk-fG4/s1600-h/Glimmer+Login+Sample.png"&gt;&lt;img style="cursor:pointer; cursor:hand;width: 174px; height: 155px;" src="http://3.bp.blogspot.com/_XQt1Vabxo5g/SUE6iD2TErI/AAAAAAAAAHA/xmBAoIk-fG4/s400/Glimmer+Login+Sample.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5278564595077943986" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Here is the user-interface Glimmer code relying on data-binding:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;    @shell = shell {&lt;br /&gt;      text "Login"&lt;br /&gt;      composite { &lt;br /&gt;        layout GridLayout.new(2, false) #two columns with differing widths&lt;br /&gt;        &lt;br /&gt;        label { text "Username:" } # goes in column 1&lt;br /&gt;        text {                     # goes in column 2&lt;br /&gt;          text bind(presenter, :user_name) &lt;br /&gt;          enabled bind(presenter, :logged_out)&lt;br /&gt;        } &lt;br /&gt;        &lt;br /&gt;        label { text "Password:" } &lt;br /&gt;        text(SWT::PASSWORD | SWT::BORDER) { &lt;br /&gt;          text bind(presenter, :password) &lt;br /&gt;          enabled bind(presenter, :logged_out)&lt;br /&gt;        }&lt;br /&gt;        &lt;br /&gt;        label { text "Status:" } &lt;br /&gt;        label { text bind(presenter, :status) }&lt;br /&gt;        &lt;br /&gt;        button { &lt;br /&gt;          text "Login"&lt;br /&gt;          enabled bind(presenter, :logged_out)&lt;br /&gt;          on_widget_selected { presenter.login }&lt;br /&gt;        }&lt;br /&gt;        &lt;br /&gt;        button { &lt;br /&gt;          text "Logout"&lt;br /&gt;          enabled bind(presenter, :logged_in)&lt;br /&gt;          on_widget_selected { presenter.logout }&lt;br /&gt;        }&lt;br /&gt;      }&lt;br /&gt;    }&lt;br /&gt;    @shell.open&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;In a future post, I will discuss the technical details of how this works.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/32881756-5723541114306490373?l=andymaleh.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://andymaleh.blogspot.com/feeds/5723541114306490373/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=32881756&amp;postID=5723541114306490373' title='5 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/32881756/posts/default/5723541114306490373'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/32881756/posts/default/5723541114306490373'/><link rel='alternate' type='text/html' href='http://andymaleh.blogspot.com/2008/12/glimmers-got-bdd-through-rspec-and.html' title='Glimmer&apos;s Got BDD through RSpec and SWTBot'/><author><name>Annas "Andy" Maleh</name><uri>http://www.blogger.com/profile/10268484073612495328</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/-f6UYG8WIYJI/Tpw6vYi2nTI/AAAAAAAAAPk/ICI9GDbAxh4/s1600/7312067a2015194b853856820711a178%253Fsize%253D200'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/_XQt1Vabxo5g/SUE6iD2TErI/AAAAAAAAAHA/xmBAoIk-fG4/s72-c/Glimmer+Login+Sample.png' height='72' width='72'/><thr:total>5</thr:total></entry><entry><id>tag:blogger.com,1999:blog-32881756.post-281936885531426101</id><published>2008-12-10T08:31:00.001-06:00</published><updated>2008-12-10T08:31:01.135-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Object Oriented Programming'/><category scheme='http://www.blogger.com/atom/ns#' term='Java'/><title type='text'>OO Language Use to Write Stored Procedures</title><content type='html'>Co-workers at &lt;a href="http://obtiva.com"&gt;Obtiva&lt;/a&gt; meet up every Tuesday for a weekly event called "GeekFest." Lunch is ordered for us for free and we use that time to enjoy discussing the latest technologies, giving presentations, demoing programs, and having heated debates about things like mock-based testing vs state-based testing and Ruby vs Python.&lt;br /&gt;&lt;br /&gt;So anyways, I always like to think outside the box and ask some crazy questions, and yesterday I committed a crime by asking the following question after I saw a demo of a trigger and a stored procedure written to solve a specific problem that would have been harder to solve with writing application code (rare case): "Now that Oracle allows writing stored procedures in Java and MS SQL Server allows writing stored procedures in C#, isn't that the holy grail for developers that complain about how procedural and non-OO stored procedures are and how they produce difficult to maintain code? The Oracle Java version may be behind its time, but it's light years ahead as a language than that of stored procedures, isn't it?"&lt;br /&gt;&lt;br /&gt;I got a backlash almost by everyone, even from the most OO-centric developers. Apparently, I forgot about one very important detail that one of our new co-workers reminded me of. Stored procedure code meshes well with SQL, which is a DSL that makes writing query code much easier than in Java. This ends up with simpler code that is easier to read than embedding SQL queries within another language with a different paradigm, such as Java.&lt;br /&gt;&lt;br /&gt;Now, if we take that to the extreme, we would write all the application's query logic in stored procedures. So obviously, there is a point of diminishing returns. Stored procedures may be simple to write for small cases, but when used to write a whole application, they end up with the same issues that prompted the invention of OO methodologies, like lack of expressiveness for domain models due to no support for inheritance and polymorphism, and difficult maintenance as a developer is required to dig many levels into a procedure's code before understanding what it does due to no support for abstraction (assuming the code is well factored in many tiny procedures calling each other.) When a procedure is a method on an object, there is a lot more context to what it does, which saves developers from having to dig to understand what it does.&lt;br /&gt;&lt;br /&gt;So, while the stored procedure language is easier than Java for writing code intermingled with SQL for simple cases, that does not necessarily mean it scales well for big projects with complex domains.&lt;br /&gt;&lt;br /&gt;One last point that one of my co-workers mentioned that made a lot of sense is that you don't need an Object-Oriented language to write clean code. My response to that though is while that's absolutely true, you may still need an Object-Oriented language to write clean code that is easy to maintain when dealing with a complex domain. Just because the code is clean, it does not mean it's easy to maintain if the language is not expressive enough (no polymorphism, no inheritance, etc...)&lt;br /&gt;&lt;br /&gt;What do you think?&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/32881756-281936885531426101?l=andymaleh.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://andymaleh.blogspot.com/feeds/281936885531426101/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=32881756&amp;postID=281936885531426101' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/32881756/posts/default/281936885531426101'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/32881756/posts/default/281936885531426101'/><link rel='alternate' type='text/html' href='http://andymaleh.blogspot.com/2008/12/oo-language-use-to-write-stored.html' title='OO Language Use to Write Stored Procedures'/><author><name>Annas "Andy" Maleh</name><uri>http://www.blogger.com/profile/10268484073612495328</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/-f6UYG8WIYJI/Tpw6vYi2nTI/AAAAAAAAAPk/ICI9GDbAxh4/s1600/7312067a2015194b853856820711a178%253Fsize%253D200'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-32881756.post-7775676299898250872</id><published>2008-12-09T08:04:00.002-06:00</published><updated>2008-12-10T11:08:34.573-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Craftsmanship'/><title type='text'>Software Craftsmanship vs Software Engineering</title><content type='html'>I often hear a reference of &lt;a href="http://www.amazon.com/Software-Craftsmanship-Imperative-Pete-McBreen/dp/0201733862"&gt;Software Craftsmanship&lt;/a&gt; mentioned in opposition to Software Engineering, and I wonder: Are they really in conflict with each other?&lt;br /&gt;&lt;br /&gt;The word engineering often gives people the feeling that a bunch of engineers are working very hard on a drawing board to solve big problems and come up with complete execution plans before getting to the implementation phase. Craftsmanship on the other hand gives the image of an apprentice humbly climbing up the ladder of competency by learning the craft step-by-step with a journeyman or master who is quite comfortable with delivering value to the customer.&lt;br /&gt;&lt;br /&gt;Now, these are the touchy feely aspects of those two terms, and I can appreciate people leaning towards craftsmanship and seeing it in opposition to engineering with that regards. &lt;br /&gt;&lt;br /&gt;However, I believe there is real value in knowing what software engineering is truly about as opposed to simply a common feel about it.&lt;br /&gt;&lt;br /&gt;Here is one of the original definitions of Software Engineering (Naur and Randell, 1969):&lt;br /&gt;&lt;span style="font-style:italic;"&gt;Software engineering is the establishment of sound engineering principles in order to obtain economical software that is reliable  and works efficiently on real machines.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;At one point, Waterfall was the process of choice for accomplishing that goal. Later, iterative processes such as the Rational Unified Process became better agents for accomplishing it. Finally, the agile movement with XP and Scrum provided the most effective practices for accomplishing that goal.&lt;br /&gt;&lt;br /&gt;Now, with that definition in mind, is Software Craftsmanship in conflict with Software Engineering at all? Nope. Does Software Craftsmanship help with accomplishing the goal cited in the definition of Software Engineering? You bet.&lt;br /&gt;&lt;br /&gt;While engineering is about the macro goal of delivering economical software that is reliable and efficient, craftsmanship is about the micro process that can help with achieving that macro goal.&lt;br /&gt;&lt;br /&gt;One thing that can actually be considered the opposite of Software Craftsmanship though is academia without practice. Traditionally, the majority of software developers took a degree in Computer Science, Computer Engineering, or Electrical Engineering, and then proceeded to work after graduation with very little practical experience beyond relatively small school projects. Such developers tend to follow a lot of the theory they learned without personal validation or playing around outside the box of their education. Unfortunately, this ends up teaching them the hard and expensive way that they cannot take everything they learn for granted as they eventually remember that theory is simply distillation of reality and may always go out of sync or become inappropriate for certain work projects or situations.&lt;br /&gt;&lt;br /&gt;Craftsmanship on the other hand is more about learning the skills gradually and practically with the guidance of a skilled journeyman or master while working on real projects. Theory is still useful in that case in the form of supplemental reading, but practical work always ends up validating the theory or revealing its weakness in a certain setting. &lt;br /&gt;&lt;br /&gt;That said, going the academia route is not in conflict with Software Craftsmanship as long as students end up validating their skills in the real world during their education or shortly afterwards (e.g. open-source projects or internship projects) with the guidance of other developers in the software community. That was the route I went in fact, and I'm greatly appreciative of the guidance I received from &lt;a href="http://www.ktaylor.name/"&gt;Kevin Taylor&lt;/a&gt; and &lt;a href="http://redsquirrel.com/cgi-bin/dave"&gt;Dave Hoover&lt;/a&gt; who are strong believers in craftsmanship at &lt;a href="http://obtiva.com"&gt;Obtiva&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;So to recap, Software Engineering is not about over-engineering or heavy-weight processes like Waterfall; it is about delivering economical software that is reliable and efficient. Software Craftsmanship is therefore not in conflict with Software Engineering, yet in fact in harmony with it as it helps accomplish its goal through practical learning of software development with the guidance of experienced developers.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/32881756-7775676299898250872?l=andymaleh.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://andymaleh.blogspot.com/feeds/7775676299898250872/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=32881756&amp;postID=7775676299898250872' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/32881756/posts/default/7775676299898250872'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/32881756/posts/default/7775676299898250872'/><link rel='alternate' type='text/html' href='http://andymaleh.blogspot.com/2008/12/software-craftsmanship-vs-software.html' title='Software Craftsmanship vs Software Engineering'/><author><name>Annas "Andy" Maleh</name><uri>http://www.blogger.com/profile/10268484073612495328</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/-f6UYG8WIYJI/Tpw6vYi2nTI/AAAAAAAAAPk/ICI9GDbAxh4/s1600/7312067a2015194b853856820711a178%253Fsize%253D200'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-32881756.post-4683133629550869774</id><published>2008-12-08T07:52:00.000-06:00</published><updated>2008-12-08T07:52:00.731-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Java'/><title type='text'>To Get or To Do</title><content type='html'>So, the standard for getting property values from a model in Java is to call a getXYZ() method, like getName(), getAge(), getPrice(), etc...&lt;br /&gt;&lt;br /&gt;Sometimes though, a model may have a property calculated dynamically, such as total. Other times, a property is determined dynamically based on passed parameters, like sales for a particular customer.&lt;br /&gt;&lt;br /&gt;In these cases, do you prefer the name of the method to be getTotal() and getSales(Customer customer) or would names that reflect the behavior be more preferable, like calculateTotal() and determineSalesFor(Customer customer)?&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/32881756-4683133629550869774?l=andymaleh.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://andymaleh.blogspot.com/feeds/4683133629550869774/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=32881756&amp;postID=4683133629550869774' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/32881756/posts/default/4683133629550869774'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/32881756/posts/default/4683133629550869774'/><link rel='alternate' type='text/html' href='http://andymaleh.blogspot.com/2008/12/to-get-or-to-do.html' title='To Get or To Do'/><author><name>Annas "Andy" Maleh</name><uri>http://www.blogger.com/profile/10268484073612495328</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/-f6UYG8WIYJI/Tpw6vYi2nTI/AAAAAAAAAPk/ICI9GDbAxh4/s1600/7312067a2015194b853856820711a178%253Fsize%253D200'/></author><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-32881756.post-1426440211700420316</id><published>2008-12-07T09:59:00.007-06:00</published><updated>2008-12-08T01:11:51.145-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Java'/><category scheme='http://www.blogger.com/atom/ns#' term='Ruby'/><category scheme='http://www.blogger.com/atom/ns#' term='Craftsmanship'/><category scheme='http://www.blogger.com/atom/ns#' term='Agile Methodologies'/><title type='text'>NIH Syndrome or Blowing Reuse Out of Proportion?</title><content type='html'>I see a lot of developers nowadays favoring re-inventing the wheel over reusing an external library or component, especially in the Ruby and Javascript communities.&lt;br /&gt;&lt;br /&gt;The first thing that pops in my mind when I see them doing that is NIH (&lt;a href="http://en.wikipedia.org/wiki/Not_Invented_Here"&gt;Not Invented Here syndrome&lt;/a&gt;.)&lt;br /&gt;&lt;br /&gt;From my experience, reuse is not just about getting the features I need. It is also about stability, performance, usability, and other non-functional requirements that have been ironed out by the people who have created the reusable component and the communities that consumed it. Unless it fails in most of these areas, I usually don't see the point of re-inventing the wheel. While it seems simple to do on the surface, it is those hidden edge cases and bugs that creep up now and then that get me when re-writing it. This happens in the code when I have not thought of every possible scenario and in the design when I have not exercised the component in a real-world setting.&lt;br /&gt;&lt;br /&gt;What's the flip-side to this argument though?&lt;br /&gt;&lt;br /&gt;A lot of people in the agile community place great importance on minimalism. An ideal minimalistic code base does no more than necessary by your application. So, if you end up reusing components that do a lot more than needed, the complexity of learning how to configure them for your needs ends up offsetting the productivity gains behind using the components. In that case, re-inventing a smaller simpler wheel becomes a viable option.&lt;br /&gt;&lt;br /&gt;The key thing though is determining whether a required feature is complex enough that figuring out all its edge cases and usage scenarios would be worth the time to re-write from scratch vs simply reusing an existing component that gets the job done. That trade-off is the key determining factor.&lt;br /&gt;&lt;br /&gt;Does the programming language used play any role in the matter? I'd say yes. For example, I rarely find this option of "re-inventing the wheel" viable in Java since writing components in it is very slow. On the other hand, dynamic languages like Ruby and Javascript make it so quick and easy to build a component from scratch (when writing tests first) that it often is easier to re-write smaller components than to figure out how to use 3rd party ones.&lt;br /&gt;&lt;br /&gt;What is your opinion of the matter? Do you have examples where you reused a component vs other examples where you ended up writing your own?&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/32881756-1426440211700420316?l=andymaleh.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://andymaleh.blogspot.com/feeds/1426440211700420316/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=32881756&amp;postID=1426440211700420316' title='5 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/32881756/posts/default/1426440211700420316'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/32881756/posts/default/1426440211700420316'/><link rel='alternate' type='text/html' href='http://andymaleh.blogspot.com/2008/12/nih-syndrome-or-blowing-reuse-out-of.html' title='NIH Syndrome or Blowing Reuse Out of Proportion?'/><author><name>Annas "Andy" Maleh</name><uri>http://www.blogger.com/profile/10268484073612495328</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/-f6UYG8WIYJI/Tpw6vYi2nTI/AAAAAAAAAPk/ICI9GDbAxh4/s1600/7312067a2015194b853856820711a178%253Fsize%253D200'/></author><thr:total>5</thr:total></entry><entry><id>tag:blogger.com,1999:blog-32881756.post-5176257531634441299</id><published>2008-12-06T05:00:00.000-06:00</published><updated>2008-12-06T05:00:00.910-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Ruby'/><category scheme='http://www.blogger.com/atom/ns#' term='Eclipse'/><category scheme='http://www.blogger.com/atom/ns#' term='Glimmer'/><title type='text'>Glimmer on JRuby 1.1.5</title><content type='html'>Glimmer is now compatible with JRuby 1.1.5.&lt;br /&gt;&lt;br /&gt;Thanks to dacm for taking the effort to report a Glimmer incompatibility bug on Eclipse BugZilla:&lt;br /&gt;&lt;a href="https://bugs.eclipse.org/bugs/show_bug.cgi?id=257793"&gt;https://bugs.eclipse.org/bugs/show_bug.cgi?id=257793&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;It is now fixed.&lt;br /&gt;&lt;br /&gt;Thanks to Steve, Tom, and Starling too for reporting that bug along with the fix.&lt;br /&gt;&lt;br /&gt;The changes were deployed to both SVN and GitHub repositories.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/32881756-5176257531634441299?l=andymaleh.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://andymaleh.blogspot.com/feeds/5176257531634441299/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=32881756&amp;postID=5176257531634441299' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/32881756/posts/default/5176257531634441299'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/32881756/posts/default/5176257531634441299'/><link rel='alternate' type='text/html' href='http://andymaleh.blogspot.com/2008/12/glimmer-on-jruby-115.html' title='Glimmer on JRuby 1.1.5'/><author><name>Annas "Andy" Maleh</name><uri>http://www.blogger.com/profile/10268484073612495328</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/-f6UYG8WIYJI/Tpw6vYi2nTI/AAAAAAAAAPk/ICI9GDbAxh4/s1600/7312067a2015194b853856820711a178%253Fsize%253D200'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-32881756.post-9021766737814057617</id><published>2008-12-05T07:49:00.004-06:00</published><updated>2008-12-05T07:49:00.813-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Ruby'/><category scheme='http://www.blogger.com/atom/ns#' term='Eclipse'/><category scheme='http://www.blogger.com/atom/ns#' term='Glimmer'/><title type='text'>Glimmer Finally Available at GitHub</title><content type='html'>Yes! After so many requests, Glimmer's Eclipse SVN Repository is finally cloned at GitHub (thanks to Soleone's suggestion to use git-svn):&lt;br /&gt;git://github.com/AndyObtiva/glimmer.git&lt;br /&gt;&lt;br /&gt;Here is the main GitHub project page:&lt;br /&gt;&lt;a href="http://github.com/AndyObtiva/glimmer/tree/master"&gt;http://github.com/AndyObtiva/glimmer/tree/master&lt;/a&gt; &lt;br /&gt;&lt;br /&gt;This will make it much easier for people to contribute to Glimmer. Instead of checking out the SVN repository and submitting patches back to me to merge. Developers can now fork Glimmer completely on GitHub, commit multiple changes, and then notify me to merge the forked version back into the origin/trunk.&lt;br /&gt;&lt;br /&gt;Happy Glimmering!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/32881756-9021766737814057617?l=andymaleh.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://andymaleh.blogspot.com/feeds/9021766737814057617/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=32881756&amp;postID=9021766737814057617' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/32881756/posts/default/9021766737814057617'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/32881756/posts/default/9021766737814057617'/><link rel='alternate' type='text/html' href='http://andymaleh.blogspot.com/2008/12/glimmer-finally-available-at-github.html' title='Glimmer Finally Available at GitHub'/><author><name>Annas "Andy" Maleh</name><uri>http://www.blogger.com/profile/10268484073612495328</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/-f6UYG8WIYJI/Tpw6vYi2nTI/AAAAAAAAAPk/ICI9GDbAxh4/s1600/7312067a2015194b853856820711a178%253Fsize%253D200'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-32881756.post-8518034940338046735</id><published>2008-12-04T07:05:00.004-06:00</published><updated>2010-12-02T13:55:35.433-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Craftsmanship'/><category scheme='http://www.blogger.com/atom/ns#' term='Agile Methodologies'/><title type='text'>The Illusion of Delivery</title><content type='html'>Writing code without following certain &lt;a href="http://andymaleh.blogspot.com/2007/11/eclipseworld-2007-day-2-keynote-by-bob.html"&gt;professional&lt;/a&gt; practices often reminds me of a story I heard in Steven R Covey's book, The 7 Habits of Highly Effective People. The story was told to illustrate the difference between a leader and a manager. Here is roughly how it goes:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style:italic;"&gt;A group of people are cutting trees in the forest. One of them is a leader and another is a manager. The leader decides to climb a high tree at one point to see if they're making progress in the right direction. To his surprise, he finds out that they're actually cutting the wrong forest, so he yells at the top of his lungs "Wrong forest!!!" What does the manager say in response? "Shut up! We're making progress!"&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;This is pretty much what happens whenever a &lt;a href="http://andymaleh.blogspot.com/2007/11/eclipseworld-2007-day-2-keynote-by-bob.html"&gt;professional&lt;/a&gt; developer tries to remind a colleague of writing tests before writing code, pair-programming, or doing paper-prototyping on user-interfaces before implementing them.&lt;br /&gt;&lt;br /&gt;When the colleague resists the suggestion, reasoning that it is more important to deliver than follow one of the suggested practices, would the resulting delivery be real progress? Or would it just be an illusion?&lt;br /&gt;&lt;br /&gt;Let's look at test-driven development for an example. If a developer is delivering code without writing tests first, he may be delivering features "now," but if they have bugs that need to be fixed later with double the time at least that would have been spent writing the tests in the first place, was that real delivery or was it just an illusion?&lt;br /&gt;&lt;br /&gt;What about skipping pair-programming and working solo? After having a few years of experience in pair-programming, I am completely aware now of how slower I am at delivering complex features whenever I work on them on my own. Often, such features are scrapped completely and redone after a review with someone. Was that real delivery or just an illusion?&lt;br /&gt;&lt;br /&gt;How about delivering user-interfaces without doing any sort of conceptual design or paper-prototyping, let alone user testing? I've seen quite a number of user-interface screens developed and done only to be completely overhauled afterwards because they reflected the developer's mental model as opposed to the user's. Was that real delivery or just an illusion?&lt;br /&gt;&lt;br /&gt;Writing tests first guides developers towards better code design, provides a safety harness that enables future refactoring of the code and maintenance by other developers without unexpected bugs popping up in other areas of the application, and keeps progress real and linear as opposed to illusory and unpredictable.&lt;br /&gt;&lt;br /&gt;Pair-programming saves quite a bit of time by having developers sell each other on the benefits of certain designs before diving to implement them, results in transfer of knowledge between team members that makes them much stronger, and gets the benefit of unexpected synergistic solutions that often save hours of work. That's often much better delivery than having two programmers working independently all the time.&lt;br /&gt;&lt;br /&gt;Finally, a little bit of time spent on designing user-interface paper-prototypes (10 minutes) and a bit more time spent testing the prototypes with real (or model) users (10 more minutes,) saves developers from so much time in rewriting bad user-interfaces or figuring out a reasonably usable user-interfaces for the actual users.&lt;br /&gt;&lt;br /&gt;So, the next time you think about skipping one of the recommended professional practices, ask yourself: "Will I be delivering to the customer the most value in the long run if I skip this practice, or will I just be kidding myself into thinking that I'm delivering now when I'm hindering delivery in the long run and keeping myself in an illusion?"&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;One yardstick&lt;/span&gt; I use to evaluate whether my resistance to a suggested practice is legitimate or is just plain human resistance to change is to also ask myself "Am I only resisting it because I don't see how it can help the customer or is there a little bit of feeling of inconvenience to adopt it?" If there is even a nugget of feeling that I do not want to be inconvenienced by change, I give the practice another chance, keeping in mind that often it takes getting good at a certain practice before I can reap benefits from it.&lt;br /&gt;&lt;br /&gt;Final Note: there are of course situations where some of the practices mentioned above may not be appropriate. For example, in a situation where a legacy app requires one extra feature and the team is not trained in TDD, it wouldn't make sense to apply it, but it does make sense to think about implementing that practice strategically in the future.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/32881756-8518034940338046735?l=andymaleh.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://andymaleh.blogspot.com/feeds/8518034940338046735/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=32881756&amp;postID=8518034940338046735' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/32881756/posts/default/8518034940338046735'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/32881756/posts/default/8518034940338046735'/><link rel='alternate' type='text/html' href='http://andymaleh.blogspot.com/2008/12/illusion-of-delivery.html' title='The Illusion of Delivery'/><author><name>Annas "Andy" Maleh</name><uri>http://www.blogger.com/profile/10268484073612495328</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/-f6UYG8WIYJI/Tpw6vYi2nTI/AAAAAAAAAPk/ICI9GDbAxh4/s1600/7312067a2015194b853856820711a178%253Fsize%253D200'/></author><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-32881756.post-2599581601238141482</id><published>2008-12-03T07:08:00.000-06:00</published><updated>2008-12-03T07:08:01.110-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Ruby'/><category scheme='http://www.blogger.com/atom/ns#' term='Eclipse'/><category scheme='http://www.blogger.com/atom/ns#' term='Glimmer'/><title type='text'>Glimmer WIKI and FAQ</title><content type='html'>Glimmer's got pages on the Eclipse WIKI now:&lt;br /&gt;&lt;br /&gt;&lt;a href="http://wiki.eclipse.org/Glimmer"&gt;http://wiki.eclipse.org/Glimmer&lt;/a&gt;&lt;br /&gt;&lt;a href="http://wiki.eclipse.org/Glimmer/FAQ"&gt;http://wiki.eclipse.org/Glimmer/FAQ&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;They will be updated gradually as the project continues to grow.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/32881756-2599581601238141482?l=andymaleh.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://andymaleh.blogspot.com/feeds/2599581601238141482/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=32881756&amp;postID=2599581601238141482' title='6 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/32881756/posts/default/2599581601238141482'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/32881756/posts/default/2599581601238141482'/><link rel='alternate' type='text/html' href='http://andymaleh.blogspot.com/2008/12/glimmer-wiki-and-faq.html' title='Glimmer WIKI and FAQ'/><author><name>Annas "Andy" Maleh</name><uri>http://www.blogger.com/profile/10268484073612495328</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/-f6UYG8WIYJI/Tpw6vYi2nTI/AAAAAAAAAPk/ICI9GDbAxh4/s1600/7312067a2015194b853856820711a178%253Fsize%253D200'/></author><thr:total>6</thr:total></entry><entry><id>tag:blogger.com,1999:blog-32881756.post-2653782574100350492</id><published>2008-12-02T07:15:00.002-06:00</published><updated>2008-12-03T17:38:27.393-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Ruby'/><category scheme='http://www.blogger.com/atom/ns#' term='Eclipse'/><category scheme='http://www.blogger.com/atom/ns#' term='Conferences'/><category scheme='http://www.blogger.com/atom/ns#' term='Glimmer'/><title type='text'>Video of Glimmer DSL Engine lightning talk @ RubyConf 2008</title><content type='html'>A number of people expressed interest in contributing to Glimmer, and they wanted to get an understanding of Glimmer's internal workings in order to get started.&lt;br /&gt;&lt;br /&gt;I gave a lightning talk about Glimmer's DSL engine during RubyConf 2008, and fortunately the ConFreaks guys recorded a video of it, just as they recorded one of my &gt;&gt;&lt;a href="http://andymaleh.blogspot.com/2008/11/video-of-glimmer-talk-rubyconf-2008.html"&gt;main Glimmer talk&lt;/a&gt;&lt;&lt;.&lt;br /&gt;&lt;br /&gt;Check it out over here:&lt;br /&gt;&lt;a href="http://rubyconf2008.confreaks.com/glimmers-dsl-engine.html"&gt;http://rubyconf2008.confreaks.com/glimmers-dsl-engine.html&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;It is pretty short (10 minutes,) but provides a good primer for Glimmer's internal DSL engine.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/32881756-2653782574100350492?l=andymaleh.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://andymaleh.blogspot.com/feeds/2653782574100350492/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=32881756&amp;postID=2653782574100350492' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/32881756/posts/default/2653782574100350492'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/32881756/posts/default/2653782574100350492'/><link rel='alternate' type='text/html' href='http://andymaleh.blogspot.com/2008/12/video-of-glimmer-dsl-engine-lightning.html' title='Video of Glimmer DSL Engine lightning talk @ RubyConf 2008'/><author><name>Annas "Andy" Maleh</name><uri>http://www.blogger.com/profile/10268484073612495328</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/-f6UYG8WIYJI/Tpw6vYi2nTI/AAAAAAAAAPk/ICI9GDbAxh4/s1600/7312067a2015194b853856820711a178%253Fsize%253D200'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-32881756.post-7497756770317722912</id><published>2008-12-01T08:17:00.006-06:00</published><updated>2008-12-01T08:27:04.382-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Ruby'/><category scheme='http://www.blogger.com/atom/ns#' term='Eclipse'/><category scheme='http://www.blogger.com/atom/ns#' term='Glimmer'/><title type='text'>Glimmer Easy Tab Item Syntax</title><content type='html'>Have you ever found using TabItems and TabFolders somewhat painful due to their inconsistencies with the rest of the SWT widgets? For example, TabItem is not just any kind of widget as it does not get added to the children of TabFolder, yet to a special list of tab items instead. Additionally, you cannot use TabItem as a parent for other widgets. Instead, you must instantiate a Composite and then pass it to the setControl method on TabItem. It is something that I forget to do whenever I haven't used the TabItem widget for a while.&lt;br /&gt;&lt;br /&gt;Well, worry no more. Glimmer's got the solution.&lt;br /&gt;&lt;br /&gt;Check out this syntax:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;shell {&lt;br /&gt;  text "SWT"&lt;br /&gt;  tab_folder {&lt;br /&gt;    tab_item {&lt;br /&gt;      text "Tab 1"&lt;br /&gt;      label { &lt;br /&gt;        text "Hello World!" &lt;br /&gt;      }&lt;br /&gt;    }&lt;br /&gt;    tab_item {&lt;br /&gt;      text "Tab 2"&lt;br /&gt;      label { &lt;br /&gt;        text "Bonjour Univers!" &lt;br /&gt;      }&lt;br /&gt;    }&lt;br /&gt;  }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;The new tab_item in Glimmer acts as a special widget that feels like a composite by allowing you to lay widgets inside it, but still behaves like a tab item by allowing you to set the tab title text. Give it a spin, and let me know what you think. &lt;br /&gt;&lt;br /&gt;Here is the interface produced:&lt;br /&gt;&lt;br /&gt;Tab 1&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_XQt1Vabxo5g/STIKHlUcM2I/AAAAAAAAAGg/oai-baiNuWs/s1600-h/Hello+Easy+Tabs+Screenshot+1.png"&gt;&lt;img style="cursor:pointer; cursor:hand;width: 128px; height: 88px;" src="http://3.bp.blogspot.com/_XQt1Vabxo5g/STIKHlUcM2I/AAAAAAAAAGg/oai-baiNuWs/s400/Hello+Easy+Tabs+Screenshot+1.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5274289238997480290" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Tab 2&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_XQt1Vabxo5g/STIKLSbD7iI/AAAAAAAAAGo/tWOy-F8O7AA/s1600-h/Hello+Easy+Tabs+Screenshot+2.png"&gt;&lt;img style="cursor:pointer; cursor:hand;width: 129px; height: 86px;" src="http://1.bp.blogspot.com/_XQt1Vabxo5g/STIKLSbD7iI/AAAAAAAAAGo/tWOy-F8O7AA/s400/Hello+Easy+Tabs+Screenshot+2.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5274289302644452898" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;By the way, this feature was implemented in response to a suggestion by Tom Robinson. So, if there are any other features that you would like to see in Glimmer, please share in a comment, an email (andy &lt;at&gt; obtiva [dot] com,) or a post on the &lt;a href="http://www.eclipse.org/newsportal/thread.php?group=eclipse.technology.glimmer"&gt;Glimmer Eclipse newsgroup&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/32881756-7497756770317722912?l=andymaleh.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://andymaleh.blogspot.com/feeds/7497756770317722912/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=32881756&amp;postID=7497756770317722912' title='5 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/32881756/posts/default/7497756770317722912'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/32881756/posts/default/7497756770317722912'/><link rel='alternate' type='text/html' href='http://andymaleh.blogspot.com/2008/12/glimmer-easy-tab-item-syntax.html' title='Glimmer Easy Tab Item Syntax'/><author><name>Annas "Andy" Maleh</name><uri>http://www.blogger.com/profile/10268484073612495328</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/-f6UYG8WIYJI/Tpw6vYi2nTI/AAAAAAAAAPk/ICI9GDbAxh4/s1600/7312067a2015194b853856820711a178%253Fsize%253D200'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/_XQt1Vabxo5g/STIKHlUcM2I/AAAAAAAAAGg/oai-baiNuWs/s72-c/Hello+Easy+Tabs+Screenshot+1.png' height='72' width='72'/><thr:total>5</thr:total></entry><entry><id>tag:blogger.com,1999:blog-32881756.post-5915439426646996901</id><published>2008-11-30T08:58:00.002-06:00</published><updated>2011-03-25T09:38:33.330-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Ruby'/><category scheme='http://www.blogger.com/atom/ns#' term='Eclipse'/><category scheme='http://www.blogger.com/atom/ns#' term='Glimmer'/><title type='text'>Glimmer List Box Multi-Selection Data-Binding</title><content type='html'>I added data-binding support for multi-selection List boxes.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;class Person &lt;br /&gt;  attr_accessor :provinces, :provinces_options&lt;br /&gt;  &lt;br /&gt;  def initialize&lt;br /&gt;    self.provinces_options=[&lt;br /&gt;      "", &lt;br /&gt;      "Quebec", &lt;br /&gt;      "Ontario", &lt;br /&gt;      "Manitoba", &lt;br /&gt;      "Saskatchewan", &lt;br /&gt;      "Alberta", &lt;br /&gt;      "British Columbia", &lt;br /&gt;      "Nova Skotia", &lt;br /&gt;      "Newfoundland"&lt;br /&gt;    ]&lt;br /&gt;    self.provinces = ["Quebec", "Manitoba", "Alberta"]&lt;br /&gt;  end&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;class HelloMultiSelectList&lt;br /&gt;  include Glimmer&lt;br /&gt;  def launch&lt;br /&gt;    shell {&lt;br /&gt;      list(:multi) {&lt;br /&gt;        selection bind(Person.new, :provinces)&lt;br /&gt;      }&lt;br /&gt;    }.open&lt;br /&gt;  end&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;HelloMultiSelectList.new.launch&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;This produces a tiny shell with a multi-selection list box that has "Quebec", "Manitoba", and "Alberta" preselected:&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_XQt1Vabxo5g/STCHmPpZD1I/AAAAAAAAAGY/HdJISejnEAY/s1600-h/Hello+Multi-Select+List+Screenshot.png"&gt;&lt;img style="cursor:pointer; cursor:hand;width: 135px; height: 194px;" src="http://4.bp.blogspot.com/_XQt1Vabxo5g/STCHmPpZD1I/AAAAAAAAAGY/HdJISejnEAY/s400/Hello+Multi-Select+List+Screenshot.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5273864254755770194" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Stay tuned for &lt;a href="http://andymaleh.blogspot.com/2008/12/glimmer-easy-tab-item-syntax.html"&gt;simplified tab syntax&lt;/a&gt; next!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/32881756-5915439426646996901?l=andymaleh.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://andymaleh.blogspot.com/feeds/5915439426646996901/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=32881756&amp;postID=5915439426646996901' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/32881756/posts/default/5915439426646996901'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/32881756/posts/default/5915439426646996901'/><link rel='alternate' type='text/html' href='http://andymaleh.blogspot.com/2008/11/glimmer-list-box-multi-selection-data.html' title='Glimmer List Box Multi-Selection Data-Binding'/><author><name>Annas "Andy" Maleh</name><uri>http://www.blogger.com/profile/10268484073612495328</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/-f6UYG8WIYJI/Tpw6vYi2nTI/AAAAAAAAAPk/ICI9GDbAxh4/s1600/7312067a2015194b853856820711a178%253Fsize%253D200'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/_XQt1Vabxo5g/STCHmPpZD1I/AAAAAAAAAGY/HdJISejnEAY/s72-c/Hello+Multi-Select+List+Screenshot.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-32881756.post-8309909091688664471</id><published>2008-11-29T08:49:00.003-06:00</published><updated>2011-03-25T09:39:28.320-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Ruby'/><category scheme='http://www.blogger.com/atom/ns#' term='Eclipse'/><category scheme='http://www.blogger.com/atom/ns#' term='Glimmer'/><title type='text'>Glimmer List Box Single-Selection Data-Binding</title><content type='html'>I added data-binding support for List boxes.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;class Person &lt;br /&gt;  attr_accessor :country, :country_options&lt;br /&gt;  &lt;br /&gt;  def initialize&lt;br /&gt;    self.country_options=["", "Canada", "US", "Mexico"]&lt;br /&gt;    self.country = "Canada"&lt;br /&gt;  end&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;class HelloList&lt;br /&gt;  include Glimmer&lt;br /&gt;  def launch&lt;br /&gt;    shell {&lt;br /&gt;      list {&lt;br /&gt;        selection bind(Person.new, :country)&lt;br /&gt;      }&lt;br /&gt;    }.open&lt;br /&gt;  end&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;HelloList.new.launch&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;This produces a tiny shell with a list box that has "Canada" preselected:&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_XQt1Vabxo5g/STBojEkd4II/AAAAAAAAAGQ/Gv8oHekV7O0/s1600-h/Hello+List+Screenshot.png"&gt;&lt;img style="cursor:pointer; cursor:hand;width: 128px; height: 105px;" src="http://4.bp.blogspot.com/_XQt1Vabxo5g/STBojEkd4II/AAAAAAAAAGQ/Gv8oHekV7O0/s400/Hello+List+Screenshot.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5273830115382255746" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;This works pretty much like &gt;&gt;&lt;a href="http://andymaleh.blogspot.com/2008/11/glimmer-combo-box-data-binding.html"&gt;Combo box data-binding&lt;/a&gt;&lt;&lt;. &lt;br /&gt;&lt;br /&gt;By default, List boxes allow single selection. In order to create a multi-selection list that enables users to hold the shift button and select multiple items, you would pass the "SWT::MULTI" constant (e.g. "list(SWT::MULTI) {...} or "list(:multi) {...}") &lt;br /&gt;&lt;br /&gt;Stay tuned for my &lt;a href="http://andymaleh.blogspot.com/2008/11/glimmer-list-box-multi-selection-data.html"&gt;post on multi-selection data-binding support&lt;/a&gt;, which will allow binding selection to an array property on the model.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/32881756-8309909091688664471?l=andymaleh.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://andymaleh.blogspot.com/feeds/8309909091688664471/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=32881756&amp;postID=8309909091688664471' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/32881756/posts/default/8309909091688664471'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/32881756/posts/default/8309909091688664471'/><link rel='alternate' type='text/html' href='http://andymaleh.blogspot.com/2008/11/glimmer-list-box-single-selection-data.html' title='Glimmer List Box Single-Selection Data-Binding'/><author><name>Annas "Andy" Maleh</name><uri>http://www.blogger.com/profile/10268484073612495328</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/-f6UYG8WIYJI/Tpw6vYi2nTI/AAAAAAAAAPk/ICI9GDbAxh4/s1600/7312067a2015194b853856820711a178%253Fsize%253D200'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/_XQt1Vabxo5g/STBojEkd4II/AAAAAAAAAGQ/Gv8oHekV7O0/s72-c/Hello+List+Screenshot.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-32881756.post-8079774095389161926</id><published>2008-11-28T10:53:00.005-06:00</published><updated>2008-11-28T13:43:18.112-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Ruby'/><category scheme='http://www.blogger.com/atom/ns#' term='Eclipse'/><category scheme='http://www.blogger.com/atom/ns#' term='Conferences'/><category scheme='http://www.blogger.com/atom/ns#' term='Glimmer'/><title type='text'>Video of Glimmer Talk @ RubyConf 2008</title><content type='html'>A video of my RubyConf 2008 talk, Simplifying Desktop Development with Glimmer, was posted &lt;a href="http://rubyconf2008.confreaks.com/desktop-development-with-glimmer.html"&gt;&gt;&gt;over here&lt;&lt;&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;I will revise it before EclipseCon 2009 to reflect the latest advancements in the project.&lt;br /&gt;&lt;br /&gt;Note that MonkeyBars, a competing Ruby library that relies on Java Swing, was presented by David Koontz right before my talk, and thus my mention of him at the beginning.&lt;br /&gt;&lt;br /&gt;Beware! Typical Eclipse SWT vs Sun Swing rivalry showed up during the talk.&lt;br /&gt;&lt;br /&gt;Enjoy... :)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/32881756-8079774095389161926?l=andymaleh.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://andymaleh.blogspot.com/feeds/8079774095389161926/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=32881756&amp;postID=8079774095389161926' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/32881756/posts/default/8079774095389161926'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/32881756/posts/default/8079774095389161926'/><link rel='alternate' type='text/html' href='http://andymaleh.blogspot.com/2008/11/video-of-glimmer-talk-rubyconf-2008.html' title='Video of Glimmer Talk @ RubyConf 2008'/><author><name>Annas "Andy" Maleh</name><uri>http://www.blogger.com/profile/10268484073612495328</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/-f6UYG8WIYJI/Tpw6vYi2nTI/AAAAAAAAAPk/ICI9GDbAxh4/s1600/7312067a2015194b853856820711a178%253Fsize%253D200'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-32881756.post-4235185552351401063</id><published>2008-11-27T23:39:00.002-06:00</published><updated>2008-11-27T23:42:21.883-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Ruby'/><category scheme='http://www.blogger.com/atom/ns#' term='Eclipse'/><category scheme='http://www.blogger.com/atom/ns#' term='Glimmer'/><title type='text'>Glimmer Page &lt;&lt; Download, Instructions, Upcoming</title><content type='html'>I added new sections to the Eclipse Glimmer web page: Download, Instructions, and Upcoming.&lt;br /&gt;&lt;br /&gt;Check them out here:&lt;br /&gt;&lt;a href="http://www.eclipse.org/glimmer/download.php"&gt;http://www.eclipse.org/glimmer/download.php&lt;/a&gt;&lt;br /&gt;&lt;a href="http://www.eclipse.org/glimmer/instructions.php"&gt;http://www.eclipse.org/glimmer/instructions.php&lt;/a&gt;&lt;br /&gt;&lt;a href="http://www.eclipse.org/glimmer/upcoming.php"&gt;http://www.eclipse.org/glimmer/upcoming.php&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/32881756-4235185552351401063?l=andymaleh.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://andymaleh.blogspot.com/feeds/4235185552351401063/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=32881756&amp;postID=4235185552351401063' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/32881756/posts/default/4235185552351401063'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/32881756/posts/default/4235185552351401063'/><link rel='alternate' type='text/html' href='http://andymaleh.blogspot.com/2008/11/glimmer-page-download-instructions.html' title='Glimmer Page &lt;&lt; Download, Instructions, Upcoming'/><author><name>Annas "Andy" Maleh</name><uri>http://www.blogger.com/profile/10268484073612495328</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/-f6UYG8WIYJI/Tpw6vYi2nTI/AAAAAAAAAPk/ICI9GDbAxh4/s1600/7312067a2015194b853856820711a178%253Fsize%253D200'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-32881756.post-3131547332968200329</id><published>2008-11-26T07:49:00.006-06:00</published><updated>2011-03-21T10:11:01.397-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Ruby'/><category scheme='http://www.blogger.com/atom/ns#' term='Eclipse'/><category scheme='http://www.blogger.com/atom/ns#' term='Glimmer'/><title type='text'>Glimmer Combo Box Data-Binding</title><content type='html'>Glimmer development has finally resumed.&lt;br /&gt;&lt;br /&gt;I added data-binding support for Combo boxes.&lt;br /&gt;&lt;br /&gt;I also committed a Rakefile to be able to run tests using jrake.&lt;br /&gt;&lt;br /&gt;Simply run: jrake test_core&lt;br /&gt;&lt;br /&gt;Right now, it only covers the core tests for Glimmer. In the future, I will add a task to handle all tests in the test directory.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;class Person &lt;br /&gt;  attr_accessor :country, :country_options&lt;br /&gt;  &lt;br /&gt;  def initialize&lt;br /&gt;    self.country_options=["", "Canada", "US", "Mexico"]&lt;br /&gt;    self.country = "Canada"&lt;br /&gt;  end&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;class HelloCombo&lt;br /&gt;  include Glimmer&lt;br /&gt;  def launch&lt;br /&gt;    shell {&lt;br /&gt;      combo(:read_only) {&lt;br /&gt;        selection bind(Person.new, :country)&lt;br /&gt;      }&lt;br /&gt;    }.open&lt;br /&gt;  end&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;HelloCombo.new.launch&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;This produces a tiny shell with a combo box that has "Canada" preselected:&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_XQt1Vabxo5g/SSzaG_0MofI/AAAAAAAAAGA/ZieL7pdzWAY/s1600-h/Hello+Combo+Screenshot+1.png"&gt;&lt;img style="cursor:pointer; cursor:hand;width: 128px; height: 68px;" src="http://2.bp.blogspot.com/_XQt1Vabxo5g/SSzaG_0MofI/AAAAAAAAAGA/ZieL7pdzWAY/s400/Hello+Combo+Screenshot+1.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5272829077488443890" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_XQt1Vabxo5g/SSzaLgB0JHI/AAAAAAAAAGI/BI8xGtwWplk/s1600-h/Hello+Combo+Screenshot+2.png"&gt;&lt;img style="cursor:pointer; cursor:hand;width: 131px; height: 86px;" src="http://1.bp.blogspot.com/_XQt1Vabxo5g/SSzaLgB0JHI/AAAAAAAAAGI/BI8xGtwWplk/s400/Hello+Combo+Screenshot+2.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5272829154854970482" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Since convention over configuration is one of the principles behind Glimmer's design, when declaring data-binding for a combo box, there is no need to declare it for both the property being bound (e.g. country) and the collection that contains the available options (e.g. US, Canada, Mexico.) Simply ensure that the collection property on the model follows the convention of having the same name as the property being bound suffixed with "_options", and Glimmer will figure out the rest during data-binding. &lt;br /&gt;&lt;br /&gt;Take a look at this unit test for more details on how combo box data-binding is expected to work:&lt;br /&gt;&lt;a href="http://dev.eclipse.org/svnroot/technology/org.eclipse.glimmer.core/test/glimmer_combo_data_binding_test.rb"&gt;http://dev.eclipse.org/svnroot/technology/org.eclipse.glimmer.core/test/glimmer_combo_data_binding_test.rb&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Next up is List box data-binding support. Stay tuned!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/32881756-3131547332968200329?l=andymaleh.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://andymaleh.blogspot.com/feeds/3131547332968200329/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=32881756&amp;postID=3131547332968200329' title='5 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/32881756/posts/default/3131547332968200329'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/32881756/posts/default/3131547332968200329'/><link rel='alternate' type='text/html' href='http://andymaleh.blogspot.com/2008/11/glimmer-combo-box-data-binding.html' title='Glimmer Combo Box Data-Binding'/><author><name>Annas "Andy" Maleh</name><uri>http://www.blogger.com/profile/10268484073612495328</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/-f6UYG8WIYJI/Tpw6vYi2nTI/AAAAAAAAAPk/ICI9GDbAxh4/s1600/7312067a2015194b853856820711a178%253Fsize%253D200'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/_XQt1Vabxo5g/SSzaG_0MofI/AAAAAAAAAGA/ZieL7pdzWAY/s72-c/Hello+Combo+Screenshot+1.png' height='72' width='72'/><thr:total>5</thr:total></entry></feed>
