I've been using Javan's Whenever gem to manage scheduled jobs in my project and its fantastic!! There are many existing resources where you can learn more (readme, railscastgoogle group) but I'd like to describe the specific way I'm using it
When the gem is not installed on my server
How administrators can use Capistrano to both schedule and unschedule your jobs
How to use a library such as the Oracle client that requires certain environment variables
At the end of the day we want to have 2 capistrano tasks we can run to have cron call a rake task of ours on the schedule we want.
cap schedule_jobs cap unschedule_jobs
If we want to get fancy and pass a custom configuration argument that will be passed into the rake task.
cap schedule_jobs SOME_CONFIGURATION=false
When the gem is not installed on my server
Let's start with the Capfile
#Capfile desc "Schedule the jobs" task :schedule_job, :roles => :app, :only => { :primary => true } do some_configuration = ENV['SOME_CONFIGURATION'] || true #default to true arguments = ["RAILS_ENV=#{rails_env}", "APP_PATH=#{current_path}", "SOME_CONFIGURATION=#{some_configuration}"].join(' ') run "cd #{current_path} && #{rake} whenever:update_crontab #{arguments}" end
desc "Unschedule the jobs" task :unschedule_job, :roles => :app, :only => { :primary => true } do run "cd #{current_path} && #{rake} whenever:update_crontab UNSCHEDULE=true" end
How does this differ from the example on the whenever site? Since the gem is not installed on the server we cannot call whenever from the command line so invoke the whenever:update_crontab rake task instead and to allow administrators to easily disable the scheduled jobs we define the unschedule_jobs capistrano task. Let's take a look at the whenever:update_crontab Rake task that gets this all done.
#lib/tasks/whenever.rake namespace :whenever do desc "updates crontab with our scheduled jobs" task :update_crontab => :load_whenever_gem do Whenever::CommandLine.execute({:update=>true, :identifier=>'YOUR_APP_NAME'}) end
task :load_whenever_gem do begin gem_dir_root = "#{RAILS_ROOT}/vendor/gems/" chronic_gem_dir = Dir["#{RAILS_ROOT}/vendor/gems/*"].detect do |subdir| subdir.gsub(gem_dir_root,"") =~ /^(\w+-)?chronic-(\d+)/ && File.exist?("#{subdir}/lib/chronic.rb") end require "#{chronic_gem_dir}/lib/chronic"
whenever_gem_dir = Dir["#{RAILS_ROOT}/vendor/gems/*"].detect do |subdir| subdir.gsub(gem_dir_root,"") =~ /^(\w+-)?whenever-(\d+)/ && File.exist?("#{subdir}/lib/whenever.rb") end require "#{whenever_gem_dir}/lib/whenever"
rescue MissingSourceFile => e raise "Cannot find Whenever or Chronic : #{e}" end end end
The actual whenever:update_crontab task just does the same the command line does but unless you add config.gem 'whenever' to your environment (which I don't since whenever is not needed by my app at runtime) we also have the other task that loads whenever and chronic from the vendor/gems directory.
At this point we've gotten Capistrano calling a rake task to invoke whenever even though the gem is localized in my application but not installed on the server.
How administrators can use capistrano to both schedule and unschedule your jobs
The whenever gem does not have any support for unscheduling but it will schedule whatever is included in your schedule.rb file so if that file tells it to schedule nothing that's the same as unscheduling. Its easy to do that by wrapping the entire file with unless ENV['UNSCHEDULE'] (remember the UNSCHEDULE parameter we passed in the Capfile?)
#config/schedule.rb unless ENV['UNSCHEDULE']
module MyApp module Job class CronRakeTask < Whenever::Job::Default def output path_required "cd #{@path} && /usr/bin/env /usr/local/bin/cron_rake #{task} SOME_CONFIGURATION=#{ENV['SOME_CONFIGURATION']} RAILS_ENV=#{@environment}" end end end end
set :path, ENV['APP_PATH'] || RAILS_ROOT set :environment, RAILS_ENV || 'production' every 1.day, :at => '10:00pm' do command 'do_something', :class => MyApp::Job::CronRakeTask, :environment => @environment, :path => @path end end
What's going on with the weird CronRakeTask? This brings us to the final point
How to use a library such as the Oracle client that requires certain environment variables
Cron loads its environment settings differently than an interactive shell and typically does not have all the environment variables you may have in your profile file. You could solve this by adding them to the top of your crontab file but I prefer to leave that file as simple as possible and create a wrapper script to call instead of rake. Basically the CronRakeTask does the same as Whenever's built in RakeTask except it calls /usr/local/bin/cron_rake instead of rake.
The cron_rake file just sets the environment variables I need then calls rake.
As I said in the beginning since I've been using the Whenever gem I no longer need to manually edit my crontab files ever and I can enable my jobs as part of my normal deployment process. Its wonderful and I think everyone should use it!
The idea of Ignite talks has taken over many cities around the world. There is one likely in your city coming up and if there isn't perhaps help get one started?
On Saturday afternoon I popped into Two Little Red Hens to grab a scone to have for breakfast before my flight to California. While I was waiting for the crowds to part so I could see what breakfast pastries were left, I noticed a new kind of cupcake in the display case: pumpkin.
That's right, folks! It's officially fall - the kind folks at Two Little Red Hens say so!
I added a miniature pumpkin cupcake to my scone order and scooted home to enjoy it in private. It was, in a word, delicious. The frosting was a whipped cream cheese, flavored with a touch of pumpkin. The cake itself was remarkably moist, but delicate and with a soft, light crumb. And at about three bites, the miniature version was a perfect afternoon pick-me-up.
Hello, my lovelies! If I've timed things right, you'll be reading this post just as I land in sunny California. I'm headed to the Sonoma Valley to celebrate my 30th birthday with a group of family and friends. We've rented a house in Santa Rosa, and will be scampering all over the valley, with a few detours to Napa.
I've never been to Sonoma, so I'd love to hear any recommendations you have. My friends Wendy and Dayne just visited for their anniversary, so I'm using their trip as something of a crib sheet (they were also based in Santa Rosa). They know everything there is to know about wine and food and cocktails, so I can't wait to see their favorites.
I'm off to California tomorrow, and I'm a bit over-excited about it (Well, about every aspect of it save my 7:30 AM flight.), so please excuse any too-wordy or run-on writing. Let's get to it!
I have a gorgeous peppermill, but, for some reason, I always find myself craving another one. So far, I've been a good girl and have managed to control myself. These might change that. Handmade in North Carolina, Mica Knob Studio's walnut and cherry specimens are absolutely stunning. I'm normally attracted to laquered peppermills (like this one from Peugeot), but I can't help loving the natural grain of the wood on these.
Some of you might remember that I'm almost as obsessed with design as I am with food. Almost. This week, one of my favorite interior design blogs, Decor8, published an inspiring post full of some of my favorite rooms. I find this dining salon dreamy.
Finally, as I head off to my own gorgeous vacation destination in Sonoma, I've discovered a new drool-worthy spot. Design*Sponge unveiled the first photos of the oh-so-talented stephmodo's labor of love, a renovated cottage in the Dordogne region of France. The best part? You can rent this place by the week over on VRBO. Who's in?
Design*Sponge linked to these teacups the other day, and I have been deep in lust ever since. I love the little branch handles, the smooth white surface, and the suprising pop of gilt on the inside. They would look amazing on any table, but I keep picturing them on a stretch of heather gray felt.
An old labourer, bent double with age and toil, was gathering sticks in a forest. At last he grew so tired and hopeless that he threw down the bundle of sticks, and cried out: "I cannot bear this life any longer. Ah, I wish Death would only come and take me!"
As he spoke, Death, a grisly skeleton, appeared and said to him: "May I help you? I heard you called me just now."
"Please, sir," replied the woodcutter, "would you kindly help me to lift this faggot of sticks on to my shoulder?"
We would often be sorry if our wishes were gratified.
OK, guys. It's finally here. My best friend Louisa Edwards has released her debut novel, and it's awesome. The first in her Recipe For Love trilogy, Can't Stand The Heat is the story of the romance between Miranda Wake, a restaurant critic, and Adam Temple, a chef.
That's right - it's a romance novel. About food.
I have read said novel (all in one go on a Friday night a few weeks back), and I promise that you will love it. It's funny and smart and full of delicious food (including a recipe for this cocktail and this product of our 2008 Pork Belly-Off). It's also full of punk music, men with sexy accents, lessons in how to poach an egg, and, well - booty. After all, it is a romance novel.
I know, dear readers, that you are dying to get your hands on a copy. I'm here to help. Better yet - I will get you a signed copy, dedicated to you (or the friend or loved one of your choice), inked by none other than the authoress herself.
All you have to do to win is comment below and tell me about your favorite food-related scene from all of literature - if you can choose just one, that is. You have until 5 PM EDT on Monday, September 28th to enter, after which a lucky winner will be chosen at random!
Traditional information security measures primarily involved securing enterprise network from outsiders using firewalls. However with growing focus on collaboration, evolution of web 2.0 (and cloud computing), we are seeing a paradigm shift in the way enterprises used to operate.
These days we work with people and organizations that are partners rather than employees. To be effective, they need access to data and intellectual property that the organization owns, but it must often be delivered to an environment that it does not control. Ultimately the only reliable security strategy is to protect the information itself, rather than the network and the IT infrastructure.
In this context I came across the following recommendations from the Jericho forum:
Extending these ideas, checkout Jericho forums' recommended 11 commandments on enterprise security.
In coming days, as we move more towards distributed computing over the cloud, I see the above recommendations gaining in relevance.
Interesting video on "Software Development" and new methodology's.Recommended for all and not just for those who are working on SCRUM Agile :-) (Length: 1 hr 10 min)
Check it out --> http://www.infoq.com/presentations/cockburn-bury-not-praise-agile
I have been attending lot of team retros (retrospectives) as part of our effort this year to "reinvigorate continues improvement through retros". The good thing is that these teams have a consistent repeatable process. As prescribed, these teams figure out what they should start, stop or continue and come up with some action plan before starting their next sprint. This process continues every sprint...
However, one thing I observed is that even for those good teams that are doing retros diligently, it is becoming monotonous. Also, the improvements these teams are making every sprint is very small. So over a period of time the team members start to feel that these meetings are not adding enough value and end up becoming boring.
So what can they do to bring the value back in their retros? Three things...
Mix it up: Dont always do start, stop and continue. Rotate the facilitator, invite external facilitator, change the format, change focus, do video conference etc. to bring some freshness. Be creative!
Challenge themselves with tough questions: Teams tend to be satisfied with minor improvements they make every sprint. They need to ask tough questions like .... why cant we have 100% automation or TDD? Why cant our velocity be double? Why are we not adhering to done list all the time? etc.
Do proper problem solving for at least one big ticket item: Keep asking the why question, until we get to the root cause. Use problem solving techniques like 5 why's or something similar
If teams do these things continuously, I am sure that they are going to make a leap from good to great and retros will become more interesting.
After 22-yr-old Ben Kaufman achieved great success with Mophie, an iPod accessories company he created, Ben started Kluster, a company that made Mophie's collaborative brainpower its business. Ben consequently became a poster boy for inventors aspiring to bring their ideas to life. This occurrence inspired Ben to create Quirky, a company that may have uncovered the solution to bringing any product idea to life and putting it into the hands of consumers. It's part process, part platform, part awesomeness. Check it out:
This Sunday, I took the M86 crosstown bus over to the Upper West Side to check out the Greenmarket behind the Museum of Natural History. I had a bit of a late start on Saturday morning (I blame my friends Mark and Jim - they're major enablers), so I didn't make it to the Union Square or the East 82nd Street outposts. The Upper West Side market, however, is open on Sundays. Score!
Even more of a score? Piles of gorgeous, late-season Kirby cucumbers, new-season Gala apples, and a create-your-own-pint-of-cherry-tomatoes offer, courtesy of Berried Treasures Farm. I love having an assortment of tiny tomatoes on hand; the slight variations in tang and sweetness make for a more interesting salad, and the different colors are just so darn pretty.
Even better, they only charged three dollars for a pint - a pretty good deal in Greenmarket land. I think I'll have to make a rainbow version of spaghetti with tomatoes, garlic and basil sometime very soon.
When people have options on how to accomplish a given task, they typically follow the path of least resistance. So if we want to influence the choice they make, we should make our preferred choice really easy.
For businesses, it translates to making our preferred option really cheap and quick. Traditional approaches (policies, checkpoints) cause a lot of friction and people find easier alternatives, for example:
individuals don't follow mail archive or working paper policy (instead copy mail/docs on DVDs)
business units don't use standard web content management platform (instead use other preferred solutions).
When people have options on how to accomplish a given task, they typically follow the path of least resistance. So if we want to influence the choice they make, we should make our preferred choice really easy.
For businesses, it translates to making our preferred option really cheap and quick. Traditional approaches (policies, checkpoints) cause a lot of friction and people find easier alternatives, for example:
individuals don't follow mail archive or working paper policy (instead copy mail/docs on DVDs)
business units don't use standard web content management platform (instead use other preferred solutions).
I learnt this thumb rule while learning Ruby On Rails. I liked Ruby very much and found it very intelligent and smart. Whatever may be the reason for not pursuing with Ruby but I liked this concept of DRY.
I found this has nothing in specific with any development language but a general principle to increase efficiency at whatever you do.
An effort once invested should be preserved in such a way so as it can be re-used by you or someone next time.
In a recent post, ZDNet blogger Dennis Howlett asserts that Enterprise 2.0 is a "crock." It's a smart and thought-provoking post, which has elicited equally smart and thought-provoking replies from Andrew McAfee, Thomas Vander Wal, Larry Hawes, Gil Yehuda, and...
CSS Sprites is a well known technique for webpage optimization.
It typically takes about ~ 2 to 3 days of work by UI designers and web developers to implement it. Steve Souders (UI magician) has shrunk it to zero! Try it out -> http://spriteme.org/demo.php
It automates all "spriting" activities: - finding all images on a page - grouping them into sprites - you can even generate the sprite! - it computes the complex CSS positions as well - and yeah get ready for the magic, it also injects the sprite in your current page
Could we ask for more? We can't make any excuse to not use sprites now :-)
http://spriteme.org
We need more such ideas to decrease the barrier of doing the right thing. Lets make doing the right thing, really easy!
CSS Sprites is a well known technique for webpage optimization.
It typically takes about ~ 2 to 3 days of work by UI designers and web developers to implement it. Steve Souders (UI magician) has shrunk it to zero! Try it out -> http://spriteme.org/demo.php
It automates all "spriting" activities: - finding all images on a page - grouping them into sprites - you can even generate the sprite! - it computes the complex CSS positions as well - and yeah get ready for the magic, it also injects the sprite in your current page
Could we ask for more? We can't make any excuse to not use sprites now :-)
http://spriteme.org
We need more such ideas to decrease the barrier of doing the right thing. Lets make doing the right thing, really easy!
As is well-documented on this blog, I love meat. Chicken, pork, lamb, beef, fish - you name it, I eat it with relish. Same goes for butter, eggs, wheat and sugar. But all of that doesn't mean I can't appreciate a good vegan, wheat- and sugar-free treat when I see one.
Saturday afternoon, I headed down to the Lower East Side to have my hair done (by the fabulous Holly at Fringe Salon). My salon is on Broome Street, right next to Babycakes, one of the best-known vegan bakeries in the city, and an agave brownie bite seemed just the thing to make my afternoon of pampering complete.
The brownie bites are about an inch and a half across, filled with a chocolate pudding. They're more cakey than fudgey in texture; I think of them as a virtuous version of Hostess cupcakes - free of wheat and sugar, but still satisfyingly chocolatey and gooey and delicious.
This weekend has been a bit of a whirlwind for me, so I apologize for the slightly late arrival of this week's edition of the Treasury. Without further ado...
One of the coolest, lust-worthy things making the blog rounds this week is Ikea's new Charley Harper-esque melamine tray. Emblazoned with a flock of multicolored birds, it's cheerful, it's cheap, and it's great design.
Next up, a drool-worthy look at Paris through the eyes of a first-time visitor, Erin Gates of the design blog Elements of Style. You all know how much I love Paris, and it's been a joy to read along as Erin falls in love with the city in her own way. I've always avoided doing too much shopping in Paris (the better to save my money for food and booze), but I might have to make an exception on my next visit.
Finally, a little holiday fun. Today is the first full day of Rosh Hashanah, the festival celebrating the Jewish new year. Up in Portsmouth, at the Strawberry Banke museum (one of the coolest examples of living history there is), it's being celebrated much as it was by first-generation Russian immigrants back in 1919. Barbara Ann Paster plays Shiva Shapiro at Strawberry Banke, right down to preparing roast chicken with kasha and putting up late summer peaches. Check out the New York Times story for some fun history lessons - and some gorgeous recipes.
In previous posts I wrote about an initiative we are working on to change the way we engage with our users. Our first release toward this goal is planned for the end of this month and the team has made great progress and will achieve our release goals. Our goal for this release is to begin seeding a virtual community space (a simple blog for now) with content to help people visualize what the community can be. Our thinking is that if the content is compelling people will begin gravitating to it. When this happens we can have a set of people that feel strongly about the content and the forming community that we can then work with to help determine how best to evolve the platform to meet the communities needs. As we provide better tools we hope to have the community take over and move forward on their own. Once the community takes over, openly discussing how they work and sharing ideas with each other, we can hopefully learn more about what truly matters to them and find new and better ways that IT can impact the way they work.
First of all, I have to acknowledge that conducting effective retrospectives is hard... Its not easy, so hang in there... don't give up. Lets just try to get better at it, one step at a time...
Lets own our retrospectives and make the best use of our time. If it didn't work well, lets make sure the next one works better. Lets raise the bar every time and demand better retrospectives (for that matter, any discussion).
Here are some things I learned and plan to apply in the next retrospective...
My key takeaway is that retrospectives are really problem solving sessions. We're better off structuring retrospectives for effective problem solving and leverage online/offline and asynchronous/synchronous means to achieve the desired result. For example, problem solving is ineffective in a distributed team setting, so decrease the barrier as much as possible using video conferencing etc.
1) Allow more time for problem solving We put a lot of pressure on ourselves when we expect to walk out of a 1-2 hour discussion with most important opportunities, their root causes and action plans identified.
Effective problem solving (root cause identification, action planning) can take longer (sometimes days, weeks and its okay!). So I plan to let the team mull over the opportunities longer via online, asynchronous means. This can be effective as more ideas, discussions can happen without any time pressure. E.g. online discussions, brainstorming, debates.
2) Use team time efficiently - Don't force the team to come together for activities that can be done as/more effectively without all of them present at the same time e.g. data gathering, data sharing, voting.
- Perform all activities (possible) before the retrospective to focus the team on problem solving. Leverage easy and effective online tools like wiki, microblogs/discussions, survey.
3) Don't follow the routineblindly Be thoughtful of what you do and when.
- Don't follow all steps suggested for retrospectives blindly. For example, once you've identified the opportunities for your team, you may not need to collect data in the next few weeks to identify the opportunities again. The team might be better off focusing on actions for those opportunities. When a new opportunity comes up, discuss it and if it has higher priority, add it to your list.
- Forget the rhythm of doing it every 1or 2 weeks just because you have to reflect in each sprint... Have a specific purpose in mind and conduct a retrospective only when needed... Make sure you know exactly why and when is the right time to do it. People get bored with ineffective discussions.
4) Go slow Don't take big bites. Too many teams try to improve too many things, too quickly, which often results in inaction. We're better off identifying the biggest opportunity and working on it, letting it become a part of our team's DNA before moving ahead to the next opportunity.
Bottom line: Effective retrospectives require everything that effective meetings need. Think about it. Don't follow the process blindly. Demand improvements.
First of all, I have to acknowledge that conducting effective retrospectives is hard... Its not easy, so hang in there... don't give up. Lets just try to get better at it, one step at a time...
Lets own our retrospectives and make the best use of our time. If it didn't work well, lets make sure the next one works better. Lets raise the bar every time and demand better retrospectives (for that matter, any discussion).
Here are some things I learned and plan to apply in the next retrospective...
My key takeaway is that retrospectives are really problem solving sessions. We're better off structuring retrospectives for effective problem solving and leverage online/offline and asynchronous/synchronous means to achieve the desired result. For example, problem solving is ineffective in a distributed team setting, so decrease the barrier as much as possible using video conferencing etc.
1) Allow more time for problem solving We put a lot of pressure on ourselves when we expect to walk out of a 1-2 hour discussion with most important opportunities, their root causes and action plans identified.
Effective problem solving (root cause identification, action planning) can take longer (sometimes days, weeks and its okay!). So I plan to let the team mull over the opportunities longer via online, asynchronous means. This can be effective as more ideas, discussions can happen without any time pressure. E.g. online discussions, brainstorming, debates.
2) Use team time efficiently - Don't force the team to come together for activities that can be done as/more effectively without all of them present at the same time e.g. data gathering, data sharing, voting.
- Perform all activities (possible) before the retrospective to focus the team on problem solving. Leverage easy and effective online tools like wiki, microblogs/discussions, survey.
3) Don't follow the routineblindly Be thoughtful of what you do and when.
- Don't follow all steps suggested for retrospectives blindly. For example, once you've identified the opportunities for your team, you may not need to collect data in the next few weeks to identify the opportunities again. The team might be better off focusing on actions for those opportunities. When a new opportunity comes up, discuss it and if it has higher priority, add it to your list.
- Forget the rhythm of doing it every 1or 2 weeks just because you have to reflect in each sprint... Have a specific purpose in mind and conduct a retrospective only when needed... Make sure you know exactly why and when is the right time to do it. People get bored with ineffective discussions.
4) Go slow Don't take big bites. Too many teams try to improve too many things, too quickly, which often results in inaction. We're better off identifying the biggest opportunity and working on it, letting it become a part of our team's DNA before moving ahead to the next opportunity.
Bottom line: Effective retrospectives require everything that effective meetings need. Think about it. Don't follow the process blindly. Demand improvements.
Technology giants Google have finally forayed into programming languages arena with their first language being called Noop. Noop is initially targetted to run on the Java Virtual Machine (JVM) with its source form looking similar to Java. Noop attempts to blend the best lessons of languages old and new, while syntactically encouraging industry best-practices and discouraging the worst offenses, according to a description of the language on the Noop language web site.
Though in the early stages of development, it promises a lot of features. Its goal is to build dependency injection and testability into the language from the beginning, rather than relying on third-party libraries as all other languages do. Other key characteristics of Noop include: "Readable code is more important than any syntax feature; Executable documentation that's never out-of-date; and Properties, strong typing, and sensible modern stdlib".
As new languages take time to mature and become a mainstream language, Noop's future will strongly depend on the feedback it will get.
We didn't want to get hung up on improvement opportunities only and ignore what this team of timezone warriors had achieved. So we started with celebrations - looked back at what was accomplished, shared thank you notes and acknowledged that we were proud of what we produced.
4) Highlight strengths and opportunities from data gathered (10 mins)
We reflected on team's strengths and opportunities collected from the survey and discussed: - if there were any surprises - if there was anything missing to add - if there was anything incorrect to remove
Team agreed with the strengths and opportunities identified from the survey.
I also highlighted the areas where Business and IT had a disconnect (voted differently).
5) Ask the team to select top 3 opportunities to discuss today (30 mins) Team members voted (hidden*) to identify top 3 opportunities that would have the biggest impact on the future releases.
* to ensure team members were not influenced by each other
We wasted a lot of time here. Wish I had done more effectively. Perhaps before the discussion? Perhaps another survey for this completely distributed team?
6) Facilitate problem solving session to identify root causes for these opportunities (60 mins)
The team discussed various issues freely to try to identify the root causes. I wish we had more time for this.
7) Brainstorm action plan to avail the opportunities identified
We left this for the new team that was staffed on the project. I've emailed the survey responses and discussion deck to the team to carry the root cause analysis and action planning forward. Looking forward to that discussion.
At the end, I requested team's input to make future retrospectives better thru an anonymous 1-minute survey and indicate if in this session - - Received value < Time invested - Received value = Time invested - Received value > Time invested
They also had a place to leave general comments to improve our retrospectives.
-I got a copy of Agile Retrospectives - Making good teams great and skimmed thru it quickly (1 hour) to identify relevant techniques for this discussion (FYI, I read it earlier this year, so skimming was possible).
- I attended other retrospectives - one in person (1 hour) and another on the phone (1 hour)
- I discussed it with a colleague who's good at facilitating retrospectives
B) Get data (2 hours)
- I interviewed team members - spoke to business (sponsor, program manager) and IT (BA, tech lead, portfolio lead) teams to identify relevant topics, as well as understand why past retrospectives weren't perceived to be useful
- I learned that data gathering took a lot of time in previous retrospectives (teleconference with 20 people in 6-7 geographic locations), and was one of the reasons why the team could not engage in effective root cause identification and action planning for continuous improvement.
I wanted to eliminate this friction by making data gathering about the product and the process super easy. So I created a survey to identify team's strengths and opportunities. I added team barometer questions to get the pulse of the team and launched an anonymous 15-minute survey (30 questions* with satisfaction scale) to minimize team's time investment and to capture their actual feeling/emotions.
C) Analyze data (1 hour)
The survey response was fantastic (100% participation by team members). I extracted the data into a spreadsheet to find patterns (team's interpretation of their strengths/opportunities, disconnect between IT and Business' satisfaction).
D) Share data with the team before the retrospective (5 mins)
I emailed survey results to the team before the retrospective so that they could understand and reflect on it and share insights on the day.
I got ~ 2.5 days advance notice to facilitate the retrospective. Given other prior commitments, I had ~ 6 hours to prepare.
The retrospective was scheduled for 2 hours (teleconference) and I was told that the team (sponsors and development) didn't find retrospectives particularly useful i.e. Received benefit < Time invested
So my challenge was to make this retrospective useful or at least tilt the scale towards it being useful.
Scrum recommends periodic retrospectives for continuous improvement (inspect and adapt).
I recently facilitated a release retrospective for a large project team*. In the next few posts, I will share my experience and learnings.
* This was no doubt a large project... ~ 20 team members distributed across New York, San Francisco, Atlanta, Bangalore, Mumbai, Dusseldorf, Paris that have worked together for ~ 2 years with multiple 3-month releases.
Google launched Fast Flip - A web application that let's users discover and share news articles.
On first look, It greatly enhances the UX factor i.e I liked the feeling of being able to flip through pages before reading the details. You automatically get 'Most Viewed' and 'Recent' news items which helps you keep abreast of latest top stories. Fast Flip also features a search engine and let users share content. Based on their reading choices, users will see suggestions for other articles they might find interesting.
Downside: At this point, Google isn't making any tools available for external developers to integrate Fast Flip with their Web sites and applications.
To me, It's unclear how this product is positioned vis-a-vis google news. Nonetheless, I won't complain as long as I have option to choose.
I got up early on Saturday morning (one of the good things about a quiet Friday night) and hoofed it down to the Union Square Greenmarket around eight o'clock. Upon arrival, I was thrilled to see box upon box of new-harvest (as opposed to cold-storage) apples at the Terhune stand. Gala and Honeycrisp and Fuji - oh my!
I helped myself to a couple of the rosy-golden Gala apples and snapped a photo of the bounty. Nothing says fall like a big ol' pile of apples - except for a big ol' pile of leaves, something we don't see a lot of in Manhattan.
I had to create a quick online survey last week for a retrospective. I used Zoomerang and loved the ease of use such online survey tools offer (I dislike typical enterprise offerings in this space. They are bulky, complicated, slow and self-service is next to impossible for business-users).
I had one issue using a free account though. Survey creation and launch only took 10 minutes, whereas data export took 45 mins! (export wasn't available for a free account, so I had to manually export data into a spreadsheet).
In the future, I plan to use Google forms instead.
Over the weekends, the blogosphere, much like TV, tends to be lacking in terribly exciting content. I'm as guilty of this as anyone - occasionally I'll post something on Sunday afternoons (the time of week I tend to do most of my writing), but most of my weekend is devoted to gathering blog fodder, as opposed to dispensing the final product.
To help you get through those long Saturdays and Sundays, I'm starting a new feature here at Queenie, called Queenie's Treasury. Each Saturday, I'll bring you a few links to some of the things that have captured my attention in the last seven days. Most of these will be related to food, travel or entertaining - but some will just be cool things I've come across in my surfing.
And now, without further ado, I present the Treasury's inaugural picks!
If you don't read Smitten Kitchen yet, you absolutely should. Fantastic recipes, inspiring photography, the works. This week, Deb published what looks to me like the perfect late-summer dish: roasted tomatoes and cipollini onions. I read the recipe three days ago, and I'm still drooling.
Last but not least, dessert. Design*Sponge may be a (duh) design blog, but each Friday it features a recipe. These are usually desserts, and they always look fantastic - not least because the contributions usually come care of other design bloggers. This week's recipe is no exception, but the look is slightly different. In place of the usual worshipful food photography, Julia Rothman submits her blackberry pie recipe with frame-worthy cartoon instructions. Helpful and fun, to boot.
Ice cream sandwiches are one of summers great pleasures, and I wasn't about to let the fact that summer is pretty much over keep me from enjoying mine.
On Monday afternoon, a bit bored and a tad restless, I decided to make some chocolate chip cookies to take into work on Tuesday. As I took the first batch out of the oven, I remembered one of my grand plans from earlier in the summer: homemade ice cream sandwiches filled with salted caramel ice cream.
I didn't have the ingredients for homemade ice cream on hand, but I did have some delicious Ronnybrook vanilla in the freezer. Cue light bulb and deliciousness.
I took two same-size, completely cool cookies and spooned some slightly softened ice cream onto one of them, pressing the other down to complete the sandwich. I cut off a piece of parchment paper, wrapped the newborn sandwich, and put the packet in the freezer to firm up for a couple of hours.
Later that night, after dinner, I took the sandwich out of the freezer and took a bite. Keller's cookies are distinguished by their large quantity of dark brown sugar, and I think this helped keep the cookies nice and chewy, even after a few hours on ice. The ice cream had firmed up nicely, too, so the sandwich held together nicely.
The salty, sweet, rich cookie worked really well with the Ronnybrook. They make a very traditional vanilla: sweet, creamy and fairly neutral in flavor. As it turns out, that's what you want when the cookie in question is super-flavorful.
In a distributed environment, Cognos 8 balances request load automatically. By default, as servers are added to the system, each server dispatcher processes the same number of requests. If there is more than one instance of a given service, the dispatcher distributes requests to all the enabled instances of the service that are registered in Content Manager.
Load Balancing Dispatchers
Without a software or hardware load balancing mechanism, each Cognos 8 gateway is aware of only one dispatcher, and distributes all requests to that dispatcher. The dispatcher then distributes the requests among Cognos 8 servers. Because every request initially goes through the same dispatcher on one server, the load on that server is increased. An extra step is needed to automatically balance the load, as shown in the following diagram.
Load Balancing Without an External Mechanism
Since gateway servers often have less load than Cognos 8 servers, you may achieve better performance by configuring dispatchers together with the gateways, as shown in the following diagram.
This ensures that the processing capacity of the Cognos 8 servers is directed toward serving report requests rather than load balancing requests.
You can also achieve load balancing by having gateways direct all traffic to a Cognos 8 server computer that is dedicated to dispatching, as shown in the following diagram.
This configuration also removes dispatching load from the Cognos 8 servers. However, it does require separate dispatching computers.
There are recipes you make once, forget about, and leave behind you forever. And then there are those you make once that haunt you, confronting you at every opportunity, screaming, "Make me!" You find excuses, reasons not to - and then, one day, the perfect scenario materializes, and you finally scratch the itch.
I first made the BLTomatoes from the Gourmet Cookbook back in 2004, for my friend Louisa's 25th birthday party. The night was a blur of delicious food and bounteous booze, but one morsel went faster than the others. Louisa's now-husband and I cooked all afternoon; I went home to shower and returned about twenty minutes after the first guests had arrived. The 50 or 60 BLTomatoes we'd painstakingly prepared? They were gone. Gone!
BLTomatoes are pretty much exactly what they sound like - cherry or grape tomatoes stuffed with a combination of bacon, lettuce, mayonnaise, and scallions. They are a pain in the ass to make - you have to hollow out the tomatoes and stuff their tiny insides with the filling - but oh my god are they good. The tricks to taking them from tasty to lip-smacking? Use the best bacon you can find (I prefer Schaller & Weber's double-smoked.), don't skimp on the salt and pepper, and don't leave out the scallion. Its peppery bite is key.
And be patient with the trimming and seeding of the tomatoes - it can be slow-going (especially if you use grape tomatoes), but it's well worth the effort. BLTomatoes Adapted from The Gourmet Cookbook
14 cherry or grape tomatoes 1 tsp. salt 1/4 lb. bacon, thinly sliced 1 scallion, thinly sliced 1/4 c. thinly sliced romaine lettuce 2 tbs. mayonnaise Salt and pepper, to taste
Slice a tiny bit off of the bottom of each tomato (to help them stand upright on the plate). Cut off the tops of the tomatoes, and carefully scoop out and discard the pulp and seeds. Sprinkle the salt over the tomatoes, then invert them on a paper towel. Set aside to drain while preparing the filling.
Cook the bacon in a skillet over medium heat until crisp. Drain on paper towels, then crumble or chop finely. In a small bowl, gently mix the scallion, lettuce, mayonnaise, salt and pepper until well-combined. Test the filling for seasoning; remember, you will be eating the tomato, too, so you want it to be a bit on the salty side.
Stuff each tomato full of the filling; eat any leftover filling yourself, straight off the spoon.
Serve immediately, or chill in the fridge for up to five hours.
If you place curly braces ({}) around your SQL statement in a Tabular SQL object, that SQL statment will be sent directly to the database. Note that no validity checking is done on the SQL, so the report author is fully responsible for the correct operation of the SQL statement. Steps: Create a Tabular SQL object. Write you SQL statement. Ensure that it is surround by curly braces. For example, if your SQL statement isSELECT * FROM ORDER_HEADERyou need to write it as: {SELECT * FROM ORDER_HEADER}
G.ho.st offers every person in the world a free Virtual Computer (VC). G.ho.st is simply pronounced "ghost", an acronym of Global hosted operating system. The G.ho.st Virtual Computer includes almost everything you would have in a physical computer - a desktop, file storage (like a disk drive) and applications.
G.ho.st frees you from being tied to any one physical device - and frees you from the worries of installing software, backing up, and other administration.
"G.ho.st Lite" is a lightweight user interface to access VC using Mobile phones, an embedded widget in another web site like iGoogle and from a very old computer or dial-up connection.
Visit their home page to check out list of key features and services.
I would say good use of cloud computing powered by Amazon Web Services (AWS) and solutions from RightScale Technologies.
We've talked about leftovers here before, and I've made my feelings known: I actually kind of like them. They force me to be creative, and to think about my food in a new way. They provide building blocks for future meals. They help me make quick, easy dinners on busy evenings. And, frankly, they're major money-savers.
On Sunday night, my friend Cristin and I got together at her place to try out Kerry Saretsky's (as it turns out, awesome) recipe for drunken angel hair with leeks and cream. It was delicious - but even a half recipe was too much for the two of us. We were brainstorming ways to use the leftovers, and hit upon the idea of using a tuft or two of the pasta and leeks as filling for baked eggs.
I had steak for dinner on Monday, so I thought Tuesday would be a good night for some lighter fare. I piled a bit of the leftover pasta into a buttered ramekin, cracked an egg over it, seasoned it with salt, pepper and parsley, and baked the whole thing in a hot oven.
The result? A rich, delicious meal, ready in pretty much no time flat, and made for mere pennies. Sure, you factor in the green salad I ate on the side, and we're probably talking a dollar or two total. But, I mean - still: you can't beat that.
Baked Eggs with Leftover Pasta
You should by no means limit yourself to including pasta in this dish. Do you have leftover roasted vegetables? A bit of chicken or steak? Chili? Throw that in instead!
Unsalted butter, for greasing the ramekin 1/4 cup leftover pasta, sauce included 1 egg 1 tbs milk or half & half Salt and pepper to taste 1 tsp. chopped parsley
Preheat the oven to 400?F.
Using a bit of unsalted butter, lightly butter the bottom and sides of the ramekin, all the way up to the lip. Pile the pasta evenly in the ramekin, and crack the egg over it, taking care to keep the yolk as centered as possible. Pour the milk over the egg (it will fall to the sides and into the pasta).
Season the contents of the ramekin with the salt, pepper and most of the parsley. Place in the oven and bake until the white is just set, but the yolk is still a bit...jiggly. Top with the remaining parsley and dig in!
Serves one, though, obviously, it easily multiplies to serve many!
Web Portals The IBM Cognos 8 Web portal is IBM Cognos Connection. IBM Cognos Connection replaces Upfront and the PowerPlay Table of Contents as the portal for accessing PowerPlay reports.
IBM Cognos Administration also allows you to run the Migration Assistant to move your IBM Cognos Series 7 PowerPlay content to IBM Cognos 8 PowerPlay.
Data Sources
IBM Cognos 8 uses data sources contained in packages. Connections to the data sources are maintained in IBM Cognos Administration. For IBM Cognos 8 PowerPlay, a package contains a data source connection to a PowerCube. When you publish a PowerCube, that is, when you create a data source connection to a PowerCube, you can optionally create a package for the cube. PowerPlay users can then build reports from that cube by using the package.
IBM Cognos 8 Transformer allows you to create cubes and to publish them to IBM Cognos Connection for use in Cognos 8 studios.
All IBM Cognos 8 studio users access data from published packages. PowerPlay accesses data only from packages that use PowerCubes as data sources. Other IBM Cognos 8 studios can access data from packages that use different types of data sources, including PowerCubes. IBM Cognos 8 PowerPlay Studio and IBM Cognos 8 PowerPlay Client do not support data source connections to OLAP data sources other than PowerCubes, nor do they support compressed PowerCubes.
Security
IBM Cognos 8 can use your existing IBM Cognos Series 7 namespace, however, you will need to continue using IBM Cognos Series 7 Access Manager to administer the namespace.
Security information in your PowerPlay content will be maintained when you migrate to IBM Cognos 8. Only users and user classes referenced in NewsBoxes and NewsItems being migrated are migrated. Password protected cubes will remain password protected. If you use user class security in your cubes, the security is maintained and you must continue to use your IBM Cognos Series 7 namespace in your IBM Cognos 8 environment.
In IBM Cognos 8 PowerPlay, you cannot access a cube password that is stored in IBM Cognos Series 7 Access Manager. An administrator must add the cube password to the data source signon when they create the data source connection in IBM Cognos Administration. Also, you cannot open local cubes that are secured against a namespace using IBM Cognos 8 PowerPlay Client. As an alternative, you can use password protected local cubes.
Request Flow
In IBM Cognos Series 7, incoming requests are sent from the gateway to the PowerPlay server and from the PowerPlay server to a query processor. In the default configuration, the query processor sends the response directly to the gateway, bypassing the PowerPlay server. To do this, the gateway listens for connections on a server socket and the query processor opens a socket connection back to the gateway. This requires open outbound ports in firewalls between the Web tier and the Application Tier Components. In IBM Cognos 8, responses always travel back through the same socket connections that the request arrived on. This is the same as enabling the restrict outgoing port configuration option in IBM Cognos Series 7.
The Migration Service
Migration is a service in the IBM Cognos 8 service-oriented architecture. The migration service migrates PowerPlay content from IBM Cognos Series 7 to IBM Cognos 8 PowerPlay. The migration service also migrates PowerPlay reports to an IBM Cognos 8 report specification when a user opens the report in Report Studio or Analysis Studio.
Note: There are two migration services; one is an IBM Cognos Series 7 service and one is an IBM Cognos 8 service. Both services must be started before you can migrate your content. The IBM Cognos Series 7 Migration service is started from the Windows Services manager or on UNIX using the command ./configure.sh --start. The IBM Cognos 8 migration service is run by the IBM Cognos 8 dispatcher and is automatically started when you start the IBM Cognos 8 service.
Replacing or Updating Cubes
If you are using IBM Cognos 8 Transformer version 8.4, you can update PowerCubes using new deployment features without having to restart services, disable cubes, or use scripts. If you are using IBM Cognos Series 7 PowerCubes in IBM Cognos 8, you can also take advantage of new deployment features using a utility named pcactivate.
As former denizens of New England, Miles and I were both thoroughly indoctrinated into the church of Friendly's at a very young age.
You think I exaggerate, but I do not. Ice cream is something of a religion in New England; the abundance of dairy farms combines with the fervent embrace of a short summer season to create a frenzy for frozen, creamy goodness. The region is chock full of local, artisanal creameries. I remember, for example, my brother's deep and abiding passion for the banana split at Kimball's in Westford, Massachusetts. And there are two local ice cream places within walking distance of my aunt's condo in Bristol, Rhode Island.
All this local goodness, and Miles and I wind up at Friendly's. I know, I know.
Friendly's, for those of you who've never had the luck to visit it, is a hamburger and ice cream chain with outlets found mainly in the Northeast - but who, in the last ten years or so, have begun to sell their ice cream in grocery stores around the country.
For me, Friendly's was always, primarily, a place for dessert. My dad would take us there as a Sunday afternoon treat, or I'd go with fellow community theatre cast members after a late-night dress rehearsal or to celebrate an opening night. It was a treat, a special occasion kind of place, and it was there that my love of peanut butter sundaes was born.
Friendly's, you see, has this Reese's Pieces sundae that I remember as pretty much the best thing ever. The peanut butter sauce is a warm, salty counterpoint for the rich hot fudge (Friendly's has real fudge sauce, not syrup) and the cold vanilla ice cream. All of these things remain awesome, but I'm actually kind of over the Reese's Pieces themselves. When eaten at room temperature, they are as delicious as ever, in that peanut-butter-plus-chemical-emulsifiers kind of way. But dotted in a sundae, they are frozen, rock hard, and practically tasteless.
Not that this stopped me from enjoying my sundae to the utmost; I just ate around them. I am, after all, an expert in the field.
One of my favorite books of all time is The Secret Garden, by Frances Hodgson Burnett.* Growing up, it seemed impossibly exotic, full of foreign lands (India, England) and secret spots. In fact, I think one of the reasons it's such an enduring story is that Mary's search for a place of her own and her discovery of the tucked away and forgotten garden resonate with something very human: the quest for that which is hidden.
As a child, I was obsessed with secret passages, hidden gardens, and overgrown paths. I'd roam our hundred year-old house, feeling the walls for catches or painted-over door frames, and explore the wooded park near our home, in search of abandoned encampments. This thirst hasn't abated.
As a result, I expect, I found myself enchanted by Maudslay State Park, an old Newburyport estate (home of the Moseleys) which became a park in the mid-1980s. The park is right on the river, and the estate's old gardens (some maintained, some running wild) dot the property. There are also the remains of two old houses - the foundation of the original 72-room mansion as well as that of the smaller (but still respectably-sized) home the Moseleys built for their daughter.
The park's visitor center was closed on Sunday afternoon, so Miles and I found ourselves exploring the woods, fields and gardens unguided. We contemplated every path, wondering if we'd found the service driveway, or the path created to impress visitors to the estate. We stumbled on kitchen gardens, arbors, greenhouses long since missing their glass roofs, and overgrown thatches of rhododendron - those were everywhere.
It was all I could to stop myself looking for a nosy misselthrush and a poorly-buried key.
*It should also be noted that Miles & I met 12 years ago performing in a production of the musical version of The Secret Garden. Yes, we are officially old.
Back when Miles was still living here in New York (He and his partner, Hall, now own and run a gorgeous lodge in New Zealand.), we used to spend many a Sunday afternoon drinking coffee and working on the Sunday Times crossword puzzle. When I did not perform as well as I should have on our joint puzzle effort back in June, I decided it was time for some intense puzzle training.
I started doing the puzzle, daily, with some friends from work. And so, when Miles declared that we were going to Fowle's for breakfast and the crossword, I was ready.
I bought a Sunday Times from the newsstand side of the store, we sat down at the counter and ordered, and got down to business. Breakfast for Miles was yogurt and berries; for me, it was scrambled eggs and corned beef hash. Hey, people - I was on vacation, and vacation, to me, means nothing so much as fried potatoes for breakfast. Yum.
Once we'd shown the puzzle who was boss, we headed out for a walk along the waterfront. It was a beautiful day, the sun sparkling like mad on the river. We decided to explore a bit, ending up in Oldie's, one of those classic New England antique barns. The pickings were plentiful, but there was no way I was carrying a cast-iron skillet all the way home with me.
Our ramble also included a trip to Miles's favorite toy store, where I found eco-friendly toy cookware - and it wasn't pink! Gender neutral and environmentally friendly, guys! I was so excited, I took multiple pictures. I'll only make you look at one, though.
After our nostalgic (and filling) evening at The Grog, it was all Miles & I could do to drag our piggy little butts home and into bed. Saturday morning, we got up bright and early, had some breakfast (and coffee) in the Garrison's dining room, and piled into the car for a drive up to New Hampshire, and back into my own adolescence.
We were on our way to meet my friends Ginelle and Rob for lunch in Portsmouth - but, first, we had a stop planned at Phillips Exeter Academy, the prep school Ginelle & I attended for four years in the fashion-unfriendly mid-90s. Miles had never seen the campus, and even though things were shut down for the annual late-summer renovation frenzy, I wanted to show him around a bit.
We took a walking tour of the campus - which has changed a bit since my time, with new-fangled buildings all over the place and far too many luxuries, in my crotchety opinion - and just generally enjoyed the ridiculously warm weather. We ran into a few faculty members enjoying their time off (we were there during the break between summer school and the fall term) and visited the Hill Bridge, off of which you must jump, if you wish to graduate. No, really.
After our walk, we hopped in the car and sped off toward Portsmouth, an adorable town on the Piscataqua River, just across the bridge from Kittery, Maine. We had some time to kill before meeting up with Rob & Ginelle, and decided to take a little drive out to Wentworth by the Sea, a big old white elephant of a resort in New Castle. New Castle is just south of Portsmouth, and is built entirely on islands - a really cool place, full of beautiful vistas and cute little coves.
On our drive, we also discovered one of the most beautiful wedding venues on earth - really. A tiny, gorgeous little chapel is hidden in the woods leading down to the coast, and about half a mile past it is the Wentworth-Coolidge Mansion, a rambling yellow house on a gentle slope, smack next to the water. Absolutely stunning. I wish we'd gotten to poke around a bit more, but since there was an actual wedding in progress, we thought it best to make ourselves scarce.
Finally, we rolled into Portsmouth, where lunch - and chocolate - awaited us.
Postcard of the Wentworth by the Sea hotel via Wikipedia.
Cognos SQL: Generic representation of a Query. More verbose than native sql Formatted for readability and comprehension and generated by CQE Native SQL: Designed to use the database optimizers. Leverages features of databases wherever possible. We cant use Native SQL in a Query subject that references more than one data source query subjects Pass-through SQL: Use When a database vendor does not extend support for a particular construct in a sub-query. Cognos 8 will pass anything you type directly to the database. With Pass-through SQL what ever you type is passed to the Data base processing with out the intervention of the Cognos 8 Query Engine
My trip to New England with Miles had a primary purpose: nostalgia. Lots and lots of nostalgia. Miles, you see, was born in Massachusetts, and lived with his family in West Newbury until junior high, when they moved to Richmond, Virginia. Miles hadn't been back in years, and invited me to tag along for the fun.
I took the bus up to Boston and met Miles at Logan, where we hopped in our rental car and sped up to Newburyport. Newburyport is an adorable seaside town north of Boston. It sits at the mouth of the Merrimack River, ideally situated as a port for trade with northern New England (hence the name, I imagine).
After we'd checked in to our hotel (The Garrison Inn - super cute, though in need of a little touching up), we headed off on foot through downtown Newburyport. Our destination? The Grog.
The Grog lives in Miles's memory as a family dinner destination - but, above all, it lives as the home of delicious clam chowder. He warned me ahead of time that The Grog's chowder was not terribly thick, and was far more buttery than the usual suspects. But, he assured me, it was delicious.
After a five-minute walk through cobblestone streets, we arrived and were seated at a little table in the bar. We each ordered the chowder (a cup for me, a bowl for Miles) and sandwiches (a burger on an English muffin for me, a Cuban for Miles) - and beer, of course.
The chowder arrived about five seconds later, piping hot and accompanied by oyster crackers. And I am not exaggerating about that piping hot bit, either - after the first, scorching bite, I had to let mine cool down for a few minutes before diving back in.
The chowder was indeed brothier than your average New England version, but it was still delicious. Swimming in sherry and butter, it was full of flavor. The clams were soft and toothsome, not tough and chewy, and the chunks of potato were well-seasoned and just the right texture. It was easy to see why Miles held this soup in such high esteem - though he claims it's not quite as good as it used to be.
Often our peers and leaders ask us "so what?"... by this they're implying that they don't clearly understand why we're saying what we're saying... Here's a good way to structure our verbal and written communication...
On Sunday, I spent the morning running errands: dropping clothes and shoes off at Housing Works, stopping at the drug store to replenish my gum supply, hitting Kate's Paperie for some birthday cards, and stopping by Citarella for some shrimp.
I'm not sure where the idea to make shrimp scampi for dinner came from - maybe from a desire to eat something delightfully garlicky and slightly boozy? Who knows - but one thing I do know is that scampi, like so many pasta dishes, is a great dinner to make for one. It's fast, it's ludicrously delicious, and it's one of those things that's annoying to make for a dinner party, since you need to make it there and then - plus, who the hell wants to peel and devein shrimp for eight? Not I.
For my version, I use vermouth in the place of white wine, for a couple of reasons. First of all, I'm unlikely to have a bottle of wine open at any given time, since I can rarely make it through a bottle in any reasonable amount of time. Second, the herbs and spices in the vermouth add a bit more flavor than your standard white wine.
It may also seem, at first glance, that this recipe is a little heavy on the salt. I don't find it to be (you need it to season the shrimp and the pasta), but you should obviously use your own judgment. After all, you can always add salt later - but you can't take it out.
Next time you're on your own for dinner (or with a friend - this recipe easily doubles to feed two), try it out, and let me know what you think!
Queenie's Scampi for One
1/4 lb. dried spaghetti 1 tbsp. olive oil 3 cloves garlic, thinly sliced 1/3 lb. medium shrimp, peeled & de-veined 1/8 tsp. ground black pepper 1 tsp. kosher salt, divided Pinch of red pepper flakes 1/4 c. parsley, finely chopped 3 tbs. dry vermouth (or other white wine) 1 plum tomato, cut into a 1/2 inch dice 1/2 tbs. unsalted butter, divided
In salted, boiling water, cook the spaghetti to al dente. Drain and set aside. (You can cook the sauce & shrimp while the pasta cooks; just wait to start the sauce till the pasta is about halfway done.)
Rinse the shrimp in cold water and pat dry.
In a medium skillet set over medium-high heat, warm the olive oil until just shimmering. Add the garlic, lower heat to medium, and cook gently until the garlic has turned slightly golden and is fragrant.
Turn the heat to medium-high and add the shrimp the pan, distributing them evenly. Season with the black pepper and 1/2 tsp. of the salt and saute until the shrimp begin to turn pink all over. Add the red pepper flakes and 3/4 of the parsley and continue to cook for a minute or two.
Add the vermouth and continue to cook, stirring constantly. Add the tomatoes and another 1/4 tsp. salt to the pan at this point. Cook the shrimp until they are completely pink, but not overdone. Add half the butter to the pan along with the cooked spaghetti. Cook the pasta & sauce together for a minute, add the remaining parsley, and transfer to a shallow bowl.
Dot the pasta with the remaining butter, sprinkle with the remaining salt - and eat!
You know autumn is around the corner when grapes start popping up in earnest. Dark-skinned, musky grapes are my personal favorite, and I get pretty excited when they appear at the markets. I bought two pounds and have been eating them, ice cold from the fridge, all week.
Go get yourself some. You won't regret it, I promise.
In part one of this tutorial I wrote a simple rails generator that creates a controller code file in app/controllers. This time I want to finish up my simple “VersionGenerator” example by enabling it to add a line to the routes.rb file. In other words, I want to be able to use a manifest action called “route” like this:
def manifest
record do |m|
m.template('controller.rb', 'app/controllers/version_controller.rb')
m.route :name => 'version',
:controller => 'version',
:action => 'display_version'
end
end
The problem for today is how to implement the “route” action, which is not supported by Rails by default. The Rails generator base class code does provide a few other actions you can use in your manifest, like “file” or “directory,” which create a file or directory. Rails even provides a method called “route_resources” to add a “map.resources” line to routes.rb, but not a simple named route line like what we need for this example.
This specific action might be useful for you, but my real goal is to explore how Rails generators work in general and discuss some of the issues you might run into if you need a custom manifest action like this for any purpose. Let’s get started by just adding the new action method we need right inside our generator class…
def route(route_options)
puts "This will create a new route!"
end
…and see what happens when we run script/generate with manifest method above:
$ ./script/generate version ../build-info/version.txt
identical app/controllers/version_controller.rb
This will create a new route!
Very promising! All we need to do is add the necessary code here and we’ll be all set. But first let’s take a closer look at what’s happening by adding a call to “caller” inside this new method and see how it’s being called by the Rails generator system:
def route(route_options)
puts "This will create a new route!"
puts caller
end
Here’s what is displayed when we run this (paths shortened for readability):
$ ./script/generate version ../build-info/version.txt
identical app/controllers/version_controller.rb
This will create a new route!
/usr/local/lib/ruby/1.8/delegate.rb:270:in `__send__'
/usr/local/lib/ruby/1.8/delegate.rb:270:in `method_missing'
/path/to/rails-2.3.2/lib/rails_generator/manifest.rb:47:in `send'
/path/to/rails-2.3.2/lib/rails_generator/manifest.rb:47:in `send_actions'
/path/to/rails-2.3.2/lib/rails_generator/manifest.rb:46:in `each'
/path/to/rails-2.3.2/lib/rails_generator/manifest.rb:46:in `send_actions'
/path/to/rails-2.3.2/lib/rails_generator/manifest.rb:31:in `replay'
/path/to/rails-2.3.2/lib/rails_generator/commands.rb:42:in `invoke!'
/path/to/rails-2.3.2/lib/rails_generator/scripts/../scripts.rb:31:in `run'
/path/to/rails-2.3.2/lib/commands/generate.rb:6
/usr/local/lib/ruby/site_ruby/1.8/rubygems/custom_require.rb:31:in `gem_original_require'
/usr/local/lib/ruby/site_ruby/1.8/rubygems/custom_require.rb:31:in `require'
./script/generate:3
There’s a lot going on here; in fact, when I started to learn more about Rails generators and how they work I was shocked at how complicated their object model and design are. I won’t try to explain all of it here, but let’s take a closer look at the one line I bolded above: line 31 of lib/rails_generator/scripts.rb
This is called when you run script/generate, by the “Rails::Generator::Scripts::Generate” class. Translating this line of Ruby into English, we get: “Create an instance of the specified generator, passing in the arguments and options provided on the command line; then create an instance of the specified command that uses that generator; then invoke the command.”
What this means is that actually Rails generator classes do not do the real work of generating code – Rails generator “commands” do! The lib/rails_generator/commands.rb file defines a series of command objects inside the Rails::Generator::Commands module. The two most important command classes are Create and Destroy. The “Create” command is called when you execute script/generate, like what happened in the stack trace above. This class contains the implementation of the “template” method we used before, plus various other methods like “file” and “directory” that create files and directories, etc.
The “Destroy” command is called when you execute script/destroy from the command line (I removed “puts caller” first before running this):
$ ./script/destroy version ../build-info/version.txt
This will create a new route!
rm app/controllers/version_controller.rb
This class has all of the same methods that the Create class does, except that they perform the opposite action: instead of creating a file or directory, they delete them. The Destroy class also executes the actions in the opposite order, by looping backwards through the manifest that we recorded in our generator. Here the destroy command has deleted our version_controller.rb file we generated earlier. Note that it still displays “This will create a new route!”
If you’re interesting in diving into the real details about how Rails generators work, then read the code in commands.rb very carefully. In particular, look at how the “self.included” and “self.instance” methods at the top work; these methods are used in the line I showed above to create the specified command, supplying the specified generator as an argument to the command constructor. The “invoke!” method on commands actually plays back the recorded manifest. Also all of the actions that are available to your generator's manifest method are defined in this file. One other interesting detail I don’t have space to explain carefully here is that the command objects contain the corresponding generator class as a delegate object; in other words they contain an instance of the generator as a member variable:
# module Rails::Generator::Commands...
class Base < DelegateClass(Rails::Generator::Base)
This explains the top two lines in the stack trace above:
“DelegateClass” is defined by delegate.rb, which is a Ruby library that implements the delegate pattern. This is why we were able to add the new “route” method right in our generator; when Ruby found the “route” method missing in the Create command, it delegated the call to our generator object.
Obviously we have a problem here: our new “route” method needs to be able to remove a route from routes.rb if the Destroy command is called, as well as create a new one for the Create command. One way to implement our new “route” method would be check the “options[:command]” value that we saw above on line 31 of scripts.rb, like this:
def route(route_options)
if options[:command] == :create
puts "This will add a new route to routes.rb."
elsif options[:command] == :destroy
puts "This will remove the new route from routes.rb."
end
end
Now if we run script/generate again, our new method will create a route:
$ ./script/generate version ../build-info/version.txt
create app/controllers/version_controller.rb
This will add a new route to routes.rb.
And if we run the destroy command, we’ll remove the route:
$ ./script/destroy version ../build-info/version.txt
This will remove the new route from routes.rb.
rm app/controllers/version_controller.rb
It turns out a cleaner way to implement the “route” method is to directly add the method to both the Create and Destroy command classes. This allows me to call a utility method called “gsub_file” in the Rails::Generator::Commands::Base class which I wouldn’t have direct access to from my generator class. It also avoids the somewhat ugly if statement on the options[:command] value, and finally it might make it easier for me someday to refactor the new route methods into a separate module that I could use with various different generators that might need to add and remove routes.
Anyway, here’s the finished code for the entire generator:
class VersionGenerator < Rails::Generator::NamedBase
attr_reader :version_path
def initialize(runtime_args, runtime_options = {})
super
@version_path = File.join(RAILS_ROOT, name)
end
def manifest
record do |m|
m.template('controller.rb', 'app/controllers/version_controller.rb')
m.route :name => 'version',
:controller => 'version',
:action => 'display_version'
end
end
end
module Rails
module Generator
module Commands
class Base
def route_code(route_options)
"map.#{route_options[:name]} '#{route_options[:name]}', :controller => '#{route_options[:controller]}', :action => '#{route_options[:action]}'"
end
end
# Here's a readable version of the long string used above in route_code;
# but it should be kept on one line to avoid inserting extra whitespace
# into routes.rb when the generator is run:
# "map.#{route_options[:name]} '#{route_options[:name]}',
# :controller => '#{route_options[:controller]}',
# :action => '#{route_options[:action]}'"
class Create
def route(route_options)
sentinel = 'ActionController::Routing::Routes.draw do |map|'
logger.route route_code(route_options)
gsub_file 'config/routes.rb', /(#{Regexp.escape(sentinel)})/mi do |m|
"#{m}\n #{route_code(route_options)}\n"
end
end
end
class Destroy
def route(route_options)
logger.remove_route route_code(route_options)
to_remove = "\n #{route_code(route_options)}"
gsub_file 'config/routes.rb', /(#{to_remove})/mi, ''
end
end
end
end
end
More or less copied from the existing route_resources action found in commands.rb, this works as follows: If we call script/generate then the route action method in the Create command class is called. This uses gsub_file to look for the “sentinel” or target area of the file and replaces it with the sentinel + the new route code. I also use the “logger” method to display log messages using the Rails::Generator::SimpleLogger class. Here’s what it looks like on the command line:
If script/destroy is called, then the second route implementation in the Destroy class is called. This uses gsub_file to remove the route code. Finally, the “route_code” method returns the route code that we want to generate or remove from routes.rb. This time on the command line we get:
Last week, my sister-in-law Miriam's friend Natalie was in town from the UK. Now, Natalie is a stylish, dynamic sort of woman, and so the bar for our girls' night out was, I knew, set pretty damn high. I knew I had to pick something fun, delicious, and with a good, solid buzz. And, of course, in close proximity to excellent cocktails. The winner? Momofuku Noodle Bar.
We ordered some watermelon lemonade slushies (spiked with soju) to start. Last time around, we'd gone the sensible route and ordered the small, aperitif size, but this time we went whole hog and got the proper, large size. All the better to sip through the giant, bubble tea-sized straws.
The slushies were quickly followed to the table by some delicious appetizers: smoked chicken wings and steamed pork buns. I've waxed poetic about the pork buns before, so I won't bore you here, except to say: EAT THEM. The wings are cold smoked before being brined and then sauteed and served in a sauce of wine, chiles, scallions and garlic. More flavorful than most chicken wings (which only have sauce on the outside) and less messy, too.
Next up, and most importantly, the noodles themselves. Natalie and I ordered the Momofuku ramen, while Miriam went for the ginger scallion noodles - both were delicious. The Momofuku Ramen is, unsurprisingly, a bowl of porky goodness. Ramen noodles in a pork broth with a runny poached egg, pork belly and pork shoulder. I like to season mine with a generous amount of Sriracha to cut through the richness.
Miriam's ginger scallion noodles were more delicately flavored and came with a healthy portion of lightly-pickled cucumbers. They were gorgeous, and an alternative that just might tear me away from the Momofuku ramen's porkalicious delights on a future visit.
In my previous post, I argued that companies should Skip the Pilot for Enterprise 2.0 applications. The argument, which came out of my own experience with hundreds of implementations, is that small-scale pilots are not representative of the way companies...
Once every couple of weeks, I give in to temptation and pick up dessert at Two Little Red Hens. Usually I spring for a cupcake, or maybe a cookie - but last week, I noticed a new item on offer: a lemon mousse tart.
Since this is an American bakery, it's rare to see anything (aside from chocolate mousse cake) with "mousse" in the name. There are pastries, to be sure, but they're usually of the apple pie variety - or blueberry, in the summer.
My curiosity piqued, I ordered one to go. Once I'd finished my dinner (a penitently healthful green salad with grilled chicken), I pulled the tart out of the fridge and sat down to enjoy it.
From the bottom up: a buttery, crumbly tart shell; a rich, not-too-sweet lemon curd; a light, impossibly airy lemon mousse, more akin to a rich meringue, as opposed to a heavy mousse; three strips of candied lemon peel.