<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
 <title>Brian Doll</title>
 <link href="http://emphaticsolutions.com/atom.xml" rel="self"/>
 <link href="http://emphaticsolutions.com/"/>
 <updated>2021-01-14T22:03:51+00:00</updated>
 <id>http://emphaticsolutions.com</id>
 <author>
   <name>Brian Doll</name>
 </author>
 
 <entry>
   <title>Tell Me A Story</title>
   <link href="http://emphaticsolutions.com/2014/01/15/tell-me-a-story.html"/>
   <updated>2014-01-15T00:00:00+00:00</updated>
   <id>http://emphaticsolutions.com/2014/01/15/tell-me-a-story</id>
   <content type="html">&lt;p&gt;I gave a presentation at &lt;a href=&quot;http://www.phpconference.com.ar/&quot;&gt;PHP Conference Argentina&lt;/a&gt; in Buenos Aires recently. I talked about the benefits of story telling as they apply to marketing our products, services and even our open source projects.&lt;/p&gt;

&lt;p&gt;Here is the video and slides from the presentation. I’d love to &lt;a href=&quot;https://twitter.com/briandoll&quot;&gt;hear your thoughts&lt;/a&gt;.&lt;/p&gt;

&lt;iframe width=&quot;640&quot; height=&quot;360&quot; src=&quot;//www.youtube.com/embed/G7jLUfkQXpE?rel=0&quot; frameborder=&quot;0&quot; allowfullscreen=&quot;true&quot;&gt;&lt;/iframe&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;script async=&quot;&quot; class=&quot;speakerdeck-embed&quot; data-id=&quot;7d133270139201318e8226b064201532&quot; data-ratio=&quot;1.77777777777778&quot; src=&quot;//speakerdeck.com/assets/embed.js&quot;&gt;&lt;/script&gt;

&lt;p&gt; &lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>Writing it down</title>
   <link href="http://emphaticsolutions.com/2013/12/28/writing-it-down.html"/>
   <updated>2013-12-28T00:00:00+00:00</updated>
   <id>http://emphaticsolutions.com/2013/12/28/writing-it-down</id>
   <content type="html">&lt;p&gt;&lt;img src=&quot;https://f.cloud.github.com/assets/4590/1701820/dcfd905c-6070-11e3-94f9-9bfce773f0c6.JPG&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;As a young kid, I always loved journeys to the office supply store. It felt very grown-up to buy your own pens and paper.  When I went to art school, &lt;a href=&quot;http://www.pearlpaint.com/&quot;&gt;Pearl’s&lt;/a&gt; was my favorite spot. That’s where I fell in love with &lt;a href=&quot;http://www.pearlpaint.com/shop-Pigma-Micron-Pen_5919_5931.html&quot;&gt;Pigma Micron pens&lt;/a&gt; and &lt;a href=&quot;http://www.pearlpaint.com/shop-Winsor-&amp;amp;-Newton-Designer-Gouache_8994_8893.html&quot;&gt;gouache paints&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Starting at a very early age, I always had those small pocket notebooks close by. My grandfather on my mother’s side worked for a railroad company and he used to share his Weights and Measures notebooks with his grandkids. My grandmother worked for the &lt;a href=&quot;http://en.wikipedia.org/wiki/USG_Corporation&quot;&gt;US Gypsum Company&lt;/a&gt; as a typist(!!!) and brought home all sorts of paper pads, forms and  those small pocket notebooks, too.&lt;/p&gt;

&lt;p&gt;My father always carried a pocket day planner with him and I got myself one sometime in high school. I went through every format over time and eventually got way too into the Franklin Planner. For a few years, I was obsessed with keeping up my Franklin Planner, always trying to do the most important work first, and never missing an appointment. This was several years before there were online calendars, so it seems a bit silly now, but I could never figure out how anyone got anything done without a Franklin Planner.&lt;/p&gt;

&lt;p&gt;I eventually &lt;a href=&quot;http://emphaticsolutions.com/2011/07/01/the-ultimate-productivity-hack-having-kids.html&quot;&gt;turned my time management obsession toward other frameworks&lt;/a&gt;… GTD, Kanban, Pomodoro. I eventually realized that this obsession was more about the &lt;em&gt;idea&lt;/em&gt; of efficiency, not the actual work I was trying to accomplish. I drifted. Then I read Getting Real by 37Signals, the first real book I’d ever read on building products.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;So what do you do with all these requests that pour in? Where do you store them? How do you manage them? You don’t. Just read them and then throw them away.&lt;/p&gt;

  &lt;p&gt;— &lt;a href=&quot;http://gettingreal.37signals.com/ch05_Forget_Feature_Requests.php&quot;&gt;“Feature Requests” in Getting Real, 37Signals&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Holy shit. This was incredible to read. The next paragraph suggests that if something is important enough, you’ll be reminded of it often. No need to manage some nasty product backlog. It hit me that if this worked for products, it probably works for your own tasks too.&lt;/p&gt;

&lt;p&gt;By then I had already started using Moleskine notebooks to jot things down in. I still have some of the elastic-banded notebooks my great-grandfather used when he traveled around the States in the 1920s. He kept notes on mileage, gas, and oil details for his Model-T and meticulous budgeting for food and lodging during his multi-year road trips. Perhaps because of how much I was in awe of his notebooks, I treated my Moleskins with a similar sense of awe. Basically, I didn’t use them much because I felt most of what I wanted to jot down wasn’t worthy of them.&lt;/p&gt;

&lt;p&gt;This is when I discovered &lt;a href=&quot;http://fieldnotesbrand.com/&quot;&gt;Field Notes&lt;/a&gt;. Back then &lt;a href=&quot;http://37signals.com/&quot;&gt;37Signals&lt;/a&gt; shared an office with &lt;a href=&quot;http://coudal.com/&quot;&gt;Jim Coudal&lt;/a&gt;, who teamed up with the amazing &lt;a href=&quot;http://draplin.com/&quot;&gt;Aaron Draplin&lt;/a&gt; to make these amazing pocket notebooks, just like the ones my grandfather used to give me. They were small and fit in your back pocket, meant for scribbling things down, getting beat up, and getting shit done. Watch &lt;a href=&quot;https://vimeo.com/47178197&quot;&gt;this&lt;/a&gt;, &lt;a href=&quot;https://vimeo.com/17567585&quot;&gt;this&lt;/a&gt; and &lt;a href=&quot;https://vimeo.com/75224994&quot;&gt;this&lt;/a&gt; and I bet you’ll be hooked too.&lt;/p&gt;

&lt;p&gt;Today, while technology has seeped into every cranny of our personal and professional lives, when a thought comes to me, when I want to remember something now, when I need to draw that sketch of an idea, or make yet another list of lists, writing it down in a Field Notes notebook is essential to how I get shit done. It’s not a planner, it’s not a todo list, it’s not the sacred keeping place of everything. It’s a simple tool that captures the ephemera of life and work, freezing ideas in place, for just a little while. Every day I scan through my scribbles and evolve them into &lt;a href=&quot;https://github.com/features&quot;&gt;Issues or Pull Requests on GitHub&lt;/a&gt;, emails, or just let them percolate a little longer on paper. Many ideas and notes don’t go anywhere, and that’s ok.&lt;/p&gt;

&lt;p&gt;As I’ve relied more and more on my notebooks, I started caring a lot more about  what pens I use. I still love those Pigma Micron pens, but I wanted to try something new. I scoured every review on sites like &lt;a href=&quot;http://penaddict.com/&quot;&gt;Pen Addict&lt;/a&gt;  and re-read Rands’ &lt;a href=&quot;http://randsinrepose.com/archives/the-gel-dilemma/&quot;&gt;Gel Dilemma&lt;/a&gt; a few times and took a gamble on a new pen this year. I am now incredibly in love with &lt;a href=&quot;http://karaskustoms.com/pens/the-bolt-357.html&quot;&gt;The Bolt by Karas Kustoms&lt;/a&gt; with a &lt;a href=&quot;http://www.jetpens.com/Pilot-G-2-Gel-Ink-Pen-Refill-0.5-mm-Black-Pack-of-2/pd/1381&quot;&gt;Pilot G2 0.5mm refill&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;These little pocket notebooks feel like home. Comfortable, reassuring and personal. It feels like what I’d always been looking for in those dusty old office supply stores. Maybe you actually can go home again.&lt;/p&gt;

</content>
 </entry>
 
 <entry>
   <title>Marketing Culture</title>
   <link href="http://emphaticsolutions.com/2013/09/25/marketing-culture.html"/>
   <updated>2013-09-25T00:00:00+00:00</updated>
   <id>http://emphaticsolutions.com/2013/09/25/marketing-culture</id>
   <content type="html">&lt;p&gt;I spoke about Marketing Culture at the &lt;a href=&quot;http://turingfestival.com/&quot;&gt;Turing Festival&lt;/a&gt; in Edinburgh, Scotland recently. The centrail message was to show that:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Marketing is the intentional transfer of culture&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Here is the video and slides from the presentation. I’d love to &lt;a href=&quot;https://twitter.com/briandoll&quot;&gt;hear your thoughts&lt;/a&gt;.&lt;/p&gt;

&lt;iframe width=&quot;640&quot; height=&quot;480&quot; src=&quot;//www.youtube.com/embed/t4n9Vwin9so?rel=0&quot; frameborder=&quot;0&quot; allowfullscreen=&quot;true&quot;&gt;&lt;/iframe&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;script async=&quot;&quot; class=&quot;speakerdeck-embed&quot; data-id=&quot;ecd0c770f7b7013047e50607b1b57830&quot; data-ratio=&quot;1.77777777777778&quot; src=&quot;//speakerdeck.com/assets/embed.js&quot;&gt;&lt;/script&gt;

&lt;p&gt; &lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>Thanks, Dad</title>
   <link href="http://emphaticsolutions.com/2013/06/03/thanks-dad.html"/>
   <updated>2013-06-03T00:00:00+00:00</updated>
   <id>http://emphaticsolutions.com/2013/06/03/thanks-dad</id>
   <content type="html">&lt;p&gt;My dad turns 60 today. If you were ever lucky enough to have met my grandfather or father, you’d know that we’re essentially the same person, just in different life stages. To make sense of this post you’ll just need to know a few things. My grandfather Frank started a grocery store business in my impossibly small hometown in upstate NY sometime around 1950 or so. The business grew, moved and expanded a few times, and my father ran that business until it was sold in 1998. They say few family businesses ever survive three generations and for us that was true. I learned a lifetime from my father, most before I even turned 16. I wanted to capture a few thoughts on what he taught me and say thanks.&lt;/p&gt;

&lt;h3 id=&quot;lead-by-doing-not-by-commanding&quot;&gt;Lead by doing, not by commanding&lt;/h3&gt;

&lt;p&gt;I still remember the first time you told me I was going to “manage” the evening shift on a Friday night. I was probably 14 or so, and everyone else on that shift was several years older than I was. You reminded me that it’s not much different from what I was already doing, but my job was to keep everyone focused on getting the list of tasks done before the truck showed up in the morning. Management and leadership isn’t something distinct from the work, it only differs by your perspective. You taught me that if I needed to “manage” getting a hole dug, the first thing I should do is pick up a shovel.&lt;/p&gt;

&lt;h3 id=&quot;leadership-happens-on-the-floor-not-in-the-office&quot;&gt;Leadership happens on the floor, not in the office&lt;/h3&gt;

&lt;p&gt;I remember being curious about the distinction between the type of work that you did in the upstairs office, the back room office and on the store floor. I knew that everything to do with  stock, supplies and orders were handled in the back room office. The upstairs office was for finance, legal and big decisions. What took me a while to realize is that leadership happened not in either of those locations, but out on the floor.&lt;/p&gt;

&lt;p&gt;Customer service is leadership. Leadership is the small talk with your employees while we all go about our day. Leadership is  cleaning the floors, mopping up spills, pulling inventory forward and changing lightbulbs.&lt;/p&gt;

&lt;h3 id=&quot;experimentation-is-survival&quot;&gt;Experimentation is survival&lt;/h3&gt;

&lt;p&gt;I can remember every big change that happened in the store. Changes in floor layout, changes in delivery times, changes in big vendors and changes in management. I remember what a monumental decision it was to sell the business. I remember how you turned a hobby-job of being a chauffeur into a second career in transportation management. You taught me that experimentation is essential to survival and growth.&lt;/p&gt;

&lt;h3 id=&quot;days-off-are-special-use-them&quot;&gt;Days off are special, use them&lt;/h3&gt;

&lt;p&gt;Owning and running a business doesn’t really provide any downtime. Weekends were not for relaxing, they were the busiest days at the store. Instead, Thursdays were your day off. I remember how different and special Thursdays were. Even on days where we were just running errands to hardware stores, you always took the time to make them feel like an adventure together with Arby’s sandwiches and a little too much Phil Collins.&lt;/p&gt;

&lt;h3 id=&quot;prepare-for-everything-especially-vacations&quot;&gt;Prepare for everything, especially vacations&lt;/h3&gt;

&lt;p&gt;Long before I learned that the Boy Scouts’ motto is ‘be prepared’, I learned all about being prepared from you. “Work” was a time to just get shit done, but it was in the preparation that makes the difference. While everything you did involved an impressive amount of preparation, I always admired how thoroughly you prepared for vacations the most. We knew routes, distances, hotels, rest stops, restaurants and must-see sights for every road trip, long before the internet. Canoe trip were planned months in advance, and late nights laying out all of our gear before packing were my favorite.&lt;/p&gt;

&lt;h3 id=&quot;donuts--celebrating-your-team&quot;&gt;Donuts &amp;amp; celebrating your team&lt;/h3&gt;

&lt;p&gt;Saturday morning, just after 6AM, from the warm summer mornings through the bitter snow-filled winters, a semi-truck full of groceries would be parked at the back door waiting to be unloaded. I loved every bit of this work. I loved using the pallet jack to move them to the back of the truck. I loved organizing the pallets, but especially the process of breaking down the pallets onto endless green carts. By the end of the day we’d have the shelves re-stocked and extra inventory packed up against the wall in the back room. Around 10AM, though, we had donuts. We’d all pitch in a few bucks, two guys would buy two dozen donuts and some orange juice and bring them to the back room. We all took a break from the intensity of the morning’s work to talk shit and rest for a few moments. You knew how important this was in bonding the early morning team. It was a badge of honor to have been there for the early shift, and donuts were our badge.&lt;/p&gt;

&lt;h3 id=&quot;honesty-and-integrity&quot;&gt;Honesty and integrity&lt;/h3&gt;

&lt;p&gt;Growing up in a small town where everyone knew who I was before I opened my mouth was… interesting. It took me years to understand how that effected me, but I spent a lot of time thinking about who I thought I was compared to who other people thought I was. In a way, our reputations always precede us, it’s just not always that obvious. You taught me to always act with integrity and to be honest. Everyone knew that if they had a meeting with you, they got it straight and direct. Friendly, with no bullshit. I aspire to live each day with that level of honesty and integrity.&lt;/p&gt;

&lt;h3 id=&quot;give-selflessly&quot;&gt;Give selflessly&lt;/h3&gt;

&lt;p&gt;Perhaps the thing that most people would say they’ve learned from you is that you constantly give your time and energy to others without any expectation of something in return. You weren’t just casually involved with us at school, you were on the school board. You didn’t just drop me off at boy scout camp, you hiked, camped and worked with us. You made college visits, and both you and mom helped me with several life-changing moves across the country. You’re support of our endeavors has been so consistent and so immediate that I think I’ve been guilty of taking it for granted in the past. Thank you.&lt;/p&gt;

&lt;h3 id=&quot;the-speaker-we-all-need-at-the-hardest-times&quot;&gt;The speaker we all need, at the hardest times&lt;/h3&gt;

&lt;p&gt;I never knew until just now, but to “eulogize” actually means “to speak or write in high praise of”. I guess I’ve been too full of tears to look that up before. It brings more tears to my eyes to even think of the names of the people you have eulogized. I’ve been sitting here for a half hour not even able to continue this paragraph. See what I mean? I don’t know how you do it, but I’m inspired every time. I wish you didn’t have to, but somebody has to, and you’re always there saying the right thing, at the absolute hardest time. If how we act in the most trying times is the core of our character, you’ve shown everyone that you are strong, honest and caring all the way through. There’s not much more anyone can ask of a friend, or a father for that matter.&lt;/p&gt;

&lt;p&gt;Happy birthday, dad.&lt;/p&gt;

</content>
 </entry>
 
 <entry>
   <title>2012, A look back</title>
   <link href="http://emphaticsolutions.com/2013/01/01/2012-a-look-back.html"/>
   <updated>2013-01-01T00:00:00+00:00</updated>
   <id>http://emphaticsolutions.com/2013/01/01/2012-a-look-back</id>
   <content type="html">&lt;p&gt;A brief look back over what I’ve been up to in 2012. (&lt;a href=&quot;http://emphaticsolutions.com/2012/01/26/2011-a-look-back.html&quot;&gt;2011&lt;/a&gt;)&lt;/p&gt;

&lt;p&gt;I &lt;a href=&quot;https://github.com/blog/1042-brian-doll-is-a-githubber&quot;&gt;started at GitHub in February&lt;/a&gt; which has been life-changing in several ways. &lt;a href=&quot;https://speakerdeck.com/holman/how-github-works-v2&quot;&gt;GitHub works differently&lt;/a&gt; and I can’t imagine working any other way. I’ll elaborate on this more in another post.&lt;/p&gt;

&lt;h3 id=&quot;learning&quot;&gt;Learning&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;Marketing: Not just marketing, but GitHub marketing, which is much more about taste, product improvements and customers than anything else.&lt;/li&gt;
  &lt;li&gt;Growth: We had a &lt;a href=&quot;https://github.com/blog/1359-the-octoverse-in-2012&quot;&gt;big year&lt;/a&gt; for growth at GitHub. I’m still learning the ropes of growing a business at this pace, and it’s been incredible.&lt;/li&gt;
  &lt;li&gt;Public Relations: I ran PR for just long enough to know that we needed someone amazing to focus on it full-time. &lt;a href=&quot;https://github.com/blog/1294-liz-clinkenbeard-is-a-githubber&quot;&gt;Liz&lt;/a&gt; started in October and is already off to an amazing start.&lt;/li&gt;
  &lt;li&gt;Speaking: I only gave &lt;a href=&quot;http://emphaticsolutions.com/talks.html&quot;&gt;three talks this year&lt;/a&gt;, but I felt like these were my best yet. I’m looking forward to more story telling in 2013.&lt;/li&gt;
  &lt;li&gt;Passion: Witnessing what is possible when &lt;a href=&quot;https://github.com/about/team&quot;&gt;140 passionate people&lt;/a&gt; do the best work of their life is inspiring and addicting.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;doing&quot;&gt;Doing&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Shipped&lt;/strong&gt; lots of awesome stuff at GitHub, and schemed more awesomeness for 2013&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Traveled&lt;/strong&gt; to Portland, Sweden, New York City and Bulgaria for conferences&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Shipped&lt;/strong&gt; &lt;a href=&quot;https://github.com/briandoll/influencer.tweets&quot;&gt;influencer.tweets&lt;/a&gt; - What are ‘influencers’ on twitter saying right now about X?&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Presented&lt;/strong&gt; &lt;a href=&quot;http://emphaticsolutions.com/2012/06/22/marketing-for-geeks.html&quot;&gt;Marketing for Geeks&lt;/a&gt; - Web Visions, Portland Oregon and Nordic Ruby, Sweden&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Presented&lt;/strong&gt; &lt;a href=&quot;http://strataconf.com/stratany2012/public/schedule/detail/25718&quot;&gt;Analyzing Millions of GitHub Commits: What Makes Developers Happy, Angry, and Everything in Between?&lt;/a&gt; - Strata, New York City, NY&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Presented&lt;/strong&gt; &lt;a href=&quot;http://emphaticsolutions.com/2012/12/02/github-an-egalitarian-love-story.html&quot;&gt;GitHub, an egalitarian love story&lt;/a&gt; - OpenFest, Sofia Bulgaria&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;personal-changelog&quot;&gt;Personal changelog&lt;/h3&gt;

&lt;p&gt;I made some changes to my digital and computing life in 2012:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;http://www.apple.com/macbookair/&quot;&gt;No monitor w/ 13” MacBook Air&lt;/a&gt; - Fullscreen apps when possible, focus focus focus&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;http://www.apple.com/ipad/&quot;&gt;iPad&lt;/a&gt; - I’ve been digging the iPad 2 for reading and catching up on things in the evenings&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;http://culturedcode.com/things/&quot;&gt;Things.app&lt;/a&gt; - I’m back to Things.app after years away, getting my GTD on&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;http://getpocket.com/&quot;&gt;Pocket&lt;/a&gt; - After trying tons of “read it later” apps, Pocket for Mac, iPad and iPhone are perfect&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/&quot;&gt;GitHub.com&lt;/a&gt; - Using GitHub fulltime has been amazing and keeps getting better&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;http://www.getconcentrating.com/&quot;&gt;Concentrate&lt;/a&gt; - Great app to curtail distractions and get down to business&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;http://instagram.com/briandoll&quot;&gt;Instagram&lt;/a&gt; - Love my instagram feed and love sharing good snaps&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;http://getprismatic.com/&quot;&gt;Prismatic&lt;/a&gt; - A smart news discovery service that gets better the more you use it&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;http://stitcher.com/&quot;&gt;Stitcher&lt;/a&gt; - On-demand podcasts, perfect for the commute&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;2012 was pretty great.  2013 is going to be even better.&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>GitHub, an egalitarian love story</title>
   <link href="http://emphaticsolutions.com/2012/12/02/github-an-egalitarian-love-story.html"/>
   <updated>2012-12-02T00:00:00+00:00</updated>
   <id>http://emphaticsolutions.com/2012/12/02/github-an-egalitarian-love-story</id>
   <content type="html">&lt;p&gt;I gave this talk in November at &lt;a href=&quot;http://openfest.org/&quot;&gt;Open Fest&lt;/a&gt; in Sofia, Bulgaria. The word &lt;em&gt;egalitarian&lt;/em&gt; struck me as a great way to describe the essence of our culture at GitHub. This talk reviews the tenets of egalitarianism and relates them to git, &lt;a href=&quot;https://github.com/&quot;&gt;GitHub.com&lt;/a&gt;, GitHub the company, and open source software in general. There were a lot of really great questions from the audience after the talk, which are also included in the video.&lt;/p&gt;

&lt;iframe width=&quot;853&quot; height=&quot;480&quot; src=&quot;http://www.youtube.com/embed/S7RNoDoSPV4?rel=0&quot; frameborder=&quot;0&quot; allowfullscreen=&quot;true&quot;&gt; &lt;/iframe&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;script async=&quot;async&quot; class=&quot;speakerdeck-embed&quot; data-id=&quot;50954089ec70e70002031f03&quot; data-ratio=&quot;1.33333333333333&quot; src=&quot;//speakerdeck.com/assets/embed.js&quot;&gt; &lt;/script&gt;

&lt;p&gt; &lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>Marketing for Geeks</title>
   <link href="http://emphaticsolutions.com/2012/06/22/marketing-for-geeks.html"/>
   <updated>2012-06-22T00:00:00+00:00</updated>
   <id>http://emphaticsolutions.com/2012/06/22/marketing-for-geeks</id>
   <content type="html">&lt;script async=&quot;async&quot; src=&quot;http://speakerdeck.com/assets/embed.js&quot; class=&quot;speakerdeck-embed&quot; data-id=&quot;4fdd9a710d13f903d800e147&quot;&gt; &lt;/script&gt;

&lt;p&gt;I recently gave this talk at &lt;a href=&quot;http://www.webvisionsevent.com/portland/&quot;&gt;WebVisions in Portland&lt;/a&gt; and at &lt;a href=&quot;http://nordicruby.org/&quot;&gt;Nordic Ruby in Sweden&lt;/a&gt;. Several people asked what books and blogs I’d recommend to learn more about marketing, so I’ve put together a list of things that have influenced me.&lt;/p&gt;

&lt;h3 id=&quot;resources&quot;&gt;Resources&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;http://voiceandtone.com/&quot;&gt;VoiceAndTone.com&lt;/a&gt; - MailChimp’s guidance on the voice they use in all communication. You’ll want to re-write every error message in your product after reading this.&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;http://hbswk.hbs.edu/item/6496.html&quot;&gt;Clay Christensen’s Milkshake Marketing&lt;/a&gt; - also known as the “Jobs to be Done” framework. I’d suggest reading everything you can about this idea. I can’t think of a better framework to use when considering how to market a product.&lt;/li&gt;
  &lt;li&gt;Everything &lt;a href=&quot;http://twitter.com/destraynor&quot;&gt;Des Traynor&lt;/a&gt; writes at the &lt;a href=&quot;http://blog.intercom.io/&quot;&gt;Intercom.io blog&lt;/a&gt; is pure gold. Read every post a few times through, they’re worth it.&lt;/li&gt;
  &lt;li&gt;I read &lt;a href=&quot;http://www.shopify.com/technology/4018382-defining-churn-rate-no-really-this-actually-requires-an-entire-blog-post&quot;&gt;Steven H. Nobel’s post on churn&lt;/a&gt; on the Shopify blog every other month or so. I’m looking forward to more in-depth posts like this from them.&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;http://www.avc.com/&quot;&gt;Fred Wilson’s blog&lt;/a&gt; is always a great read. He runs a series of posts called &lt;a href=&quot;http://www.avc.com/a_vc/mba-mondays/&quot;&gt;“MBA Mondays”&lt;/a&gt; which is a great way to get up to speed on financing and business concepts.&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;http://sivers.org/&quot;&gt;Derek Sivers blog&lt;/a&gt;, especially his &lt;a href=&quot;http://sivers.org/book&quot;&gt;notes on books he’s recently read.&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;http://www.amazon.com/dp/B00506NRBS&quot;&gt;Anything You Want by Derek Sivers&lt;/a&gt; - short stories by Derek on his CDBaby days. This book has lots of great anecdotes that rarely ever follow the typical and boring path.&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;http://sethgodin.typepad.com/&quot;&gt;Seth Godin’s blog&lt;/a&gt; is full of pithy and interesting ideas.&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;http://www.amazon.com/exec/obidos/ASIN/1591843162/&quot;&gt;Seth’s book Linchpin&lt;/a&gt; is about the new model of work.&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;http://www.amazon.com/exec/obidos/ASIN/1936719223&quot;&gt;Seth’s book We Are All Weird&lt;/a&gt; sums up much of what was in his previous marketing books. The mass market is dead, long live niche markets.&lt;/li&gt;
&lt;/ul&gt;
</content>
 </entry>
 
 <entry>
   <title>My Setup</title>
   <link href="http://emphaticsolutions.com/2012/03/13/my-setup.html"/>
   <updated>2012-03-13T00:00:00+00:00</updated>
   <id>http://emphaticsolutions.com/2012/03/13/my-setup</id>
   <content type="html">&lt;p&gt;I love reading &lt;a href=&quot;http://usesthis.com/&quot;&gt;The Setup&lt;/a&gt; and thought I’d do my own interview to document what I’m using these days to get things done.&lt;/p&gt;

&lt;h2 id=&quot;who-are-you-and-what-do-you-do&quot;&gt;Who are you, and what do you do?&lt;/h2&gt;

&lt;p&gt;I’m &lt;a href=&quot;http://emphaticsolutions.com&quot;&gt;Brian Doll&lt;/a&gt;, a business and technology hacker that runs marketing at &lt;a href=&quot;https://github.com&quot;&gt;GitHub&lt;/a&gt;. I’ve been &lt;a href=&quot;http://www.linkedin.com/in/briandoll&quot;&gt;building things on the web professionally since 1997&lt;/a&gt; and have been involved in marketing for the past few years.&lt;/p&gt;

&lt;h2 id=&quot;what-hardware-are-you-using&quot;&gt;What hardware are you using?&lt;/h2&gt;

&lt;p&gt;I’ve got a maxed-out &lt;a href=&quot;http://www.apple.com/macbookair/&quot;&gt;13” MacBook Air&lt;/a&gt; and I love it. At my desk at work, I connect it to a 27” Apple Cinema Display, but I still use the laptop keyboard and trackpad when I’m docked. I really like the touchpad and keeping it close means never having to reach far for a mouse.&lt;/p&gt;

&lt;p&gt;At home I have a second generation Mac Mini that I use primarily as a media center serving my similarly old AppleTV. I store everything on a &lt;a href=&quot;http://www.amazon.com/Western-Digital-My-Book-Studio/dp/B0016P7H3Q/ref=dp_cp_ob_e_title_2&quot;&gt;2TB Western Digital My Book&lt;/a&gt; drive.&lt;/p&gt;

&lt;p&gt;At one point I had a dozen or so custom-build servers running at my house, but I grew to appreciate the simplicity and quiet of hosting things at a colo and then to a VPS with &lt;a href=&quot;http://www.slicehost.com/&quot;&gt;SliceHost&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;I have a &lt;a href=&quot;http://www.ikea.com/us/en/catalog/products/S89843460/#/S09843459&quot;&gt;stand-up desk from IKEA&lt;/a&gt; at home. I sit and stand at various desks, couches and tables &lt;a href=&quot;http://web.stagram.com/location/3774811&quot;&gt;at work&lt;/a&gt;, and find myself at &lt;a href=&quot;http://www.yelp.com/biz/marin-coffee-roasters-san-anselmo&quot;&gt;coffee shops in Marin&lt;/a&gt; just as often.&lt;/p&gt;

&lt;p&gt;My phone is an &lt;a href=&quot;http://www.apple.com/iphone/&quot;&gt;iPhone 4S&lt;/a&gt; and I love the &lt;a href=&quot;http://www.amazon.com/gp/product/B0051QVESA/&quot;&gt;basic kindle&lt;/a&gt; for reading books and articles (sent through &lt;a href=&quot;http://www.readability.com/&quot;&gt;Readability&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;For sketching ideas and making countless lists of things, I love &lt;a href=&quot;http://www.pearlpaint.com/shop-Pigma-Micron-Pen_5919_5931.html&quot;&gt;Pigma Micron pens&lt;/a&gt; and &lt;a href=&quot;http://fieldnotesbrand.com/&quot;&gt;Field Notes&lt;/a&gt; notebooks. I love my Moleskines too, but Field Notes are easier to stuff into a back pocket.&lt;/p&gt;

&lt;p&gt;I’m rarely without music, so headphones are important. For long sessions in a cone of silence, I love the &lt;a href=&quot;http://www.amazon.com/Sennheiser-HD-280-Pro-Headphones/dp/B000065BPB&quot;&gt;Sennheiser HD-280 Pros&lt;/a&gt;, but I’m usually wearing my &lt;a href=&quot;http://www.amazon.com/gp/product/B003YTPP72/&quot;&gt;Etymotic Research ER7&lt;/a&gt; “canalphones”, which are also great for phone calls and pairing over Skype or Google Hangout.&lt;/p&gt;

&lt;h2 id=&quot;and-what-software&quot;&gt;And what software?&lt;/h2&gt;

&lt;p&gt;I’ve been slowly slimming down the list of software I use on a regular basis. I use &lt;a href=&quot;http://sparrowmailapp.com/&quot;&gt;Sparrow&lt;/a&gt; for email on my mac and iPhone and Chrome is my browser of choice. For focused programming (mostly in Ruby), I use &lt;a href=&quot;http://www.iterm2.com/&quot;&gt;iTerm2&lt;/a&gt; full-screen, running a tmux session with Vim and a few bash shells. I use a variety of &lt;a href=&quot;http://www.catonmat.net/blog/set-operations-in-unix-shell/&quot;&gt;unix tools&lt;/a&gt; as well for data analysis. I use git for version control and keep all &lt;a href=&quot;https://github.com/briandoll&quot;&gt;my code on github&lt;/a&gt;, including my &lt;a href=&quot;https://github.com/briandoll/dotfiles&quot;&gt;dotfiles&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;I use &lt;a href=&quot;http://code.google.com/p/macvim/&quot;&gt;MacVim&lt;/a&gt; for writing and programming, and use &lt;a href=&quot;http://markedapp.com/&quot;&gt;Marked&lt;/a&gt; to preview my Markdown documents, which we use a lot at GitHub. &lt;a href=&quot;http://propaneapp.com/&quot;&gt;Propane&lt;/a&gt; for Campfire &lt;a href=&quot;http://www.codeux.com/textual/&quot;&gt;Textual&lt;/a&gt; for IRC and iChat make it easy to keep in touch with everyone. Twitter, Instagram and &lt;a href=&quot;http://eyeappsllc.com/Home.html&quot;&gt;Pro HDR&lt;/a&gt; are the apps I used most on my iPhone.&lt;/p&gt;

&lt;p&gt;I use &lt;a href=&quot;http://atmos.org&quot;&gt;Atmos’&lt;/a&gt; &lt;a href=&quot;https://github.com/atmos/smeagol&quot;&gt;smeagol&lt;/a&gt; to set up the initial development environment on my mac. I don’t know what I would do without &lt;a href=&quot;http://www.dropbox.com/&quot;&gt;Dropbox&lt;/a&gt;, &lt;a href=&quot;https://agilebits.com/onepassword&quot;&gt;1Password&lt;/a&gt; and &lt;a href=&quot;http://rdio.com&quot;&gt;rdio&lt;/a&gt;. &lt;a href=&quot;http://www.wunderlist.com/&quot;&gt;Wunderlist&lt;/a&gt; keeps me on track and I use &lt;a href=&quot;http://evernote.com&quot;&gt;Evernote&lt;/a&gt; to keep all the things I’d otherwise forget. For &lt;a href=&quot;http://speakerdeck.com/u/briandoll&quot;&gt;presentations&lt;/a&gt; I use Keynote, and &lt;a href=&quot;http://connectedflow.com/viewfinder/&quot;&gt;Viewfinder&lt;/a&gt; for finding creative-commons photos.&lt;/p&gt;

&lt;h2 id=&quot;what-would-be-your-dream-setup&quot;&gt;What would be your dream setup?&lt;/h2&gt;

&lt;p&gt;I’d like my glasses to be able to turn into a high-resolution monitor. Of course they would also need to support AirPlay. Other than that, I’d like the internet to be faster. That’ll do.&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>2011, A look back</title>
   <link href="http://emphaticsolutions.com/2012/01/26/2011-a-look-back.html"/>
   <updated>2012-01-26T00:00:00+00:00</updated>
   <id>http://emphaticsolutions.com/2012/01/26/2011-a-look-back</id>
   <content type="html">&lt;p&gt;A brief look back over what I’ve been up to in 2011.&lt;/p&gt;

&lt;h2 id=&quot;learning&quot;&gt;Learning&lt;/h2&gt;

&lt;p&gt;I wrote &lt;a href=&quot;http://emphaticsolutions.com/2011/01/06/the-fallacies-of-distributed-computing-in-the-cloud-era.html&quot;&gt;The Fallacies of Distributed Computing Reborn: The Cloud Era&lt;/a&gt; in Januaray of last year and gave a talk on it at Dreamforce.  Broadly speaking, these fallacies are just known constraints imposed on distributed systems by the current state of technology.  I spent a lot of time this year talking to &lt;a href=&quot;http://newrelic.com/&quot;&gt;New Relic&lt;/a&gt; customers about the systems they are building.  It’s so great to see continued awareness of the challenges in scaling web applications, and even better to see the many interesting solutions people are working on.&lt;/p&gt;

&lt;p&gt;I learned a lot in the last year about the nuances of scaling a SaaS business as well. The rate of signups and new customers for New Relic in 2011 increased dramatically and it was quite the wild ride.&lt;/p&gt;

&lt;p&gt;When New Relic moved from South Park in San Francisco to SOMA, I started to take the ferry.  Since I’m no longer driving, I started reading a lot more.  Some notable reads from the year:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;http://www.amazon.com/gp/product/B005G5DSLW/ref=kinw_myk_ro_title&quot;&gt;We Are All Weird by Seth Godin&lt;/a&gt; - the mass-market is dead, long live the weird!&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;http://www.amazon.com/gp/product/B002RKR1BC/ref=kinw_myk_ro_title&quot;&gt;Autobiography of a Yogi by Paramahansa Yogananda&lt;/a&gt; - a personal and simple book about zen&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;http://www.amazon.com/gp/product/B002W5UVSM/ref=kinw_myk_ro_title&quot;&gt;A Confederacy of Dunces by John Kennedy Toole&lt;/a&gt; - great novel; the source of &lt;a href=&quot;http://twitter.com/hotdogsladies&quot;&gt;@hotdogsladies&lt;/a&gt; nick&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;http://www.amazon.com/gp/product/B004W2UBYW/ref=kinw_myk_ro_title&quot;&gt;Steve Jobs by Walter Isaacson&lt;/a&gt; - of course&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href=&quot;http://peepcode.com/&quot;&gt;Peepcode&lt;/a&gt; also played a big role in what I was learning this year.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;http://peepcode.com/products/backbone-js&quot;&gt;Backbone.js&lt;/a&gt; - I have a few side projects in the queue where I’ll likely use Backbone&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;http://peepcode.com/products/eventmachine&quot;&gt;Event Machine&lt;/a&gt; - I’m really curious to try out &lt;a href=&quot;https://github.com/postrank-labs/goliath&quot;&gt;Goliath&lt;/a&gt; so I wanted to brush up on EM&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;http://peepcode.com/products/coffeescript&quot;&gt;CoffeeScript&lt;/a&gt; - I only wrote a tiny bit of CoffeeScript this year, but it feels good, man&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;http://peepcode.com/products/smash-into-vim-i&quot;&gt;Vim&lt;/a&gt; - I switched to Vim fulltime and love it (again)&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;http://peepcode.com/products/ryan-singer-ux&quot;&gt;UX with Ryan Singer&lt;/a&gt; - it’s great to see Ryan’s thought process and the considerations he makes when designing a UI&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;doing&quot;&gt;Doing&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Learned&lt;/strong&gt; from &lt;a href=&quot;http://distilleryimage11.s3.amazonaws.com/2ffb7b70121c11e1abb01231381b65e3_7.jpg&quot;&gt;a dozen or so tech conferences&lt;/a&gt; - best: &lt;a href=&quot;http://py.codeconf.com/&quot;&gt;PyCodeConf&lt;/a&gt;, &lt;a href=&quot;http://ncc.garage.co.jp/en/&quot;&gt;New Context Conference&lt;/a&gt;, &lt;a href=&quot;http://sxsw.com/&quot;&gt;SXSW&lt;/a&gt; &amp;amp; &lt;a href=&quot;http://velocityconf.com/velocityeu&quot;&gt;Velocity EU&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Traveled&lt;/strong&gt; to Japan, Germany and Argentina for conferences&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Shipped&lt;/strong&gt; newrelic.com + countless split tests and marketing programs&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Shipped&lt;/strong&gt; then killed &lt;a href=&quot;http://wodfinder.com/&quot;&gt;WODFinder.com&lt;/a&gt; - This was a realtime aggregator of Crossfit workouts all over the world using &lt;a href=&quot;http://superfeedr.com/&quot;&gt;superfeedr&lt;/a&gt;.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Shipped&lt;/strong&gt; &lt;a href=&quot;http://eatmoreprotein.com/&quot;&gt;EatMoreProtien.com&lt;/a&gt; - A quick idea for a single-page app w/ JQuery. Simple and useful, though I should make this more mobile friendly.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Shipped&lt;/strong&gt; the start of a &lt;a href=&quot;https://github.com/briandoll/movableink-api&quot;&gt;ruby wrapper for the MoveableInk API&lt;/a&gt; - love the idea behind MovableInk&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Shipped&lt;/strong&gt; &lt;a href=&quot;https://github.com/github/hubot-scripts/blob/master/src/scripts/newrelic.coffee&quot;&gt;a New Relic script&lt;/a&gt; for &lt;a href=&quot;http://hubot.github.com/&quot;&gt;Hubot&lt;/a&gt; - GitHub’s awesome and capable chat bot&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Shipped&lt;/strong&gt; &lt;a href=&quot;http://nextferry.emphaticsolutions.com/&quot;&gt;Next Ferry&lt;/a&gt; - a mobile web app to help you catch the next ferry (geo-optimized, SF-Marin only)&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Shipped&lt;/strong&gt; &lt;a href=&quot;https://github.com/briandoll/change-inside-surroundings.vim&quot;&gt;change-inside-surroundings.vim&lt;/a&gt; - my first Vim plugin, mostly as a learning exercise&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Presented&lt;/strong&gt; &lt;a href=&quot;http://ncc.garage.co.jp/en/&quot;&gt;Shipping it Faster: Agile Development and Feedback System (Panel)&lt;/a&gt; - New Context Conference, Tokyo&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Presented&lt;/strong&gt; &lt;a href=&quot;http://www.slideshare.net/briandoll/the-performance-and-scalability-mindset&quot;&gt;The Performance &amp;amp; Scalability Mindset&lt;/a&gt; - San Francisco Rails Meetup&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Presented&lt;/strong&gt; &lt;a href=&quot;http://dev2ops.org/blog/2011/7/2/devops-days-mountain-view-2011-devops-metrics-measurement-vi.html&quot;&gt;DevOps Metrics and Measurement (Panel)&lt;/a&gt; - DevOps Days Mountain View, CA&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Presented&lt;/strong&gt; &lt;a href=&quot;http://emphaticsolutions.com/2011/07/01/the-ultimate-productivity-hack-having-kids.html&quot;&gt;The Ultimate Productivity Hack: Having Kids&lt;/a&gt; - Ignite RailsConf in Baltimore, MD&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;personal-changelog&quot;&gt;Personal changelog&lt;/h2&gt;

&lt;p&gt;I made some changes to my digital and computing life in 2011:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;http://rdio.com/&quot;&gt;rdio is awesome&lt;/a&gt; - I have terabytes of music at home, but convenience is king. Love discovering music from friends as well.&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;http://code.google.com/p/macvim/&quot;&gt;(mac)Vim&lt;/a&gt; - I left Vim behind when I started writing Java in 2001 (&lt;em&gt;shudder&lt;/em&gt;). TextMate was fun for a while, but it feels great to be back, baby.&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;http://www.apple.com/macbookair/&quot;&gt;13” MacBook Air&lt;/a&gt; - The best laptop I’ve ever had&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;http://www.amazon.com/gp/product/B0051QVESA/ref=famstripe_k&quot;&gt;Kindle&lt;/a&gt; - The smallest and simplest kindle is amazing to read on. I don’t know why I waited so long.&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;http://www.apple.com/macosx/&quot;&gt;OSX Lion&lt;/a&gt; - fullscreen for everything is the ultimate productivity hack&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;http://www.wunderlist.com/&quot;&gt;Wunderlist&lt;/a&gt; - finally, a beautiful TODO list that syncs properly across mobile, desktop and web&lt;/li&gt;
  &lt;li&gt;Partial success and goals: Less apps, less stuff, less process, less email, less waste, less cruft.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;2011 was pretty great.  2012 is going to be even better.&lt;/p&gt;

</content>
 </entry>
 
 <entry>
   <title>The Ultimate Productivity Hack - Having Kids</title>
   <link href="http://emphaticsolutions.com/2011/07/01/the-ultimate-productivity-hack-having-kids.textile"/>
   <updated>2011-07-01T00:00:00+00:00</updated>
   <id>http://emphaticsolutions.com/2011/07/01/the-ultimate-productivity-hack-having-kids</id>
   <content type="html">I was honored to be selected to speak at Ignite RailsConf again this year.  &lt;a href=&quot;https://www.youtube.com/user/igniterails&quot;&gt;All the talks were great&lt;/a&gt; and I had a blast.

&lt;iframe width=&quot;560&quot; height=&quot;315&quot; src=&quot;http://www.youtube.com/embed/BtxEKK8DllI&quot; frameborder=&quot;0&quot; allowfullscreen&gt;&lt;/iframe&gt;

&lt;div style=&quot;width:595px&quot; id=&quot;__ss_8472736&quot;&gt;&lt;iframe src=&quot;http://www.slideshare.net/slideshow/embed_code/8472736?rel=0&quot; width=&quot;595&quot; height=&quot;497&quot; frameborder=&quot;0&quot; marginwidth=&quot;0&quot; marginheight=&quot;0&quot; scrolling=&quot;no&quot;&gt;&lt;/iframe&gt;&lt;/div&gt;
</content>
 </entry>
 
 <entry>
   <title>Agile Construction Projects</title>
   <link href="http://emphaticsolutions.com/2011/04/23/agile-construction-projects.textile"/>
   <updated>2011-04-23T00:00:00+00:00</updated>
   <id>http://emphaticsolutions.com/2011/04/23/agile-construction-projects</id>
   <content type="html">&lt;span class=&quot;subtitle&quot;&gt;This article was originally written on May 25th, 2007&lt;/span&gt;&lt;br/&gt;

How is it that a 30 year old construction company can defeat a clichéd image of a slow moving, deadline-missing, tax-eating machine to that of an industry-leading, lean and fast infrastructure development firm? By adopting agile methodologies, probably without even knowing it.

&lt;h4&gt;The Collapse&lt;/h4&gt;
First, let's get some incredible facts out of the way. On April 29th 2007, a gasoline tanker truck took a bit of a spill here in the bay area and turned an incredible amount of liquid into an incredible amount of flame.  Twenty-six days later everything was back to normal.

&lt;div class=&quot;line indent&quot;&gt;
  &lt;div class=&quot;unit size1of2&quot;&gt;&lt;img src=&quot;/images/flames.jpg&quot;&gt;&lt;/div&gt;
  &lt;div class=&quot;unit size1of2&quot;&gt;&lt;img src=&quot;/images/fixed.jpg&quot;&gt;&lt;/div&gt;
&lt;/div&gt;

&lt;h4&gt;Typical Construction Management&lt;/h4&gt;

I don't know about the rest of you, but about mid-way through my commute we've got a bit of a construction project going on. You know the drill, there is a sign posted next to this construction that marks &quot;October 2006&quot; as the completion date and there they are, about 20 construction workers doing their thing. It's May 2007 by the way, and the overpass they are working on has a wooden external frame, which I'm guessing isn't their final design. Let's call this &quot;typical&quot; of construction management projects.

&lt;h4&gt;Agile for Construction Projects?&lt;/h4&gt;
In stark contrast, we have the now soon-to-be infamous &quot;I-580 / 880 Emergency Repair&quot; project, run by &lt;a href=&quot;http://www.ccmyers.com/&quot;&gt;C.C. Myers&lt;/a&gt;. In reading the &lt;a href=&quot;http://www.sfgate.com/cgi-bin/article.cgi?file=/c/a/2007/05/25/MNG6EQ1IDG1.DTL&quot;&gt;article&lt;/a&gt; I started seeing very familiar concepts appear. Now I'm not sure if Michael Cabanatuan or anyone at C.C. Myers has ever heard of agile or not, but they certainly act like it. Let's take a look.

&lt;h5&gt;Individuals and interactions over processes and tools&lt;/h5&gt;
&lt;ul&gt;
  &lt;li&gt;Within hours – some say it was closer to 15 minutes – Myers had workers on the site of the maze collapse.&lt;/li&gt;
  &lt;li&gt;Workers wrote a message on the side of the girders in chalk: &quot;To the people of Oakland, California, from Stinger Welding, Coolidge, Arizona,&quot; and the trucks rolled off with two drivers in each rig.&lt;/li&gt;
&lt;/ul&gt;

&lt;h5&gt;Working software over comprehensive documentation&lt;/h5&gt;
&lt;ul&gt;&lt;li&gt;&quot;They had a design roughed out within hours – once they figured out where it happened and what it looked like,&quot; said Rick Land, Caltrans' chief engineer.&lt;/li&gt;
&lt;li&gt;In another example, instead of requiring the contractor to wait for detailed construction drawings to be approved, Caltrans agreed to let the work start while they were being reviewed. It was a risk for both the contractor and Caltrans, Land said, but was a relatively safe bet &quot;because the work was so straightforward.&quot; It ended up saving about five days.
&lt;/li&gt;&lt;/ul&gt;
  
&lt;h5&gt;Customer collaboration over contract negotiation&lt;/h5&gt;
&lt;ul&gt;&lt;li&gt;&quot;Caltrans came in and put good people in our shop,&quot; Douglas said. &quot;If there were any problems, we could go to them and get immediate answers. Usually (done by phone, fax or email), it takes weeks. It was a breath of fresh air to have a government agency come in and perform like that.&quot;&lt;/li&gt;
&lt;li&gt;&quot;C.C. Myers was very good at coordinating things. They eliminated the transitions, the waiting time,&quot; he said, mentioning the importance of flexibility on the job.&lt;/li&gt;&lt;/ul&gt;

&lt;h5&gt;Responding to change over following a plan&lt;/h5&gt;
When Caltrans mentioned a willingness to be flexible when it awarded the job, some critics feared it would mean lower standards and inferior quality. In fact, UC Berkeley civil engineering professor Abolhassan Astaneh said Thursday he was not convinced that four concrete columns supporting 580 or 880 could withstand a major earthquake. Instead, they should have been demolished and replaced, he said. But Land and Peter Strykers, Caltrans senior engineer, said multiple tests were performed on both the surviving structures and the new construction, and they are confident of its safety. Relying on Testing over a professors guesstimations? TDD in action!

&lt;h5&gt;Time for new traditions&lt;/h5&gt;
Customers, banking executives as well as the commuting moms on their way to drop the kids off at the pool, all expect high quality in a timely fashion. The basic tenets of the agile manifesto are proven ways for people to execute change, no matter what you call them.

I just wish somebody would tell the guys working on the overpass on my way to work!

&lt;h5&gt;Quick Facts:&lt;/h5&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;26&lt;/strong&gt; : Days I-580 was closed&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;17&lt;/strong&gt; : Days it took C.C. Myers to rebuild I-580&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;96&lt;/strong&gt; : Hours of curing time for concrete road deck&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;200&lt;/strong&gt; : Cubic yards of concrete in road deck&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;35&lt;/strong&gt; : Cubic yards of concrete in railing walls&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;12&lt;/strong&gt; : Number of steel girders supporting I-580 connector&lt;/li&gt;
&lt;/ul&gt;
</content>
 </entry>
 
 <entry>
   <title>Object-oriented CSS Heuristics for Programmers</title>
   <link href="http://emphaticsolutions.com/2011/03/19/object-oriented-css-for-programmers.textile"/>
   <updated>2011-03-19T00:00:00+00:00</updated>
   <id>http://emphaticsolutions.com/2011/03/19/object-oriented-css-for-programmers</id>
   <content type="html">I've been holding in a deep, dark secret that could easily get me kicked out of &quot;Blue Bottle&quot;:http://www.bluebottlecoffee.net/ or &quot;Philz&quot;:http://www.philzcoffee.com/ during the late morning rush.  &lt;em&gt;I don't know how do write quality CSS.&lt;/em&gt;  That's right.  I built my first website in 1995 and have been making things on the web professionally since 1997, but like many engineers I know, I've been &quot;cargo culting&quot;:http://en.wikipedia.org/wiki/Cargo_cult CSS for about as long as that's been possible.

h4. Where do I find &quot;best practices&quot; for developing coherent &amp; cohesive CSS???

I recently took this secret to &lt;strike&gt;my therapist&lt;/strike&gt; &quot;twitter&quot;:http://twitter.com/#!/briandoll/status/48812621943672832 and saw that I wasn't alone.  15 years ago we were building HTML by hand with &lt;code&gt;&lt;font size=&quot;2&quot;&gt;&lt;/code&gt; tags.  Now we have Rails.  Let that sink in a bit.  That's an insane amount of progress.  BUT... Look at the CSS for virtually every big web app and the CSS is a disaster.  There's a mix of naming conventions, no organization, loads of repetition and probably hundreds if not thousands of lines of styles that are not even used anymore.  So... how do we do it right?  You can find a CSS snippet for a 3D spinning logo on fire on a thousand websites right now, but where are folks taking about building coherent, cohesive and maintainable CSS?  How can we apply the practices of regular programming to CSS?

h4. Enter: Object-Oriented CSS

Nicole Sullivan, aka &quot;stubbornella&quot;:http://www.stubbornella.org/, &quot;wrote about&quot;:http://www.stubbornella.org/content/2009/02/28/object-oriented-css-grids-on-github/ her &quot;oocss framework&quot;:https://github.com/stubbornella/oocss in 2009 and has been whacking sense into folks ever since (and probably long before). Be sure to read &quot;the original OOCSS blog post that started it all&quot;:http://www.stubbornella.org/content/2009/02/28/object-oriented-css-grids-on-github/ and check out &quot;Nicole's presentations, all of which are pure gold.&quot;:http://www.slideshare.net/stubbornella/presentations  (And many, many thanks to &quot;Brent Miller&quot;:http://twitter.com/foliosus/ for turning me on to this!)

Of the &quot;10 Best Practices&quot;:http://www.slideshare.net/stubbornella/object-oriented-css/19 highlighted in the original presentation, these three had the biggest effect on me:
* Separate structure and skin
* Separate container and content
* Extend objects by applying multiple classes to an element
* (*Bonus #4!) Use classes for style. Save &lt;code&gt;id&lt;/code&gt;s for JavaScript.

h4. Object-Oriented Design Heuristics

Once we purposefully design CSS in an object-oriented fashion, suddenly a whole new world opens up.  We're no longer jamming in long CSS rules with repetitive styles.  We're creating unique, small classes that can be composed to style our elements.  Hey, that sounds like real programming!  Let's do this!

&quot;Object-Oriented Design Heuristics&quot;:http://www.amazon.com/Object-Oriented-Design-Heuristics-Arthur-Riel/dp/020163385X is one of my favorite programming books.  Inside the cover the author lists about a hundred heuristics for object-oriented programming.  If you're looking for the 1996 winner of the &quot;best index&quot; award, this is it. Here are a few of the heuristics from the book, applied to OOCSS.

h4. A class should capture one and only one key abstraction

This is a more specific goal than the best practices listed above.  To me, this means creating different classes to handle style behavior that isn't always going to be used together.  The anti-pattern version of this though is to have loads of tiny classes that do very little and elements that need a dozen classes to work right.  Herein lies the art of good OOCSS.

h4. Do not create god classes in your system

Similar to the earlier statement, we shouldn't see classes with a large number of styles specified.  I wonder what a good rule of thumb is?  How many lines does a CSS class need to be before it's too big?

h4. Model the real world whenever possible

Semantic names! Now that we're not cluttering our classes with dozens of styles, we can name them well.  Think first of the &quot;user&quot; of your CSS.  When someone is reading the markup, they see a list of class names styling an element.  How easily can they visualize where and what an element will render like by reading those names?

h4. Minimize the number of classes with which another class collaborates

I'd argue that we should work hard to break this rule.  We are composing classes (collaborating) as a rule.  We should aim to limit the number of classes necessary to achieve a desired style, however.

h4. A class must know what it contains, but it should never know who contains it

This is huge.  This specifically relates to separating structure and skin.  Classes should be portable.

h4. Inheritance should be used only to model a specialization hierarchy

Related: &quot;Choose composition over inheritance&quot;.  Think of it this way: The DOM represents inheritance, while custom classes are used in composition.

h4. Factor the commonality of behavior as high as possible in the inheritance hierarchy

Great rule for CSS.  Leverage that &quot;cascading&quot; effect of CSS.  Place common styles as high up in the inheritance hierarchy (DOM), and override when necessary.

h3. Classes over IDs

I'm calling out bonus point #4 from above for a second time because it's really important.  Nicole says we shouldn't use IDs to style elements because an ID is supposed to refer to a single instance, and our goal of OOCSS is reusability and composition.  There is an even more plain reason to use classes instead of IDs, however.  An element may have zero or one IDs assigned to it, but an element can have many classes.  Compose styles out of several classes and keep your IDs to actually identify a single element, most notably when you need to grab it with JavaScript.

h3. Submit your own rules for OOCSS!

I'd love to hear your object-oriented rules for creating good, maintainable CSS.  Add them in the comments, &quot;email me&quot;:mailto:brian@emphaticsolutions.com or copy me on twitter &quot;@briandoll&quot;:http://twitter.com/briandoll and I'll add them to this post.


*Note:* I'm aware of &quot;Saas (SCSS)&quot;:http://sass-lang.com/ and &quot;Compass&quot;:http://compass-style.org/, but for the purposes of clarity around OOCSS, this post is aimed at bare CSS.  I know lots of folks love CSS generator frameworks, I guess I'm just not there yet personally.


&lt;a href=&quot;http://science.webhostinggeeks.com/heuristike-objektno-orjentisanog&quot;&gt;This article was translated to Serbo-Croatian&lt;/a&gt; by Anja Skrba from Webhostinggeeks.com.
</content>
 </entry>
 
 <entry>
   <title>Functional Widgets with Rails, JavaScript and JSONP</title>
   <link href="http://emphaticsolutions.com/2011/01/21/functional-widgets-with-rails-javascript-jsonp.textile"/>
   <updated>2011-01-21T00:00:00+00:00</updated>
   <id>http://emphaticsolutions.com/2011/01/21/functional-widgets-with-rails-javascript-jsonp</id>
   <content type="html">h3. What's a widget?

&lt;img src=&quot;/images/wireframe.jpg&quot; style=&quot;float:right; margin:10px;&quot;/&gt; I have no idea.  I'm sure the cool kids have a better name for it these days, but we'll just call 'em widgets for now.  When we draw a wireframe of a web app with a box around some bit of functionality, we tend to refer to that thing as a 'widget'.

Taking this a step further, while a widget is often thought of as a discreet piece of functionality, we also tend to think of it as being portable.  That lovely little widget is just so great, let's share it with the world!  Can't we just &quot;drop that in&quot; to another website?  Yes we can!

h3. JavaScript widgets

Rendering the HTML content of our widget on a separate &quot;consuming&quot; web application is typically done with JavaScript. If our widget includes only static content, it's very simple to render that content remotely.  Ilya Grigorik's post on &lt;a href=&quot;http://www.igvita.com/2007/06/05/creating-javascript-widgets-in-rails/&quot;&gt;Creating JavaScript Widgets in Rails&lt;/a&gt; demonstrates this technique, essentially wrapping each line of HTML output in a call to &lt;code&gt;document.write&lt;/code&gt;.

h3. Functional Javascript widgets

What if our widgets actually do stuff?  How can we build fully-functional widgets with Rails that can be consumed by other websites?  Here's one way to do it...

&lt;h4&gt;1. Create the feature that you want to 'widgetize' with Rails&lt;/h4&gt;

Let's say you'd like to support CRUD actions on content for your awesome home-grown blog app.  Create your model, controller, view(s) and routes as usual.  Don't forget your tests.  Set up some nice model validation and build your forms The Rails Way.  Don't forget to use the &lt;code&gt;route_url&lt;/code&gt; route name instead of the &lt;code&gt;route_path&lt;/code&gt; name in the form actions, since we'll be interacting with this form from a different host eventually.

&lt;h4&gt;2. AJAX, baby!&lt;/h4&gt;

I prefer jQuery over Prototype, so I'd suggest using the &lt;a href=&quot;https://github.com/indirect/jquery-rails&quot;&gt;jquery-rails&lt;/a&gt; gem in addition to the latest version of &lt;a href=&quot;http://www.jquery.com&quot;&gt;jQuery&lt;/a&gt;.

Rails has made it very convenient to create RESTful &lt;strike&gt;widgets&lt;/strike&gt; services.  However, as soon as we want to interact with a RESTful service using AJAX, we have to come up with our own pattern for our views.  We often want to send back content to be rendered as HTML.  We'll also need a way to communicate success or failure along with specific error messages we may want to render in the widget.  Additionally, we often need to redirect our users to new pages after they complete a certain step.

&lt;a href=&quot;http://paydrotalks.com/&quot;&gt;Peter Bui&lt;/a&gt; wrote &lt;a href=&quot;https://github.com/paydro/js_message&quot;&gt;js_message&lt;/a&gt; that solves this pattern nicely.  Her's a quick example:

&lt;script src=&quot;https://gist.github.com/780331.js?file=controller.rb&quot;&gt;&lt;/script&gt;

&lt;script src=&quot;https://gist.github.com/780331.js?file=js_message_example.js&quot;&gt;&lt;/script&gt;

&lt;h4&gt;3. Cross-domain JSON with JSONP&lt;/h4&gt;

JSONP is an awesome hack.  Here is a &lt;a href=&quot;http://stackoverflow.com/questions/3839966/can-any-one-explain-me-what-is-jsonp-in-layman-terms?tab=votes#tab-top&quot;&gt;great explanation of what JSONP is&lt;/a&gt; on Stack Overflow.  Now that we know what it is, Kevin Chiu shows us how to use &lt;a href=&quot;http://kevinchiu.org/archives/jsonp-in-rails-3&quot;&gt;JSONP in a Rails3 controller&lt;/a&gt;.

We're now using JSONP, but we're still getting these strange &lt;a href=&quot;http://en.wikipedia.org/wiki/Same_origin_policy&quot;&gt;same origin policy errors&lt;/a&gt;.  No worries! Here's how we can &lt;a href=&quot;http://blog.jetthoughts.com/2010/12/22/allow-multiple-access-control-requests-for-rails/&quot;&gt;allow multiple access control requests in Rails&lt;/a&gt;.

This is great, we've got a widget that pulls content in asynchronously across domains.  Unfortunately, the content we're getting is just JSON.  We want HTML!

&lt;h4&gt;4. Square peg in a round hole&lt;/h4&gt;

Let's render our erb template &lt;em&gt;to a string&lt;/em&gt;, then wrap it in a tasty JSON envelope!  We'd have to take care of quotes and newlines though, to make it JSON safe...

Example:
&lt;script src=&quot;https://gist.github.com/790915.js?file=some_controller.rb&quot;&gt;&lt;/script&gt;

(Hat tip to &lt;a href=&quot;http://www.jsonlint.com/&quot;&gt;JSON Lint&lt;/a&gt; for testing my JSON output)

&lt;h4&gt;5. Finally, the widget view&lt;/h4&gt;

&lt;script src=&quot;https://gist.github.com/791610.js?file=widget.js.erb&quot;&gt;&lt;/script&gt;

Then all the consuming web app needs to do in order to render your awesome widget, is drop in this JavaScript file:

&lt;script src=&quot;https://gist.github.com/791610.js?file=widget_on_consuming_site.html&quot;&gt;&lt;/script&gt;

&lt;h4&gt;6. Profit!&lt;/h4&gt;

Now you've got fully functional widgets in Rails that you can let other web applications drop into their site.  Surely it won't be long before the cash starts rolling in.
</content>
 </entry>
 
 <entry>
   <title>The Fallacies of Distributed Computing Reborn - The Cloud Era</title>
   <link href="http://emphaticsolutions.com/2011/01/06/the-fallacies-of-distributed-computing-in-the-cloud-era.html"/>
   <updated>2011-01-06T00:00:00+00:00</updated>
   <id>http://emphaticsolutions.com/2011/01/06/the-fallacies-of-distributed-computing-in-the-cloud-era</id>
   <content type="html">&lt;p&gt;&lt;em&gt;This post was originally written for &lt;a href=&quot;http://newrelic.com&quot;&gt;New Relic&lt;/a&gt; in January, 2011&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Seventeen years ago, long before Sun Microsystems was putting the &lt;em&gt;“dot in dot-com”&lt;/em&gt;, &lt;a href=&quot;http://en.wikipedia.org/wiki/L._Peter_Deutsch&quot;&gt;L. Peter Deutsch&lt;/a&gt;, then a Fellow at Sun, wrote &lt;a href=&quot;http://blogs.sun.com/jag/resource/Fallacies.html&quot;&gt;The Fallacies of Distributed Computing&lt;/a&gt;, a classic and often quoted list of assumptions that programmers may falsely believe when building distributed systems.&lt;/p&gt;

&lt;p&gt;The fallacies are:&lt;/p&gt;
&lt;ol&gt;
	&lt;li&gt;The network is reliable&lt;/li&gt;
	&lt;li&gt;Latency is zero&lt;/li&gt;
	&lt;li&gt;Bandwidth is infinite&lt;/li&gt;
	&lt;li&gt;The network is secure&lt;/li&gt;
	&lt;li&gt;Topology doesn't change&lt;/li&gt;
	&lt;li&gt;There is one administrator&lt;/li&gt;
	&lt;li&gt;Transport cost is zero&lt;/li&gt;
	&lt;li&gt;The network is homogeneous&lt;/li&gt;
&lt;/ol&gt;

&lt;h3 id=&quot;tldr&quot;&gt;TL;DR&lt;/h3&gt;

&lt;p&gt;The Fallacies of Distributed Computing applies directly to web applications, and is especially important when developing applications hosted in the cloud.&lt;/p&gt;

&lt;h3 id=&quot;what-is-a-distributed-system&quot;&gt;What is a Distributed System?&lt;/h3&gt;

&lt;blockquote&gt;
  &lt;p&gt;A collection of independent computers that appears to its users as a single coherent system&lt;br /&gt;  - Tanenbaum and Steen: &lt;a href=&quot;http://www.cs.vu.nl/~ast/books/ds1/&quot;&gt;Distributed Systems: Principles and Paradigms&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;blockquote&gt;
  &lt;p&gt;You know you have a distributed system when the crash of a computer you’ve never heard of stops you from getting any work done.&lt;br /&gt;   - Leslie Lamport : &lt;a href=&quot;http://www.cl.cam.ac.uk/~rja14/book.html&quot;&gt;Security Engineering: A Guide to Building Dependable Distributed Systems&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;blockquote&gt;
  &lt;p&gt;A distributed system is an application that executes a collection of protocols to coordinate the actions of multiple processes on a network, such that all components cooperate together to perform a single or small set of related tasks.&lt;br /&gt;  - &lt;a href=&quot;http://code.google.com/edu/parallel/dsd-tutorial.html&amp;quot;&quot;&gt;Introduction to Distributed System Design - Google Code University&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3 id=&quot;web-apps-are-distributed-systems&quot;&gt;Web Apps Are Distributed Systems&lt;/h3&gt;

&lt;p&gt;Web applications are composed of multiple systems working closely together.  Proxy servers, cache servers, load balancers, web servers, application servers and databases are all likely to be involved in processing a single web request.  Many web applications also leverage other web-APIs. An application may show your &lt;a href=&quot;http://developers.facebook.com/&quot;&gt;friends on Facebook&lt;/a&gt;, allow you to &lt;a href=&quot;https://dev.twitter.com/&quot;&gt;post to Twitter&lt;/a&gt;, or store some files on &lt;a href=&quot;http://aws.amazon.com/s3/&quot;&gt;Amazon’s S3 storage service&lt;/a&gt;.&lt;/p&gt;

&lt;h3 id=&quot;web-apps-in-the-cloud&quot;&gt;Web Apps in The Cloud&lt;/h3&gt;

&lt;p&gt;Ignore the fallacies at your own peril.  For a little while, you might pretend that some of the fallacies don’t apply to you when you host applications in datacenters with your own hardware.  Hosting applications in the cloud provides no such grace period.  Failure will happen.  Hosting in the cloud, while being the easiest way to scale a web application, means facing up to these fallacies immediately.&lt;/p&gt;

&lt;p&gt;When Netflix moved to the cloud, they were &lt;a href=&quot;http://techblog.netflix.com/2010/12/5-lessons-weve-learned-using-aws.html&quot;&gt;quick to realize that they could not ignore the fallacies&lt;/a&gt;:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;“I knew to expect higher rates of individual instance failure in AWS, but I hadn’t thought through some of these sorts of implications.” &lt;br /&gt;&lt;br /&gt; “AWS networking has more variable latency. We’ve had to be much more structured about “over the wire” interactions, even as we’ve transitioned to a more highly distributed architecture.”&lt;br /&gt;&lt;br /&gt;“Co-tenancy can introduce variance in throughput at any level of the stack. You’ve got to either be willing to abandon any specific subtask, or manage your resources within AWS to avoid co-tenancy where you must.”&lt;br /&gt;&lt;br /&gt; “We’re designing each distributed system to expect and tolerate failure from other systems on which it depends.”&lt;br /&gt;&lt;br /&gt;   -  John Ciancutti, Vice President of Personalization Technology at Netflix, Inc&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3 id=&quot;the-cloud-vs-the-fallacies&quot;&gt;The Cloud vs. The Fallacies&lt;/h3&gt;

&lt;p&gt;The Fallacies of Distributed Computing are even more important to consider when building web applications in the cloud.  While it seems obvious that the cloud highlights these fallacies more than ever (as Netflix noted recently), not everyone agrees.  &lt;a href=&quot;http://www.tbray.org/ongoing&quot;&gt;Tim Bray&lt;/a&gt; is currently an Android Developer Advocate at Google, former Director of Web Technologies at Sun and editor of the W3C XML specification.  I was surprised to find a post from 2009, &lt;a href=&quot;http://www.tbray.org/ongoing/When/200x/2009/05/25/HTTP-and-the-Fallacies-of-Distributed-Computing&quot;&gt;The Web vs. The Fallacies&lt;/a&gt;, where Tim suggests that the Fallacies are much less important to systems built on the web.  I was even more surprised that he &lt;a href=&quot;http://twitter.com/timbray/status/15548456986742784&quot;&gt;still agrees with that assertion&lt;/a&gt; when &lt;a href=&quot;http://twitter.com/briandoll/status/15496214912966656&quot;&gt;I asked him&lt;/a&gt;.   Let’s see if I can change Tim’s mind.&lt;/p&gt;

&lt;h2 id=&quot;disputing-the-fallacies-the-cloud-era&quot;&gt;Disputing The Fallacies: The Cloud Era&lt;/h2&gt;

&lt;h3 id=&quot;1-the-network-is-reliable&quot;&gt;1. The network is reliable&lt;/h3&gt;

&lt;p&gt;When you consume web APIs from Facebook, Twitter or Amazon, “the network” is the internet.  How reliable, within a given performance window, is the aggregate of all the web services you interact with?  Tim Bray suggests “if a &lt;code&gt;GET&lt;/code&gt; gets a network blowup, just do it again”.  Sure, we all do that.  If a page loads really slowly and appears to hang, we just refresh. Do you do that with each of your services and API calls?&lt;/p&gt;

&lt;p&gt;The network is not reliable.  When you add up all the points of failure for all the various services and APIs you use, the odds of failure are not just high, they are a given.  Instead, build an app that can function at reduced capacity when a given service is offline.&lt;/p&gt;

&lt;h3 id=&quot;2-latency-is-zero&quot;&gt;2. Latency is zero&lt;/h3&gt;

&lt;p&gt;Try as we might, there just isn’t a way to improve the speed of light.  Serving customers half-way around the globe affects performance in big ways.  Moving services closer to your customers via cloud availability zones and content delivery networks can help tremendously.  Ignore latency online and you’re likely throwing away customers from half the globe.&lt;/p&gt;

&lt;h3 id=&quot;3-bandwidth-is-infinite&quot;&gt;3. Bandwidth is infinite&lt;/h3&gt;

&lt;p&gt;Not long ago everyone had high-speed internet access at home. (Not everyone, of course.  The &lt;a href=&quot;http://en.wikipedia.org/wiki/Digital_divide&quot;&gt;digital divide&lt;/a&gt; is real.) Wireless hotspots filled every home and apartment and the web felt fast.  A few years ago this started to change.  Starting with the iPhone, web applications were being used not just over high-speed internet connections, but over phone networks.  Using web apps on mobile devices and tablets reminds us that bandwidth problems did not disappear with the dial-up modem.  Stay mindful of how much data you’re shipping across the wire and all your users will be grateful.  For a great read on how The Fallacies apply to mobile development, check out this great series of posts by our friends at &lt;a href=&quot;http://blog.carbonfive.com/2010/11/17/fallacy-1-the-network-is-reliabl&quot;&gt;Carbon Five on iPhone Distributed Computing Fallacies&lt;/a&gt;.&lt;/p&gt;

&lt;h3 id=&quot;4-the-network-is-secure&quot;&gt;4. The network is secure&lt;/h3&gt;

&lt;p&gt;Network security can be a full-time job for a prominent web business.  &lt;a href=&quot;http://en.wikipedia.org/wiki/Transport_Layer_Security&quot;&gt;Transport layer security&lt;/a&gt; is great, except when we leak security tokens over insecure connections.  &lt;a href=&quot;http://codebutler.com/firesheep&quot;&gt;Firesheep&lt;/a&gt; brought some necessary attention last year to the prevalence of private security tokens littering insecure connections, ripe for snooping by the guy in the corner of your favorite coffee shop sipping chai.  The network is not secure, and the more we move our lives online the higher the risk of exposure.  Keep a &lt;a href=&quot;http://www.schneier.com/blog/archives/2008/03/the_security_mi_1.html&quot;&gt;security mindset&lt;/a&gt;  when developing your apps and keep your users safe.&lt;/p&gt;

&lt;h3 id=&quot;5-topology-doesnt-change&quot;&gt;5. Topology doesn’t change&lt;/h3&gt;

&lt;p&gt;One of the biggest benefits of moving applications to the cloud is the ability to change topology at will.  Add new app servers.  Upgrade (and possibly change the architecture of) the CPU on your database server in the middle of the day.  Add reverse proxy servers, cache servers, change CDN providers, migrate availability zones.  Topology changes all the time.  Depending on a static infrastructure design not only limits your ability to respond to change, it increases the likelihood of site-wide outages.&lt;/p&gt;

&lt;h3 id=&quot;6-there-is-one-administrator&quot;&gt;6. There is one administrator&lt;/h3&gt;

&lt;p&gt;Of course there isn’t just one administrator.  Even with applications hosted in your own private datacenter, your applications are likely interacting with systems outside your administrative control.  These systems may have performance, availability or security issues that you have no direct influence over.  Staying mindful that these systems are beyond your control can help you ensure they have minimal impact on your services when they are unresponsive.&lt;/p&gt;

&lt;h3 id=&quot;7-transport-cost-is-zero&quot;&gt;7. Transport cost is zero&lt;/h3&gt;

&lt;p&gt;Not only is transport cost not zero, it’s priced like any other commodity and can be purchased per transaction, per gigabyte, per compute hour, etc.  Cloud storage costs (and transport of that storage) are a major component of application hosting costs, just ask anyone doing video streaming online how close to zero their transport costs are.&lt;/p&gt;

&lt;h3 id=&quot;8-the-network-is-homogeneous&quot;&gt;8. The network is homogeneous&lt;/h3&gt;

&lt;p&gt;This fallacy was added to the original seven by James Gosling, creator of Java, in 1997.  The best part of this fallacy is that it might actually be true.  Almost.  Between &lt;a href=&quot;http://en.wikipedia.org/wiki/Representational_State_Transfer&quot;&gt;REST&lt;/a&gt; and &lt;a href=&quot;http://en.wikipedia.org/wiki/Json&quot;&gt;JSON&lt;/a&gt; APIs, have you ever had to think about the implementation of an external service, beyond satisfying your curiosity?  You’re much more likely to see &lt;a href=&quot;http://www.google.com/#sclient=psy&amp;amp;q=invalid+json&quot;&gt;libraries producing invalid messages&lt;/a&gt; than you are operating systems playing a role.&lt;/p&gt;

&lt;h3 id=&quot;building-performant-distributed-web-applications-is-hard&quot;&gt;Building performant distributed web applications is hard&lt;/h3&gt;

&lt;p&gt;The Fallacies were coined 17 years ago, but they apply just as well today.  Back then folks might have been fooled into actually believing them, but we’re smarter than that, right?  Knowing what gotchas await our web applications, most notably those hosted in the cloud, can help us build better, faster and more performant applications.  Isn’t that what we all want?&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>Engineers - build businesses not apps</title>
   <link href="http://emphaticsolutions.com/2010/12/10/build-businesses-not-apps.textile"/>
   <updated>2010-12-10T00:00:00+00:00</updated>
   <id>http://emphaticsolutions.com/2010/12/10/build-businesses-not-apps</id>
   <content type="html">h3. Hey, I had that idea years ago!

It's happened to you a dozen times, at least.  You had an &quot;aha!&quot; moment.  You told that friend of yours over pints one night.  You may have even built a prototype.  What you didn't do is build that business.

Earlier this month, &quot;Ebay purportedly paid 75M to buy Milo.com&quot;:http://venturebeat.com/2010/12/02/ebay-milo-e-commerce/, a &quot;local shopping&quot; site that &quot;got seed funding in November of 2008&quot;:http://www.crunchbase.com/company/milo.  Guess what?  In May of 2008, I had that idea too.

h3. The epiphany

Anticipating the summer months ahead, I was planning on buying a replacement pair of Reef sandals online.  While I was picking out my pair, my wife and I decided to order takeout. I drove a mile or so down the street, parking a half block from the restaurant.  Walking along the sidewalk I noticed several pairs of Reef sandals, the same ones I was looking to buy online, were on display at a local skate shop.  Instant gratification!  Supporting a local retailer!  Perfect!

h3. Some quick history

My family has been running local businesses for several generations.  My great-great grandfather owned a bar and restaurant not far from where I grew up.  My grandfather started a grocery store business in the '50s that my father took over in the 70's.  I grew up working at the family grocery store, which had also spawned a diner and laundromat in town.  I'm very familiar with the ongoing decline of local businesses.  My understanding of how grocery stores worked, as well as the systems that run them, proved quite valuable when I started building online commerce systems in the late '90s.  The idea of building an eCommerce app that got more people to shop locally was really appealing on many levels.

h3. The prototype

Like most programmers, the first thing I did was to start building.  The primary feature of this type of app is search, and it needed to account for location and odd product names.  For example, the Reef sandals I was going to buy need to also show up for a search on &quot;flip flops&quot;, etc.  In one night I grabbed a zip-code list, found a library online to do searches by geo-location w/ specified distances. I populated the app with a dozen or so products, and got the search feature working reasonably well.

I launched the prototype of &quot;FindNearBuy.com&quot;:http://findnearbuy.com/ that same night.  It was an exhilarating feeling.  I had been working with Ruby/Rails for several months by then, but this was one of my first ideas that went from concept to live app so quickly.

h3. Now what do I do?

By the end of that first night, I was eager to talk to some local merchants to get my neighborhood online.  I started documenting how that conversation would go.  What benefits there were to the merchant, what information I'd need, and how frequently I'd need it.  I started to build out what I thought would be the formula for ROI for these merchants.  They pay me a monthly fee, I send them more paying customers.  I wondered how I'd price this, and how I might account for small, low-margin shops vs. larger more established businesses.  Do I price this on the number of SKUs?  Annual revenue?  To get up and running in the first few stores, I had a lot of legwork ahead, not to mention a business model I couldn't quite nail down.

h3. Giving up

I spoke with a few shop owners that week and none of them were interested.  They were uneasy at the idea that I'd be grabbing their QuickBooks (or whatever) inventory data on a regular basis.  They were constantly being harassed by someone who thought they could help them run their business better, but who always came with their hands out.  The friction for getting a small business online was high, and the value was most certainly going to be very low for a while.  I gave up.

h3. Building a business worth $75M, not just building an app

While Milo.com bills itself as local shopping, they only have inventory for huge national chains available online.  Their business doesn't achieve what I had hoped for FindNearBuy.com, but they probably also saw the writing on the wall.  Get the giant retailers first, where there is huge impact with a single business integration.  They didn't just build an app.  They built a business.  They understood their customers and their partners.  They built relationships.  They built value.

In contrast, I built an app and only saw a flicker of the long struggle it would be to make good of this business opportunity and I quit.  I failed this idea, quite willingly, because all I really wanted to do was build an app.

h3. Focus on value

I still love to tinker.  I've built a dozen apps like FindNearBuy since then.  I've never built a business.  Every time I get excited about an idea, I jump into the code first.  Inevitably, I'll launch a prototype and immediately see the great chasm in front of me between this app and any potential customers.

I'm not suggesting anyone stop building prototypes.  I'm not suggesting we don't explore the idea of an application through its development.  However, *the next time you have that &quot;aha&quot; moment, think first of the value you can create and the app will follow.*  The app, it turns out, really is the easy part.</content>
 </entry>
 
 <entry>
   <title>What kind of maker are you?</title>
   <link href="http://emphaticsolutions.com/2010/09/04/makers.textile"/>
   <updated>2010-09-04T00:00:00+00:00</updated>
   <id>http://emphaticsolutions.com/2010/09/04/makers</id>
   <content type="html">Software Developer.  Programmer.  Software Architect.  Code Monkey.  Many names are given to the things we do, but in the simplest terms, we make things.  Digital things, web things, social things, interactive things.  We make things that people use.  We make things of value.

h3. So, what do you do?

Responding to a blog post entitled &quot;So, what do you do?&quot;:http://blog.scoutapp.com/articles/2010/08/24/so-what-do-you-do, &quot;Derek Sivers&quot;:http://sivers.org/blog recently explained that when he ran CDBaby, he would say &quot;I help musicians.&quot;  That is the value in the work he was doing at the time. Helping musicians.  Not managing a warehouse.  Not deploying code to a dozen servers.  Not A/B testing the signup form.  Derek built a great business helping musicians.  Every detail in the work he did was applied to that end.  As you may know, he was &quot;more than a little successful at it&quot;:http://sivers.org/trust.

h3. Transparency, Responsibility and Accountability

When &quot;Kent Beck spoke at RailsConf in 2008&quot;:http://emphaticsolutions.com/2008/09/08/transparency-responsibility-accountability.html, he talked about the origins of XP and what we now call Agile. He talked about how many folks got caught up in the weeds paying more attention to some stated technique than the value of their output.  A maker, according to Kent, should be transparent, responsible and accountable.  I would add that what we're responsible for and accountable for, is producing maximum value.  Being responsible for implementing strict rules on how your team develops software is missing the point.  Those practices exist solely to help you produce more value as efficiently as possible.  That is the goal.

h3. Stop estimating and start shipping

Recently someone asked the Hacker News community &quot;what techniques they use for software estimating&quot;:http://news.ycombinator.com/item?id=1646510.  This was my reply:

bq. How about doing it the other way around? How much value do you think a certain feature is worth? How much time should you spend producing that feature, as relative to its value? Then, figure out a way to ship a viable implementation in that amount of time.&lt;br/&gt;
There are many techniques for estimating how long software development tasks will take primarily because they all suck. Estimating takes time, and is almost always wrong. Some people even advocate figuring out how off your estimates are, to improve your future estimates, so you can be a better estimator. What?&lt;br/&gt;
I think it's best to stop estimating and start shipping.

&quot;Some good dialogue followed&quot;:http://news.ycombinator.com/item?id=1647736 and I promised to expand on what I meant.

h3. The factory worker model for commodity products

The &quot;industrial revolution&quot;:http://en.wikipedia.org/wiki/Industrial_Revolution was kind of a big deal.  We could produce mass quantities of things at a reasonable level of quality.  That's great for cookie-cutter products, and still is.  For this work, estimating is key.  How big should the factory be?  What are the output goals?  How many workers on the assembly line?  How much steel to order this month?

When you produce a commodity product the factory model works well.  Someone else had the ingenious idea of making a baking sheet specifically for cupcakes.  They studied the market.  The studied the consumer.  They chose the materials.  They designed the product.  The factory worker produced the commodity product as quickly as possible for as little money as possible.

h3. The thought worker model for value products

In his latest book &quot;Linchpin&quot;:http://www.amazon.com/gp/product/1591843162?ie=UTF8&amp;tag=emphaticsolut-20&amp;linkCode=as2&amp;camp=1789&amp;creative=390957&amp;creativeASIN=1591843162 Seth Godin draws a great distinction between the old a new model of work.  Instead of laboring a day's work for a day's wages, the new model focuses on being indispensable by way of providing incredible value.  Creativity, new ideas, focusing on the value, not the slog of the day-to-day.

Toyota's &quot;5 Whys&quot;:http://en.wikipedia.org/wiki/5_Whys is useful for more than just troubleshooting. You can use that question-asking technique to uncover the core value of a feature request.  Let's say you're being asked to build (or worse, estimate how long it would take to build) a feature to allow users to upload photos.  What's that all about?  Why are users uploading photos?  Who are they ultimately for?  How will they be accessed?  What's the value?

Once you've understood the value, it's time to iterate.  Attempting to implement every edge of your idea at once is a failure in the making.  Keep that core value in mind.  What is the smallest feature you could ship right now that satisfies the essence of that value?  This is thought work.  This is indispensable work.  This is the art of making things that provide value.  Build it small, ship it, gather feedback, and iterate.  Do the most valuable task next.  Very soon, you'll have another idea of value, and you'll call your current feature &quot;good enough&quot;.

Understanding the value of your product/service and continually increasing that value is the ultimate level of work for a maker of things.

h3. What kind of maker are you?

Factory work can be artistic.  Making hand-crafted furniture takes incredible craftsmanship and artistic talents.  This work, however, still falls into the model of factory labor.  Estimating how long that custom chair will take to build is a big part of the job.

Thought work isn't free of laborious tasks.  Even the best ideas still need to actually be implemented before they are valuable.

So what kind of maker are you?  I'm a thought worker.  Every time I felt my work slipping into that of the factory, I knew it was time to move on.  The factory is just no place for me.</content>
 </entry>
 
 <entry>
   <title>Get Fit to Win!</title>
   <link href="http://emphaticsolutions.com/2010/06/07/get-fit-to-win.textile"/>
   <updated>2010-06-07T00:00:00+00:00</updated>
   <id>http://emphaticsolutions.com/2010/06/07/get-fit-to-win</id>
   <content type="html">&quot;Ignite&quot;:http://ignite.oreilly.com/ is an intense, addicting and inspired format of sharing ideas in a very short time.  The tagline for any Ignite event is: &quot;Inspire us, but be quick about it!&quot;

I was honored to have &quot;my proposal&quot;:http://igniterailsconf.com/speakers/365 selected for the first annual &quot;IgniteRailsConf&quot;:http://www.igniterailsconf.com/ event this year.  I wanted to share with my fellow nerds that physical fitness is important, is not out of reach for anyone, and to help inspire them toward their own fitness goals.

&quot;I've written about my path to fitness before&quot;:http://emphaticsolutions.com/2009/01/12/clean-eating-how-I-make-it-work.html, but this time I wanted to share _why_ I think fitness is so important.

&lt;iframe width=&quot;560&quot; height=&quot;315&quot; src=&quot;http://www.youtube.com/embed/AqzlCZk9Vao&quot; frameborder=&quot;0&quot; allowfullscreen&gt;&lt;/iframe&gt;

&lt;div style=&quot;width:425px&quot; id=&quot;__ss_4428255&quot;&gt; &lt;strong style=&quot;display:block;margin:12px 0 4px&quot;&gt;&lt;a href=&quot;http://www.slideshare.net/briandoll/get-fit-to-win&quot; title=&quot;Get Fit to Win&quot; target=&quot;_blank&quot;&gt;Get Fit to Win&lt;/a&gt;&lt;/strong&gt; &lt;iframe src=&quot;http://www.slideshare.net/slideshow/embed_code/4428255&quot; width=&quot;425&quot; height=&quot;355&quot; frameborder=&quot;0&quot; marginwidth=&quot;0&quot; marginheight=&quot;0&quot; scrolling=&quot;no&quot;&gt;&lt;/iframe&gt; &lt;/div&gt;

h2. Resources

The feedback from this presentation has already been great.  I had a great time talking with several people afterwards about their own weightloss, or their own path to fitness.  To help answer some of the questions I got after my talk, here are some resources that might help.

h4. &quot;Robb Wolf&quot;:http://robbwolf.com/

Formerly a research biochemist, Robb is a nutrition expert and strength and condition coach.  His blog, seminars and weekly Q&amp;A podcasts are incredible.  When Robb says jump, I ask how high.

h4. &quot;The Paleo Diet&quot;:http://paleodiet.com/definition.htm

Paleo eating follows the idea that humans are just not evolutionarily fit to eat garbage.  Sugar, in all its forms, is garbage.  Grains and dairy are nothing but sugar.  As I noted in my presentation, eat real food: meat, vegetables, fruit, nuts and seeds.  *Body composition changes come directly from nutrition.*  If you want to lose weight, eat right.  Yes, it is actually that simple.

h4. &quot;Crossfit&quot;:http://www.crossfit.com/cf-info/what-crossfit.html

While I've been Crossfitting for two years now, I still find it hard to describe in a sentence.  Check out that link and get addicted!

h4. &quot;TJ's Gym&quot;:http://tjsgym.com/

In July 2008 I got the idea that I was sadly out of shape and needed a big change.  That big change came from eating well and being intensely active.  TJ's Gym is where it happens.

h2. Getting ready for an Ignite Talk

Speaking at an event like Ignite really requires some practice.  Distilling an idea into 20 slides, each with exactly 15 seconds of content and making the whole thing cohesive is quite a task.  I've been geeked out on the ideas of presenting for a while now, so here are some resources that have helped.

h4. &quot;Presentation Zen by Garr Reynolds&quot;:http://www.amazon.com/gp/product/0321525655?ie=UTF8&amp;tag=emphaticsolut-20&amp;linkCode=as2&amp;camp=1789&amp;creative=390957&amp;creativeASIN=0321525655

A simple, direct and inspiring book on presentation design and concept

h4. &quot;Confessions of a Public Speaker by Scott Burkun&quot;:http://www.amazon.com/gp/product/0596801998?ie=UTF8&amp;tag=emphaticsolut-20&amp;linkCode=as2&amp;camp=1789&amp;creative=390957&amp;creativeASIN=0596801998

Great stories and techniques on the mechanics of presenting

h4. &quot;The Story Factor by Annette Simmons&quot;:http://www.amazon.com/gp/product/0465078079?ie=UTF8&amp;tag=emphaticsolut-20&amp;linkCode=as2&amp;camp=1789&amp;creative=390957&amp;creativeASIN=0465078079

How humans relate to information via story, and how to tell better stories.  I learned in this book that telling stories with lots of seemingly extraneous details actually makes your stories more relatable.  In my presentation I included lots of tidbits about my experience and my children, to make my story feel more relatable to the audience.

h4. &quot;The Talent Code by Daniel Coyle&quot;:http://www.amazon.com/gp/product/055380684X?ie=UTF8&amp;tag=emphaticsolut-20&amp;linkCode=as2&amp;camp=1789&amp;creative=390957&amp;creativeASIN=055380684X

Great book on the neuroscience of talent and learning.  I used various &quot;deep practice&quot; techniques from this book to rehearse my presentation.

h3. Tweetable Quotes

In the age of social media, we have even more reason to consider nailing a distilled essence of our presentation concept in short, memorable phrases.  Ideally you want to deliver a core idea that's short enough to remember and short enough to tweet.  This is _exactly_ what I was after, thanks Chad!

&lt;style type='text/css'&gt;.bbpBox{#FFFFFF;padding:0px;}&lt;/style&gt;&lt;div id='tweet_15587799246' class='bbpBox' style=''&gt;&lt;p class='bbpTweet' style='background:#fff;padding:10px 12px 10px 12px;margin:0;min-height:48px;color:#000;font-size:16px !important;line-height:22px;-moz-border-radius:5px;-webkit-border-radius:5px;'&gt;&quot;real food doesn't have an ingredient list. Real food IS an ingredient.&quot; - &lt;a href=&quot;http://twitter.com/briandoll&quot; target=&quot;_new&quot;&gt;@briandoll&lt;/a&gt; &lt;a href=&quot;http://search.twitter.com/search?q=%23igniterailsconf&quot; target=&quot;_new&quot;&gt;#igniterailsconf&lt;/a&gt;&lt;span class='timestamp' style='font-size:12px;display:block;'&gt;&lt;a title='Sun Jun 06 23:31:25 ' href='http://twitter.com/chadfowler/status/15587799246'&gt;Sun Jun 06 23:31:25 &lt;/a&gt; via &lt;a href=&quot;http://itunes.apple.com/app/twitter/id333903271?mt=8&quot; rel=&quot;nofollow&quot;&gt;Twitter for iPhone&lt;/a&gt;&lt;/span&gt;&lt;span class='metadata' style='display:block;width:100%;clear:both;margin-top:8px;padding-top:12px;height:40px;border-top:1px solid #fff;border-top:1px solid #e6e6e6;'&gt;&lt;span class='author' style='line-height:19px;'&gt;&lt;a href='http://twitter.com/chadfowler'&gt;&lt;img src='http://a3.twimg.com/profile_images/892071631/chadfowler.com_normal.png' style='float:left;margin:0 7px 0 0px;width:38px;height:38px;' /&gt;&lt;/a&gt;&lt;strong&gt;&lt;a href='http://twitter.com/chadfowler'&gt;Chad Fowler&lt;/a&gt;&lt;/strong&gt;&lt;br/&gt;chadfowler&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;&lt;/div&gt; &lt;!-- end of tweet --&gt;

</content>
 </entry>
 
 <entry>
   <title>Twitever - A workflow for Twitter and Evernote</title>
   <link href="http://emphaticsolutions.com/2010/06/06/twitever-a-workflow-for-twitter-and-evernote.textile"/>
   <updated>2010-06-06T00:00:00+00:00</updated>
   <id>http://emphaticsolutions.com/2010/06/06/twitever-a-workflow-for-twitter-and-evernote</id>
   <content type="html">I fell in love with &lt;a href=&quot;http://evernote.com/&quot;&gt;Evernote&lt;/a&gt; as soon as I started using it.  Like any nerd, I come across a dizzying amount of information during a typical day.  I would often find a really interesting article or blog post I wanted to read at inconvenient times.  Evernote let me stash away all this great information into what they refer to our &quot;online brain&quot; and come back to it later.  I can search it, tag it or find stuff by date.  It's awesome.

For me, the primary source for finding great stuff to read online comes from &lt;a href=&quot;http://twitter.com/briandoll&quot;&gt;Twitter&lt;/a&gt;.  I'd see posts from people throughout the day, linking to something that sounded interesting.  I would click on the link, opening it in my browser, and use an Evernote browser plugin to create a note from that webpage and stick it into Evernote.

This had several downsides, however.  First, It takes a few steps.  If I don't have time to read the article, I might not want to break from whatever I'm doing to open up the document and get it into Evernote right then and there either.  Secondly, I had lost the context.  I'd read a great article a few days later and forget where the link came from.  Who posted this link to Twitter?  Who can I chat with about it?  The last issue with this is that I often read Twitter from my phone.  The whole tweet to browser to Evernote plugin to Evernote workflow on a phone is just not going to happen.

h2. Introducing Twitever

&lt;a href=&quot;http://github.com/briandoll/twitever&quot;&gt;Twitever brings the flow-of-awesome that is Twitter to the remember-it-for-later of Evernote.  Check it out on GitHub.&lt;/a&gt;

h3. The Twitever workflow

1. See a tweet that has a link to something you might want to read later
2. Mark that tweet as a Favorite
3. Whenever it's convenient, run twitever.rb on your mac, which downloads your twitter favorites and adds linked pages to Evernote

h3. Tweet to Note

To keep the twitter context in mind, notes added to Evernote from Twitever will have the original tweet as the name of the note.

h3. Enjoy!

While this is essentially a quick hack, it's already been incredibly convenient and useful for me.  Feel free to fork the project and spiff if up if you like.

Note: I should mention this is Mac only.  If you use Windows, I'm sorry.  Really, really sorry.
</content>
 </entry>
 
 <entry>
   <title>Rit. - The anti-CMS content scheduling system in Rails</title>
   <link href="http://emphaticsolutions.com/2010/02/20/rit-the-anti-CMS-content-scheduling-system-in-Rails.textile"/>
   <updated>2010-02-20T00:00:00+00:00</updated>
   <id>http://emphaticsolutions.com/2010/02/20/rit-the-anti-CMS-content-scheduling-system-in-Rails</id>
   <content type="html">You have a web app.  Your marketing folks would like to update some site content.  You need a content management system, right?  Probably not.

If you're building a cute little website for the bakery down the street that needs to occasionally update prices, go get yourself that fancy CMS.  If you'd like a Rails-based CMS, go ahead and use &quot;Radiant&quot;:http://radiantcms.org/.  As they say, _Radiant is a no-fluff, open source content management system designed for small teams._  

Keep that _small teams_ part in mind, though.  If that bakery website gets any real traffic, you're going to serve somewhere between one to two pages a year.  Radiant is so slow, you're better off hand-typing HTML directly into the serial port of your 28.8 modem.  Radiant also makes your web app its bitch.  If _your_ web app wants to use some Radiant content (they call them 'snippets'), you put _your_ web app _inside_ Radiant's extensions directory.  How does that make you feel?  Now you have a Radiant app and you have more than two problems.

h2. What do you really need?

Your web app needs fresh content.  There are really only two questions you need to answer for each piece of content.  _Where_ should the content appear and _when_ should it show up?

The 'where' question focuses on context.  The marketing copy on your 'Sale' page might show up below the headline but before your product listing.  Your last-minute holiday shipping guide might show up on your homepage, just below your nav bar.

The 'when' question is even more critical.  Most real-world applications need more than just a single version of published content.  If you're introducing a sale on Monday morning at 8AM EST, how do you make sure those 10 pieces of content are updated at exactly that time?  How do you update that last-minute holiday shipping guide every single day for two weeks, at noon?  _When_ you release fresh content is as important as where it goes.

h2. Solving 'where' and 'when' quickly

&quot;We&quot;:http://www.sheetmusicplus.com/ needed a way to allow our marketing team to update site content where they wanted, and when they wanted, without any involvement from our technical team.  We distilled our issues down to their essence and set out to find a solution.

Unfortunately, the more CMS systems you find, the more you see how lacking they all are.  If you're building a mini brochure site, go for it.  If you are building a web app with Rails, you probably don't need a CMS to go along with it.  You need fresh content.  You need to schedule that content, and have it show up where you want it.  What you need, is Rit.

h2. Introducing Rit.

Rit. is not a content management system.  You don't build site templates in Rit.  You don't build 'pages' in Rit.  You author content in Rit, and you schedule exactly when you want that content to show up.  That's it.

Rit. was designed in about a day by &quot;Kasima Tharnpipitchai&quot;:http://www.linkedin.com/pub/kasima-tharnpipitchai/8/7b4/7a2 and I, and developed by Kasima in about a month.  It does exactly what we want, very efficiently, and it might just be what you need, too.  This work was sponsored by my employer, &quot;Sheet Music Plus&quot;:http://www.sheetmusicplus.com/, and is being &quot;released today as an open-source product&quot;:http://github.com/briandoll/Rit.

&quot;Rit.&quot;:http://github.com/briandoll/Rit is a simple content scheduler.  We pulled our terminology from &quot;prepress printing&quot;:http://en.wikipedia.org/wiki/Prepress, and built a scheduling system that allows you to create multiple editions of content that will display exactly when you want.  You can schedule individual pieces of content, or group them into scheduled events.  To help convey how the scheduler works, the &quot;README&quot;:http://github.com/briandoll/Rit has ASCII art.  Seriously, what more could you want?

I'll be managing patches through github, so fork away and submit pull requests.  Thanks to &quot;Sheet Music Plus&quot;:http://www.sheetmusicplus.com/ for agreeing to release this great project, and a million thanks to Kasima, who is one of the strongest developers I've ever had the pleasure of working with.

&quot;*Check out the README to learn more about Rit.*&quot;:http://github.com/briandoll/Rit
</content>
 </entry>
 
 <entry>
   <title>The dangers of url_for in Rails applications</title>
   <link href="http://emphaticsolutions.com/2010/02/16/the-dangers-of-url_for-in_rails_apps.textile"/>
   <updated>2010-02-16T00:00:00+00:00</updated>
   <id>http://emphaticsolutions.com/2010/02/16/the-dangers-of-url_for-in_rails_apps</id>
   <content type="html">In a great post about &quot;named routes in Rails, path vs. url&quot;:http://www.viget.com/extend/rails-named-routes-path-vs-url/, Viget Labs ponders which variant is best used.

Most often we use foo_path, which when used in Rails URL helpers will generate a relative path, where foo_url generates a full URL.  In most cases the path makes most sense, but not always.

h3. Prerequisites to coax the url_for dragons out of hiding

# A web server that is listening to any incoming request by IP (rather than by hostname)
# A Rails app that is generating some links with full URL named routes
# Cached pages that store content that includes those full URLs

Can you see where this is going yet?

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ruby&quot; data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;c1&quot;&gt;# to take Viget's example&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;resources&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:doohickeys&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;link_to&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'index of doohickeys'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;doohickeys_url&lt;/span&gt;
  &lt;span class=&quot;c1&quot;&gt;# =&amp;gt; &amp;lt;a href=&quot;http://www.example.com/doohickeys&quot;&amp;gt;index of doohickeys&amp;lt;/a&amp;gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

Where did _www.example.com_ come from?  Let's take a look.  In both &quot;Rails 2.3.5&quot;:http://github.com/rails/rails/blob/v2.3.5/actionpack/lib/action_controller/url_rewriter.rb#L173 and &quot;Rails 3 beta&quot;:http://github.com/rails/rails/blob/6f247347a11c7f59c510dd3ff8ee94628bc1df8b/actionpack/lib/action_controller/url_rewriter.rb#L12, if we have not explicitly passed in a :host option, we get @request.host_with_port.  So, no matter what hostname you used to resolve the app, that hostname will be used to generate full URLs.

h3. Exploiting url_for

One man's casual bug is another man's security exploit, right?  Let's modify our local hosts file:

&lt;pre&gt;
 # /etc/hosts
 # map the target website's IP to your favorite web destination
 10.0.0.0  emphaticsolutions.com
&lt;/pre&gt;

Now, when we visit the target website with our own domain, those URLs look like this:

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ruby&quot; data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;n&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;resources&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:doohickeys&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;link_to&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'index of doohickeys'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;doohickeys_url&lt;/span&gt;  
  &lt;span class=&quot;c1&quot;&gt;# =&amp;gt; &amp;lt;a href=&quot;http://emphaticsolutions.com/doohickeys&quot;&amp;gt;index of doohickeys&amp;lt;/a&amp;gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

If the target application is caching content that includes these links, and you're lucky enough to hit an uncached section of the site, you've just injected your own hostname into the target's website content for other users to see and click on.  Your directing clicks on their site, back to yours.

h3. Many stars must align

Sure, there are a lot of variables that have to pan out for this issue to be exploitable.  That doesn't make the issue any less real.  One solution to this would be to include a configuration option that is defined per environment, to identify the desired hostname for a given app.  Think of it as the canonical hostname that should be used unless you explicitly set one when generating a URL.  I think this solution works for most applications, and if you don't use the configuration, you'll get the existing behavior.

Another solution is to configure your web server to use a specific hostname for both http and https URLs.  Here is that configuration for Apache:

&lt;script src=&quot;http://gist.github.com/306100.js?file=apache.force-hostname-within-vhost.conf&quot;&gt;&lt;/script&gt;


So what do you think?  Should Rails provide a configuration option to specify an app's hostname, or is that outside the scope of what the app should be concerned with?</content>
 </entry>
 
 <entry>
   <title>People, not process, is the soul of "agile"</title>
   <link href="http://emphaticsolutions.com/2010/02/09/people-not-process-the-soul-of-agile.textile"/>
   <updated>2010-02-09T00:00:00+00:00</updated>
   <id>http://emphaticsolutions.com/2010/02/09/people-not-process-the-soul-of-agile</id>
   <content type="html">I've been guilty of it myself.  I even &quot;wrote about it recently&quot;:http://emphaticsolutions.com/2009/12/05/lean-software-engineering-a-progression-toward-kanban.html.  Working in an &quot;agile&quot; environment seems to bring out the tinkerer in all of us.  Not only do we get to devise new and interesting techniques in the software we build, but with a focus on &quot;agile&quot; methodologies, we get to tweak and shape and adjust and hone the _process_ of _how_ we build our software too.  In a sense, &quot;agile&quot; is an excuse to for endless &quot;yak shaving&quot;:http://catb.org/esr/jargon/html/Y/yak-shaving.html.

h2. _Individuals and interactions over processes and tools_

As proponents, evangelists and practitioners, we've not only read this line over and over, we've probably shouted it a few times, too.  We get to abhor one set of processes and tools in favor of building new processes and tools that seemingly favor individuals and their awe-inspiring interactions.  After all, we are _tool makers_ so it seems rather obvious, really.

But what does it really mean?  Can we justify all this talk about process?  All this focus on the next awesome tool?  I'll bore you to death with why I think &quot;kanban is the right process for ongoing software development&quot;:http://emphaticsolutions.com/2009/12/05/lean-software-engineering-a-progression-toward-kanban.html without a moments hesitation, but is that really the secret sauce?

h2. _Individuals and interactions over processes and tools_

I love kanban.  I love test-driven development.  I love dynamic languages. I love expressive domain modeling.  I love modeling function after a users desired behavior.  These are all implementation details.  They enable us but they miss the bigger point.

A software team is made up of uniquely minded, smart and energetic _individuals_.  A team's _interactions_ are the life force of their success. A team is most productive, most focused and delivers the best products when they themselves are the focus.  When their interactions are primary, and the tools and processes are secondary.

Paul Graham wrote &quot;_The other half of 'Artists Ship'_&quot;:http://paulgraham.com/artistsship.html in which he states: _One of the differences between big companies and startups is that big companies tend to have developed procedures to protect themselves against mistakes._  He goes on to describe just what a grave mistake it is for smaller companies to follow suit, developing processes and procedures to &quot;protect themselves&quot; at an incredibly high cost.  Beyond the initial cost of developing a process, building out a new tool or other means of not shipping you may devise, the cost of these processes are incalculable.  You pay for them every single day, in every missed opportunity.

h2. &quot;agile&quot; is about culture

The best &quot;process&quot; you can employ is the trust and reliance in one another.  Your team is smarter, and more efficient when each member owns their collective success, rather than relying on adding to the onion of processes every time there is a misstep.

Bugs happen.  Bugs you can't imagine testing for.  Bugs you can't imagine _how_ you'd test for.  Software systems don't exist in a vacuum and our pal Murphy can show up at any turn.  No matter how precise your process, no matter how powerful your tools, it's your team, your individual ideas, your gut feelings, your lunchtime conversations, your debates over coffee and your banging on the executives door.... it's _you_ that drives your success and it's you that makes &quot;agile&quot; work.


_I'm continually inspired and impressed with my team at &quot;Sheet Music Plus&quot;:http://www.sheetmusicplus.com/, who inspired this post._</content>
 </entry>
 
 <entry>
   <title>My favorite books from 2009</title>
   <link href="http://emphaticsolutions.com/2009/12/27/favorite-books-of-2009.textile"/>
   <updated>2009-12-27T00:00:00+00:00</updated>
   <id>http://emphaticsolutions.com/2009/12/27/favorite-books-of-2009</id>
   <content type="html">It looks like I made my way through about 35 books in 2009.  I've never actually evaluated how much I've read before, but it felt like a fairly good year for page turning.  Some books were pretty forgettable without the help of browsing through my Amazon order history, but a few really stood out as major influences throughout the year.  

So here they are... my favorite books from this year:

h2. Software Engineering

I read a lot of &quot;work&quot; books this year, primarily on &quot;Ruby&quot;:http://www.ruby-lang.org/en/.  While they each served some purpose, they were all fairly forgettable.  None of the books on language, programming technique or software design influenced how I work or write code.  I'm not sure what that means. Instead, I found these two books very influential in how I think of the craft of software engineering.

&lt;a href=&quot;http://www.amazon.com/gp/product/0060891548?ie=UTF8&amp;tag=emphaticsolut-20&amp;linkCode=as2&amp;camp=1789&amp;creative=390957&amp;creativeASIN=0060891548&quot;&gt;*On Writing Well, 30th Anniversary Edition: The Classic Guide to Writing Nonfiction*&lt;/a&gt;&lt;img src=&quot;http://www.assoc-amazon.com/e/ir?t=emphaticsolut-20&amp;l=as2&amp;o=1&amp;a=0060891548&quot; width=&quot;1&quot; height=&quot;1&quot; border=&quot;0&quot; alt=&quot;&quot; style=&quot;border:none !important; margin:0px !important;&quot; /&gt;

Writing good software requires great communication and this is _the_ best book I've ever read on writing well.  You could read this entire book imagining the author talking about how to write good _code_ rather than good nonfiction and get a wealth of advice you'd do well for accepting.  Aspiring for clear and concise communication helps in all aspects of life, and I found lots of specific tidbits that did help in how I think about programming.

&lt;a href=&quot;http://www.amazon.com/gp/product/0578002140?ie=UTF8&amp;tag=emphaticsolut-20&amp;linkCode=as2&amp;camp=1789&amp;creative=390957&amp;creativeASIN=0578002140&quot;&gt;*Scrumban - Essays on Kanban Systems for Lean Software Development*&lt;/a&gt;&lt;img src=&quot;http://www.assoc-amazon.com/e/ir?t=emphaticsolut-20&amp;l=as2&amp;o=1&amp;a=0578002140&quot; width=&quot;1&quot; height=&quot;1&quot; border=&quot;0&quot; alt=&quot;&quot; style=&quot;border:none !important; margin:0px !important;&quot; /&gt;

&quot;I've mentioned this book before&quot;:http://emphaticsolutions.com/2009/12/05/lean-software-engineering-a-progression-toward-kanban.html, but Scrumban has been the most useful book I've ever read on managing the process of developing a product and team.  Corey Ladas includes the right balance of theory and practice, while never dictating a specific technique or workflow.  This book provided the blueprint for the workflow &quot;we use now.&quot;:http://www.sheetmusicplus.com

h2. The making of Awesome

I really don't know how to categorize these books, but they all seem related in some way.  If you're interested in adding more Awesome to your world, settle into these...

&lt;a href=&quot;http://www.amazon.com/gp/product/0385530609?ie=UTF8&amp;tag=emphaticsolut-20&amp;linkCode=as2&amp;camp=1789&amp;creative=390957&amp;creativeASIN=0385530609&quot;&gt;*Sway: The Irresistible Pull of Irrational Behavior*&lt;/a&gt;&lt;img src=&quot;http://www.assoc-amazon.com/e/ir?t=emphaticsolut-20&amp;l=as2&amp;o=1&amp;a=0385530609&quot; width=&quot;1&quot; height=&quot;1&quot; border=&quot;0&quot; alt=&quot;&quot; style=&quot;border:none !important; margin:0px !important;&quot; /&gt;

This book is both awesome and frustrating.  I would consider myself a very logical person, espousing emotional decision-makers and priding myself on a logical and unbiased approach to problem solving.  Wrong.  We're all hackable and chapter after chapter you learn just how easy it is to sway the most data-driven thinker.

&lt;a href=&quot;http://www.amazon.com/gp/product/0316017922?ie=UTF8&amp;tag=emphaticsolut-20&amp;linkCode=as2&amp;camp=1789&amp;creative=390957&amp;creativeASIN=0316017922&quot;&gt;*Outliers: The Story of Success*&lt;/a&gt;&lt;img src=&quot;http://www.assoc-amazon.com/e/ir?t=emphaticsolut-20&amp;l=as2&amp;o=1&amp;a=0316017922&quot; width=&quot;1&quot; height=&quot;1&quot; border=&quot;0&quot; alt=&quot;&quot; style=&quot;border:none !important; margin:0px !important;&quot; /&gt;

I love Malcolm Gladwell and this is likely his best work so far.  How well do we capitalize our available talents, as a group or even within ourselves?  Outliers is full of fun stories and offers just enough pop-science to get you interested in the research he cites.

&lt;a href=&quot;http://www.amazon.com/gp/product/055380684X?ie=UTF8&amp;tag=emphaticsolut-20&amp;linkCode=as2&amp;camp=1789&amp;creative=390957&amp;creativeASIN=055380684X&quot;&gt;*The Talent Code: Greatness Isn't Born. It's Grown. Here's How.*&lt;/a&gt;&lt;img src=&quot;http://www.assoc-amazon.com/e/ir?t=emphaticsolut-20&amp;l=as2&amp;o=1&amp;a=055380684X&quot; width=&quot;1&quot; height=&quot;1&quot; border=&quot;0&quot; alt=&quot;&quot; style=&quot;border:none !important; margin:0px !important;&quot; /&gt;

Buy this book now!  This book discusses new neurological research thought to be the physical embodiment of skill within our brains.  The author first identifies techniques for acquiring skills that are based on this scientific approach.  Later in the book we explore talent 'hot beds', what makes them, how they survive and what makes great coaches so great.

&lt;a href=&quot;http://www.amazon.com/gp/product/0307465357?ie=UTF8&amp;tag=emphaticsolut-20&amp;linkCode=as2&amp;camp=1789&amp;creative=390957&amp;creativeASIN=0307465357&quot;&gt;*The 4-Hour Workweek by Tim Ferris*&lt;/a&gt;&lt;img src=&quot;http://www.assoc-amazon.com/e/ir?t=emphaticsolut-20&amp;l=as2&amp;o=1&amp;a=0307465357&quot; width=&quot;1&quot; height=&quot;1&quot; border=&quot;0&quot; alt=&quot;&quot; style=&quot;border:none !important; margin:0px !important;&quot; /&gt;

I can't explain why, but I've put off this book for years.  I've heard Tim speak, I've occasionally read his blog and generally agree with his positions, while appreciating his showmanship.  I recently picked up the latest edition of this book and am blown away.  Tim isn't telling us anything particularly new, but his passion and optimism are hard to resist.  I'm really looking forward to the projects that I'll be kicking off after soaking this in.

&quot;*Radio Lab*&quot;:http://www.wnyc.org/shows/radiolab/

Radio Lab, as its name implies, is not a book but a radio program.  They tend to cover math, science and ethics from a variety of perspectives.  The sound design alone is quite captivating and the storytelling is unbelievable.  I fell hard and fast for Radio Lab this year and have started ticking off back episodes on my commute.  Give it a shot and you'll be hooked.

h2. Physical Performance

This is a relatively new category of reading for me, but since starting &quot;Crossfit&quot;:http://www.crossfit.com/ I've been more interested in learning more about movement and other aspects of human performance.

&lt;a href=&quot;http://www.amazon.com/gp/product/074325144X?ie=UTF8&amp;tag=emphaticsolut-20&amp;linkCode=as2&amp;camp=1789&amp;creative=390957&amp;creativeASIN=074325144X&quot;&gt;*Chi Running*&lt;/a&gt;&lt;img src=&quot;http://www.assoc-amazon.com/e/ir?t=emphaticsolut-20&amp;l=as2&amp;o=1&amp;a=074325144X&quot; width=&quot;1&quot; height=&quot;1&quot; border=&quot;0&quot; alt=&quot;&quot; style=&quot;border:none !important; margin:0px !important;&quot; /&gt;

Crossfit typically recommends the &quot;pose method&quot;:http://athletics.wikia.com/wiki/Pose_Method of running.  I was then turned onto &quot;ChiRunning&quot;:http://www.chirunning.com/shop/home.php which seemed to be a similar style, with a deeper appreciation for movement and the spirit of running.  I'm no real fan of running, actually, but after having read this book I have a stronger connection to running and have even enjoyed it this year.  I took one of their running clinics in San Francisco as well, which was really helpful.

&lt;a href=&quot;http://www.amazon.com/gp/product/0307266303?ie=UTF8&amp;tag=emphaticsolut-20&amp;linkCode=as2&amp;camp=1789&amp;creative=390957&amp;creativeASIN=0307266303&quot;&gt;*Born to Run: A Hidden Tribe, Superathletes, and the Greatest Race the World Has Never Seen*&lt;/a&gt;&lt;img src=&quot;http://www.assoc-amazon.com/e/ir?t=emphaticsolut-20&amp;l=as2&amp;o=1&amp;a=0307266303&quot; width=&quot;1&quot; height=&quot;1&quot; border=&quot;0&quot; alt=&quot;&quot; style=&quot;border:none !important; margin:0px !important;&quot; /&gt;

Another running book?  This was a really fun read.  It's a really interesting story very well told and really difficult to put down.

&lt;a href=&quot;http://www.amazon.com/gp/product/0976805421?ie=UTF8&amp;tag=emphaticsolut-20&amp;linkCode=as2&amp;camp=1789&amp;creative=390957&amp;creativeASIN=0976805421&quot;&gt;*Starting Strength (2nd edition)*&lt;/a&gt;&lt;img src=&quot;http://www.assoc-amazon.com/e/ir?t=emphaticsolut-20&amp;l=as2&amp;o=1&amp;a=0976805421&quot; width=&quot;1&quot; height=&quot;1&quot; border=&quot;0&quot; alt=&quot;&quot; style=&quot;border:none !important; margin:0px !important;&quot; /&gt;

Ah, now we're back to the good stuff!  If you do any weight training, you should read this book.  Mark Rippetoe has an incredible approach to breaking down each movement and building a straightforward program for building strength.

h2. How about you?

What were the most interesting or influential for you this year?</content>
 </entry>
 
 <entry>
   <title>Lean Software Engineering - My progression toward Kanban</title>
   <link href="http://emphaticsolutions.com/2009/12/05/lean-software-engineering-a-progression-toward-kanban.textile"/>
   <updated>2009-12-05T00:00:00+00:00</updated>
   <id>http://emphaticsolutions.com/2009/12/05/lean-software-engineering-a-progression-toward-kanban</id>
   <content type="html">h3. In the beginning, there was...

Nothing.  That's right.  I'll bet that long before many of us suffered &quot;the waterfall model&quot;:http://en.wikipedia.org/wiki/Waterfall_model we first suffered from the lack of any process at all.  As a maker of things, having no defined process can feel wonderful and free at first.  In hindsight, many have called this &quot;cowboy coding&quot;:http://en.wikipedia.org/wiki/Cowboy_coding but it's actually worse than that.  Cowboy coding sounds romantic.  A man or woman on their horse, acting on any whim that strikes them, as hedonistic as they want to be.  In reality, having no process, no schedule, and basically no rules leads to nothing more than horse shit.  No maker wants that.

h3. Waterfall, Rational Unified Process, Six Sigma, etc.

For longer than I've been alive, it was thought that big software systems required big processes.  They come in many flavors and are each as painful as the others.  There are plenty of horror stories on why heavyweight processes are bad models for building systems so I wont bother recounting them. There are common themes that emerge from systems build with heavyweight processes though.  They take a long time.  There is little customer interaction for months or years.  Worse still, the system delivered is rarely ever the one that is actually needed.  I was never satisfied with a project I developed using these models, and unfortunately, our business partners weren't completely satisfied either.

h3. Extreme Programming (Don't we all want to be extreme?)

In 1999, I was lucky enough to be working with &quot;Todd Jonker&quot;:http://www.linkedin.com/pub/todd-jonker/1/48/360, who attended &quot;OOPSLA '99&quot;:http://www.sigplan.org/oopsla/oopsla99/ where everyone was buzzing about two things.  First was &quot;Kent Beck's&quot;:http://en.wikipedia.org/wiki/Kent_Beck new book, &quot;Extreme Programming Explained&quot;:http://www.amazon.com/Extreme-Programming-Explained-Embrace-Change/dp/0321278658/ref=sr_1_1?ie=UTF8&amp;s=books&amp;qid=1260050840&amp;sr=1-1.  The second was this &quot;editable website&quot; idea by Ward Cunningham, that he called a &quot;wiki.&quot;:http://c2.com/cgi/wiki Todd's enthusiasm was hard to resist and soon enough we started taking baby steps in the direction of extreme programming.

Unfortunately XP was like a bright shiny object to our relatively fresh-faced team and we failed to really grasp what a fundamental change this would be for our company, our clients and even our team culture.  In some ways, I think we're all still trying to grasp the essence of XP.  &quot;The rules of extreme programming&quot;:http://www.extremeprogramming.org/rules.html set a new model for how software was built, what the teams looked like and how they interact.

In fact, I've had entire projects change drastically for the better, just by focusing on one single XP rule.  In '97 I worked for a consultancy in New York City developing &quot;multimedia applications&quot;, back when we shipped CD-ROMs frequently and only occasionally got to drop a Perl script in &lt;code&gt;cgi-bin&lt;/code&gt;.  We worked for some large clients, usually working with one of their project managers for client interaction.  A few days before our &quot;gold master&quot;:http://en.wikipedia.org/wiki/Golden_master was due, the president of the company stopped by to check in.  It was awful.  The game of telephone between their sales team, their project manager and our office was showing through.  With the president deciding to take the afternoon off, we suddenly had an &quot;on site customer&quot;:http://www.extremeprogramming.org/rules/customer.html  In the next few hours, we got an incredible amount of work done, and the best part of course, is that it was exactly what they wanted.  Weeks had been wasted and everybody knew it.  From that point on, we always arranged for frequent customer interaction including all-day sessions which always paid off.

h3. The marketing blitzkrieg of &quot;Agile&quot;

Fast forward ten years and &quot;Agile&quot; had become a major buzzword not just in software development communities, but in business communities as well.  Promises of better, cheaper, and faster were impossible to resist and &quot;agile coaches&quot; popped up everywhere.  From San Francisco startups to century-old corporate enterprises, everyone was &quot;agile&quot;.  Beyond the buzzword, though, nobody could agree on what being agile really meant.

At RailsConf 2008, &quot;Kent Beck spoke about Extreme Programming and &quot;Agile&quot; development&quot;:http://emphaticsolutions.com/2008/09/08/transparency-responsibility-accountability.html.  In his keynote, he points out how so many are missing the essence of what extreme programming was all about: _transparency, responsibility and accountability._ You can't go wrong focusing on that.  Kent was a great speaker, and his refocusing on those three tenets was really encouraging.

h3. Scrum

My first experience with &quot;scrum&quot;:http://en.wikipedia.org/wiki/Scrum_(development) was in the context of a fairly large development organization within a major financial institution.  I was really impressed with how much work the various development teams could accomplish, given the fairly bureaucratic environment they were working in.  Scrum brings some fairly specific and rigorous processes to agile development that appeals to the sensibilities of project managers.  For developers used to working in waterfall or similar processes, this can be blast of fresh air.

h3. Thinking Lean

After a few years of working in a scrum environment, it started to feel too formal.  I had the feeling that we were fulfilling the ceremony of scrum, while missing the essence of extreme programming.  Iteration planning meetings, retrospectives and even some story jams felt not only like work, but work that wasn't immediately benefiting our customers.  The payoff of some of this effort was there, but each iteration still contained a lot of &quot;process work&quot; within each team, for each project.  When every developer essentially throws away any productivity every other Monday to deal with the process of how you deliver customer value, &quot;wasteful&quot; is an understatement.  In defense of scrum practitioners in large enterprise environments, however, scrum provides enough busy work for project managers that it can be legitimized, where other less-formal processes may not be.

My first exposure to &quot;lean&quot; software development was in the book &lt;a href=&quot;http://www.amazon.com/gp/product/0321150783?ie=UTF8&amp;tag=emphaticsolut-20&amp;linkCode=as2&amp;camp=1789&amp;creative=390957&amp;creativeASIN=0321150783&quot;&gt;Lean Software Development: An Agile Toolkit by Mary Poppendieck.&lt;/a&gt;&lt;img src=&quot;http://www.assoc-amazon.com/e/ir?t=emphaticsolut-20&amp;l=as2&amp;o=1&amp;a=0321150783&quot; width=&quot;1&quot; height=&quot;1&quot; border=&quot;0&quot; alt=&quot;&quot; style=&quot;border:none !important; margin:0px !important;&quot; /&gt;  In this book, Mary introduces common lean manufacturing practices like &quot;_The Toyota Way_&quot;:http://en.wikipedia.org/wiki/The_Toyota_Way and draws similarities to how we could develop software in a similar manner.  Her ideas were inspiring and it was hard for me to see strict scrum processes as anything but a little wasteful.  While the concept of &quot;lean software development&quot;:http://en.wikipedia.org/wiki/Lean_software_development was alive and well, unfortunately I didn't feel like I had an idea of how to implement it.  

h3. Kanban: lean manufacturing meets software engineering

Earlier this year I had a great conversation with &quot;Joe Arnold&quot;:http://joearnold.com/, Director of Engineering at &quot;Engine Yard&quot;:http://www.engineyard.com about their software development team and process.  While rambling on about the potential wastefulness of scrum and how I had been looking for practices that could lead to real-world lean software development, Joe mentioned &quot;Kanban&quot;:http://en.wikipedia.org/wiki/Kanban.  After a ten-second introduction leaving me with &quot;you should check it out&quot;, I was hooked.

The &quot;lean software engineering blog&quot;:http://leansoftwareengineering.com/ by &quot;Corey Ladas&quot;:http://leansoftwareengineering.com/2007/04/12/about-the-authors/ was and still is an incredible resource, both as an introduction to Kanban in general as well as specific adaptations to help serve software development teams.  If you're curious, this is a great &quot;comparison of Kanban vs. Scrum&quot;:http://www.infoq.com/news/2009/05/kniberg-kanban-v-scrum, and for a more lighthearted comparison, &quot;Scrum vs. Kanban: FIGHT!&quot;:http://lizkeogh.com/2009/09/16/scrum-vs-kanban-fight/

Not long after I started reading up on Kanban, Corey Ladas released &lt;a href=&quot;http://www.amazon.com/gp/product/0578002140?ie=UTF8&amp;tag=emphaticsolut-20&amp;linkCode=as2&amp;camp=1789&amp;creative=390957&amp;creativeASIN=0578002140&quot;&gt;Scrumban - Essays on Kanban Systems for Lean Software Development&lt;/a&gt;&lt;img src=&quot;http://www.assoc-amazon.com/e/ir?t=emphaticsolut-20&amp;l=as2&amp;o=1&amp;a=0578002140&quot; width=&quot;1&quot; height=&quot;1&quot; border=&quot;0&quot; alt=&quot;&quot; style=&quot;border:none !important; margin:0px !important;&quot; /&gt;.  This book is _awesome._  Corey illustrates the key points of Kanban, from a quick review of queue theory to a variety of specific workflows.  While Corey doesn't prescribe a specific workflow, he leaves you with a deep appreciation for Kanban practices and you'll quickly be able to identify the right workflow for your team or project.

h3. My first Kanban board

As luck would have it, as soon as I discovered Kanban, I was also &quot;starting a new job&quot;:http://www.linkedin.com/in/briandoll.  In no time at all, I found myself with a great team, eager to experiment with new processes and workflows, and strong management support.  With post-it notes in hand, we quickly built our first Kanban board:

!http://emphaticsolutions.com/images/physical.kanban.board.jpg!

Our approach:
* Business Value Stream along the X axis
* Development workflow along the Y axis
* Workflow: 
** Backlog - Managed in a bug tracker
** Next Actions - Can't stop using GTD phrases!
** User Stories - Ensure the story or stories are testable and define what &quot;done&quot; means
** Test _then_ Code - Test driven development, pairing optional
** Business Green Light - Get business sign-off on that specific token
** Ready to Ship - Committed to trunk and ready for final review on a staging environment
** Current release - Features that were just recently released to production
** Previous Release - The penultimate release tokens.  We discovered it was great to have two release of tokens on the board that represents one week of releases in our twice-per-week release schedule.
* Tokens are typically small &quot;minimum marketable features&quot;:http://www.netobjectives.com/glossary/7#letterm
* Tokens can optionally be given a swag estimate by the developer that picks the token
* A developer adds their initials to a token that they are working on and reports any issues during our morning standup
* A red mark underlines a blocked token
* A date is written in bold red on the token for any token that must ship by a certain date (atypical)
* We ship twice per week, and ship whatever is in the &quot;ready to ship&quot; phase of our process

After several months of using this approach we all felt like we needed to make some improvements.  After all, even XP recommends &quot;Fixing XP when it breaks&quot;:http://www.extremeprogramming.org/rules/fixit.html.

Some things were working well:
* We were shipping more business value per week than any of us have done before
* We responded to shifting priorities with grace, and delivered the most relevant value each release
* Software releases are non-events
* Who is working on X is a glance away
* Our board quickly answered &quot;Where in our value stream are we spending our time this week?&quot;
* If our business partners wanted to immediately prioritize a particular feature, they could easily see which tokens would be affected
* Since our morning standup centered around our Kanban board, it was easy to ensure the board and the team were updated with any blocking issues, re-prioritization or deadlines

Some things needed to be improved:
* Identifying which value stream a particular token belonged in became tedious and wasn't providing value
* Ideally stories would be defined before a token can appear in Next Actions. Having a separate phase for User Stories wasn't providing much value, and would often cause confusion as to who was working on a token, a developer or a business partner.
* Prioritizing tokens for the Next Actions phase was taking a lot of time within our development team, and we were often wrong about overall priorities
* Our Kanban board was in the CIO's office where we held our standups.  While it was easy for the development team to see and use, it was not easy for our business partners to interact with
* Lastly, everyone on our team has _unique_ handwriting.  Between our own unique chicken scratch and our terse token names, it was becoming difficult to say with any certainty what some tokens were going to deliver

h3. A virtual Kanban board: AgileZen in action

After we identified our problem spots, I set off to find an online tool to replace our beloved physical Kanban board. &quot;Pivotal Tracker&quot;:http://www.pivotaltracker.com/ came immediately to mind.  I had used it in a work scenario before as well as on a personal project.  After catching up with the current state of Tracker, it hit me that this tool had an problem we were unlikely to overcome.  Pivotal Tracker is a very sophisticated tool, enabling a dizzying array of process refinements.  What it isn't is Simple and Simple is what we needed.  More than just a developer tool, we needed a virtual Kanban board that our development team and business partners could use.

A small startup from Ohio called Enkari has a product aptly called &quot;Zen&quot;:http://agilezen.com/ and it's exactly what we were looking for.  Zen is an online Kanban board that provides just enough features to be extremely useful without being prescriptive on how you use it.  &quot;Take the tour of Zen to see what it's all about.&quot;:http://agilezen.com/tour

Now that we're using &quot;Zen&quot;:http://agilezen.com/ for our virtual Kanban board, we're seeing even more improvement:
* All of our business partners can check in to see exactly what is being worked on and by whom
* We simplified our workflow: 
** Backlog: An unlimited list of tokens in approximate business priority
** Next Actions: Tokens in specific business priority that are ready to act on, limited to 10 tokens
** Design/Test/Develop: Developer-owned phase, limited to 10 tokens
** Ready to Ship: committed code.  When the code has been released to staging and approved, it is marked as &quot;Ready&quot;
** Shipped: an archive of released tokens, in reverse order of when they were released
* Instead of categorizing tokens according to our customer value stream, we color code them by requesting business group (Marketing, Customer Service, etc.).
* Re-prioritizing can be performed by our business users directly, so our business partners can discuss among themselves what the sorting order should be, without any involvement from the development team
* No physical board can be in a convenient location for all users.  The simple fact that Zen is an online tool means we're all seeing the same board at all times.
* Also, everyone's handwriting is the same on the internet!
* The UI draws great attention to blocked tasks, tasks with quickly approaching deadlines, and overburdened WIP limits
* We started using the tool within our development team and our business partners were immediately able to work in it with us, prioritize their work and get status information without any help

While we have loved using Zen so far, there are a few areas we already see that the tool could be improved:
* Zen allows you to use any scheme to indicate a token's size.  You can use numerical values or t-shirt sizes, for example.  A downside of this is that all performance metrics are gathered by token, not by token value.  For example, a velocity report would be ideally described as a total number of points delivered vs. the number of tokens.
* Color-coding is a great way to segment tokens.  It would be great to label the colors with your usage of them, within a specific project.  (Ie. Green = Marketing)
* Tags will be very useful soon (they have limited functionality in the app at the moment).  Auto-completing tags as we type them would also be useful, to make sure we use the same terms all the time
* Zen has a slick UI, but it is not using any push technology to ensure you have a recent copy of your board.  If you have not refreshed your browser window and another team member modifies a token, you will not see those changes until you refresh.  The only real-life scenario where this has bit us before is when two developers attempt to move a token, one back to the backlog and another forward.  In this scenario, the last one in wins.

h3. Reflecting on development process: sharpening the saw

Steven Covey talked about &quot;sharpening the saw&quot;:https://www.stephencovey.com/7habits/7habits-habit7.php in his book &lt;a href=&quot;http://www.amazon.com/gp/product/0743269519?ie=UTF8&amp;tag=emphaticsolut-20&amp;linkCode=as2&amp;camp=1789&amp;creative=390957&amp;creativeASIN=0743269519&quot;&gt;The 7 Habits of Highly Effective People&lt;/a&gt;&lt;img src=&quot;http://www.assoc-amazon.com/e/ir?t=emphaticsolut-20&amp;l=as2&amp;o=1&amp;a=0743269519&quot; width=&quot;1&quot; height=&quot;1&quot; border=&quot;0&quot; alt=&quot;&quot; style=&quot;border:none !important; margin:0px !important;&quot; /&gt;.  It's great to develop a process and workflow that seems to work for you and your team, but that's not enough.  You are not the only customer of your software development process.  How do your business partners feel your delivering?  How often are you reflecting on the effectiveness of your processes and your tools?  How often do you sharpen your saw?  Developing software systems requires many different disciplines and no two projects or teams are the same.  Spending time focusing on how you deliver value can dramatically increase your effectiveness and reduce unnecessary work, which reduces frustration.  No matter where you end up, you'll likely be happier than where you are now.
</content>
 </entry>
 
 <entry>
   <title>has_many :through across multiple databases in Rails</title>
   <link href="http://emphaticsolutions.com/2009/11/23/has_many_through_across_databases.textile"/>
   <updated>2009-11-23T00:00:00+00:00</updated>
   <id>http://emphaticsolutions.com/2009/11/23/has_many_through_across_databases</id>
   <content type="html">h3. A tale of two databases

Web applications usually start out so simply, yet so few of them stay that way for long.  Some applications grow to utilize multiple databases, for instance.  Perhaps your an eCommerce site that has a different database for your catalog and transactional data.  &quot;In Rails, we can do this pretty easily.&quot;:http://jonathansng.com/ruby-on-rails/multiple-database-connections-with-rails/

h3. Joining forces

Now your Rails app is happily working with two databases.  It won't be long now before you wonder how nice it could be to relate data between those two disparate databases.  _If_ your databases are on the same database host, you can achieve this by prefixing all of your tables with your database name.  Here is an example on how to do this with ActiveRecord:
&lt;script src=&quot;http://gist.github.com/239853.js?file=has_many_through_across_databases.rb&quot;&gt;&lt;/script&gt;

h3. Joining forces... over the cloud!

How can we make this harder on ourselves?  What if our databases are not on the same host, but instead are separated by thousands of miles, across the _CLOUD!!!_

&lt;img src=&quot;http://emphaticsolutions.com/images/dbs_across_the_CLOUD.png&quot;&gt;

h3. Introducing... St. Elsewhere

St. Elsewhere is a Ruby gem that implements the basic relationship API methods for ActiveRecord associations for use when your databases are on different hosts.

For example:
&lt;script src=&quot;http://gist.github.com/243240.js?file=gistfile1.rb&quot;&gt;&lt;/script&gt;

h3. Known inefficiencies

has_many_elsewhere is certainly much less efficient than a comparable has_many relationship. has_many :through relationships use SQL JOINs which while efficient, do not work across multiple database connections. St. Elsewhere implements much of the same resulting API methods in code, using less efficient SQL.

h3. Installation

&gt; gem install st-elsewhere
Or contribute on github: &quot;github.com/briandoll/st-elsewhere&quot;:http://github.com/briandoll/st-elsewhere

h3. Roadmap

Currently st-elsewhere is implemented as a basic ruby module that implements some of the basic functionality of has_many :through relationships in ActiveRecord. A much more robust implementation would be to create an ActiveRecord association proxy, like HasManyThroughAssociation, that emulates the same API and could be integrated into the standard has_many class method. I will likely be waiting for Rails 3 to be released (and thus the new base ORM implementation) before attempting the association proxy route.

h3. Thanks

Thanks to James Reynolds for the great name and thanks to Tanner Donovan for patches and being the first production customer.</content>
 </entry>
 
 <entry>
   <title>Allowing multiple failed assertions per test</title>
   <link href="http://emphaticsolutions.com/2009/10/01/multiple-assertion-failures-per-test.textile"/>
   <updated>2009-10-01T00:00:00+00:00</updated>
   <id>http://emphaticsolutions.com/2009/10/01/multiple-assertion-failures-per-test</id>
   <content type="html">h3. One assertion per test

This is a very common TDD guideline. Jay Fields posted &quot;a good summary of why he feels one assertion per test is a good practice&quot;:http://blog.jayfields.com/2007/06/testing-one-assertion-per-test.html.  If you read closely, however, you can see that the main reasons Jay doesn't like multiple assertions per test is that the feedback provided from the test suite is usually poor.

There are circumstances, however, where you may choose to make multiple assertions per test.  Personally, I use &quot;shoulda&quot;:http://www.thoughtbot.com/projects/shoulda in my Ruby projects.  One feature I really love are the nested contexts.  The way these work, however, is that each context in your scope have their setup methods run in order, prior to executing each should statement.  In some testing scenarios, you may find that you're setup blocks are taking a good amount of time to run.  If you were to have similar assertions in one test, you can speed up that test class quite a bit.

h3. The goal

Let's make it possible to have multiple assertions per test, while keeping the feedback actionable.

* All assertions in the test should be run
* All assertion failures should be reported
* Each assertion should report actionable feedback

h3. A solution

I've implemented &quot;assert_each&quot;:http://gist.github.com/197818 as a way to specify a list of assertions that meet our goals.  Add this to your test_helper.rb and enjoy!

&lt;script src=&quot;http://gist.github.com/197818.js&quot;&gt;&lt;/script&gt;</content>
 </entry>
 
 <entry>
   <title>The rules of software deployment</title>
   <link href="http://emphaticsolutions.com/2009/09/06/the-rules-of-software-deployment.textile"/>
   <updated>2009-09-06T00:00:00+00:00</updated>
   <id>http://emphaticsolutions.com/2009/09/06/the-rules-of-software-deployment</id>
   <content type="html">Any sufficiently complex software application will require a well thought-out deployment strategy.  While a basic deployment strategy is quite suitable for a basic application, many applications require careful orchestration of interdependent systems to make for a successful release.  For example, a web application may need to consider: source code, configuration files, content management data, application data, user data, cached data, search indexes, content delivery networks, background jobs, system monitoring tools, external services and APIs, as well as the user experience during the release process.

No matter how seemingly simple or complex your application is, there are a number of rules that should be followed.  These rules apply regardless of language, release schedule, SCM, deployment toolset or infrastructure.

h2. The rules

h4. Have a common language for each type of release

_There is more than one type of release?_ Most likely, yes.  If you think there is only one type of release, try asking your business partners what they think.  Do they always want the content management data released along with your source code?  Do you need to coordinate with them when a particular set of changes should be released?  The important rule is not how many release types you have, but that the technology and business teams are using the same words to describe them.

h4. All release activity is documented in an issue tracking system

No matter how frequently or how un-ceremonial you are about your releases, its best to track all release activity in a central place.  This will help ensure everyone has the same understanding and expectations for each release.  Who requested it?  When is it scheduled to go live?  Which software version is being deployed?  Are we deploying our database content with this release?  Who approved the release?  Who is doing the deployment?  Is it done yet?  Is it?  IS IT?

h4. Absolutely everything must be in version control

Obviously all software and configuration should reside in your &quot;software configuration management system&quot;:http://en.wikipedia.org/wiki/Software_configuration_management.  I'm also advocating that you store all your sensitive data there too, using encrypted files.  Storing sensitive data (database passwords, encryption passwords, etc.) within encrypted files in your SCM system allows that data to be versioned, backed up and kept in a convenient location along with the rest of your application.  There are countless methods that allow a privileged user to decrypt the files during the release process, by prompting for the passphrase.

h4. Each environment has a single, well-defined responsibility

Which environment do your business users use to verify a software release?  Where might you test system performance prior to a production release?  Which environment verifies that all tests are passing?  The only incorrect answer to these types of questions is &quot;it depends&quot;.  If you verify production releases on a &quot;staging&quot; environment, then that is what it is for.  In that case, never allow software, configuration or data changes to reside in that environment unless they are part of the next release.  Confusion in any form will eventually lead to a bad release.

h4. A software version is represented by an SCM tag

A &quot;tag&quot; represents a single point in time in your SCM system.  Since everything is in version control, your tag represents everything you need to build that version of your software.  Many deployment tools use a timestamp by default to refer to a specific exported copy of a software product.  This is _insane_.  We should instead refer to a tangible, unchanging artifact that we can resurrect at will.  Is commit _x_ included in that release?  What is the sate of file _y_ in that release?  When you refer to an SCM tag as your release version, these questions are easy.  When you refer to a timestamp, that was generated on what machine, using what timezone with what amount of drift... you're lost.  For Rails folks, both &quot;Capistrano&quot;:http://capify.org and &quot;Vlad the deployer&quot;:http://rubyhitsquad.com/Vlad_the_Deployer.html can be coerced into using tags regardless of the SCM system in use.

If your team separates the responsibilities of development from release management, ensure that it is the developers responsibility for tagging a release, and specifying which tag should be included in a release.  Even in the pristine dream-world where everything on trunk can be released at will, a development team needs to be aware of exactly what is included in a release in order to support and troubleshoot it.  Having a developer perform the gesture of tagging reenforces their responsibility of the software being released.

h4. Every step of the release process is scripted and can be run by anyone with sufficient privileges

The requirements for deploying to production should include access privileges, not system domain knowledge.  While there is a lot of system domain knowledge necessary to perform a successful release, that information should be maintained within the release scripts themselves.  Which hosts are included in a production release?  Which hosts are included in a staging release?  What is the process for updating the CDN?  Database migrations?  In what order do these steps get performed?  All of the answers need to be included in your release scripts.  

The only arguments that should be necessary to pass into your deploy scripts are the environments your acting on, and the version of software you're looking to deploy.  If you do have different types of deploys, make sure those are scripted as well.  Even if you only _occasionally_ need to release a new version without database content changes, make sure that type of release is supported and documented so you can do it reliably and effortlessly each time.

h4. Plan for failure

It can be temping to call your release process complete once you've had a few successful releases in a row.  Unfortunately you have only just begun.  No amount of shouting &quot;Failure is not an option!&quot; will keep failures at bay.  Instead, plan for failure, and build processes to support you during those stressful times.

Rolling back to the previous release version should be a single command and only take a few moments.  Caches gone funky?  Make sure you can flush them all with a single command.  Some CDN files seem out of date?  Rebuild your CDN content from scratch with a single command.

h4. Don't treat servers like your laptop; _nuke and pave!_

A good TDD practice is to constantly ask yourself (or better yet, your pair), do you have a test for that?  Any manual change to a server should prompt a similar question.  _How could I automate that?_  This isn't to fetishize automation, but to give you complete freedom to change your systems at will.  The moment you have a configuration change that does not reside in your SCM, a service enabled by hand, etc., your infrastructure owns you.  Every change from that moment on is brittle and you've just invited failure to the party.

Embracing a _nuke and pave_ attitude forces you to trust your processes and think of your servers as providing a set of services, not a cozy place to get work done.  Nuke and pave means that when a server is acting strangely, you can kill it and redeploy to a brand new instance without worry.  Nuke and pave means every service can be constructed from bare metal up, in an automated fashion.

Managing deltas is a suckers game, and will quickly lead to an unknown state.  Imagine the pain involved in performing a long list of system patches, system configuration changes and upgrades on every single production instance.  Now imagine shutting down an outdated production VM and starting up the new, patched and upgraded VM and deploying to it.  The latter provides a known state, faster and provides rollback capability.

h2. A sample software deployment workflow

# A developer tags a release in the SCM system (productname-113)
# A developer creates an issue in the issue tracking system (issue-567)
** The issue is assigned to the deployer
** The type of release is identified
** The software version is identified (productname-113)
# The deployer exports a copy of the application from the SCM system, based on the given tag
# The new version of the software is pushed out to each server in the appropriate environment
** Push to /apps/productname/productname-113
# The deployer enables the new version by repointing the symlink to the latest version
** /apps/productname/current should now point to /apps/productname/productname-113
# The deployer restarts the environment as necessary (restarting apache, etc.)

Once the version is vetted by the appropriate parties, this version may progress out to production.

# The product owner updates the release issue (issue-567) to indicate that this release is ready for production
** They may also specify a specific time when this release should occur
# The deployer copes the approved version (productname-113) from the staging environment to each of the production environments
** Push to /apps/productname/productname-113
** By releasing from staging to production, we make it much harder to release a version to production without going through the approval process.
# The same symlink and restarting processes occur, and you're live!

h2. Your release process is an important part of your application

I'd love to hear what important rules you have to add to the list.  No matter how &quot;killer&quot; your next feature is, it won't do much good if you can't release it.  The rules stated here are a good place to start no matter where you are in your path toward automation. Chris Wanstrath recently &quot;wrote about improvements he made to to the deploy process for github.com&quot;:http://github.com/blog/470-deployment-script-spring-cleaning showing how efficient your workflow can be using git.  Imagine how fast you can get things done when you know your deploy process only takes 14 seconds!
</content>
 </entry>
 
 <entry>
   <title>Always a student</title>
   <link href="http://emphaticsolutions.com/2009/05/19/always-a-student.textile"/>
   <updated>2009-05-19T00:00:00+00:00</updated>
   <id>http://emphaticsolutions.com/2009/05/19/always-a-student</id>
   <content type="html">&quot;You're like a student of this stuff&quot;, he said.  I thanked him, realizing that it was one of the greatest compliments I had ever received.  I never felt the urge to pursue an advanced degree; my associates degree in _visual communications_ was hardly a deep dive into academia.   Instead, I have always felt a constant need to learn on my own.  In a way, I'm a life-long student of everything that I find interesting.

I'm always surprised, then, to meet people interested in a topic, but never actually learning much about it.  &quot;I was never given the opportunity&quot; or &quot;My company never paid for that training course&quot; are poor excuses.  The act of learning something can be different from person to person.  Some people can learn a lot just by reading, others learn best by seeing and doing.  Any way you slice it, you too can become an  &quot;autodidact&quot;:http://en.wikipedia.org/wiki/Autodidact, you just need to have the right perspective on learning.

h2. The beginner's mind

bq. &quot;In the beginner's mind there are many possibilities, in the expert's mind there are few.&quot;:http://en.wikipedia.org/wiki/Shoshin

You might assume that when learning something new, it would be easy to have a beginner's mind.  Instead, we often get in our own way.  Our life experience provides a certain perspective, and it can be difficult to see something with fresh eyes. 

You'll find &quot;lots of pointers online&quot;:http://zenhabits.net/2008/09/how-to-live-life-to-the-max-with-beginners-mind/, suggesting ways to attain the beginners mind.  One method I find very useful is to assume an imaginary master is accompanying you on your learning journey.  Having to formulate your questions to this imaginary guide, allows you to clarify what it is you're looking to understand.  And like any zen master, your guide will help you find the answer on your own.  You can almost hear his response: &quot;Good question!  How might we find that out?  Where should we look?&quot;  Off you go, with a clear objective and back you'll come with an answer in hand.

h2. Actively seeking learning opportunities

&quot;If I only had a chance to work on X some day. I'm sure I'd pick it up quickly!  Poor me!&quot; Yes, poor you.  If only some magical external force brought the perfect opportunity to your doorstep.  As &quot;Guy Kawasaki has said&quot;:http://www.istockphoto.com/article_view.php?ID=29:

bq. You have to sit by the side of a river a very long time before a roast duck will fly into your mouth.

Actively seek out learning experiences and you're bound to actually find one.  Want to improve your knife skills in the kitchen?  Volunteer at a soup kitchen.  Want to learn what it's like to run a small business?  Ask your local coffee shop owner to let you work with them for a few weekends.  Want to become a better writer?  Start writing, every single day.

There is a lot to be learned just from those we surround ourselves with, both at home and at work.  But don't assume that because none of your friends are master cheese makers, that you will have no opportunity to learn how to run a fromagerie.  It is up to you to create opportunities to learn.  Get down to the closest dairy farm and start asking around.

h2. Teaching as learning

You have probably noticed this before.  A child asks you a question, or maybe just continues to probe you with &quot;why?&quot;, and you find that by teaching them, you learn more too.  Seeing even the most familiar subject through the eyes of a true beginner provides an opportunity to enrich your understanding.  By teaching someone something, often using more basic language and focusing on the essence of a subject, you can appreciate the subject matter all the more.

So why not teach more?  You can seek teaching experiences, even for topics you don't know.  Yet.  Talking to &quot;Ilya Grigorik&quot;:http://www.igvita.com/ at RailsConf earlier this month, he mentioned the inspiration for his talk on &quot;building a 'mini Google' in Ruby&quot;:http://en.oreilly.com/rails2009/public/schedule/detail/7966 was simply to learn more about the technology and math behind Google.  Deciding to present on this topic gave him a great opportunity to learn about it, both in his preparation and in the act of presenting.  With &quot;meet up's&quot;:http://meetup.com/ happening all over the country on every topic imaginable, we all have countless opportunities to teach on a regular basis.

h2. Staying coachable

Learning something new can be challenging.  Even more challenging, however, is to continually improve your understanding of things you already know.  As we pass some level of proficiency, it is easy to slip into assumed mastery.  &quot;I already know that&quot;, you might say, without really listening.  Any topic worth knowing is immensely deep.  None of us needed to be taught to breathe, yet a whole world of meditation opens up when we learn to breathe deeply and deliberately.

Good athletes are often said to be very &quot;coachable&quot;.  They listen to their coaches and peers, but more importantly, they act on it.  Stepping outside their comfort zone to try out a new technique, they may begin to see the errors in their usual form.  Stay coachable.  Listen to your teachers, your peers and your friends.  Try things out and see things from a new perspective.  You might just learn something.</content>
 </entry>
 
 <entry>
   <title>Is there such a thing as free automated user acceptance testing?</title>
   <link href="http://emphaticsolutions.com/2009/05/02/automated-user-acceptance-testing.textile"/>
   <updated>2009-05-02T00:00:00+00:00</updated>
   <id>http://emphaticsolutions.com/2009/05/02/automated-user-acceptance-testing</id>
   <content type="html">&quot;User acceptance testing&quot;:http://en.wikipedia.org/wiki/Acceptance_testing#User_acceptance_testing is a big milestone in software development, regardless of the methodology in use.  At this stage, the customer (business analyst, system owner, client, etc.) is determining if the feature that's been developed actually matches their needs.  To perform acceptance testing on web-based applications, people tend to fire up their browser and click around until they feel confident that things are working as expected.

Tests like these are very coarse grained.  Unlike a &quot;unit test&quot;:http://en.wikipedia.org/wiki/Unit_testing, where specific small components are tested in isolation, an acceptance test requires all the various moving parts to work together perfectly.  Even when your unit test suite runs perfectly, that's no guarantee that the entire application stack is performing as expected.  However, when an acceptance test fails, you know something is wrong.  It also requires much more work to locate the exact issue, since there may be many moving parts that are working together in support of a particular feature.

h2. Automate!

So what would _automated_ user acceptance testing be?  For almost as long as there have been web browsers, there have been tools to &quot;drive&quot; web browsers programatically.  While there are many ways to crack this nut, we'll take a look at three popular ones:
* &quot;*Selenium*&quot;:http://seleniumhq.org/ - language agnostic, can test any website, has IDE for creating tests
* &quot;*Watir*&quot;:http://wiki.openqa.org/display/WTR/Project+Home - Ruby-based, can test any website
* &quot;*Webrat*&quot;:http://wiki.github.com/brynary/webrat - Ruby-based, tests a variety of ruby web frameworks

h2. Webrat is awesome

For proof, check out &quot;Bryan Halmkamp's presentation on webrat from GoGaRuCo&quot;:http://www.brynary.com/2009/4/18/webrat-slides-from-gogaruco.  If you're building a web app in a ruby framework, and you're looking to build clean and fast acceptance tests, webrat wins.  The API is simple.  It works with any reasonable Ruby web framework.  It works with any reasonable ruby test framework.  It's faster than driving a GUI-based browser, because it doesn't use one.  Webrat is awesome and you should be using it right now.

h2. Similarities between Selenium and Watir

* Both support writing tests in Ruby
* Both can drive a variety of GUI browsers
* Both can be automated

h2. But what about the cost?

Each of these frameworks are open source, or free software, if you prefer.  However, both Watir and webrat come at the cost of developer time.  Shocking, isn't it?  Now before we get all feisty, let me say that I do believe that testing, especially testing first, saves you time and leads to a higher quality product.  No question.  _But..._ sometimes, behind that building over there, across the hall and in a shadowy room, applications can be built without any tests at all.  Call them legacy, call them late for dinner, but don't say they can't be tested.  The problem is, they don't have any developer time to spend.

h2. The fantasy of free

What if our business users were able to record all that clicking around they do, and save those as acceptance tests?  No developer time required!  We could automatically run those tests against our web application, and get immediate feedback!  Without a single developer hour spent, we could have automated user acceptance testing, which serves as coarse-grained regression testing too.  It could be _awesome,_ right? Let's see...

h2. Selenium IDE + Selenium RC

An advantage Selenium has over Watir and other similar competitors, is the &quot;Selenium IDE&quot;:http://seleniumhq.org/projects/ide/.  As the story goes, a business user (ie. not a developer) can click around a website, free as a bird, and record their gestures as a test to be played back later.  These tests can be exported to a variety of languages, which could then be run in an automated fashion.

h2. Bringing it all together

# Business users install the Selenium IDE
# They record their tests, saving them as HTML and exporting them to &quot;Ruby Selenium RC&quot;, on a network drive somewhere
## Saving the files as HTML allows the business team to run the tests locally, as well as edit the tests in the unimaginable case where the test is bad.
# Tests are committed into a skeleton Rails app repository, which holds only these tests (in ./test/unit) 
# CruiseControl.rb monitors the repository, running the tests when something changes
# Selenium RC, running on the same server as CruiseControl.rb, executes the Selenium tests in the browser(s) of your choice
# CruiseControl.rb sends out failure notifications to the team, when that blue moon of a failed test occurs ;)

h2. Gotchas

The first problem with this setup is that Selenium IDE exports these ruby tests in less than ideal ways.
* They load &quot;test/unit&quot;, not &quot;test_helper&quot;
* They class names are *all* ExampleTest
** Running _rake test:units_ will run all _unique_ test classes that are found in the test/unit directory, that end in &quot;_test.rb&quot;
** If you have 10 unique file names, all of which hold classes called _ExampleTest_, running _rake test:units_ will run *one* of them, not all of them.
* Often, due to a bug or user error with Selenium IDE, your tests will be set to run against &quot;http://change-this-to-the-site-you-are-testing&quot; rather than the site you're testing.

To remedy these issues as best we can, we can add in step 3A to the process above.  We'll set up a rake task to run every few minutes to scrub the test files and prepare them to be used in our testing project.  (Yes, for a more robust solution, we should check return codes from our system calls.)

&lt;script src=&quot;http://gist.github.com/106123.js&quot;&gt;&lt;/script&gt;
 
h2. So, was it worth it?

If you need to automate UI testing for an application without soliciting time from developers or testers, this could work for you.  The fantasy of free however, is still likely to be a fantasy.  Sure, business users can open up the saved Selenium tests locally and run them to verify a failed test scenario, but at some point, a developer is going to have to get involved.  Additionally, without the perspective of a developer, or the almost-out-of-style job title of &quot;tester&quot;, it's likely that the test suite will be incomplete and generate both false positives and false negatives.  In the right circumstance, however, this solution might be just good enough, free enough, and fast enough, to get that app out the door.
</content>
 </entry>
 
 <entry>
   <title>Golden Gate Ruby Conference</title>
   <link href="http://emphaticsolutions.com/2009/04/20/Golden-Gate-Ruby-Conference.textile"/>
   <updated>2009-04-20T00:00:00+00:00</updated>
   <id>http://emphaticsolutions.com/2009/04/20/Golden-Gate-Ruby-Conference</id>
   <content type="html">&quot;GoGaRuCo&quot;:http://gogaruco.com/ was a huge success by any measure.  &quot;Josh Susser&quot;:http://blog.hasmanythrough.com/ first mentioned his idea for a local Ruby conference during a &quot;San Francisco Ruby Meetup&quot;:http://www.meetup.com/sfruby/ a year ago or so.  This past weekend 200 rubyists gathered at the &quot;Swedish American Hall&quot;:http://www.cafedunord.com/?page=directions ready for &quot;18 presentations&quot;:http://gogaruco.com/schedule/ and lots of break time in between to hang out and hack.  

&quot;Pivotal Labs&quot;:http://pivotallabs.com/, a sponsor of the event, provided live video coverage (&quot;video available soon&quot;:http://pivotallabs.com/gogaruco/talks) and live-blogged every talk.  Instead of rehashing each presentation, I wanted to collect my thoughts on the presentations that I liked the most.

h2. &quot;MacRuby &amp; HotCocoa by Rich Kilmer&quot;:http://pivotallabs.com/users/edward/blog/articles/779-gogaruco-talk-macruby-hotcocoa

* Great overview of the history of Ruby on OS X
* Great overview of what each of the Ruby technologies are on the mac
* I was really impressed with the current state of MacRuby and HotCocoa
* I'd gladly consider HotCocoa to develop a native client app for the Mac after seeing the demo

h2. &quot;Sinatra - The Framework Within by Aaron Quint&quot;:http://pivotallabs.com/users/chad/blog/articles/780-gogaruco-09-sinatra-the-framework-within-aaron-quint

* I realized I had marginalized Sinatra for no good reason.  Sinatra is really great for simple HTTP services
* Aaron's talk on &quot;The power of the local web&quot; was really interesting.  I like the idea of building HTTP services as a way of interacting with a system.  HTTP is a really flexible and well understood API for this.

h2. &quot;Building Custom Web Proxies in Ruby by Ilya Grigorik&quot;:http://pivotallabs.com/users/stevend/blog/articles/789-gogaruco-09-building-custom-web-proxies-in-ruby-ilya-grigorik

* Described proxies as one of many transparent HTTP layers that are often present in between the client and the application server (firewall, load balancer, etc.). 
* Had a huge *wow* moment when Ilya was explaining how they use their ruby duplex proxy to send production traffic to a production server _and_ a staging server.  No more simulated traffic, this is the real deal!
* At &quot;PostRank&quot;:http://www.postrank.com/, they deploy a proxy in front of a few servers and load balance across them all, meaning any overhead introduced by the proxy only applies to a portion of their requests.
* With their duplex proxy, they can run post processors on the request and response data.  The two examples were response times and deltas of the response.
* Ilya pulled this code out and &quot;released it on github.&quot;:http://github.com/igrigorik/em-proxy/tree/master/  It's based on &quot;EventMachine&quot;:http://rubyeventmachine.com/.  Ilya also has a great &quot;writeup on EventMachine on his blog.&quot;:http://www.igvita.com/2008/05/27/ruby-eventmachine-the-speed-demon/
* I talked to Ilya about wanting to add in a more generic API for post processors.  I'd love be able to hot-swap post processors at runtime, which could be really helpful when debugging production issues and testing solutions in a staging environment.

h2. &quot;Discussion Panel - Ruby Application Frameworks&quot;:http://pivotallabs.com/users/chad/blog/articles/791-gogaruco-09-discussion-panel-ruby-application-frameworks

* This was a great panel and somehow the Pivotal guys were able to document much of the discussion.  Worth a read.

h2. &quot;Magic Scaling Sprinkles by Nick Kalen&quot;:http://pivotallabs.com/users/stevend/blog/articles/793-gogaruco-09-magic-scaling-sprinkles-nick-kalen

* Nick gave a simple and solid presentation on age-old distributed computing techniques.  
* He reminded everyone that these recommendations are computer science basics, and to reach for them, not a specific technology, when thinking about scalability.
* I'd recommend reading the blog on this talk and checking out &quot;the code used during the demo.&quot;:http://github.com/nkallen/gogaruco/tree/master (note: each step of the talk is kept in a different branch)
* During the presentation, Nick used his tool &quot;ss&quot;:http://github.com/nkallen/ss/tree/master, which is  _A cross between Awk, a spreadsheet, and a relational database. A command line 'language' for statistical analysis._  If, like Nick, you spend a lot of time analyzing log data for statistical information, you need to add this to your tool kit!

h2. &quot;Shoes - Programming for fun by Tim Elliot&quot;:http://pivotallabs.com/users/chad/blog/articles/799-gogaruco-09-using-shoes-to-create-better-iphone-apps-tim-elliott

* It was great to meet Tim.  Besides being an incredibly nice guy, he has contagious passion for his work and his play, which came across in his presentation.
* &quot;Shoes&quot;:http://shoooes.net/ seems like a really neat environment to play around with.  Tim showed some quick examples of fun UI tricks in Shoes, but he also showed that it works really well for a majority of desktop application needs, too.

h2. &quot;Using Ruby to Fight AIDS by Jaqui Maher&quot;:http://pivotallabs.com/users/stevend/blog/articles/800-gogaruco-09-using-ruby-to-fight-aids-jacqui-maher

* Highly recommended presentation!  The stats alone are shocking.
* Really interesting to see what tools and techniques helped push this project forward
** Git and github.  Centralized SCM made it virtually impossible to get help from people outside of Africa, and was still difficult within Africa.  Now lots of folks help via github.
** &quot;Peepcode screencasts&quot;:http://peepcode.com/ - Geoffrey Grosenbach sent a DVD to Africa of every Peepcode screencast
* Ad-hoc networks FTW!
* It's amazing to see an app like this being rolled out, providing such incredible impact right away.  It also really shows how much waste and inefficiencies exist in our crippled healthcare system in the US.

h2. &quot;Webrat - Rails acceptance testing by Brian Helmkamp&quot;:http://pivotallabs.com/users/chad/blog/articles/802-gogaruco-09-webrat-rails-acceptance-testing-evolved-bryan-helmkamp

* Webrat is _awesome_.
* If you really need browser specific tests, or need in-browser testing of JavaScript, Selenium is still recommended.  You can use them together, too.
* With web forms, webrat shines when you have proper HTML forms, with good labels.  Webrat encourages proper HTML like TDD encourages better API design.
* I asked some people about the ease that one might convert Selenium tests to webrat.  The consensus was that form-based pages could be converted relatively easily, where other pages may be less so.  Problem seems to be the often crufty Selenium tests.

h2. &quot;Lighting talks - various&quot;:http://pivotallabs.com/users/zach/blog/articles/803-gogaruco-09-lightning-talks

* Observation: &quot;Yehuda Katz&quot;:http://yehudakatz.com/ is not only a great programmer, he has helped nearly everyone at one time or another, with their own projects.  He gave a lightning talk on a common API for key/value stores called Moneta, but was mentioned by name in nearly every other talk.  Not just last year's Ruby Hero award winner, but everybody's hero all the time.

h2. &quot;Arduino is Rails for hardware hacking by Greg Bornstein&quot;:http://pivotallabs.com/users/chad/blog/articles/805-gogaruco-09-arduino-is-rails-for-hardware-hacking-greg-borenstein

* Awesome demos of hardware hacking with Ruby.  Greg had lots of cool gadgets and it was hard not to get swept up into dreaming up your own hardware hackery.
* While controlling hardware via software looks insanely fun, some tiny glitches showed how flakey some of the middle bits can be (MIDI and USB can both be a PITA).
* Greg's library is a great example of using Ruby to create a clean and powerful API on top of a powerful but ugly one.

h2. &quot;Relational Modeling Framework by Nathan Sobo&quot;:http://pivotallabs.com/users/chad/blog/articles/806-gogaruco-09-relational-modeling-framework-nathan-sobo

* Nathan's library &quot;June&quot;:http://github.com/grockit/june/tree/master blew me away.  It's an event-driven relational framework in JavaScript.
* The API is really elegant, pulled straight from traditional relational algebra.
* &quot;Grockit&quot;:http://grockit.com/ built a massively multi-player online game environment for learning.  The UI is all event-driven and feels really fast.  What seems like chaos to manage, seems simple with this framework.
* There was a lot of live coding that helped bring the framework to life, so the video of this talk is highly recommended.

Thanks again, GoGaRuCo!  I'm already anticipating next year's conference.
</content>
 </entry>
 
 <entry>
   <title>Clean Eating, How I make it work</title>
   <link href="http://emphaticsolutions.com/2009/01/12/clean-eating-how-I-make-it-work.textile"/>
   <updated>2009-01-12T00:00:00+00:00</updated>
   <id>http://emphaticsolutions.com/2009/01/12/clean-eating-how-I-make-it-work</id>
   <content type="html">h2. &quot;But I already eat healthy!&quot;

I'm not sure when the hype hit you, but for me it came hard and fast somewhere around 2002.  I had come back from an adventurous year off traveling and had just moved in with my beloved, now wife, Brigid in North Beach, San Francisco.  While much of my nutrition in those days came from pint glasses and greasy bar food, when we ate at home, we tried to eat _healthy_ food.  

*Whole grains* appeared in everything, the little green triangle showed up on lots of packaged foods, and we were sold.  We slowly began cooking more and eating out a little less.  Whole wheat pasta, with low fat turkey and sauce, was a staple.  No bread was purchased without at least 7 of the holy whole grains.  Rice?  Brown, please.  Breakfast?  Wheaties!  Every morning, and often as a snack.  

In 2004 Brigid and I moved to Marin county and bought a house.  This certainly helped to dramatically cut down on those greasy bar meals, and far fewer pints of Guinness passed my lips.

The next progression of my supposed healthy eating was based on a fear of _high fructose corn syrup_ and the like.  I'm a voracious reader, so Michael Pollan's &quot;_The Omnivore's Dilemma: A Natural History of Four Meals_&quot;:http://www.amazon.com/Omnivores-Dilemma-Natural-History-Meals/dp/0143038583/ref=pd_bbs_sr_2?ie=UTF8&amp;s=books&amp;qid=1232228716&amp;sr=8-2 and &quot;_In Defense of Food: An Eater's Manifesto_&quot;:http://www.amazon.com/Defense-Food-Eaters-Manifesto/dp/1594201455/ref=pd_bbs_sr_1?ie=UTF8&amp;s=books&amp;qid=1232228716&amp;sr=8-1 had been ingested as fast as they were printed.  I was, after all, starting to get concerned about my health.

Strangely though, my health didn't seem to be improving.  As I became more and more watchful of fat intake and ensured my grains were as whole as possible, I actually weighed _more_ than I did when I was drinking pints of Guinness by the bakers dozen and choosing between fish-n-chips and shepherd's pie for dinner.

It was Einstein who described insanity as &quot;&quot;_doing the same thing over and over again and expecting different results_&quot;&quot;:http://www.quotationspage.com/quote/26032.html.  I was eating low-fat, whole grain foods for years expecting the results to be different from what I had repeatedly seen.  It didn't work for me, and it won't work for you, either.

h2. Finding Crossfit

Six weeks before my 31st birthday I was swimming laps in a pool in Lake Tahoe.  After swimming two lengths of the pool freestyle, I started sucking wind like I hadn't exercised in years.  Hmm.  That _may_ be because I hadn't exercised in years.  It was time for serious change, and I was looking anew for a solution.

After lots of research I came to find &quot;Crossfit&quot;:http://www.crossfit.com/.  I started doing the &quot;Crossfit warmup&quot;:http://www.crossfit.com/cf-info/faq.html#General7 in my garage for a few days, reading the &quot;discussion boards&quot;:http://board.crossfit.com/ online and started to get the general idea that fitness was a much broader and important concept than just thinking about health in general.  The degree that one may consider themselves healthy may be quantified by their distance away from death.  To consider oneself fit, well, that's a whole different story.  For probably the first time ever, I now aspired to be fit.

I signed up for classes at &quot;TJ's Gym&quot;:http://tjsgym.com/ and started showing to myself and others, just how unfit I had become.  My first few workouts would be recorded as DNF, or _did not finish_.  The scale, which I felt I now had to actually utilize after years of neglect, provided an even and round number for me to start off with.  On July 8th, 2008 I weighed 250#!  And so it began...

h2. Zoning Paleo foods

A few hard sweating weeks after my first class, TJ offered to chat with me about nutrition.  I was all over it.  I was going to really impress him, certainly, with my low-fat foods and my whole wheat pasta.  All summer I had gone to the farmers market every week to pick up my fruit and veggie box from &quot;Full Belly Farm&quot;:http://www.fullbellyfarm.com/. Surely I was on the right track.

There was this moment, before we got into the nutrition chat, that TJ talked about the big picture.  Eating well was a foundation of fitness.  You need quality foods in order to perform well.  He reached toward me, his arms floating a few inches from what had become my impressive gut, to say that the goal was to &quot;turn this machine into a fat burning machine.&quot;  _This machine?_  Holy shit!  Images of my more youthful years flashed before me, a glimmering reminder of the times when I felt like a machine.  Powerful.  Unstoppable.  Ready for anything.  At that moment I decided that I would be dumb enough to believe that I could not only relive that feeling, but surpass it.

I listened intently and started to get the message.  
* Eat &quot;zone portions&quot;:http://www.zonediet.com/ of &quot;paleo foods&quot;:http://paleodiet.com/.  
* Fat does not make you fat
* Sugar, in its many forms, makes you fat
* Grains, whole or otherwise, are just sugar in a brown wrapper
* Obesity is one of many side effects of underlying disease, brought on by bad nutrition
* Body composition change must come from nutrition
* Don't expect that working out hard will balance out poor nutrition
* Zone portions == the right quantity of foods
* Paleo foods == quality foods

h2. &quot;How do I know what to believe?&quot;

I know what you're thinking.  This is yet another sales pitch on _the ultimate, easy, guaranteed, weight loss secret that will blow...you...away!_  Thankfully, no.  Let's look at what &quot;paleo foods&quot;:http://paleodiet.com/ are: Meat, vegetables, fruit, nuts and seeds.  You couldn't turn that into a million dollar idea if you tried.  Boiled down to it's essence, the idea is to eat _real_ food.  Pollan had great ways of putting this in his book &quot;_In Defense of Food: An Eater's Manifesto_&quot;:http://www.amazon.com/Defense-Food-Eaters-Manifesto/dp/1594201455/ref=pd_bbs_sr_1?ie=UTF8&amp;s=books&amp;qid=1232228716&amp;sr=8-1.  _&quot;If your great grandmother wouldn't recognize it as food, don't eat it!&quot;_ 

After all, how many millions of Americans have eaten just the way I did, as we're told from every magazine and TV commercial.  How many of those same people are over weight?  How many of them have high cholesterol?  High blood pressure?  Diabetes?  Cancer?  Exactly.

During the first nutrition lecture at &quot;TJ's Gym&quot;:http://tjsgym.com/, &quot;Matt Barnes&quot;:http://mattbarnes.multiply.com/ gave us the do-it-yourself challenge to see how sugary our beloved whole wheat pastas or breads are.  Get a blood sugar test strip from your local pharmacy.  Chew on a bite of your favorite whole grain item for 30 seconds.  Insert the sugar test strip into your mouth.  Look at it and _freak out_.  Through the magic of saliva and pearly whites, you've just turned your _healthy_ whole grain super food into a mouthful of sugar.  Congratulations!  

During that same nutrition lecture, Matt and TJ mentioned a book that aimed to investigate and summarize over 100 years of science on nutrition and diet.  The book is &quot;Good Calories, Bad Calories&quot;:http://www.amazon.com/Good-Calories-Bad-Controversial-Science/dp/1400033462/ref=pd_bbs_sr_1?ie=UTF8&amp;s=books&amp;qid=1232232506&amp;sr=8-1 by Gary Taubes.  If you read it, it will change your life.  (I read over 30 books a year, and this damn _nutrition_ book is in my top 5!)  If you want to opt out of this 640 page tome, but still get the message, here it is.  *Eat zone portions of paleo foods, or you'll die sooner than you should.*  I'm not meaning to be critical.  Reading the science, perspectives and hypothesis, I started to get scared.  Every chapter unveiled deeper and more disturbing things about the foods I had been eating so much of.  When you start to see how that bread, rice and pasta on the dinner plate equates to high cholesterol, diabetes, obesity and cancer, you start to see just how serious we need to consider the foods we eat. 

h2. Where do you want to be?

Hardcore clean eating takes work.  Eating perfect zone portions means measuring and weighing.  Eating a strict paleo diet means no dairy, no sugar and no cheap and easy carbs.  Finding grass fed beef is hard.  Eating salsa is nice, but without chips, it's hard.  Having a tough day at work is hard enough, but not consoling yourself with that routine glass of wine at home.. that's hard.  Even when we know the consequences, when we have a clear picture of what clean eating is, it can still be hard to stick to it.

TJ has always offers up the 80/20 rule as a good guideline of where we should aim to be.  Eat clean 80% of the time.  That other 20% is up to you.  Over the long term, the most important factor to successfully implementing good nutrition in your life, is finding _your_ own balance.  How strict are you during that 80%?  What do you eat during that 20%?  

Where do _you_ want to be?  What are _your_ performance goals?  Are you happy with your body composition?  Are those cheese and crackers worth it?  Once you know precisely where clean eating is on that nutrition curve, with bagels, pasta and french fries at the other end, you need to decide for yourself where you want to be on that curve.  Here's the obvious part: the closer you are to eating clean, the easier it will be to accomplish your goals.  Get too far away, and just like a paying the minimum balance on an maxed out credit card, you'll never get there.

h2. My personal concessions

Can you imagine how hard it would be to eat perfectly every day, with no deviations?  It wouldn't just be hard, it would be unmaintainable.  Eating perfectly for a month, then crashing and eating nothing but pizza and coke the next month won't get you anywhere (except maybe the bathroom).

I started eating clean just after I started Crossfit.  Zone blocks were very confusing to me.  Instead of worrying about them too much, I focused on quality first.  I was _shocked_ how easily I transitioned from my morning Wheaties to eggs.  Rice in my Chinese and Indian dishes, to broccoli.  Lunchtime sandwiches to left over meat and veggies.

I bought a food scale and new measuring spoons and measured my foods for about two weeks.  I didn't count daily blocks, but wanted to see what 4 oz. of chicken looked like.  What does a cup of broccoli look like?  How much is a teaspoon of olive oil?  After those two weeks, I stopped measuring and eyeballed everything.

I continued to drink skim milk on occasion.  I also had cottage cheese and raw yogurt a few times a week.  I felt so full and satisfied by the meals I was eating, I never really felt to urge to eat a luxurious cheat meal.  My favorite &quot;cheat&quot; now, and probably forever, is still a pint of Guinness.  Every few weeks I'd go out with the guys, and like old times, toss back a handful or more.  The next day, I'd wake up a little soggy, and go on eating clean again.

I started to equate non-paleo foods as interest to be paid back.  Was it worth it?  Sometimes it was.  As fall weather settled down into November, my wife made an incredible Squash Risotto.  I ate a big bowl of it and loved every bite.  On another memorable day in November, I watched as an 8 year reign of ignorance would be overturned in favor of science, humanity and humility.  The uncounted glasses of beer, scotch and vodka were all worth it in celebrating that night.  (If Californians cared for gay rights as much as they did for animal rights, it would have been a perfect night... but I digress...)

In this recent nutrition challenge, I've gone strict paleo with no cheats.  I had fallen into the convenient trap eating _Think Thin!_ bars on the weekends, and my dairy intake was probably more than I wanted to admit.  Already I've been thrilled to see how easy it has been to cut that stuff out for a while.  When it's all over, I'll probably go back to having a drop of _real_ cream in my coffee, but I'm glad to have moved the &quot;health&quot; bars from every weekend to true food emergencies.

The point is that I had come to a point where I could decide where on that curve of clean eating I wanted to be.  I knew what a &quot;cheat&quot; was, and I felt good about when and how often I had them.  I have found the foods that I will be eating for the rest of my life.

h2. A day in the life

After the second nutrition seminar at the gym, Michael showed off his food stuffs for the day to the 9:30 class.  I think this was a great way to see, in person, how one person does it.  To that end, here is a typical day in my world:

__Note: If you want to see what other zone/paleo folks are eating regularly, befriend them on &quot;statulo.us&quot;:http://statulo.us so you are a click away from their nutrition log!_

* *Work schedule*
I'm lucky enough to work from home.  I'll admit this has provided an enormous convenience to transitioning to clean eating.  I can cook at home frequently, and have plenty of time to shop since I don't spend any time commuting.  I've also found, however, that I require a lot less time in the grocery store.  I buy a cart full of great food every 4 days or so, and I'm never in the store for more than 15 minutes.

* *Workout's at TJ's*
I started out going to TJ's about twice a week for the first few months.  I ramped up to three times a week for a bit, and am now going 4x-5x per week.  I don't have a set schedule or class, and go equally to the 6AM, 9:30AM and 4PM classes.  

* *7 AM Breakfast*
I eat two eggs for breakfast every day.  I buy those super omega 3 eggs from Trader Joe's which are incredible.  If I'm going for spicy, I'll heat up some onion, mushroom, peppers, etc. in some olive oil first.  After cooking the eggs with the veggies, I'll add some sort of fresh salsa.  Other days I feel like something a little sweeter, so I'll use a teaspoon of coconut oil in the pan to cook the eggs in.  Adding ground flax is nice with the coconut oil, and them I'm nearly drowning in Omega 3.  Every other day or so, I'll also have some fruit with breakfast, typically an orange.

* *11 AM Snack*
If I'm returning from the 9:30 class, I'll typically have a smoothie.  I blend water, 2 scoops of whey protein powder and 2 cups of fruit (strawberries, blackberries, raspberries, mango, etc.).  This makes more than can fit in two pint glasses (you just know I have a lot of these at home, right?) and tastes like a dream.  
Otherwise I'll have 2 oz of meat (left over chicken, steak or turkey burger) with an apple and some nuts or almond butter.  Peanut butter was very dear to me for years, but I've fallen hard and fast for almond butter and won't look back.  I typically have raw almond, cashew, macadamia and walnuts around.  I've recently started adding raw sunflower seeds into the mix too.

* *1 PM Lunch*
For convenience I often have leftovers from my previous dinner for lunch.  If I don't have much in the fridge, I'll use this time to cook extra food for later.  I always try to have a container of meat in the fridge for snacks or to incorporate into a quick lunch.  I have tuna on hand for 1-minute meals, but I may also grill up a few steaks, or boil a pound or two of chicken.  Boiled chicken, while not the sexiest way to cook a bird, seems to be the best way to keep chicken moist for a few days.  This is also a great time to put a turkey breast or two into the oven.  It cooks while I work, and it lasts days.

* *4 PM Snack*
This is a lighter snack, typically, and I often don't have any meat at this time.  Lately I've had an apple and some nuts to tide me over.  This is also the time I usually remember how little water I've had to drink that day, so I fill up a 1 liter bottle and start drinking.

* *6:30 PM Dinner*
A side effect of eating clean has been my interest in cooking. My wife and son (Blake - 2) get home around 5:30.  Now that we've been eating paleo dinners together for a few months, we've got a cache of recipes we cook often.  We toss around a few ideas and I begin the preparations.  I always make more food than we'll eat for dinner, to serve as lunch later.  This does sometimes make it hard to count blocks for things like cooking oils, I'll admit.  We both love Indian, Thai and Chinese food, so I'll make something like that and eat it over broccoli.  I've gathered an impressive amount of spices, and with some experimentation, I've found quite a few variations to keep it interesting.  Having recently found how good coconut milk can be, I've been cooking with that more often, and eating a lot of bok choi, too.

* *9PM Snack*
I'm often too full to need a snack at this hour, but when I do it's usually nuts and fruit.  A cup of grapes with 21 cashews is incredible.

* *Sleep schedule*
If I didn't know any better, I'd be up until midnight every night.  Fortunately I've convinced myself of the benefits of sleep and I'm getting a little more sleep now.  I may sleep from 10:30 to 5:20 (a little less than 7 hours) if I go to the 6 AM class, or 11:30 to 7 (7 and a half hours) on every other day.  I _should_ be getting more sleep, but that's where it is now.

h2. The results are in!

&lt;div style=&quot;width:100%;&quot;&gt;!/images/body.weight.graph.png!&lt;/div&gt;

(Interactive graph with notes, available &quot;on statulo.us&quot;:http://statulo.us/share/graph/2856885981/2518667660)

In 6 months of Zone/Paleo foods and Crossfit workouts, I've lost *52#*.  Currently at 198#, I'm happily in the under 200 pound club for the first time in a decade.  As you can see, this was no crash diet.  That is two pounds, _every single week_.  I put in consistent effort at 80+ percent, and that's what I got out of it.  Nice and simple.  It hasn't come cheap though!  While I now spend _less_ at the grocery store than I did before, I've had to buy a lot more clothes.  I started off wearing size 38&quot; pants, which I had to try on, as not every pair fit me.  I now buy size 34&quot; pants off the rack, knowing that they are all loose.  Goodbye XL, and hello size _medium_ shorts.  I'm sure soon enough I'll have to pick up a few pairs of size 32&quot; pants when I get sick of always having to wear a belt.

For a more embarrassing angle, here are some before and after pictures... or as I prefer to call them, before and during:

!/images/6.month.paleo.plus.crossfit.jpg!

In a few weeks we'll have the opportunity to have our body fat measured in the dunk tank, so I'm looking forward to having another metric to work on.  While the road so far has been incredibly rewarding, this is only the beginning of what I now know will be a lifetime of fitness.

One thing that has surprised me though all of this, is that I have been able to improve my strength as my weight dropped.  I have the great coaches at TJ's to thank for constant guidance and advice on form and technique.  I struggled a few months ago on strength days, but I'm glad to say now that my Crossfit Total scores are higher now than ever before, at &quot;705 [265# back squat, 105# shoulder press, 335# dead lift, on 12/30/08]&quot;:http://statulo.us/share/one/910192006

h2. Making it work for you

So that's my story so far.  If your considering clean eating and are struggling to get started, I hope that by sharing how I make it work, it makes it a little easier for you.  Everyone's habits and foods will be a little different.  What is important is finding how it can best work for you.

I'll close with a few pointers that come with that same disclaimer that all of this does, in that these are just my opinions:
* Dig deep and find out why you want to be fit.  Remember that every day.
* Spend time reading up on preferred paleo foods.  Make a list of the stuff you like.  Don't pay any attention to the stuff you don't like.
* Eat that stuff, and repeat.
* If you feel like crap, eat more fat.
* When you cheat, cheat well.  Find those off limits foods that you will cherish and savor.  (Guinness!)
* Maintain a nutrition log (&quot;on statulo.us!&quot;:http://statulo.us/).  Better yet, share your log and let friends keep tabs on you!
* Spend time developing the habits of healthy eating and cooking.  Soon enough it will be second nature and will require very little thinking.
* Paleo foods don't have to be boring!  Expand your cooking horizons, buy strange vegetables and spices and try stuff out.
* Have fun!  The quality of your life requires it.

h2. Update!

On January 24th, 2008 our gym had scheduled the &quot;Body Fat Test Truck&quot;:http://bodyfattest.com/ to be around for appointments.  My appointment was at 8:20 AM, so I didn't eat before hand.  Here's the data:
* Weight: *194#*
* Body fat: *13.5%*
* Weight of body fat: *26.1#*
* Lean body mass percentage: *86.55%*
* Weight of lean body mass: *167.9#*
* Muscle Mass (x .63): *105.8#*
* Percent body fat above *80th percentile*, in the *healthy range.*
* Resting metabolic rate: *2149*

According to my back-of-the-napkin calculations, my body fat percentage before I started would have been around *33%*, which not surprisingly is in the *very poor* range.  That means that in 6 months, I've reduced my body fat by *68%*!

h2. Update II, Cholesterol 

I had blood panels taken several months before I started eating Paleo, and then 6 months into eating Paleo.  My most recent labs are quite good by any measure.  Since folks tend to assume that eating Paleo, with lots of good fats and typically lots of eggs, leads to bad cholesterol, here is evidence to the contrary.

|Metric|Pre-Paleo|Paleo|% Change|
|Cholesterol|203|177|-13%|
|Triglyceride|170|47|-72%|
|HDL|38|57|+50%|
|LDL|140|111|-21%|
|VLDL| n/a |9| n/a |

Not that I needed any more proof, but I'm certainly sticking to eating clean from now on.

h2. Update III, Body Fat 6 months later

On June 27th, 2009 our gym had scheduled the &quot;Body Fat Test Truck&quot;:http://bodyfattest.com/ to be around again for appointments.  Here's the data:

* Weight: *182#*
* Body fat: *9.9%*
* Weight of body fat: *18.15#*
* Lean body mass percentage: *90.1%*
* Weight of lean body mass: *163.85#*
* Muscle Mass (x .63): *103.23#*
* Percent body fat above *95th percentile*, in the *very healthy range*

This means that in eleven months, I've lost *68#*.  Since my muscle mass has certainly gone up, that means I lost over 70# of pure fat.</content>
 </entry>
 
 <entry>
   <title>Train to not suck at life</title>
   <link href="http://emphaticsolutions.com/2008/12/13/train-to-not-suck-at-life.textile"/>
   <updated>2008-12-13T00:00:00+00:00</updated>
   <id>http://emphaticsolutions.com/2008/12/13/train-to-not-suck-at-life</id>
   <content type="html">In an early edition of the &quot;CrossFit Journal&quot;:http://journal.crossfit.com, Coach Glassman talks about the &quot;foundations of CrossFit&quot;:http://www.crossfit.com/cf-download/Foundations.pdf (pdf):
&lt;blockquote&gt;
We have designed our program to elicit as broad an adaptational response as possible. CrossFit is not a specialized ﬁtness program but a deliberate attempt to optimize physical competence in each of ten recognized ﬁtness domains.&lt;br/&gt;&lt;br/&gt;
&lt;/blockquote&gt;

These fitness domains are:
&lt;blockquote&gt;
Endurance, Stamina, Strength, Flexibility, Power, Speed, Coordination, Agility, Balance, and Accuracy&lt;br/&gt;&lt;br/&gt;
&lt;/blockquote&gt;

It's no surprise that some CrossFit gym's use the _&quot;Train to not suck at life&quot;_ tag line, as these fitness domains are all critical aspects to our personal success, no matter what our aim.

I've been thinking about success factors a lot since watching &quot;Malcolm Gladwell's&quot;:http://en.wikipedia.org/wiki/Malcolm_Gladwell great presentation at PopTech, loosely based on the content of his new book, &quot;Outliers&quot;:http://www.amazon.com/gp/product/0316017922?ie=UTF8&amp;amp;creativeASIN=0316017922.  Watch this presentation, then ask yourself &quot;what effects my own talent capitalization?&quot;
&lt;div&gt;&lt;object width=&quot;512&quot; height=&quot;322&quot; data=&quot;http://d.yimg.com/static.video.yahoo.com/yep/YV_YEP.swf?ver=2.2.30&quot; type=&quot;application/x-shockwave-flash&quot;&gt;&lt;param name=&quot;allowFullScreen&quot; value=&quot;true&quot; /&gt;&lt;param name=&quot;AllowScriptAccess&quot; value=&quot;always&quot; /&gt;&lt;param name=&quot;bgcolor&quot; value=&quot;#000000&quot; /&gt;&lt;param name=&quot;flashVars&quot; value=&quot;id=10577117&amp;amp;vid=10577117&amp;amp;lang=en-us&amp;amp;intl=us&amp;amp;thumbUrl=&amp;amp;embed=1&quot; /&gt;&lt;param name=&quot;src&quot; value=&quot;http://d.yimg.com/static.video.yahoo.com/yep/YV_YEP.swf?ver=2.2.30&quot; /&gt;&lt;param name=&quot;flashvars&quot; value=&quot;id=10577117&amp;amp;vid=10577117&amp;amp;lang=en-us&amp;amp;intl=us&amp;amp;thumbUrl=&amp;amp;embed=1&quot; /&gt;&lt;param name=&quot;allowfullscreen&quot; value=&quot;true&quot; /&gt;&lt;/object&gt;&lt;/div&gt;

Now, Gladwell has made clear that we're &quot;too focused on the individual&quot;:http://gladwell.com/outliers/index.html.  His book focuses on the environment around us, our culture, our birthplace and even our date of birth, which has enormous effects on how our talents are capitalized.  I do agree with Gladwell on these points, but as an individual myself (and you too, dear reader) it is always alluring to focus inward with an aim to do whatever it is we do, as well as we can do it.  While I've never read any &quot;self-help&quot; books before, I can see why they are so popular.  After watching that presentation, I couldn't stop thinking about how we could measure our performance in a more general sense.

I'd bet that if we think hard enough, the primary issues that affect the capitalization of our own talents are weaknesses in several of those fitness domains.  CrossFit may imply that those domains are for physical fitness, but as any athlete will tell you, mental fitness is as important if not more so.

Luckily for CrossFitters, improving fitness across those domains is easy.  Do your CrossFit workouts and you'll get more fit across the board.  It's also easy to track your fitness progress, which was the primary motivation for my building &quot;statulo.us&quot;:http://statulo.us/.

For thought workers, though, it may be hard at first to see how our mental fitness stacks up across these fitness domains.  Let's take a stab at describing how these terms could be applied to the average worker.

h2. Endurance

&lt;blockquote&gt;the power to withstand hardship or stress&lt;/blockquote&gt;
Tight deadline?  Fast approaching ship date? How well do you deal with the stress in your life?  How well do you endure the discomfort of useless but necessary(?) business meetings?

h2. Stamina

&lt;blockquote&gt;strength to resist fatigue and tiredness&lt;/blockquote&gt;
So much of corporate life can be tiring.  Cube dwelling zaps creativity, conference calls can quickly become white noise and idle chatter can challenge even the well rested.  How do you sustain your energy throughout the day?

h2. Strength

&lt;blockquote&gt;durability; determination; resolve; power; intensity; force&lt;/blockquote&gt;
Implementing change in any organization requires the strength to to encourage, to challenge and to lead.  When you find something worth fighting for, how much strength can you muster?

h2. Flexibility

&lt;blockquote&gt;susceptible of modification or adaptation&lt;/blockquote&gt;
Pragmatism.  Unyielding focus in a single direction, without input from others, will ultimately kill you.  Staying focused on your goals while being flexible about the details will always require less effort, and produces much better results.

h2. Power

&lt;blockquote&gt;the rate at which work is performed for a given period of time&lt;/blockquote&gt;
&quot;I'm going to put my head down and just crank this out.&quot;  When all those pesky decisions have been made, the goal is in site, and its just time to get 'er done.  How do you build and sustain your power?

h2. Speed

&lt;blockquote&gt;the rate at which an object moves&lt;/blockquote&gt;
Nobody needs more red tape. Get moving!  &lt;a href=&quot;http://www.bobdylan.com/#/songs/times-they-are-changin&quot; target=&quot;_blank&quot;&gt;Don't stand in the doorway, don't block up the hall.&lt;/a&gt;

h2. Coordination

&lt;blockquote&gt;Harmonious interaction; synchronizing movement.&lt;/blockquote&gt;
You work with others, each of you depending on one another.  How well do you coordinate with your peers?  How well do you coordinate the work you do?

h2. Agility

&lt;blockquote&gt;moving quickly and lightly&lt;/blockquote&gt;
&lt;a href=&quot;http://agilemanifesto.org/&quot; target=&quot;_blank&quot;&gt;I think we get this one.&lt;/a&gt;

h2. Balance

&lt;blockquote&gt;equality of distribution&lt;/blockquote&gt;
You play many roles from day to day.  How well do you balance the demands placed against you with your desires as a person?  If you're stressed out, you're out of balance.

h2. Accuracy

&lt;blockquote&gt;the quality of being near to the true value&lt;/blockquote&gt;
After all that, did you create anything of value?  Were your aims true?  Was it worth it?

h2. How do you rate?

Precision would miss the point.  Every day may bring us something different, something new.  But that actually _is_ the point.  Diversity, that marrow of life, requires all of the above.  How do you handle it?  How do you rate?  How do you train to not suck at life?</content>
 </entry>
 
 <entry>
   <title>Quick and Easy - Cache RSS feeds in your Rails app</title>
   <link href="http://emphaticsolutions.com/2008/11/28/quick-and-easy-cache-rss-feeds-rails.textile"/>
   <updated>2008-11-28T00:00:00+00:00</updated>
   <id>http://emphaticsolutions.com/2008/11/28/quick-and-easy-cache-rss-feeds-rails</id>
   <content type="html">Displaying a feed within your Rails app is pretty easy.  It turns out caching that RSS feed is pretty easy too.  I recently added cached RSS feeds to an app and had a few tiny hoops to jump through, so I thought I'd document them here for anyone else looking to solve the same problem.

Caching is easy.  Cache invalidation is hard.  For an RSS feed, we'd have to ping the feed to determine if any data had changed.  Why bother?  Instead of fetching the RSS feed on every single page request, let's cache it for a fixed period of time.

The &quot;timed_fragment_cache&quot;:http://github.com/GeorgePalmer/timed_fragment_cache/tree/master plugin adds a duration option to the Rails cache method, allowing you to specify how long to cache a fragment of code.  So, get it!

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; ./script/plugin &lt;span class=&quot;nb&quot;&gt;install &lt;/span&gt;git://github.com/GeorgePalmer/timed_fragment_cache.git&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

To integrate that cache method into a page, it might look like this:

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ruby&quot; data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;sx&quot;&gt;%- cache &quot;statulous_blog&quot;, (Time.now + 60.minutes) do -%&amp;gt;
  &amp;lt;%= render_rss_feed(&quot;http://example.com/rss.xml&quot;) %&amp;gt;&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;sx&quot;&gt;%- end -%&amp;gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

The render_rss_feed helper method looks like this: 

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ruby&quot; data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;nb&quot;&gt;require&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'rss/1.0'&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;require&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'rss/2.0'&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;require&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'open-uri'&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;require&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'socket'&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;module&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;ApplicationHelper&lt;/span&gt;
 
  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;render_rss_feed&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;url&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;content&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&quot;&lt;/span&gt;
    &lt;span class=&quot;nb&quot;&gt;open&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;url&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;s&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;content&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;s&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;read&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;feed&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;RSS&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Parser&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;parse&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;content&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kp&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;vi&quot;&gt;@link&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;feed&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;channel&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;link&lt;/span&gt;
    &lt;span class=&quot;vi&quot;&gt;@title&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;feed&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;channel&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;title&lt;/span&gt;
    &lt;span class=&quot;vi&quot;&gt;@items&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;feed&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;channel&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;items&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;..&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;# just use the first five items&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;render&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:partial&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'home/rss_view'&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
 
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;


And from there, pretty up that feed however you like.  Here I'm just using the link, title and date:

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ruby&quot; data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;h3&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;href&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'&amp;lt;%= @link %&amp;gt;'&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;sx&quot;&gt;%= @title %&amp;gt;:&amp;lt;/a&amp;gt;&amp;lt;/h3&amp;gt;
&amp;lt;small&amp;gt;The most recent 5 entries:&amp;lt;/small&amp;gt;&amp;lt;br/&amp;gt;
&amp;lt;% @items.each do |item| %&amp;gt;
  &amp;lt;li&amp;gt;&amp;lt;strong&amp;gt;&amp;lt;a href=&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'&amp;lt;%= item.link %&amp;gt;'&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;sx&quot;&gt;%= item.title %&amp;gt;&amp;lt;/a&amp;gt;
	&amp;lt;/strong&amp;gt; - &amp;lt;small&amp;gt;(&amp;lt;%=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;item&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;date&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;strftime&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'%m/%d/%Y'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;%&amp;gt;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;sr&quot;&gt;/small&amp;gt;
&amp;lt;% end %&amp;gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

h4. private method `gsub' called for #&lt;StringIO:0x2575df8&gt;

If you are using Rails 2+ and you try to get fancy with that duration specification, using something like 30.minutes.from_now, you'll end up getting that gsub error.  Here is why:

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ruby&quot; data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;o&quot;&gt;%&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ruby&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;script&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;console&lt;/span&gt;
&lt;span class=&quot;no&quot;&gt;Loading&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;development&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;environment&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Rails&lt;/span&gt; &lt;span class=&quot;mf&quot;&gt;2.1&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Time&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;now&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;30&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;minutes&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;class&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Time&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;30&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;minutes&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;from_now&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;class&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;ActiveSupport&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;TimeWithZone&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

Note: 30.minutes.from_now.time will result in a Time class, and will work equally as well as (Time.now + 30.minutes).  It's up to you which of those two are more readable and intention revealing.

h4. Caution: Feed parsing is hard

The best part about feed standards is that there are so many to choose from!  The code above is trivial, and will only handle feeds that fit that particular convention.  Since I'm consuming feeds that I am also responsible for creating, I can opt for this _simplest thing that could possibly work_ approach.  

As soon as you start consuming several feeds, you'll start to see just how diverse these feeds can be.  Empty channels, posts without titles, non-unique identifiers... these are just the beginning.  I'd love to hear what robust feed parsers folks are using in Ruby.  The best feed parser I know of, and that some Rubists even use, is &quot;Universal Feed Parser&quot;:http://www.feedparser.org/, a Python library with 3k unit tests.  Good luck!</content>
 </entry>
 
 <entry>
   <title>New gem - greatest_common_factor</title>
   <link href="http://emphaticsolutions.com/2008/09/19/new-gem-greatest_common_factor.textile"/>
   <updated>2008-09-19T00:00:00+00:00</updated>
   <id>http://emphaticsolutions.com/2008/09/19/new-gem-greatest_common_factor</id>
   <content type="html">Ruby already provides the ability to find the greatest common factor (gcf) of two integers.  What if we could determine the greatest common factor across a whole array of integers?  Now we can.

I've just released &quot;greatest_common_factor on github.&quot;:http://github.com/briandoll/greatest_common_factor/tree/master

Here is a sample of what you can do with it:

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ruby&quot; data-lang=&quot;ruby&quot;&gt;  &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;12&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;16&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;8&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;40&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;].&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;greatest_common_factor&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;4&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;12&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;16&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;8&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;40&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;].&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;gcf&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;4&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;12&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;16&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;8&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;40&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;].&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;factored_by_gcf&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

*Update:*
You can now also specify a tolerance for greatest common factor calculations.  In many cases, you'll have data that is _so close_ to having a common factor, but not perfectly.

Let's see how changing the tolerance can provide a greatest common factor that's close enough (or as close as you let it be, anyway).

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ruby&quot; data-lang=&quot;ruby&quot;&gt;  &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;12&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;16&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;8&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;41&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;].&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;greatest_common_factor&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;kp&quot;&gt;nil&lt;/span&gt;
  &lt;span class=&quot;c1&quot;&gt;# but, if we add a tolerance of 1&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;12&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;16&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;8&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;41&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;].&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;greatest_common_factor&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;4&lt;/span&gt;

  &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;11&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;15&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;9&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;41&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;].&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;greatest_common_factor&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;kp&quot;&gt;nil&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;11&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;15&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;9&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;41&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;].&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;greatest_common_factor&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

Enjoy!</content>
 </entry>
 
 <entry>
   <title>Transparency, Responsibility, Accountability</title>
   <link href="http://emphaticsolutions.com/2008/09/08/transparency-responsibility-accountability.textile"/>
   <updated>2008-09-08T00:00:00+00:00</updated>
   <id>http://emphaticsolutions.com/2008/09/08/transparency-responsibility-accountability</id>
   <content type="html">&quot;Kent Beck&quot;:http://www.google.com/search?hl=en&amp;q=kent+beck speaking at RailsConf 2008.  I think this is the most interesting and poignant presentation of the year.

&lt;p&gt;&lt;embed src=&quot;http://blip.tv/play/Ace1Roa8BA&quot; type=&quot;application/x-shockwave-flash&quot; width=&quot;320&quot; height=&quot;270&quot; allowscriptaccess=&quot;always&quot; allowfullscreen=&quot;true&quot;&gt;&lt;/embed&gt; &lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>statulo.us - how getting fit somehow still involves programming</title>
   <link href="http://emphaticsolutions.com/2008/09/03/statulous-how-getting-fit-somehow-still-involves-programming.textile"/>
   <updated>2008-09-03T00:00:00+00:00</updated>
   <id>http://emphaticsolutions.com/2008/09/03/statulous-how-getting-fit-somehow-still-involves-programming</id>
   <content type="html">First, &quot;David Heinemeier Hansson&quot;:http://loudthinking.com/ spoke of &quot;the surplus&quot;:http://railsconf.blip.tv/#1170044.  Spend it on yourself, he said.  Invest in you.

What does that mean to you?  How do you interpret that? Jamis got into woodworking.  Somebody else is playing the banjo.  The ukulele perhaps?  &quot;Get out of your editor&quot;, David said, and I somehow quickly forgot about that part.

When I heard David talk about that surplus, I could easily identify.  I felt like a race car driving on city streets.  I had more to give, but couldn't find that perfect outlet.  I spent a while digging into new technologies instead.  I &quot;worked with git&quot;:http://github.com/briandoll.  I dug deeper into Ruby and Rails.  I read &quot;classic programming language textbooks.&quot;:http://www.amazon.com/Programming-Language-Pragmatics-Second-Michael/dp/0126339511/ref=sr_1_1?ie=UTF8&amp;amp;s=books&amp;amp;qid=1220498856&amp;amp;sr=1-1  Essentially, I did what I always do.

Then I went swimming.  On a trip to Tahoe in early July this year, my family and I were at a pool when I heard a lifeguard shout something I hadn't heard in years.  &quot;Adult Swim!&quot;  Sweet!  The kids hopped out (mine included) and I decided to do some laps.  The last time I swam laps in a pool, I was more concerned with Merit Badges than ROIs.  Perhaps unsurprisingly, I sucked.  I did two down-and-back laps in the olympic pool, and came up sucking wind like an idiot.  I tried to reconcile my embarrassment by thinking about the altitude.  Sure, swimming at 6k feet may be a little harder than sea level, but yours truly was out of shape!

I'm an &quot;emphatic&quot;:http://dictionary.reference.com/browse/emphatic person. I do something emphatically, or not at all.  If I was going to attempt to attain personal fitness, I was going to have to do it right.  There are all sorts of paths.  My friend Shawn is running a marathon.  I could run to the edge of my driveway if my house was on fire, but I don't think that marathon stuff would work for me.  All the stuff I saw in traditional gym settings seemed lame.  Use a stationary bike with a sweaty guy shouting at me over lame techno music?  No thanks.  I needed something intense and exciting.  I needed something fun.  This would fill my surplus.

What I needed, as it turns out, was to be &lt;a href=&quot;http://www.crossfit.com/cf-info/what-crossfit.html&quot; target=&quot;_blank&quot;&gt;Crossfit&lt;/a&gt;.  I reconnected with a friend from high school who had spent some time as a Navy Seal.  He was into this &quot;Crossfit&quot; thing, so I had to check it out.  I won't attempt to summarize for you, but do yourself a favor and check out that main website.  Crossfit is intense.  It's exciting and it's incredibly fun.

I found a &lt;a href=&quot;http://tjsgym.com&quot; target=&quot;_blank&quot;&gt;local crossfit gym&lt;/a&gt; and signed up for group classes.  I've also converted half of my garage into a reasonable home gym, but the intensity in the classes is what it's all about!  During my first class, we did a &lt;a href=&quot;http://www.crossfit.com/cf-info/excercise.html&quot; target=&quot;_blank&quot;&gt;Crossfit named workout&lt;/a&gt;, and everyone was jotting down their times in a notebook.  A notebook.  The paper kind.  See, Crossfit workouts are timed, because slow workouts are less efficient and do much less for your body.  With timing being key, folks keep workout journals on paper, on the Crossfit forum or on their own blogs.

Opportunity was knocking.  The thought of writing my workouts down in a notebook gave me the kindergarten willies, and using a forum or blog had their own set of problems.  What was my last time for &lt;a href=&quot;http://media.crossfit.com/cf-video/Josh_Greg-Fran.wmv&quot; target=&quot;_blank&quot;&gt;Fran&lt;/a&gt;?  How much have I improved in the last month?  It was all lost in paper or pagination.  Lame.

Here I was, trying to fill my surplus by getting out of my editor, and my fitness choice led me right back in.  My wife was going out of town for a weekend, so I had two solid nights of hacking available.  Constraints are wonderful.  I jotted down some ideas during the week, checked out some graphing libraries and got a general idea of what I wanted to do.

After two nights of hacking, the first version of &lt;a href=&quot;http://statulo.us&quot; target=&quot;_blank&quot;&gt;statulo.us&lt;/a&gt; went live!  I've &lt;a href=&quot;http://statulous.blogspot.com/&quot; target=&quot;_blank&quot;&gt;added several features since&lt;/a&gt;, and have accumulated a reasonably sized user base, primarily from my local gym.  The weekend project was such a testament to Rails, enabling a reasonably interesting web application, using graphs of user generated data, some RSS feeds and plenty of Crossfit-specific features.

The best part, though, is that by giving back to the Crossfit community immediately after jumping in, I get back that much more from them.  The feedback on &lt;a href=&quot;http://statulo.us&quot; target=&quot;_blank&quot;&gt;statulo.us&lt;/a&gt; has been great, and has brought me closer to my trainers and fellow Crossfiters.

This path of personal fitness has no end, and I'm looking forward to continuing my newly minted active lifestyle.   Especially now that I know it also involves programming!
&lt;h3&gt;Check out &lt;a href=&quot;http://statulo.us&quot; target=&quot;_blank&quot;&gt;statulo.us&lt;/a&gt;, the free Crossfit-based fitness tracker.  Maybe you too will fill your surplus, and be all the better for it.&lt;/h3&gt;</content>
 </entry>
 
 <entry>
   <title>New gem - rails_framework_diff</title>
   <link href="http://emphaticsolutions.com/2008/08/14/new-gem-rails_framework_diff.textile"/>
   <updated>2008-08-14T00:00:00+00:00</updated>
   <id>http://emphaticsolutions.com/2008/08/14/new-gem-rails_framework_diff</id>
   <content type="html">It started on twitter:
&lt;blockquote&gt;
It's amazing how hard it is to find problems when caused by developers incorrectly modifying framework-generated files. - &quot;Chad Fowler&quot;:http://twitter.com/chadfowler/statuses/885401839
&lt;br/&gt;&lt;br/&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
i've always wanted to write a rake task to diff framework-generated files against their generated default for that very reason. - &quot;Brian Doll&quot;:http://twitter.com/briandoll/statuses/885448580
&lt;br/&gt;&lt;br/&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
I would install that gem/plugin if you released it. - &quot;Chad Fowler&quot;:http://twitter.com/chadfowler/statuses/885554743
&lt;br/&gt;&lt;br/&gt;
&lt;/blockquote&gt;

I had been looking forward to writing another gem ever since reading the _Building a gem with BDD_ article in the initial issue of &quot;The Rubyist&quot;:http://therubyist.com/.  In that article, &quot;Jamie van Dyke&quot;:http://fearoffish.co.uk/ mentioned a gem called &quot;Mr. Bones&quot;:http://codeforpeople.rubyforge.org/bones/ for creating gem skeletons.  It differs from other similar solutions in that it's just a generator and does not insert itself as a dependency on your gems.

The problem is simple enough.  The rails command builds a project skeleton which includes many key files.  If those files are modified incorrectly, lots of badness can happen.  Since they are automatically included in all rails projects though, they can look innocuous when auditing or reviewing a rails project.  When they are the culprit, you've likely spent hours and hours reviewing everything else first.

Now, with &quot;rails_framework_diff&quot;:http://github.com/briandoll/rails_framework_diff you can quickly see a diff against the rails framework-generated defaults and those corresponding files in your project.  Nice and easy, nice and quick.

I should also note that without &quot;github&quot;:http://github.com/, not only would the process of releasing a new gem into the world take a whole lot longer, it certainly wouldn't be as fun.  This gem was conceived, developed and released on a major gem server in under two hours.  Awesome.
</content>
 </entry>
 
 <entry>
   <title>Deep Send</title>
   <link href="http://emphaticsolutions.com/2008/06/10/deep-send-how-to-wrangle-with-large-object-graphs-and-come-out-alive.textile"/>
   <updated>2008-06-10T00:00:00+00:00</updated>
   <id>http://emphaticsolutions.com/2008/06/10/deep-send-how-to-wrangle-with-large-object-graphs-and-come-out-alive</id>
   <content type="html">h3. or, How to wrangle with large object graphs and come out alive

In a perfect world, all of our objects are small, orderly and well defined.  They encapsulate data that is semantically obvious and easy to work with.  And then... in an obvious homage to &quot;Jack Handey&quot;:http://en.wikipedia.org/wiki/Jack_Handey, we attack that world with large, complex and ugly object graphs, mostly the result of monolithic integration technologies like SOAP.  

Sure, with gems like &quot;soap4r&quot;:http://dev.ctor.org/soap4r, the pain of dealing with SOAP is somewhat minimized, but at the end of the day, you're still going to have to look deep into the eyes of a huge object graph, and get at the delicate properties you so covet.

What if we were able to reference deeply nested properties from within the bowels of these large object graphs, as easily as we could with neat and orderly objects?  How nice would it be not to have to repeat yourself while asking the object graph to cough up two properties buried thirty chained-methods deep?  

h2. Deep Send

This is so simple it feels like cheating.  The deep_send method could be attached somewhere high up in the SOAP hierarchy if you wish, but I like having it available everywhere.

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ruby&quot; data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Object&lt;/span&gt;  
  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;deep_send&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;chained_methods&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;nb&quot;&gt;methods&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;chained_methods&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;split&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;.&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;nb&quot;&gt;methods&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;inject&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;object&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;method&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;object&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;send&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;method&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;     
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;  
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

As you can see, deep_send works like the regular send method, but takes chained method calls as arguments.  Let's see how this might work in a sample SOAP client:

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ruby&quot; data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;HugeNastySoapClient&lt;/span&gt;

  &lt;span class=&quot;c1&quot;&gt;# produces a magnificent cacophony of data &lt;/span&gt;
  &lt;span class=&quot;c1&quot;&gt;# elements from all across the globe&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;get_nasty_graph&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;secret_key&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;...&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;secret_key&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;method_chains&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;huge_graph&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;get_nasty_graph&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;secret_key&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;results&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[]&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;method_chains&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;each&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;method&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;results&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;huge_graph&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;deep_send&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;method&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;rescue&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;NoMethodError&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;ensure&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;results&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

In our example, we have a method appropriately called get_nasty_graph.  Let's assume this invokes a SOAP service method and returns all of it's enormous goodness.  We could write a million methods in this class to pull out a few related elements to make a reasonable API.  The problem with this is that you're always wrong.  There is always a reason to pull out three of these properties and two of those, and your API just won't accommodate.  If an object needs to use two different API methods to get all that data, it may result in two SOAP calls, which is surely no good.  Using that magic get method now allows us to construct our own method to pull out exactly what we want.  Nothing more, nothing less.

h2. Encapsulate, you must!

If we stopped here, we'd end up painting ourselves in a corner.  Requiring the users of your SOAP client to know about the deep recesses of your nasty object graph is just bad manners.  It's also a leaky abstraction, so stop it!

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ruby&quot; data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;HugeNastySoapClient&lt;/span&gt;
  &lt;span class=&quot;no&quot;&gt;NAME_ENTITY&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;some.deep.reference.to.get.to.name&quot;&lt;/span&gt;
  &lt;span class=&quot;no&quot;&gt;FIRST_NAME&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;NAME_ENTITY&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;.first_name&quot;&lt;/span&gt;
  &lt;span class=&quot;no&quot;&gt;LAST_NAME&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;NAME_ENTITY&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;.last_name&quot;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

Now that we've defined a few constants, the clients of our SOAP client can use our magic get method, without knowing how horrific it is to get at those name properties.

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ruby&quot; data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;SimpleElegentPerfectClass&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;get_full_name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;secret_key&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;now_elegant&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;HugeNastySoapClient&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;instance&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;first&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;last&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;now_elegant&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;secret_key&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; 
                                  &lt;span class=&quot;no&quot;&gt;HugeNastySoapClient&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;FIRST_NAME&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
                                  &lt;span class=&quot;no&quot;&gt;HugeNastySoapClient&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;LAST_NAME&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;first&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot; &quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;last&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

h2. Gotcha!  Order thy calls!

You may have noticed that &lt;em&gt;rescue NoMethodError&lt;/em&gt; bit in our magic get method.  Choosing to implement that method in this way is not without it's faults (ha!).  If you passed in a method chain that resulted in a NoMethodError being raised, you'll need to decide what to do.  In this example, I've chosen to swallow it and return what I got so far.  This means that the order of your method chains is significant, if there is a higher likelihood that some of them will occasionally go missing.  Isn't SOAP marshaling awesome?  You may decide, of course, to rescue the error, call the authorities and raise the threat level to red instead.  Good luck with that.  </content>
 </entry>
 
 <entry>
   <title>Things I learned at RailsConf 2008</title>
   <link href="http://emphaticsolutions.com/2008/06/04/things-i-learned-at-railsconf-2008.textile"/>
   <updated>2008-06-04T00:00:00+00:00</updated>
   <id>http://emphaticsolutions.com/2008/06/04/things-i-learned-at-railsconf-2008</id>
   <content type="html">h1. Things I learned at RailsConf 2008

There were about 2k people at &quot;RailsConf 2008&quot;:http://en.oreilly.com/rails2008/public/content/home, and like most of them, I thought of posting my review of each of the presentations I saw and heard about.  Thankfully, the masses have spoken, and there are &quot;lots of reviews for you to read elsewhere&quot;:http://www.google.com/search?hl=en&amp;amp;q=RailsConf+2008&amp;amp;btnG=Google+Search.  Also, if you want to check out some of the presentations themselves, O'Reilly is hosting &quot;many of them online&quot;:http://en.oreilly.com/rails2008/public/schedule/proceedings.

What I'd like to do instead is to document the things I learned at RailsConf, that stretch across presentations.  The first thing that I noticed were the themes that seemed to find their way into almost every session, lighting talk and hallway conversation.  There was a lot of focus on testing, deployment, automation, performance benchmarking, design (anti-)patterns and the social aspects of distributed source control management.  These are real topics, discussed in great detail by people with real experience to an impassioned audience. It was impossible not to get caught up in the energy and passion, two things that may seem at odds with the typical software conference.  Thankfully, RailsConf is anything but typical.

h2. JRuby

WIth all this talk of the various Ruby implementations, my colleagues and myself have been interested to learn more about JRuby.  I attended a few JRuby events (the &quot;hackfest&quot; on Thursday was great!) and got a much better understanding of JRuby and what sort of costs/benefits there may be in using it.

The Good:
* I was able to get a small Rails app running on JRuby in a few minutes.  It just works.
* The availability of Java types from Ruby is astoundingly simple
* Simple .war and .ear deployments can make for easy integration into a Java environment
* Using JDBC drivers and JNDI is pretty sweet
* For some applications, switching between Ruby and JRuby can be seamless.  Thoughtworks does dual-development on some projects (for reasons not explained)

The &quot;bad&quot;:
* Exception handling in Java/JRuby projects is tricky.  Exceptions wrap either a Java or JRuby exception and you must unwrap and inspect upon rescuing them.
* It is not uncommon to get Java stack traces in JRuby projects.  It would be nice if these were entirely hidden regardless of root cause.
* Windows paths for file URIs is currently broken (I reported this bug during the hackfest, &quot;JRUBY-2591&quot;:http://jira.codehaus.org/browse/JRUBY-2591)
* The ease of integration for Java libraries can turn an otherwise clean and simple Rails project into a horrific beast of amalgamation.  While this is an implementation detail and not a problem of the project, I can see a Java team not wanting to follow &quot;The Rails Way&quot;, and taking away any and all advantages of using Ruby and Rails by overusing Java.
* JRuby is essentially on par with Ruby 1.9 in most performance benchmarks.  The JRuby team will be focusing on making Rails perform better on JRuby, but for the time being it does not bring significant performance improvements. 

h2. Rails Hosting

With Engine Yard as a major sponsor of the conference, and many startups opting for hosted solutions, this was a well worn topic, with a few key insights.
* The golden ratio is 3 to 4 mongrels (or instances of your app) per CPU core.  Don't debate this, it's written in copper.
* Cache, cache, cache.  Use the same file system across your app instances so they can share page cache.  &quot;Engine Yard and others spoke highly of Red Hat's GFS system&quot;:http://www.redhat.com/gfs/.
* (Almost) nobody needs database sharding.  It is a special use case, with lots of considerations.  If you don't understand it, you probably don't need it.

h2. Building Software with a dynamic language

Neil Ford had a &quot;Design Patterns&quot; in Ruby presentation, and Obie Fernandez had an interesting talk that showcased awful Rails code, which started to identify some anti-patterns.
* The Gang of Four design patterns are all structural, in that they use objects to construct them.  In Ruby, many of these patterns are solved within the standard library, and in an elegant and simple manner.
* Dynamic languages allow you to do things that you can't conceive of when working in static languages.  The mixin/unmix portion of his presentation was good on this point.
* An interesting code smell for refactoring: If code looks visually similar, and differs only in whitespace, it's likely that you should refactor.
* An obvious notion that _should_ go without saying: Know your tools.  GitHub's rss feeds on projects (like Rails) makes for an easy time keeping up with the direction of the project, on each commit.
* OOP paradigms are still critical in Ruby and Rails projects.  A programmer without OOP experience will likely make for a terrible Rails programmer.  Thanks Obie for reiterating this point.  Don't get caught up in the &quot;blog in 20 minutes&quot; vision of what Rails is.
* Beware of Helpers that try to do too much.  They can feel anti-OO and are usually the first to break down.

h2. Scalability and Performance Monitoring

* Scalability, on large and high-volume systems, is a never-ending battle of finding and reducing bottlenecks.  There is no single solution or architecture.  Understand how your app performs, and rely only on data, not hunches.
* Someone else's benchmarks are as relevant to your application as pickles to ice cream.  Sure there is an edge case where they relate, but that's just gross.
* It's essentially impossible to benchmark a framework.  However, it may be relevant to get lots of specific performance data from lots of Rails applications to determine some relationships.  I asked Koz about this during his presentation and he has already talked to New Relic about allowing their customers to share the framework-relevant performance data with the Rails core team.
* Rely solely on real-world performance data in production when making scalability or performance-related adjustments to your system.  All else will be either time poorly spent, or will end up hurting you.
* Trending is nice, but the unexpected hockey stick graphs can still happen.  Sometimes you just hit a wall (cache sizes, max IO nodes, etc.) that you never saw coming.
* Understand the ratio of capacity to application instances.  If you are not getting close to linear growth, find out why.
* New Relic offers some great real-time performance monitoring.  Their monitor points are extensible, so you can wrap your own stuff (SOAP calls, etc.) and have it monitored automatically

h2. Testing

There were several talks on testing, and the topic came up in many others.  It's nice to see a community so focused on testing from both TDD and BDD perspectives.
* Josh Susser's obscure quote that summed up his presentation well: &quot;De gustibus non est disputandum&quot; or, There is no accounting for taste.  Josh Susser wrote test suites in all the top testing frameworks for Rails and noted that personal preference  and taste may be the only core difference.
* Some testing frameworks (Rspec) influence code design to some degree, although all were capable of helping you evolve your API during the test cycle.
* Each framework had similar levels of test code to test the same app.  None stood out as particularly terse or verbose in comparison to one another.
* It is certainly possible and in some cases ideal to mix-and-match testing frameworks.  Using test/unit for unit tests and shoulda for functional  (behavioral) testing would work well.
* &quot;unit_record&quot;:http://unit-test-ar.rubyforge.org gem allows you to run unit tests without touching the database.  Huge speed improvement, but means you need to plan accordingly when dealing with models.
* fixtures, when used for test data are evil and should be avoided.  Instead rely on a Factory pattern or Object Mother pattern which assumes reasonable defaults.
* &quot;unit_controller&quot;:http://unit-controller.rubyforge.org gem allows you to better separate controller tests from the view
* &quot;deep_test&quot;:http://deep-test.rubyforge.org gem for running tests in parallel.  Will sometimes cause problems, decent for individual developers, not for CI

During the conference, I also got a better understanding of Phusion's &quot;Passenger, a.k.a mod_rails&quot;:http://www.modrails.com/.  While I didn't attend either of their sessions, I met with one of their developers at breakfast.  They seem to have a great story for reducing the complexity of rails deployment, they leverage some of the great performance of Apache and can handle up to 20 instances of your app per Apache (+mod_rails) instance. 

Both David and Kent Beck's keynote presentations were of an inspirational nature.  While David played role of &quot;life coach&quot;, Kent Beck talked a lot about what the best perspective might be on &quot;agile&quot; development, and the various value propositions that make sense when selling ideas to the masses.  While I took several lessons away from these great presentations, it's pretty difficult to sum them up in writing.  I'm sure (better quality) videos of them both will be online soon, so you can see them for yourself.

Overall, the conference far exceeded my expectations.  It was nice to meet and hang out with a lot of the Rails community, see where our collective heads are at and learn a lot along the way.
</content>
 </entry>
 
 <entry>
   <title>Connecting to Oracle from Ruby on Rails</title>
   <link href="http://emphaticsolutions.com/2008/05/22/connecting-to-oracle-from-ruby-on-rails.textile"/>
   <updated>2008-05-22T00:00:00+00:00</updated>
   <id>http://emphaticsolutions.com/2008/05/22/connecting-to-oracle-from-ruby-on-rails</id>
   <content type="html">When Rails 2 was &quot;initially announced&quot;:http://weblog.rubyonrails.org/2007/12/7/rails-2-0-it-s-done, we heard that commercial database adapters would be maintained outside of rails core.
&lt;blockquote&gt;
	The commercial database adapters now live in gems that all follow the same naming convention: activerecord-XYZ-adapter. So if you gem install activerecord-oracle-adapter, you’ll instantly have Oracle available as an adapter choice in all the Rails applications on that machine. You won’t have to change a single line in your applications to take use of it.

That also means it’ll be easier for new database adapters to gain traction in the Rails world. As long as you package your adapter according to the published conventions, users just have to install the gem and they’re ready to roll.&lt;br/&gt;&lt;br/&gt;
&lt;/blockquote&gt;

While getting ActiveRecord to speak Oracle is available by way of just one gem, connecting to Oracle from rails can still be a touch difficult.  Here are some notes from my recent venture into Rails/Oracle land, where I came out victorious, if left feeling just a little dirty.

*The Goal*
I'll assume that the desired goal is to have an &quot;application server&quot;, which hosts your Rails app, connect to a remote database server, running some recent version of Oracle (8i+).

*Application Server*
&lt;ol&gt;
	&lt;li&gt; First, make sure you've got everything you need to run your Rails app.  Ruby, rubygems, Rails, necessary gems (vendor'd or otherwise).&lt;/li&gt;
	&lt;li&gt;Install the Oracle Client (or instant client) software for your hardware architecture.  
Note: On Linux, the client requires over 1Gb of swap space to install.  (insert snide remark about how &quot;fat&quot; the Oracle database is here)  Here are some tips on &quot;adding swap space to a UNIX system&quot;:http://www.redhat.com/docs/manuals/linux/RHL-9-Manual/custom-guide/s1-swap-adding.html.&lt;/li&gt;
	&lt;li&gt;Create a tnsnames.ora file on your app server with the connection information to your trusty, hardworking oracle database.  
(/etc/tnsnames.ora is a nice (and default) spot on UNIX systems.)&lt;/li&gt;
	&lt;li&gt;Install the &quot;ruby-oci8 gem&quot;:http://www.rubyforge.org/projects/ruby-oci8.
On UNIX systems, you'll need to build the gem, which means you'll need a fairly complete development stack including make, (g)cc, headers, etc.  I'd love to find out if there is an easier way to build this gem so it could be deployed in app/vendor/gems!&lt;/li&gt;
	&lt;li&gt;Install the activerecord-oracle-adapter gem:
&gt; gem install activerecord-oracle-adapter --source http://gems.rubyonrails.org&lt;/li&gt;
	&lt;li&gt;Configure your rails environment(s) to use the oracle database adapter:
production:
  adapter: oracle
  database: [your tns name]
  username: [your user name]
  password: [your password]&lt;/li&gt;
&lt;/ol&gt;

*Gotcha!*
Rails migrations specify modifications to your schema in a ruby syntax.  The available column types defined in a rails migration will be translated into a database-specific type during the migration.  The table below maps the ruby column types to Oracle data types:

&lt;table border=&quot;0&quot; cellspacing=&quot;5&quot; cellpadding=&quot;0&quot;&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Rails migration notation&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Oracle data type&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;:integer&lt;/td&gt;
&lt;td&gt;NUMBER(38,0)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;:float&lt;/td&gt;
&lt;td&gt;NUMBER&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;:datetime&lt;/td&gt;
&lt;td&gt;DATE&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;:date&lt;/td&gt;
&lt;td&gt;DATE&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;:timestamp&lt;/td&gt;
&lt;td&gt;DATE&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;:time&lt;/td&gt;
&lt;td&gt;DATE&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;:text&lt;/td&gt;
&lt;td&gt;CLOB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;:string&lt;/td&gt;
&lt;td&gt;VARCHAR2(255)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;:binary&lt;/td&gt;
&lt;td&gt;BLOB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;:boolean&lt;/td&gt;
&lt;td&gt;NUMBER(1,0)&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;

*Fixtures*
If you're using fixtures with an Oracle database, make sure the values in your YAML file can be translated appropriately into the corresponding Oracle data types.

One example may be the translation of a bare Fixnum (eg. 100) into a column set to :text.  Since Oracle translates :text columns into CLOBs, the Fixnum in your fixture data will need to be coerced into a String.  FAIL!  In this case, quote the values in your fixtures (eg. &quot;100&quot;).

*Further Reading*
* Obie Fernandez's article on &quot;Connecting to Oracle from Ruby on Rails&quot;:http://www.oracle.com/technology/pub/articles/fernandez-rails-connections.htm (A little dated, thus this post)
* &quot;Oracle Instant Client&quot;:http://www.oracle.com/technology/tech/oci/instantclient/index.html
* &quot;Ruby on Rails with Oracle FAQ&quot;:http://www.oracle.com/technology/pub/articles/saternos-ror-faq.html
* &quot;Tips for optimizing Rails with Oracle&quot;:http://www.oracle.com/technology/pub/articles/mearelli-optimizing-oracle-rails.html
</content>
 </entry>
 
 <entry>
   <title>Supporting unique headers per SOAP request in soap4r</title>
   <link href="http://emphaticsolutions.com/2008/05/06/soap-headers-per-request-in-ruby.textile"/>
   <updated>2008-05-06T00:00:00+00:00</updated>
   <id>http://emphaticsolutions.com/2008/05/06/soap-headers-per-request-in-ruby</id>
   <content type="html">&quot;soap4r&quot;:http://dev.ctor.org/soap4r is a SOAP implementation in Ruby.   If you're writing a SOAP client in Ruby (with or without Rails), soap4r is great.  Until it isn't.  Since this is a rather specific use case that I'm solving for, I'll assume that you have some experience using soap4r.

*Headers*
Some SOAP services will utilize a header, which is part of the SOAP spec.  A header may include information that is used to process the request, but is not part of the SOAP request message body.  It is typical for some services to use headers to send API keys or other authentication mechanisms.

&quot;Here is a simple example that ships with soap4r&quot;:http://dev.ctor.org/soap4r/browser/trunk/sample/soapheader/authheader/client2.rb

*Headers are a property of the Driver?*
Yes.  As you can tell, the SOAP driver has a property called headerhandler, which stores the header(s) that will be sent along with each service call.  The call looks like this:

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ruby&quot; data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;n&quot;&gt;driver&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;headerhandler&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;ClientAuthHeaderHandler&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;new&lt;/span&gt; &lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

Since *&lt;&lt;* is an alias to *add*, we're just adding a header to the driver here.

But what if the service requires certain unique properties in the headers of each service request?  Let's say you have a service that within the header of the SOAP request, requires that you specify the IP address of the remote host, if the service is initiated via a web browser.  In this use case, we need a unique header *per SOAP request*.

*Open up the headerhandler*
We can see that the headerhandler property of the SOAP driver holds a SOAP::Header::HandlerSet object.  Let's open 'er up.  We'll add two new methods that will allow us to set a single header on the driver, regardless of its current state.

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ruby&quot; data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;SOAP::Header::HandlerSet&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;reset&lt;/span&gt;
    &lt;span class=&quot;vi&quot;&gt;@store&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;XSD&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;NamedElements&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;new&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;set&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;header&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;reset&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;add&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;header&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

*Set and send*
Now we can do this, to set the header before we make our call:

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ruby&quot; data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;n&quot;&gt;driver&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;headerhandler&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;set&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;unique_header&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;response&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;driver&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;getFoo&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;bar&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

*Gotta synchronize!*
Since the creation of a SOAP driver is expensive (for those of us who create them on-the-fly by reading in the WSDL), it is common practice to cache the driver and reuse it each time.  (Remember that this is how we got into this mess in the first place, since the headers live on the driver, and we reuse the same driver for every request.)

It is possible, then, to have two threads interacting with your service client class, which in turn is relying on this same driver for those two requests.   The code above is not thread safe, in that the driver's headerhandler may have been set by thread1, but thread2 makes the first getFoo service call, resulting in the sending of the wrong header.  DOH!

To fix this, we'll need to wrap that call in a synchronize block:

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ruby&quot; data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;vc&quot;&gt;@@guard&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Mutex&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;new&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;...&lt;/span&gt;
&lt;span class=&quot;vc&quot;&gt;@@guard&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;synchronize&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;driver&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;headerhandler&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;set&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;unique_header&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;response&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;driver&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;getFoo&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;bar&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

Sure, it is ugly.  Since the design of soap4r is such that the headers belong to the driver, this sort of solution may be our best bet.  I look forward to any alternate suggestions.

Note: This work was in response to &quot;my original question to the soap4r forum&quot;:http://groups.google.com/group/soap4r/browse_thread/thread/d9aec7dcf5a155f7.
</content>
 </entry>
 
 <entry>
   <title>Quick Book Thoughts - The Back of the Napkin</title>
   <link href="http://emphaticsolutions.com/2008/03/24/quick-book-thoughts-the-back-of-the-napkin.textile"/>
   <updated>2008-03-24T00:00:00+00:00</updated>
   <id>http://emphaticsolutions.com/2008/03/24/quick-book-thoughts-the-back-of-the-napkin</id>
   <content type="html">With a densely populated landscape of business books out there, it's nice to see something truly unique.  &quot;Solving problems and selling ideas with pictures&quot;, reads the apt subtitle of this napkin-shaped, unassuming book that may finally be what you've been looking for.

&quot;Dan Roam&quot;:http://digitalroam.com/ has written a fun and frank book about ideating through business ideas using visual methods.  Dan focuses on the _communication_ aspect of problem solving, using simple yet surprisingly impactful techniques for expressing ideas in ways that ensure everybody &quot;gets it&quot;.

In the first two parts of The Back of the Napkin, we are  re-introduced to elements of drawings, charts and graphs.  While elemental, building from a basic foundation of shapes and defining the process of visual thinking allows each of us to see that we can and do think this way, and no, you don't have to draw well to pull it off!

The second part of this book focus on the &quot;tools and rules for good visual thinking&quot;.  Experienced visual communicators and newcomers alike will appreciate the lighthearted approach to this topic, while fans of &quot;Edward Tufte&quot;:http://www.edwardtufte.com/tufte/ will surely appreciate some similarities of perspective.

The Back of the Napkin really kicks into high gear in the third and fourth parts, Developing and Selling Ideas.  We've all seen a group of professionals get stuck going in circles when presented with a visual style that in no way fits the type of problem being discussed.  In _Developing Ideas_, we see what types of pictures are best for various problem types.  In the past, I've used this &quot;Periodic Table of Visualization Methods&quot;:http://www.visual-literacy.org/periodic_table/periodic_table.html to pick an appropriate model, but like the rest of this book, Dan describes in simple terms how to solve a &quot;How Much&quot; problem, a &quot;Where&quot; and &quot;Why&quot; problem and so on.

The Back of the Napkin shows us that simple drawings, be they on a napkin or a boardroom white board,  may very well be the most succinct, efficient and accessible way to solve problems and sell ideas.   You'll be solving the right problem, with the right visual tools, with everyone &quot;on the same page&quot;.
</content>
 </entry>
 
 <entry>
   <title>Google Calendar Sync Doesn't</title>
   <link href="http://emphaticsolutions.com/2008/03/18/google-calendar-sync-doesntgoogle-calendar-sync-doesnt.textile"/>
   <updated>2008-03-18T00:00:00+00:00</updated>
   <id>http://emphaticsolutions.com/2008/03/18/google-calendar-sync-doesntgoogle-calendar-sync-doesnt</id>
   <content type="html">Many folks were near jubilation when Google &quot;announced Google Calendar Sync&quot;:http://googleblog.blogspot.com/2008/03/google-calendar-sync.html.  It's a windows application that lives in the dock that handles the chaos involved in syncing two calendars, not to mention dealing with Exchange.  Unfortunately, for business users the _hoorah!_ did not last very long.

Users will need to pay special attention when reading the &quot;known issues&quot;:http://www.google.com/support/calendar/bin/static.py?page=known_issues.cs to find:
&lt;blockquote&gt;
	Currently, Google Calendar Sync requires that you're either the organizer or a guest on an event to sync it properly.&lt;br/&gt;&lt;br/&gt;&lt;/blockquote&gt;
Translation:
&lt;blockquote&gt;
	If you are attempting to sync an Outlook calendar that keeps appointments for you at _user@somecompany.com_ with a Google Calendar registered to _foo@gmail.com_ you're out of luck.  Unless _foo@gmail.com_ is invited to that meeting, it won't sync.&lt;br/&gt;&lt;br/&gt;&lt;/blockquote&gt;
You'll note that the FAQ did say _&quot;currently&quot;_, so hopefully this will change soon.  In the mean time, if you're not looking forward to the chaos of tools, options and hacks available to perform this syncing magic, you'll just have to check two calendars for a while longer.
</content>
 </entry>
 
 <entry>
   <title>News traveling around the internets</title>
   <link href="http://emphaticsolutions.com/2008/03/06/news-traveling-around-the-internets.textile"/>
   <updated>2008-03-06T00:00:00+00:00</updated>
   <id>http://emphaticsolutions.com/2008/03/06/news-traveling-around-the-internets</id>
   <content type="html">A few interesting tidbits came across the many diverse and often redundant news sources I pay attention to lately.  It occurred to me that there is somewhat of a natural flow to information these days.  First, some event occurs, then somebody tweets about it.. and so on it goes.  It takes a bit of time to jump from one medium to the next, and the accuracy tends to wane while the audience grows.

Here is how I see it:
&lt;img src=&quot;/images/news.png&quot;&gt;

What do you think?</content>
 </entry>
 
 <entry>
   <title>Troubleshooting Tips</title>
   <link href="http://emphaticsolutions.com/2008/01/26/troubleshooting-tips.textile"/>
   <updated>2008-01-26T00:00:00+00:00</updated>
   <id>http://emphaticsolutions.com/2008/01/26/troubleshooting-tips</id>
   <content type="html">Troubleshooting a software issue can be at once fun and frustrating.  We're elated when the problem is solved (or at least, understood), but the methodical process of troubleshooting can be as much familiar as frantic.

Here are a few troubleshooting tips we all probably know, but need reminding of from time to time:

# *Physical Layer First*
When troubleshooting systems issues, it's wise to start with the bottom layer of  &quot;the OSI model&quot;:http://en.wikipedia.org/wiki/OSI_model first.  Too many nightmares have concluded with &quot;DOH, it wasn't plugged in!&quot;
# *Talk to the birds*
It's easy to  get yourself all whirled up in a twist over some esoteric branch of the ever-growing tree of troubleshooting you're growing.  Stop.  Explain it to the little birdie on your shoulder.  I personally fire up an email to a respected colleague and start explaining the issue. Start at the beginning.  Think &quot;what will they ask me to clarify?&quot; and spell it out for them.  By the time you've got a page full of explaining done, you'll likely see  the error in your ways.  I've written hundreds of these emails and probably only ever had to send one or two.
# *&quot;When you hear hooves, think horses, not zebras&quot;*
Sure, we'd all love to have our issue turn out to be so complex that it took an understanding of solar flares to solve.  You're a genius, certainly.  It's much more likely however that your problem is more common in nature.  Troubleshooting may lead us to all sorts of potential possibilities, but the more simple answer is likely the cause.
# *Yes, it may just be a bug*
A friend of mine was working with a SOAP web service in Ruby recently and found himself with an issue.  Attributes  on some XML properties just went missing when converted with soap4r.  &quot;It turned out to  be a known bug.&quot;:http://dev.ctor.org/soap4r/ticket/450  While this may seem obvious, sometimes when we feel less comfortable with a new (to us) technology it's easy to think that you're &quot;just missing something&quot;.  Notice that this is listed at the end!  It doesn't hurt to search for known bugs when troubleshooting early on, but make sure you've tried the other steps too before giving up and moving on.

Good Luck!
</content>
 </entry>
 
 <entry>
   <title>Quick Book Thoughts - Presentation Zen</title>
   <link href="http://emphaticsolutions.com/2008/01/06/quick-book-thoughts-presentation-zen.textile"/>
   <updated>2008-01-06T00:00:00+00:00</updated>
   <id>http://emphaticsolutions.com/2008/01/06/quick-book-thoughts-presentation-zen</id>
   <content type="html">I've been anticipating the release of &quot;Presentation Zen&quot;:http://www.amazon.com/Presentation-Zen-Simple-Design-Delivery/dp/0321525655/ref=pd_bbs_sr_1?ie=UTF8&amp;amp;s=books&amp;amp;qid=1199680549&amp;amp;sr=8-1 by &quot;Garr Reynolds&quot;:http://www.presentationzen.com/ for a few months now.  My copy arrived on Friday, the first of three days without electricity due to a bit of a storm we've had out here in Northern California.

The book was fun to read in all respects and the design of the book itself, along with the presentation samples inside, are truly elegant.

From the review I posted to &quot;Amazon&quot;:http://www.amazon.com/review/R1TP5I5NNSDOZD/ref=cm_cr_rdp_perm and &quot;Shelfari&quot;:http://www.shelfari.com/books/3604846/Presentation-Zen-Simple-Ideas-on-Presentation-Design-and-Deliver:
&lt;blockquote&gt;
The evolving interconnectedness of our social and business communities relies heavily on our ability to communicate with one another. As some communication has become more ephemeral (email, IM), others have become slightly more formal (presentations), involving a larger and often diverse audience.

Garr Reynolds has produced and incredibly beautiful book highlighting the virtues of a zen aesthetic as it applies to communication, and more specifically, presentations.

This book brings a sense of mindfulness to the &quot;art&quot; of presenting, which covers the multiple stages of presentation from idea to stage. Reading it once was a joy, but I'm sure that I'll be reaching for this book as a source of inspiration and reference when embarking on a presentation of any kind.

This book is a true gem, highly recommended.
&lt;/br&gt;&lt;/br&gt;
&lt;/blockquote&gt;</content>
 </entry>
 
 <entry>
   <title>ActionWebService on Rails 2</title>
   <link href="http://emphaticsolutions.com/2007/12/18/actionwebservice-on-rails-2.textile"/>
   <updated>2007-12-18T00:00:00+00:00</updated>
   <id>http://emphaticsolutions.com/2007/12/18/actionwebservice-on-rails-2</id>
   <content type="html">Well, I can't just say _nothing_ about the recent release of Rails 2 _(.0.2)_, right?

One of the apps I'm working on uses a SOAP web service.  I know, how old skool.  As you have likely read, &quot;ActionWebService (AWS) has been ousted from rails core.&quot;:http://weblog.rubyonrails.org/2007/12/7/rails-2-0-it-s-done

While I certainly don't know enough about the intricacies of the ruby load path(s) as they pertain to gems (frozen or unfrozen), the suggestion to just _gem install actionwebservice_ just doesn't seem to work.

&quot;Zack Chandler @ Depixelate shows us how it's done&quot;:http://www.depixelate.com/2007/12/13/actionwebservice-with-rails-2-0

Thanks again Zack!</content>
 </entry>
 
 <entry>
   <title>Blocks, Closures and The Ruby Way</title>
   <link href="http://emphaticsolutions.com/2007/12/05/blocks-closures-and-the-ruby-way.textile"/>
   <updated>2007-12-05T00:00:00+00:00</updated>
   <id>http://emphaticsolutions.com/2007/12/05/blocks-closures-and-the-ruby-way</id>
   <content type="html">I recently attended my first &quot;Ruby Meetup&quot;:http://ruby.meetup.com/6/calendar/6597195/ here in San Francisco.  One of the talks, given by &quot;Bala&quot;:http://ruby.meetup.com/6/members/3936949/ was on &quot;Blocks&quot; in Ruby.

Let me first say that I have somewhat of a crush on Ruby right now.  I haven't been this excited about hacking at some code in ages.  Ruby is a dynamic language, letting me do things I used to do in Perl, but in a way that seems clean and concise.  I won't dare talk ill of Perl, but I'm betting you know what I mean.

Ruby is simple.  So simple in fact that it uses a very simple term to describe something that by its very name is confusing.  I'm talking about &quot;closures.&quot;:http://en.wikipedia.org/wiki/Closure_%28computer_science%29  Just like all Bourbons are Whisky but not all Whiskies are Bourbon, Ruby closures stem from blocks, but not all blocks are closures.  Got it?  Good.

To be honest, I never really _got_ closures until recently.  I knew what they were, but the language I've been working in for most of my salaried work in recent memory has not been known to be able to spell closure.  Just like any other significant and interesting programming idiom, when I wanted to learn more, I turned to the master, &quot;Martin Fowler&quot;:http://martinfowler.com/bliki/.

Martin has two interesting articles up on closures &quot;here&quot;:http://martinfowler.com/bliki/Closure.html and &quot;here&quot;:http://martinfowler.com/bliki/CollectionClosureMethod.html.  I  don't aim to restate his thoughts nor quote him here, so if you're interested in blocks or closures you really should read them.

During the Ruby Meetup, Bala talked about the various ways to use blocks, and in some examples used blocks as closures.  One of the very common use cases for blocks (and noted in the articles by MF) is with the various collection methods available like _each, select and collect._

I'm working on a project where I have a reasonably complicated sort routine.  I leverage a class or two that contain methods to better process the elements in my array to get to a single representative element that I can use to compare elements against, to finally get to a sort that I can live with.

In my existing code, this is implemented on a collection (an Array) where by I pass in this sorting block to the sort method of the array.  Standard fare.  Nothing interesting really.

But how do I test it now?  For a while there, I had this sort routine built as a class method in one of my library classes.  As Martin Fowler has said of this behavior, _&quot;no decent rubyist would write this&quot;_.  While the block-based solution is cool and fits with &quot;The Ruby Way&quot;:http://www.amazon.com/Ruby-Way-Second-Addison-Wesley-Professional/dp/0672328844, it's anonymous, which makes it hard to exercise in unit tests.

As I'm searching around for more depth on Ruby blocks and Closures, I found &quot;this article&quot;:http://www.artima.com/intv/closures.html with &quot;Matz&quot;:http://en.wikipedia.org/wiki/Yukihiro_Matsumoto which contains quotes like this:
&quot;In fact, in early versions of Ruby, the methods called with blocks were referred to as iterators, because they were designed to iterate. But in the history of Ruby, the role of blocks was later enhanced from loop abstraction to anything.&quot;

&quot;Jamis Buck&quot;:http://weblog.jamisbuck.org/ (Rails core developer, 37 Signals employee) chimes in to let us know that &quot;blocks rock&quot;:http://weblog.jamisbuck.org/2007/1/19/blocks-rock.  In his blog post, Jamis shows how blocks can be used to DRY up  code in what is also called the &quot;execute around method&quot;:http://www.smallmemory.com/almanac/Beck97.html that first(?) appeared in &quot;Kent Beck's&quot;:http://en.wikipedia.org/wiki/Kent_Beck &quot;Smalltalk Best Practices&quot;:http://www.amazon.com/Smalltalk-Best-Practice-Patterns-Kent/dp/013476904X book.

So.. where we were?  Blocks rock.  Closures are cool, and if you have some thoughts about how to best test blocks, be they sorting routines or otherwise, please leave your thoughts in the comments.</content>
 </entry>
 
 <entry>
   <title>Dancing with dynamic features in Ruby</title>
   <link href="http://emphaticsolutions.com/2007/11/04/dancing-with-dynamic-features-in-ruby.textile"/>
   <updated>2007-11-04T00:00:00+00:00</updated>
   <id>http://emphaticsolutions.com/2007/11/04/dancing-with-dynamic-features-in-ruby</id>
   <content type="html">I was working on a &quot;browse&quot; page recently for a rails-based web application.  The page was not all that uncommon, requiring a listing of categories with a long list of subcategories.  Without getting into much detail, I'll note that each of these top-level types are represented by different models.

A particular &quot;bad smell&quot; emerged when seeing some repetitious code in a controller:

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ruby&quot; data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;n&quot;&gt;mfgs&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Manufacturer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;find&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:all&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:select&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;name&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;vi&quot;&gt;@manufacturers&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;mfgs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;join&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;, &quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;vi&quot;&gt;@manufacturers_count&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;mfgs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;length&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;archs&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Architecture&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;find&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:all&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:select&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;name&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;  
&lt;span class=&quot;vi&quot;&gt;@architectures_count&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;archs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;length&lt;/span&gt;  
&lt;span class=&quot;vi&quot;&gt;@architectures&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;archs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;join&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;, &quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;  
   
&lt;span class=&quot;n&quot;&gt;platforms&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Platform&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;find&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:all&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:select&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;name&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;  
&lt;span class=&quot;vi&quot;&gt;@platforms_count&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;platforms&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;length&lt;/span&gt;  
&lt;span class=&quot;vi&quot;&gt;@platforms&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;platforms&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;join&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;, &quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

Not only does this code repeat the same pattern for each &quot;type&quot;, but there were likely to be more types that needed to be added in.

Time for some refactoring.  &quot;Now if only there was a way to dynamically add instance variables to an object...&quot;

First, lets get a simple array of our types:

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ruby&quot; data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;n&quot;&gt;types&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;Manufacturer&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;Architecture&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;Platform&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

For each type, we’ll get a handle on the class with that name:

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ruby&quot; data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;n&quot;&gt;types&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;each&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;model&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Object&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;const_get&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

We’ll execute our ActiveRecord statement

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ruby&quot; data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;n&quot;&gt;listing&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;model&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;find&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:all&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:select&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;name&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

Get an array of the “name” property

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ruby&quot; data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;n&quot;&gt;names&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;listing&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

Now, we’ll create those instance variables on the object, the first being a comma-separated listing of the names:

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ruby&quot; data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;nb&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;instance_variable_set&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;@&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;names&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;join&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;, &quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

The second being a count of the elements:

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ruby&quot; data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;nb&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;instance_variable_set&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;@&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;_count&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;names&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;length&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

We could get into why we need those two variables (one for the list and another for the count), but I think this is a nice example of how to use instance_variable_set anyway. Ruby. Dynamic. Awesome.

The full snippet:

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ruby&quot; data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;n&quot;&gt;types&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;Manufacturer&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;Architecture&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;Platform&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;  
&lt;span class=&quot;n&quot;&gt;types&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;each&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;  
  &lt;span class=&quot;n&quot;&gt;model&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Object&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;const_get&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;  
  &lt;span class=&quot;n&quot;&gt;listing&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;model&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;find&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:all&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:select&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;name&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;  
  &lt;span class=&quot;n&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;downcase&lt;/span&gt;  
  &lt;span class=&quot;n&quot;&gt;names&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;listing&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;  
  &lt;span class=&quot;nb&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;instance_variable_set&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;@&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;names&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;join&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;, &quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;  
  &lt;span class=&quot;nb&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;instance_variable_set&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;@&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;_count&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;names&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;length&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;  
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;</content>
 </entry>
 
 <entry>
   <title>Leaky abstractions, seepage of a dangerous kind</title>
   <link href="http://emphaticsolutions.com/2007/10/26/leaky-abstractions-seepage-of-a-dangerous-kind.textile"/>
   <updated>2007-10-26T00:00:00+00:00</updated>
   <id>http://emphaticsolutions.com/2007/10/26/leaky-abstractions-seepage-of-a-dangerous-kind</id>
   <content type="html">&lt;small&gt;(This is an excerpt from an article I wrote at my day job.  Specifics about team members and the projects at hand have been removed.)&lt;/small&gt;

*What are leaky abstractions?*
The term _leaky abstractions_ comes from a posting by &quot;Joel Spolsky&quot;:http://www.joelonsoftware.com/ entitled &quot;The Law of Leaky Abstractions&quot;:http://www.joelonsoftware.com/articles/LeakyAbstractions.html where he noted *&quot;All non-trivial abstractions, to some degree, are leaky.&quot;* While this sounds like a great excuse to say when your code is found to be a bit drippy, in most cases making our abstractions as complete and non-leaky as possible is actually a trivial task.

The &quot;wikipeida article&quot;:http://en.wikipedia.org/wiki/Leaky_abstraction describes leaky abstractions as *&quot;A leaky abstraction is an unsatisfactory implementation of an abstraction.&quot;*

This is an especially good way of understanding the main problem with leaky abstractions. The abstraction exists, like a domain object that exists in your application, but the implementation is unsatisfactory in that it exposes specific details of a separate layer of abstraction (in this case, XmlBean types).

*How about some more examples?*
Leaky abstractions can and do occur in all sorts of problem domains.

In the his post that coined the term, Joel Spolsky described TCP as being a leaky abstraction on top of IP. TCP acts like a tirelessly dedicated traffic cop to the aimless and simple minded drivers that clog our information super highway (or is it a series of tubes?). The problem is, to continue this car crash of an analogy, that sometimes the highway itself can be plucked out and tossed to the ground of the NOC in another spaghetti pile of cat5 cables. Since TCP alone can't protect you from the backhoe that slices your network cable, it's unable to get those happy little packets to your browser as you had hoped.

More on TCP issues as they pertain to web apps:
&lt;blockquote&gt;
*Why do I care about little old &quot;layer 4&quot;:http://en.wikipedia.org/wiki/OSI_model*
TCP issues, like extremely slow transmission speeds between two endpoints, can easily creep up the many layers of abstractions of your application code and wreak havoc like you never expected. &quot;Michael Nygard's&quot;:http://www.michaelnygard.com/  book &quot;Release It!&quot;:http://www.pragprog.com/titles/mnee/index.html  addresses many of these issues with patterns, anti-patterns and real-life postmortems that show how we can find and fix these common issues that are rarely addressed.&lt;br/&gt;&lt;br/&gt;
&lt;/blockquote&gt;
OK, back to those pesky leaky abstractions. How about HTML? That seems simple enough. The early days of HTML gave us abilities of composing paragraphs of text documents and linking them up together. Soon after though, the language that defined the _structure_ of the document soon began to define the _style_ of the document. This bad smell is similar to what &quot;Bob&quot; referred to as &quot;Mixed Metaphors&quot;. Later versions of HTML attempt to address this issue by excluding many style-oriented tags, preferring instead to use CSS for styling the HTML document.

*So now what?*
It's a great idea to look for these leaky abstractions during code reviews. When you're writing code though, try to give some reverence to the abstraction that you're working on. In a typical MVC architecture, you should pretend to know nothing about you data access layer when authoring code in the view tier. When interacting with a domain object, you should know nothing about the XML marshaling technology behind it's properties, or even that the data came from a web service in the first place. When you wonder to yourself &quot;why would I care about that (level of detail)&quot;, it's likely that you have stumbled upon a leaky abstraction.

When it comes to abstractions, the band &quot;The Offspring&quot;:http://wc04.allmusic.com/cg/amg.dll?p=amg&amp;amp;sql=11:3pfqxqt5ldfe%7ET1 know just what to say: &quot;You gotta keep 'em separated&quot;

*The counter argument:*
You'll sometimes hear this quote by &quot;Butler Lampson&quot;:http://en.wikipedia.org/wiki/Butler_Lampson *&quot;All problems in computer science can be solved by another level of indirection&quot;*, which when lined up right next to &quot;Donald Knuth's&quot;:http://en.wikipedia.org/wiki/Donald_Knuth *&quot;Premature optimization is the root of all evil ...&quot;* can make it sound like abstractions themselves are the problem.

The balancing act here is between the benefits of abstraction with the requirements of performance. The penalty of poor performance, brought on by extraneous abstraction, requires additional physical resources. The penalty of leaky abstractions however, can be paid only in blood, sweat and tears.</content>
 </entry>
 
 <entry>
   <title>Testing - Static vs. Dynamic Typing</title>
   <link href="http://emphaticsolutions.com/2007/09/28/testing-static-vs-dynamic-typing.textile"/>
   <updated>2007-09-28T00:00:00+00:00</updated>
   <id>http://emphaticsolutions.com/2007/09/28/testing-static-vs-dynamic-typing</id>
   <content type="html">Cedric Beust recently wrote an article entitled &quot;Continuous Tax&quot;:http://beust.com/weblog/archives/000462.html where he describes the term &quot;Continuous Tax&quot; to be &quot;dead-on&quot; in describing what it's like to work with dynamically typed languages.

This topic interests me for a variety of reasons but mostly because Cedric is quite authoritative in the world of software testing, what with the &quot;framework&quot;:http://testng.org/doc/ and the &quot;book&quot;:http://beust.com/weblog/archives/000459.html and all.

I &quot;commented&quot;:http://beust.com/weblog/archives/000462.html#comments on his post and to my delight, &quot;he responded&quot;:http://beust.com/weblog/archives/000463.html.

I can't say that I disagree that static typing is akin to &quot;free tests&quot;, as you may decide you need to write those types of tests in dynamic language.  These tests however, are not free.  They come with a cost of dealing with types in the first place.  This is less of a discussion about the maintainability of software systems as it is one of values.

To quote myself:
&lt;blockquote&gt;
Typically when discussing this religious topic (it's a debate about values, as one is not superior to others in all circumstances) ...&lt;br/&gt;&lt;br/&gt;
&lt;/blockquote&gt;
	
What needs to be decided, on a project by project basis, is what things you'll value most.

Here is a little snippet of &quot;Martin Fowler's thoughts on the typing thing&quot;:http://martinfowler.com/bliki/DynamicTyping.html (the &quot;we&quot; refers to himself and &quot;Bruce Eckel&quot;:http://www.mindview.net/):
&lt;blockquote&gt;
...we both agreed that one of the most frustrating things about the static/dynamic typing debate is that it's very hard to put into words the advantages of working in a dynamically typed language. Somehow things just seem to flow better when you're programming in that environment...&lt;br/&gt;&lt;br/&gt;
&lt;/blockquote&gt;</content>
 </entry>
 
 <entry>
   <title>Drag and drop AppleScript to convert video</title>
   <link href="http://emphaticsolutions.com/2007/07/28/drag-and-drop-apple-script-to-convert-video.textile"/>
   <updated>2007-07-28T00:00:00+00:00</updated>
   <id>http://emphaticsolutions.com/2007/07/28/drag-and-drop-apple-script-to-convert-video</id>
   <content type="html">My parents were kind enough to get us a &quot;JVC Everio digital video camera&quot;:http://www.jvc.com/presentations/everio_g/ after our son was born. The camera has incredible picture quality, loads of features and fits in the palm of your hand. We shot loads of video of his first few weeks and soon enough it came time to make our first DVD to send to friends and relatives.

It turns out the Everio cameras create .mod files, which are similar to MPG files, but.. um.. aren't. I'm guessing this was a way to avoid paying royalties for MPG compression, but this does leave a little bit of leg work for the user. (And *no*, you can't just rename them to .mpg, I have no idea why most websites suggest that as they are not compatible.)

After some quick digging, I found &quot;ffmpegx&quot;:http://www.ffmpegx.com/ for the mac which provides a nice GUI to convert various video types. This is all well and good, but we had become quite the shutterbugs and I was not about to use a GUI to process a hundred individual clips (this was especially difficult seeing that your settings need to be re-done each time).

Luckily, ffmpegx also ships with the command line interface, ffmpeg2. Now we're getting somewhere. I start playing around with a recursive AppleScript script that would process nested folders of .mod video files and converting them to .dv files (which are the default/preferred format for iMovie HD).

The results are as follows.  This script is licensed under the do-what-ever-you-want-with-it license.  Enjoy.

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-applescript&quot; data-lang=&quot;applescript&quot;&gt;&lt;span class=&quot;c1&quot;&gt;-- &lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;c1&quot;&gt;-- convertMod2Dv.app&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;c1&quot;&gt;-- &lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;c1&quot;&gt;-- a simple apple script applet to convert .mod files to .dv files&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;c1&quot;&gt;-- this is an essential step for those of us who own DV video cameras&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;c1&quot;&gt;-- that use this .mod file format, but would also like to edit those videos&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;c1&quot;&gt;-- in iMove HD or other editing apps. This applet was developed solely to&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;c1&quot;&gt;-- provide drag-n-drop functionality to the command line tool ffmpeg2.&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;c1&quot;&gt;-- It supports dragging individual files or folders of files, etc.&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;c1&quot;&gt;--&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;

&lt;/span&gt;&lt;span class=&quot;c1&quot;&gt;-- PROPERTIES OF THIS APPLET, MODIFY TO SUIT&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;c1&quot;&gt;-- &lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;c1&quot;&gt;-- just work on mod files, nothing else property extension_list : {&quot;MOD&quot;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;c1&quot;&gt;-- path to ffmpeg property ffmpeg : &lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;/Applications/MULTIMEDIA/VIDEO/ffmpegx.app/Contents/Resources/ffmpeg2&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;c1&quot;&gt;-- append to file name when converting to DV property new_suffix : &quot;.converted.DV&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;c1&quot;&gt;-- converted movie count&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;property&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;movie_count&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;

&lt;/span&gt;&lt;span class=&quot;c1&quot;&gt;-- Applet Code&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;c1&quot;&gt;-- &lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;c1&quot;&gt;-- The following appears only when the droplet is double clicked&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;on&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;run&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;display dialog&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;convertMod2Dv.app&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;return&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;return&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;Convert a MOD w/Audio to a DV file&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;return&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;return&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;To convert .MOD files to .DV for editing, just drag the files
    or folders of files onto this applet. The resulting converted .DV
    movie files will be right along side the originals!&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;return&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;return&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;Enjoy!&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;run&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
 
&lt;/span&gt;&lt;span class=&quot;c1&quot;&gt;-- This droplet processes both files or folders of files dropped onto the applet&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;on&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;open&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;these_items&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;repeat&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;with&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;from&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;to&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;the&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;count&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;of&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;these_items&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;set&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;this_item&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;to&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;item&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;of&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;these_items&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;set&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;the&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;item_info&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;to&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;info for&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;this_item&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;folder&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;of&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;the&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;item_info&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;ow&quot;&gt;is&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;then&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;process_folder&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;this_item&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;else&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;alias&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;of&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;the&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;item_info&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;ow&quot;&gt;is&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;ow&quot;&gt;and&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;the&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;na&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;extension&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;of&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;the&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;item_info&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;ow&quot;&gt;is in&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;the&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;extension_list&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;then&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;process_item&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;this_item&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;repeat&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  
  &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;display dialog&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;Converted &quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;movie_count&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot; Movie(s).&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;return&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;return&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;Enjoy!&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;  
&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;open&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;

&lt;/span&gt;&lt;span class=&quot;c1&quot;&gt;-- this sub-routine processes folders&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;on&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;process_folder&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;this_folder&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;set&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;these_items&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;to&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;list folder&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;this_folder&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;without&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;invisibles&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;repeat&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;with&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;from&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;to&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;the&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;count&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;of&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;these_items&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;set&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;this_item&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;to&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;alias&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;this_folder&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;as &lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;text&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;item&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;of&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;these_items&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;set&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;the&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;item_info&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;to&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;info for&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;this_item&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;folder&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;of&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;the&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;item_info&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;ow&quot;&gt;is&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;then&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;process_folder&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;this_item&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;else&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;alias&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;of&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;the&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;item_info&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;ow&quot;&gt;is&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;ow&quot;&gt;and&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;the&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;na&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;extension&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;of&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;the&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;item_info&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;ow&quot;&gt;is in&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;the&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;extension_list&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;then&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;process_item&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;this_item&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;repeat&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;process_folder&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;

&lt;/span&gt;&lt;span class=&quot;c1&quot;&gt;-- this sub-routine processes files&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;on&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;process_item&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;this_item&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;c1&quot;&gt;-- NOTE that the variable this_item is a file reference in alias format&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;set&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;full_path&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;to&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;the&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;POSIX&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;na&quot;&gt;path&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;of&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;this_item&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;c1&quot;&gt;-- !!! MODIFY THESE PARAMETERS TO SUIT if you have other preferences you'd like to use&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;do shell script&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;ffmpeg&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot; -i &quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;full_path&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot; -target dv -aspect 16:9 &quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;full_path&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;new_suffix&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;set&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;movie_count&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;to&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;movie_count&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;process_item&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
 
 
&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;on&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;getFileName&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;thefile&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;set&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;oldDelims&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;AppleScript&lt;/span&gt;'s &lt;span class=&quot;nb&quot;&gt;text item delimiters&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;to&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;AppleScript&lt;/span&gt;'s &lt;span class=&quot;nb&quot;&gt;text item delimiters&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;:&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;set&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;mytextfilename&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;to&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;last&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;text&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;item&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;of&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;thefile&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;as &lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;text&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;set&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;AppleScript&lt;/span&gt;'s &lt;span class=&quot;nb&quot;&gt;text item delimiters&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;to&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;oldDelims&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;return&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;mytextfilename&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;getFileName&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

To fork this code and make improvements, it's available as &quot;a gist.&quot;:http://gist.github.com/5748</content>
 </entry>
 
 <entry>
   <title>Software Engineering Book Recommendations</title>
   <link href="http://emphaticsolutions.com/2007/06/28/software-engineering-book-recommendations.textile"/>
   <updated>2007-06-28T00:00:00+00:00</updated>
   <id>http://emphaticsolutions.com/2007/06/28/software-engineering-book-recommendations</id>
   <content type="html">I always find it fascinating what books people prefer on various topics. I put together the following list of books I really enjoy, broken down by category. Please feel free to add to the list, or to comment on the selections.

h3. People, Projects and surviving them both

If only software development were as simple as writing a bit of code. Here are some good books that help us better understand and survive our evolving landscape.

* *Getting Things Done* (&quot;@amazon&quot;:http://www.amazon.com/Getting-Things-Done-Stress-Free-Productivity/dp/0142000280/)
Sure, it's not specifically written with the software developer in mind, but is surely one of the best personal productivity methods out there. Yes, I drank the kool-aid fullstop!
* *Peopleware* (&quot;@bookpool&quot;:http://www.bookpool.com/sm/0932633439 )(&quot;@amazon&quot;:http://www.amazon.com/Peopleware-Productive-Projects-Teams-2nd/dp/0932633439/sr=1-1/qid=1172188899/ref=pd_bbs_sr_1/104-0433560-4352764?ie=UTF8&amp;amp;s=books)
There is a good reason why everybody and their brother recommends this book. A great book that clearly discusses the human element of software development. It's somehow reassuring to read this classic again and again, knowing that some things never change. (the new edition has some chapters (c)2000).
* *Ship It!* (&quot;@bookpool&quot;:http://www.bookpool.com/sm/0974514047) (&quot;@amazon&quot;:http://www.amazon.com/Practical-Guide-Successful-Software-Projects/dp/0974514047/sr=1-1/qid=1172189083/ref=pd_bbs_sr_1/104-0433560-4352764?ie=UTF8&amp;amp;s=books)
Simple common-sense advice for development teams to instill a repeatable sense of quality in their projects.
* *Applied Software Project Management* (&quot;@bookpool&quot;:http://www.bookpool.com/sm/0596009488) (&quot;@amazon&quot;:http://www.amazon.com/Applied-Software-Project-Management-Stellman/dp/0596009488/sr=1-1/qid=1172189281/ref=pd_bbs_sr_1/104-0433560-4352764?ie=UTF8&amp;amp;s=books)
Going with another simple recommendation here. PM books can make your eyes bleed and from the perspective of Agile development most of those same books tend to be full of useless metrics anyway. This is another common-sense book that serves as a good reminder of the no-fuss basics of good project management are.
* *Crystal Clear: A Human-Powered Methodology for Small Teams* (&quot;@amazon&quot;:http://www.amazon.com/Crystal-Clear-Human-Powered-Methodology-Development/dp/0201699478/sr=8-1/qid=1172523510/ref=pd_bbs_sr_1/105-1988709-1476447?ie=UTF8&amp;amp;s=books)
Another small yet very useful book on things that will allow you to make good software. The author even distills the book into a single page as a super quick overview. One issue that we see affecting us is the physical separation of teams - this is seen as a critical element to making good software in the book; unfortunately we&amp;#8217;re not in a place to have that option.

h3. Creating better software

It's been said that every single piece of software on earth could be written a little smaller, run a little faster and it&amp;#8217;s documentation could always be a wee bit better. Here are some books that aim to help in that noble pursuit.

* *Refactoring: Improving the Design of Existing Code* (&quot;@bookpool&quot;:http://www.bookpool.com/sm/0201485672) (&quot;@amazon&quot;:http://www.amazon.com/Refactoring-Improving-Design-Existing-Code/dp/0201485672/sr=8-1/qid=1172203278/ref=pd_bbs_sr_1/104-0433560-4352764?ie=UTF8&amp;amp;s=books)
Because all code can be better. I think this is the single greatest book on improving software that has ever been written. I can't possibly love this book more.
* *Code Complete* (&quot;@bookpool&quot;:http://www.bookpool.com/sm/0735619670) (&quot;@amazon&quot;:http://www.amazon.com/Code-Complete-Second-Steve-McConnell/dp/0735619670/sr=1-1/qid=1172205925/ref=pd_bbs_sr_1/104-0433560-4352764?ie=UTF8&amp;amp;s=books)
An award winning guide on software best practices.
* *The Pragmatic Programmer* (&quot;@bookpool&quot;:http://www.bookpool.com/sm/020161622X) (&quot;@amazon&quot;:http://www.amazon.com/Pragmatic-Programmer-Journeyman-Master/dp/020161622X/sr=1-1/qid=1172206024/ref=pd_bbs_sr_1/104-0433560-4352764?ie=UTF8&amp;amp;s=books)
A true must-read for everyone involved in the craft of software engineering.


h3. Architecture and Design

Focusing on beautiful, thoughtful and elegant object oriented design.

* *Head First Design Patterns* (&quot;@bookpool&quot;:http://www.bookpool.com/sm/0596007124) (&quot;@amazon&quot;:http://www.amazon.com/Head-First-Design-Patterns/dp/0596007124/sr=1-1/qid=1172207449/ref=pd_bbs_sr_1/104-0433560-4352764?ie=UTF8&amp;amp;s=books)
A nice gentle guide through the ever-popular design patterns made popular by &quot;the GoF&quot;:http://www.bookpool.com/sm/0201633612
* *Thinking in Java* (&quot;@bookpool&quot;:http://www.bookpool.com/sm/0131872486) (&quot;@amazon&quot;:http://www.amazon.com/Thinking-Java-4th-Bruce-Eckel/dp/0131872486/sr=1-1/qid=1172207706/ref=pd_bbs_sr_1/104-0433560-4352764?ie=UTF8&amp;amp;s=books)
An incredibly detailed and well written journey through the world of Java.
* *Object-Oriented Design Heuristics* (&quot;@bookpool&quot;:http://www.bookpool.com/sm/020163385X) (&quot;@amazon&quot;:http://www.amazon.com/Object-Oriented-Design-Heuristics-Arthur-Riel/dp/020163385X/sr=1-1/qid=1172208105/ref=pd_bbs_sr_1/104-0433560-4352764?ie=UTF8&amp;amp;s=books)
This book outlines nearly 100 heuristics for object oriented design. The inside cover of this book lists the heuristics described within, which is a great reference when performing code reviews, or looking to refactor your own code.
* *The Object Primer: Agile Model-Driven Development with UML* (&quot;@bookpool&quot;:http://www.bookpool.com/sm/0521540186) (&quot;@amazon&quot;:http://www.amazon.com/Object-Primer-Agile-Model-Driven-Development/dp/0521540186/sr=1-1/qid=1172208494/ref=pd_bbs_sr_1/104-0433560-4352764?ie=UTF8&amp;amp;s=books)
A great read and a wonderful reference for object oriented design, along with best practices for modeling those designs with UML.
* *A Software Architecture Primer* (&quot;@amazon&quot;:http://www.amazon.com/Software-Architecture-Primer-John-Reekie/dp/0646458418/sr=1-1/qid=1172208676/ref=sr_1_1/104-0433560-4352764?ie=UTF8&amp;amp;s=books)
A truly simple approach to describing the art of software architecture. A really great book to skim through at the beginning of every project.
* *Database Design for Mere Mortals* (&quot;@bookpool&quot;:http://www.bookpool.com/sm/0201752840) (&quot;@amazon&quot;:http://www.amazon.com/Database-Design-Mere-Mortals-Hands/dp/0201752840/sr=1-1/qid=1172208880/ref=pd_bbs_sr_1/104-0433560-4352764?ie=UTF8&amp;amp;s=books)
Because databases, like the software they support, are as different as snowflakes. A great guide to the multitude of database design concepts and their appropriate uses.


h3. Technology Specific
* *Effective Java* (&quot;@amazon&quot;:http://www.amazon.com/Effective-Java-Programming-Language-Guide/dp/0201310058/sr=1-1/qid=1172524024/ref=pd_bbs_sr_1/105-1988709-1476447?ie=UTF8&amp;amp;s=books)
This book goes beyond Java grammar and vocabulary (e.g. if and public class Foo to language &lt;strong&gt;usage&lt;/strong&gt;. e.g. Always override hashcode() when you override equals. Joshua Bloch designed and implemented the 1.2 Collections framework, so he is considered not only a scholar on the subject of writing good java code, but also one of its most authoritative practitioners.
* *Agile Development with Rails* (&quot;@bookpool&quot;:http://www.bookpool.com/sm/0977616630) (&quot;@amazon&quot;:http://www.amazon.com/Agile-Development-Rails-Pragmatic-Programmers/dp/0977616630/sr=1-1/qid=1172209239/ref=pd_bbs_sr_1/104-0433560-4352764?ie=UTF8&amp;amp;s=books)
The definitive, Jolt-award winning guide to learning and using Rails is now in its Second Edition. Rails is a new approach to web-based application development that enables developers to create full-featured, sophisticated web-based applications using less code and less effort. Now programmers can get the job done right and still leave work on time. - lofty book description from the publisher.
* *Pro Spring* (&quot;@bookpool&quot;:http://www.bookpool.com/sm/1590594614) (&quot;@amazon&quot;:http://www.amazon.com/Pro-Spring-Rob-Harrop/dp/1590594614/sr=1-1/qid=1172209751/ref=pd_bbs_sr_1/104-0433560-4352764?ie=UTF8&amp;amp;s=books)
An intense, detailed book on the framework everybody loves to love(?). This book does not cover Spring 2, but is a fine upstanding reference anyway.
* *Java Persistence with Hibernate* (&quot;@bookpool&quot;:http://www.bookpool.com/sm/1932394885) (&quot;@amazon&quot;:http://www.amazon.com/Java-Persistence-Hibernate-Christian-Bauer/dp/1932394885/sr=1-1/qid=1172209953/ref=pd_bbs_1/104-0433560-4352764?ie=UTF8&amp;amp;s=books)
Hibernate, everybody's favorite java-based ORM persistence tool, and a lovely deep dive into how to make the most of it in your applications. ORM is tough enough, but to then attempt to design that layer in tandem with your fancy polymorphic class hierarchy? This book helps if you like to model your classes first, or your database first.
* *Struts: The Complete Reference* (&quot;@bookpool&quot;:http://www.bookpool.com/sm/0072263865) (&quot;@amazon&quot;:http://www.amazon.com/Struts-Complete-Reference-2nd/dp/0072263865/sr=1-1/qid=1172210403/ref=pd_bbs_sr_1/104-0433560-4352764?ie=UTF8&amp;amp;s=books)
A quite-complete reference to the Struts framework.
* *sed &amp;amp; awk* (&quot;@bookpool&quot;:http://www.bookpool.com/sm/1565922255) (&quot;@amazon&quot;:http://www.amazon.com/sed-awk-2nd-Arnold-Robbins/dp/1565922255/sr=1-1/qid=1172210564/ref=pd_bbs_sr_1/104-0433560-4352764?ie=UTF8&amp;amp;s=books)
sed &amp;amp; awk describes two text processing programs that are mainstays of the UNIX programmer&amp;#8217;s toolbox.&amp;#8221; A great reference for these elusive tools, and a good reminder of the tenets of unix sensibilities.
* *jUnit pocket reference* (&quot;@bookpool&quot;:http://www.bookpool.com/sm/0596007434) (&quot;@amazon&quot;:http://www.amazon.com/JUnit-Pocket-Guide-Kent-Beck/dp/0596007434/sr=1-4/qid=1172210811/ref=sr_1_4/104-0433560-4352764?ie=UTF8&amp;amp;s=books)
A lovely pocket reference for a tool we just can&amp;#8217;t get enough of.
* *The Elements of UML Style* (&quot;@bookpool&quot;:http://www.bookpool.com/sm/0521616786) (&quot;@amazon&quot;:http://www.amazon.com/Elements-UML-TM-2-0-Style/dp/0521616786/sr=1-1/qid=1172210929/ref=pd_bbs_sr_1/104-0433560-4352764?ie=UTF8&amp;amp;s=books)
An important book for developing accurate and expressive UML diagrams that have a solid sense of style. We&amp;#8217;ve all seen those all-too-correct UML diagrams that felt like having a fork stuck in your eye. This is a great book for sharpening up your UML skills while taking some pointers on how to soften the edges a bit.
</content>
 </entry>
 
 <entry>
   <title>Passing by Value, Reference and somewhere in between</title>
   <link href="http://emphaticsolutions.com/2007/03/28/passing-by-value-reference-and-somewhere-in-between.textile"/>
   <updated>2007-03-28T00:00:00+00:00</updated>
   <id>http://emphaticsolutions.com/2007/03/28/passing-by-value-reference-and-somewhere-in-between</id>
   <content type="html">I had recently run into what one might call an anti-pattern in a code base I was recently working in, and wanted to refresh my memory on exactly how java deals with object parameters that are modified within the method body. To be totally honest, the code (similar to the first code snippet below) was so strange to me because I had never ever seen that (anti-)pattern before. It’s likely an artifact left over from a C programmer that may have forgotten the language differences.

This discussion is often had, but usually leaves the participants more confused than when they started. Java passes by value, right? Or is it reference? What is it with primitives again? Oh man, forget it.

First, &quot;let’s read up on the specifics&quot;:http://www.yoda.arachsys.com/java/passing.html of this subject, &quot;and again with pictures&quot;:http://www.javaworld.com/javaworld/javaqa/2000-05/03-qa-0526-pass.html.

Now, let’s grok this:

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-java&quot; data-lang=&quot;java&quot;&gt;&lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;testSnappyHappy&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;	
  &lt;span class=&quot;nc&quot;&gt;Map&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;snappy&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;nc&quot;&gt;Map&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;happy&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;HashMap&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;();&lt;/span&gt;

  &lt;span class=&quot;n&quot;&gt;addToMap&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;snappy&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;foo&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;bar&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;addToMap&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;happy&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;foo&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;bar&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;kd&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Map&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;addToMap&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;Map&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;String&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;key&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;String&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;map&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;){&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;map&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;HashMap&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;();&lt;/span&gt;
  &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;put&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;key&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

What is the value of snappy and happy?

In the above code, we see that we’re checking our Map for null, and if it is null we assign the parameter to a new HashMap object. This is where the world turns upside down. When we do this, we re-”point” (there, i said it, point, like pointer, i digress) the parameter to an entirely new object which we are then modifying. Snappy continues to be null after this code is run, but happy now has its foo/bar pair within.

You know what is so frustrating about this? The method will look like it’s operating on the original map parameter. Sometimes it will. When map is null in this case (or anything else that the programmer of addToMap decided to muck with), the method does not modify the original map.

Wait! It’s not all bad. Let’s note that the method addToMap does actually return something. It happens to return the right thing, all the time, in fact. Why all this madness then? Well, if we look above, the caller is completely ignoring the return value of the method! If we always were to assign the returned value back to the map in question, it would work the same way, all the time. It is possible to write a method that acts on the original parameter (object) without modifying it by using copies, but that’s expensive and usually redundant.

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-java&quot; data-lang=&quot;java&quot;&gt;&lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;testSnappyHappy&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;nc&quot;&gt;Map&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;snappy&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;nc&quot;&gt;Map&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;happy&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;HashMap&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;();&lt;/span&gt;
  
  &lt;span class=&quot;n&quot;&gt;snappy&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;addToMap&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;snappy&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;foo&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;bar&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;happy&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;addToMap&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;happy&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;foo&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;bar&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

In the above case, we would have two maps, both with a foo/bar pair inside them.

This example is using a HashMap, but imagine we were talking about Strings. Strings are immutable in Java, so whatever you do to them, you’ll end up with a new string object, which of course, isn’t the one you passed in.

The point of this rant is that just because the compiler will let us, we should not rely on the confusing art of methods that modify their object parameters in place. As the article linked above states: “If a parameter is an “in-out” parameter, then its original value should be passed into the method and its result moved to the return value.”
</content>
 </entry>
 
</feed>
