http://www.planetrubyonrails.com/ - May 16, 2012 3:58:12 PM - Dec 1, 2004 7:26:52 AM
How I Open Source
Posted about 4 hours back at Jay Fields ThoughtsIt's been recently brought to my attention that I don't view open-source the way that many of my friends do. My attitude has always been:
Here's some code that works well for what I want. If it works well for what you want, great! If not, I'm willing to make changes that improve the library; however, I'm also going to reject any code that causes the library to bloat. Lastly, the library will likely be 'done' in the next few years - at which time I expect it will be mature enough that a stable final release will be possible, or someone will (re)write a superior version. I don't expect an open-source project will ever define what I accomplish in our industry.It finally occurred to me that others don't think this way when they began telling me that they don't open-source due to -I can understand each point of view, but events have occurred in my career that have shaped my (differing) opinion. I still remember my first open-source project: I didn't tell a soul about it until I had used it in production for over a year and was very confident that I'd addressed the majority of common use cases. It was a .net object relational mapper called NORM, and it was released in 2005. No, you haven't ever heard of it. I polished it for months, and no one cared. After that I never waited to release anything. I now believe that it's highly unlikely that whatever I create will ever gain any traction, so I might as well get it out there, fail quickly, and move on. No one writes documentation for themselves, they write it for people who they hope will use their software - and very few people people ever gain anything from someone else using their open-source software. That simple equation makes documentation scarce; however, scarce documentation doesn't mean you can't open-source your software, it just means adoption rates will very likely be slowed. Two years ago I open-sourced expectations with zero documentation, and documentation stayed at zero for at least a year. In that year very few people paid any attention to expectations; however, expectations does fit a sweet spot for some people, and some adoption did occur. Eventually, new adopters began to send pull requests with documentation, and their contributions inspired me to write some documentation of my own. It can be hard to get motivated about providing documentation to theoretical adopters; however, I got my code out there and adoption began, and the motivation came along with those (no longer theoretical) adopters. If you end up lucky enough to create a project that is widely used, there's no doubt that you'll start getting swamped with email. In the beginning I expect everyone will be overjoyed with their success, and the added workload will be no big deal. However, I imagine over time it begins to feel like a second full-time job, and for what? Developer-fame doesn't get you closer to retirement any faster than watching grass-grow. However, I don't believe that should deter you from putting your work out there. Additionally, I think GitHub has changed the game with respect to moving on. If your project is on GitHub and you decide to call it quits tonight, there will probably be plenty of forks that are more than happy to take your place. I have no qualms with walking away from projects, as I expect that if the idea is valuable, someone else will be happy to step up and take my place; furthermore, it's more likely that several people will step up and the strongest will survive - which is best for everyone. The best example I've ever seen of this behavior was Capistrano. Jamis Buck famously walked away from Cap in 2009, yet I still know plenty of people using it today without any issue. I firmly believe that if an idea is good, it'll live on even if you've decided you're ready to do something else.
- the code isn't mature enough
- they don't want to write documentation
- they don't want their time monopolized by feature request emails
It occurs to me that I might be a bad open-source citizen - releasing way too early and walking away too early as well. If that's the case, then I expect well deserved criticism, but that's just not how I see the world at this point...![]()
Presentation: Grid Gain vs. Hadoop. Why Elephants Can't Fly
Posted about 8 hours back atDmitriy Setrakyan introduces GridGain, comparing it and outlining the cases where it is a better fit than Hadoop, accompanied by a live demo showing how to set up a GridGain job. By Dmitriy Setrakyan
Presentation: Games for the Masses - How DevOps Affects Architecture Design
Posted about 9 hours back atJesper Richter-Reichhelm presents the DevOps integration at Wooga, and how their system architecture has evolved over the years in order to cope with the increasing number of players. By Jesper Richter-Reichhelm
The Plight of Pinocchio: JavaScript's quest to become a real language
Posted about 11 hours back at opensoul.org - HomeJavaScript is no longer a toy language. Many of our applications can’t function without it. If we are going to use JavaScript to do real things, we need to treat it like a real language, adopting the same practices we use with real languages.
This framework agnostic talk takes a serious look at how we develop JavaScript applications. Despite its prototypical nature, good object-oriented programming principles are still relevant. The design patterns that we’ve grown to know and love work just as well in JavaScript as they do any other language. Test driven development forces us to write modular, decoupled code.
Here are the slides for my JSDay talk
<script async="" class="speakerdeck-embed" data-id="4fa986b3a117fc00220012ed" data-ratio="1.3333333333333333" src="//speakerdeck.com/assets/embed.js"></script>
Posted about 17 hours back atPosted 1 day back atPosted 1 day back atPosted 1 day back atPosted 1 day back atPosted 1 day back at InfoQ Personalized Feed for unregistered user - Register to upgrade!Posted 1 day back at
#350 REST API Versioning
Posted about 6 hours back at RailscastsAPIs should be consistent, but it is difficult to do this when returning a JSON response along side the HTML interface. Here I show how to add a versioned, RESTful API. The version can be determined from either the URL or HTTP headers.
BOSH: What, How, When
Posted about 7 hours back at Dr NicI’m still very bullish on BOSH. I’ve been experimenting with it internally at work, looking to see how it could duplicate or improve upon our current infrastructure, automation and release management. I’ve also watched the commits that have come out in the last month and I’m excited by the project velocity and direction.
A few weeks ago I was fortunate to be invited to LinkedIn to the SV Forum group to give an introduction to BOSH. What it is, why it was created, how to use it and when you might use it.
If you’re interested in BOSH or even CloudFoundry itself, this talk also includes cutaways to Vadim Spivak from the Cloud Foundry core team, who has many very interesting things to say about BOSH and the future of BOSH.
<iframe src="http://player.vimeo.com/video/42248020" width="600" height="337" frameborder="0" webkitallowfullscreen="" mozallowfullscreen="" allowfullscreen=""></iframe>
BOSH: What, How, When from Dr Nic on Vimeo
This talk is one hour. If you only have 10 minutes, there is a good introduction upfront.
I’ve rewatched this talk. Given all the things I’ve learnt about using it and living it, for the most part I still agree with myself and what I said. That’s handy.
It was two days after RedHat had released OpenShift, so I had a few bonus comments to make about OpenShift towards the end of the talk. I’m also some what liberal with making jokes about any other technology that comes into my mind at the time. A politically correct person might have said different things.
At the time of the talk, I was not able to give a live demo of BOSH. I think such a demo would be valuable to get a complete “what is BOSH?” understanding, since it was a 5 minute demo that sold me on it.
Thanks to LinkedIn for recording the talk and for letting me share the video, and to LinkedIn’s Dan Lujan for doing the great post-production work. It’s a great room they have there for giving talks, and with all the cameras in the room they got some great shots of Vadim answering questions.
Related posts:
- Creating a BOSH from scratch on AWS A lot of devops projects revolve around managing instances/VMs...
Posted about 16 hours back atPosted about 18 hours back atPosted about 20 hours back atPosted about 21 hours back atPosted about 22 hours back atPosted about 23 hours back atPosted 2 days back atPosted 2 days back atPosted 2 days back atPosted 3 days back at
Running the Tizen SDK Simulator on non-Ubuntu Linux
townx - techThis explains the steps you need to get the Tizen SDK Simulator working standalone on Linux. Also shown is a small example of how to exercise some of the HTML5 APIs in Tizen to demonstrate how the Simulator does its stuff.
The aim here is to get a working Tizen dev environment, without having to download and run the full Tizen SDK (a 1Gb download), and on platforms which aren't officially supported (only Windows and Ubuntu are supported, but I use Fedora). It's not the recommended or official way to use the Tizen SDK (see https://developer.tizen.org/sdk for that), but it is a way to use a bit of it. I also can't vouch for whether it's a sensible thing to do as I've only tested one toy application with it so far. But it is fun.
The Simulator is actually a fairly small (5Mb) Chrome extension, which is based on a fork of Ripple:
"Ripple is a multi-platform mobile environment emulator that runs in a web browser and is custom-tailored to HTML5 mobile application testing." (http://ripple.tinyhippos.com/ ; NB the company that developed it has been acquired by RIM).
The Tizen simulator extends Ripple with stubs for the APIs which are specific to Tizen, but not necessarily present in other HTML5 environments (e.g. sensor and messaging capabilities). This enables you to build applications which use those APIs if you don't have access to Tizen hardware. (The other alternative is to use the full Tizen SDK, which provides an emulator that runs "real" versions of the APIs; however, this is a big install and only works on Ubuntu and Windows.)
The steps:
1. Go to https://www.tizen.org/user/register and register for a Tizen account. This is free to anyone.
2. Register your public ssh key for Tizen Gerrit, at https://review.tizen.org/gerrit (Gerrit is the code review tool used by the Tizen project). You can then use ssh to checkout Tizen source (I couldn't check out directly from source.tizen.org and kept getting timeouts, but did manage a checkout via Gerrit). All this is explained on the platform developer orientation pages.
3. Clone the part of the SDK we're interested in: the webapp plugins for Eclipse:
git clone ssh://<your tizen.org username>@review.tizen.org:29418/sdk/ide/webapp-eplugin.git4. Now you have the source code for the Tizen SDK Simulator plugin for Eclipse (as well as a lot of other plugins). We're just going to use a part of this to set the simulator up to work with Chrome.
The piece we need is in this location (relative to the directory you made the clone from):
./webapp-eplugin/org.tizen.web.simulator/pkg/web
So copy those files somewhere else to make them easier to get at:
$ mkdir ~/tizen-simulator $ cp -a ./webapp-eplugin/org.tizen.web.simulator/pkg/web/* ~/tizen-simulator/Take a look to check you have the right files:
$ cd ~/tizen-simulator $ ls beep.wav cache.manifest images index.html package.json ripple.css ripple.js themesThat's all the code you need for the Simulator.
5. Open up Google Chrome (a recent version; I'm using 20.0.1132.3 dev) and type the URI for the Simulator in the address bar, i.e.:
file:///home/user/tizen-simulator/index.html
(replace "user" with your Linux account username)
You should see the Simulator UI with a blank "phone" in it.
6. You need a project to test against, so make one like this:
$ mkdir ~/tizen-messaging-testThen add two files to this directory.
~/tizen-messaging-test/index.html:
<!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0, target-densityDpi=device-dpi"> <meta name="description" content="Tizen web app"/> <title>messaging test</title> </head> <body> <p>Tizen SDK Simulator running on Linux.</p> <script src="main.js"></script> </body> </html>(you need to use real script tags, but I can't put them in here as the Drupal editor removes them...)
and ~/tizen-messaging-test/main.js:
window.onload = function () { var errorCb = function (err) { console.error(err); }; var successCb = function (services) { if (services.length === 0) { console.error('could not get email service'); return; } var service = services[0]; // listen for message changes; NB when the message is sent below, // it appears in the OUTBOX folder and a notification is logged var messagesChangedListener = { messagesadded: function (messages) { console.log(messages[0].folderId); }, messagesupdated: function (messages) {}, messagesremoved: function (messages) {} }; service.messageStorage.addMessagesChangeListener(messagesChangedListener); // send a message var msg = new tizen.Message("messaging.email", { 'to': ['bingo.barry@bogus.com'], 'subject': 'hello email from Tizen web app', 'plainBody': 'hello' }); service.sendMessage( msg, function (recipients) { console.log(recipients); }, errorCb ); }; tizen.messaging.getMessageServices("messaging.email", successCb, errorCb); };See the Tizen developer docs for more information about the APIs supported. Also note that I'm not suggesting this as a sane pattern for structuring an application.
7. Open the Simulator at your new project by entering the address in Chrome:
<notextile>file:///home/user/tizen-simulator/index.html?url=file:///home/user/tizen-messaging-test/index.html</notextile>
(replace "user" with your Linux username)
Note that the URL of the project is passed as a url=xxx parameter to the Tizen simulator.
Also note that things don't work so nicely if you run the Simulator and the application on different domains (you get cross domain errors), even if the Simulator is a Chrome extension with permissions set to allow requests to any domain (I tried). The easiest thing to do is run both from file:// URIs.
You should see the index.html page in the "phone" with the message:
"Tizen SDK Simulator running on Linux."Like this:
Next, Ctrl+Shift+j to see the console output. You should see something like:
Ripple :: Environment Warming Up (Tea. Earl Gray. Hot.) ripple.js:27588 TIZEN :: Initialization Finished (Make it so.) ripple.js:27588 OUTBOX main.js:11 ["bingo.barry@bogus.com"] main.js:28"OUTBOX" is the name of the folder containing the sent message (i.e. it's queued and ready to go); ["bingo.barry@bogus.com"] is an array of the recipient names to whom the message was successfully sent. This proves that the Simulator's API stubs are working correctly.
One other thing you might notice is that if you click the refresh button inside the simulator to reload the project, you get this in the console:
Uncaught ReferenceError: tizen is not defined main.js:41 TIZEN :: ----------------------------------------------------------- ripple.js:27588 TIZEN :: Pay no attention to that man behind the curtain. ripple.js:27588 TIZEN :: Environment Warning up again (Set main batteries to auto-fire cycle) ripple.js:27588 TIZEN :: Initialization Finished (Make it so.) ripple.js:27588 Uncaught TypeError: Cannot call method 'log' of undefined main.js:11 ["bingo.barry@bogus.com"]At first I thought this was a bug caused by me hacking the simulator out of the SDK. But when I checked, the same bug happens in the Simulator when run from the SDK installed on Windows. So it's either an SDK bug or I'm doing something wrong in my code (needs further investigation), but at least it isn't an artefact of the simulator being disemboweled.
That's it. You can continue developing your application with whatever JavaScript libraries take your fancy.
Types of Coupling
Posted about 10 hours back atThose of you coming from a Google search are about to be disappointed: this is a post about types of coupling in programming.
Coupling refers to the degree to which components in your program rely on each other. You should generally seek to minimize this property, though you’ll see it’s impossible to eliminate entirely.
Here are a few types of coupling, ordered by severity (first is worst):
Pathological Coupling
Your class reaches inside another class and reads (or, perish the thought, changes) its instance variables.
You are literally pathological and deserve the pain this will cause you.
class NuclearLaunchController def initialize(launch_codes) @launch_codes = launch_codes end end class ExtremelyBadIdea def initialize(nuclear_launch_controller) @launch_controller = nuclear_launch_controller end def do_bad_things # This is poison @launch_controller.instance_variable_set(:@launch_codes, 'password') end endGlobal Coupling
You have two classes that both rely on some shared global data, maybe a Singleton or a class variable.
When many test files all depend on global factory definitions, a change to any one can ripple through the system.
# spec/factories.rb FactoryGirl.define do factory :user do # Changes here are global and can affect many test files. end end # spec/model/user_spec.rb before do # This refers to global data. @user = build_stubbed(:user) end # spec/model/order_spec.rb before do # So does this. @user = build_stubbed(:user) endNote that this is probably an example where the cure (duplicating the logic for creating test objects in every spec) is worse than the disease.
Control Coupling
You pass in a flag that tells a method what to do.
Remember
save(false)inActiveRecord? That boolean argument caused control coupling. Remember how we all had to change our code when it becamesave(validate: false)? If we’d been callingsaveandsave_without_validationinstead, Rails Core could have refactored that method more times than the router and we’d never have known. Also, notice that passingvalidate: falseintosavedoes not reduce the coupling, it’s just disguised better.Control couples are smelly because the calling method has intimate knowledge of how the receiver implements the method being called. You’re determining what an object should do based from outside it. Good OOP lets objects decide what to do based on their own state.
def save(should_run_validations=true) # When you see a parameter in a conditional, that's control coupling. # The fact that this method has an if in it has leaked out into client code. # Changes can now require changes in these clients. if should_run_validations run_validations persist else persist end end # One possible fix: define two methods and let the clients # choose which to call. Now we can refactor either without # affecting clients. def save run_validations persist end def save_without_validations persist endData Coupling
You call a method and pass it a parameter that doesn’t affect its control flow.
This is still coupling, but we’re starting to reach the kind that isn’t so bad. Sometimes you need parameters! If you wanted to remove all coupling you wouldn’t be able to pass data between objects at all.
class ScreenPrinter # This method is coupled to its parameter, because a change to that argument # can cause breakage (if we undefined to_s, for example). def print(text) output_to_screen(text.to_s) end endMessage Coupling
You call a method on an object and send no parameters.
You’re coupled to the name of the message, but not any hint of its implementation. This is the loosest type of coupling and should be your goal. Notice that this makes methods that take no arguments better than methods that take one (and so on).
# No reliance on anything outside this object. Feels good, man. class ScreenPrinter def print_to_screen output_to_screen(@text) end endKeep an eye out for the nasty types of coupling in your code, and see if you can can’t refactor it into something further down the ladder.
(I cribbed this list of coupling types from Wikipedia’s article, paraphrased and added examples. The original article is worth reading.)
Posted about 12 hours back atPosted about 12 hours back atPosted about 14 hours back atPosted about 14 hours back atPosted about 17 hours back at
Posted about 3 hours back at Ruby5
Episode #272 - May 15th, 2012
We look at easier schema-less hstore on Postgres, Ruby versions in your Gemfile, and Skype in your app. We learn how to DRY better, build a Gem from scratch, build a book without scratching yourself and how to binge on Code School for free.
Listen to this episode on Ruby5
This episode is sponsored by Harvest
Harvest is a painless time tracking and invoicing Rails application relied on by the most innovative teams in over 100 countries worldwide. Track time from anywhere, and invoice your clients in seconds.meta_types
meta_types from the metaminded team is a clean implementation for using hstore (schema-less data) on postgres, which is supported on Heroku.Multiple Ruby version support on Heroku
Heroku now allows you also specify what version of Ruby you want to run in your Gemfile. The only caveat is that you can't specify a patch level. Heroku will pick the safest patch level for a specific version.Libskypekit & Skypekit
Skype, the VoIP application has a developer API that will allow you to interface with the native desktop Skype app, and another one that uses the SkypeKit runtime to basically giving you a headless Skype application. You can program it to make or receives calls or instant messages through the Skype platform and setup video conferencing. Andriy Yanko from Railsware just released a Gem using Foreign Function Interface (FFI) to communicate with SkypeKit so you can build apps using Skype.Code Duplication
In an interesting series of blog posts on Code Smells, Piotr Solnica talks about code duplication and how it’s a bit more complex than just finding redundant code. Through a few examples he demonstrates that it’s often duplicated concepts in your codebase that you should target when refactoring. He also presents cases where reducing duplication causes added complexity and obfuscation, which can be worse.From customer requirements to releasable gem
Ken Mayer dropped us a line about a blog post he wrote on Sunday where he walks through extracting some functionality from a client project into open source. While the library itself is pretty simple, allowing you to set attributes on a model to read only on a per-instance basis, the blog post itself is a great case study on all of the steps you should go through to develop a well rounded piece of open source: giving the code a MIT license, a gem specification, documentation in the README, integration tests, Generators, and shareable tests.Build a book with Bookshop
We often encourage people to contribute to open source projects on Ruby5 but there’s another great way to help improve the community: writing books. Putting digital pen to binary paper. Dave Thompson let us know about a gem he just released called Bookshop which serves as an open-source book development framework. You can write everything in HTML5, CSS and JavaScript and Bookshop will help you output to any of the common eBook formats: Print or Online PDF, mobi, and ePub.Code School Free Weekend
This weekend from Friday, May 18th at 8 PM to Sunday, May 20th at midnight eastern time everything on Code School will be completely free. If you’ve been meaning to check out some of our paid Code School courses, like Backbone.js, CoffeeScript, Rails Best Practices, CSS Cross Country, Rails Testing for Zombies, or Journey Into Mobile this would be a great opportunity to give it a try. Spots for the weekend are limited, so to reserve a space you’ll want to follow the link below.Spring JavaScript Performance Special!
Posted about 3 hours back at mir.aculo.us - HomeThere are no excuses to not have fast-loading, delightfully quick websites and apps. With Amy Hoy’s and my JavaScript Performance ebook, you’ll learn about what’s important and where the low-hanging web performance fruit hangs; as well as how to speed up your JavaScript codes—and for a short 4 days (until May 19!) we’re selling it for more than 50% off with code JSSPRING
Grab your copy now for just $19!
$39![]()
Presentation: High Availability at Heroku
Posted about 5 hours back atMark McGranaghan presents how Heroku has designed, developed and operated cloud services providing high availability for their PaaS. By Mark McGranaghan
Get your callbacks on with Factory Girl 3.3
Posted about 6 hours back atFactoryGirl 3.3.0 was released this weekend with a slew of improvements.
To install, add (or change) your Gemfile:
gem 'factory_girl_rails', '~> 3.3.0'New Callback Syntax
Callbacks have been revamped to work well in conjunction with custom strategies. Instead of declaring callbacks like this:
FactoryGirl.define do factory :user do factory :user_with_posts do after_create {|instance| create_list(:post, 5, user: instance) } end end endyou can declare callbacks with
beforeandafter, passing the symbol of the callback as the name:FactoryGirl.define do factory :user do after(:custom) {|instance| instance.do_something_custom! } factory :user_with_posts do after(:create) {|instance| create_list(:post, 5, user: instance) } end end endFinally, you can use completely custom callbacks without a before or after prepended by just calling
callback:FactoryGirl.define do factory :user do callback(:custom_callback) {|instance| instance.do_something_custom! } end endThese work great with custom strategies:
class CustomStrategy def initialize @strategy = FactoryGirl.strategy_by_name(:create).new end delegate :association, to: :@strategy def result(evaluation) @strategy.result(evaluation).tap do |instance| evaluation.notify(:custom_callback, instance) # runs callback(:custom_callback) evaluation.notify(:after_custom, instance) # runs after(:custom) end end endSupport all
*_listmethodsFactoryGirl already introduced
build_listandcreate_listto build and create an array of instances; in 3.3.0,*_listmethods are generated dynamically for all strategies registered, sobuild_stubbed_listandattributes_for_listjoin the immediate roster of methods; if you were to register a strategy named “insert”,insert_listwould exist as well.Fix
to_createandinitialize_withwithin traitsTraits are a great way to name an abstract concept of attributes, but for a long time, they didn’t support defining
to_createinitialize_with. 3.3.0 fixes this shortcoming by havingto_createandinitialize_withbehave in traits exactly as you’d expect. This is perfect for decorating objects from within FactoryGirl.class NotifierDecorator < BasicObject undef_method :== def initialize(component) @component = component end def save! @component.save!.tap do Notifier.new(@component).notify("saved!") end end def method_missing(name, *args, &block) @component.send(name, *args, &block) end def send(symbol, *args) __send__(symbol, *args) end end FactoryGirl.define do trait :with_notifications do to_create {|instance| NotifierDecorator.new(instance).save! } end factory :user end create(:user, :with_notifications) # decorates save! when the instance is created FactoryGirl.define do trait :with_notifications do initialize_with { NotifierDecorator.new(new) } end factory :post end create(:post, :with_notifications) # returns a post instance decorated with NotifierDecoratorDefine
to_createandinitialize_withgloballyIf you’re using an ORM other than ActiveRecord, you may want to call different methods for persistence. Declaring a
to_create(orinitialize_with, if you wanted to use a global decorator) within theFactoryGirl.defineblock will now apply to all declared factories, behaving much like sequences, traits, and factories.You can override the global
to_createinitialize_withwith traits or by definingto_createin a factory explicitly.FactoryGirl.define do to_create {|instance| instance.persist! } factory :user do factory :user_backed_by_active_record do to_create {|instance| instance.save! } end end endWhat’s next?
There are still cases where traits don’t behave correctly (using implicit traits is a big remaining bug) and more work for
initialize_withand accessing attributes needs to be done.Agile Development with Clojure
Posted about 8 hours back at Jay Fields ThoughtsIf you've ever spent any time learning Rails then you probably read one of the editions of Agile Web Development with Rails, and if you're like me (skeptical & pedantic) then you probably asked yourself: what the hell does Rails have to do with Agile development? At the time, I assumed that Dave and David were merely capitalizing on the buzz around Agile; however, even if that's the case, I think they did manage to highlight one of my favorite aspects to building websites with Rails: The ability to make a change, reload the page and see the results makes you a much more agile programmer - where 'agile' is defined as: Characterized by quickness, lightness, and ease of movement; nimble
It turns out, it's not very hard to get that same productivity advantage in Clojure as well. I would go so far as to say that the ability to change the server while it's running is assumed if you're using emacs+slime; however, what's not often mentioned is that it's also possible (and trivial) to reload your server code (while it's running) even if you're using IntelliJ, scripts, or anything else.
The majority of the servers I'm working on these days have some type of web UI; therefore, I tie my server side code reloading to a page load. Specifically, each time a websocket is opened the server reloads all of the namespaces that I haven't chosen to ignore. The code below can be found in pretty much every Clojure application that I work on.(defonce ignored-namespaces (atom #{})) (defn reload-all [] (doseq [n (remove (comp @ignored-namespaces ns-name) (all-ns))] (require (ns-name n) :reload )))Like I said, when I open a new websocket, I call (reload-all); however, the (reload-all) fn can be called on any event. When discussing this idea internally at DRW, Joe Walnes pointed out that you could also watch the file system and auto-reload on any changes. That's true, and the important take-away is that you can easily become more productive simply by finding the appropriate hook for what you're working on, and using the code above.
The ignored-namespaces are important for not reloading namespaces that don't ever need to be reloaded (user); other times you'll have a namespace that doesn't behave properly if it's reloaded (e.g. I've found a record + protocol issue in the past, so I don't dynamically reload defrecords in general).
The change-reload webpage-test loop is nice for making changes and seeing the results very quickly - and I strongly prefer it to having to stop and start servers to see new functionality.
Posted 1 day back atPosted 1 day back atPosted 1 day back atPosted 2 days back at
Posted about 17 hours back atPosted about 17 hours back atPosted about 19 hours back atPosted about 20 hours back atPosted 5 days back atPosted 5 days back atPosted 6 days back at
Presentation: A Snapshot of the Mobile HTML5 Revolution
Posted about 8 hours back atJames Pearce discusses the status of HTML5, what it can do today and what it still missing across major mobile browsers. By James Pearce
Interview: Big Data Architecture at LinkedIn
Posted about 8 hours back at InfoQ Personalized Feed for unregistered user - Register to upgrade!In this interview with at QCon London, LinkedIn’s Sid Anand discusses the problems they face when serving high-traffic, high-volume data. Sid explains how they’re moving some use cases from Oracle to gain headroom, and lifts the hood on their open source search and data replication projects, including Kafka, Voldemort, Espresso and Databus. By Siddharth Anand
Presentation: The JavaScript World Domination Plan at 16 Years
Posted about 10 hours back at InfoQ Personalized Feed for unregistered user - Register to upgrade!Brendan Eich recaps the major milestones and controversies in JavaScript’s history, the performance improvements, the current work on the next version of JavaScript, ending with some demoes. By Brendan Eich
All Presentation Software is Broken
Posted about 11 hours back at igvita.com
Whenever the point I'm trying to make lacks clarity, I often find myself trying to dress it up: fade in the points, slide in the chart, make prettier graphics. It is a great tell when you catch yourself doing it. Conversely, I have yet to see a presentation or a slide that could not have been made better by stripping the unnecessary visual dressing. Simple slides require hard work and a higher level of clarity and confidence from the presenter.
All presentation software is broken. Instead of helping you become a better speaker, we are competing on the depth of transition libraries, text effects, and 3D animations. Prezi takes the trophy. As far as I can tell, it is optimized for precisely one thing: generating nausea.
Next Presentation Platform: Browser
If you want your message to travel, then the browser is your (future) presentation platform of choice. No proprietary formats, no conversion nightmares, instant access from billions of devices, easy sharing, and more. Granted, the frameworks and the authoring tools are still lacking, but that is only a matter of time.
Unfortunately, we are off to a false start. Instead of trying to make the presenter more effective, we are too busy trying to replicate the arsenal of useless visual transitions with the HTML5, CSS3 and WebGL stacks. Spinning WebGL cubes and CSS transitions make for a fun technology demo but add zero value - someone, please, stop the insanity. We have web connectivity, ability to build interactive slides, and get realtime feedback and analytics from the audience. There is nothing to prove by imitating the broken features of PowerPoint and Keynote, let's leverage the strengths of the web platform instead.
Free Lunch: Web Analytics
Keynote, PowerPoint and friends are optimized to help hide your incompetence: no useful feedback, no way to measure the effectiveness of your delivery or reach of the message. On the web, we inherit all of the power of web analytics for free. We can measure slide impressions, time on slide, referrals, clicks, display heatmaps, segment the viewers, setup conversion goals and more. Let's look at a real-life example.
I've instrumented my RailsConf presentation (Making the Web Faster) with Google Analytics, where I'm tracking slide transitions and clicks via custom events and time on slide via the user timings API:
7.5K+ visits, 200K+ slides impressions, and a 40%+ return rate. An average user took 19 minutes to make their way through the slides, which translates to just over 100 "cognitive days" across all visitors. It took me roughly 20 hours to make the slides from scratch, which translates to a 1:120 hour ratio. Is this good? We can't say, but it is a baseline. I would love to compare these numbers to other RailsConf presentations.
Vanity counters are fun to share, but did the presentation convey the right message? The goal was to focus the audience on optimizing for user perceived latency and the available tools. The peaks in time on slide up to slide 20 correspond to off-site clicks to Navigation Timing spec, Google Analytics documentation, and examples - mission accomplished. Slides 30 to 40 are mostly flat: I need do a better job of motivating webpagetest.org, because it is an amazing tool. Finally, the big timing spike at the end corresponds to slides on mod_pagespeed. Next time around I will make sure to spend more time on it.
Video & YouTube Analytics
The presentation was recorded and I uploaded it to my own YouTube account - this gives you a lot of great analytics. First, it is reassuring to see that web visitors and YouTube audience retention follows the same pattern, with many of the same peaks and valleys. The added bonus: I can click on any time point and review my delivery. And what's the retention peak of entire presentation? An "inception" demo of opening Chrome's inspector, on the inspector! Not surprisingly, this also corresponds to the reaction of the audience during the live presentation.
Make me a better presenter, please!
If I was to give the same presentation again given the information above, I am confident I could now do a better job of it. Except, of course, I wouldn't give the same presentation since I can clearly see the sections that need to be improved, and a few sections that need to be cut.
I would love to see some experiments with live session feedback: am I going too fast, should I revisit a concept, perhaps even live questions. Add a websocket endpoint and all of the above is easily done. This space is ripe for disruption. Forget the animations, ornate templates, and other me-too gimmicks, make me a better presenter.
Posted 1 day back atPosted 3 days back at
Posted about 16 hours back atPosted 5 days back atPosted 5 days back atPosted 5 days back atPosted 5 days back atPosted 5 days back at
Beware Synonymatic Complexity
Posted about 3 hours back atWhen you name a class, make sure to choose something that is unlikely to refer to two different things.
For example, Visitor is a bad name for a class that represents unregistered users of your web site.
This issue is that Visitor is the name of a well-known pattern. Like it or not, the Gang of Four have claimed this one (that’s why they’re called a gang).
If you use this class name in a web-app, I can make a pretty good guess which concept you’re referring to, but there’s too much ambiguity. The name has synonymatic complexity: it sounds too much like another thing.
UnregisteredUser is a much better name. It’s easy to guess what this refers to. However, notice that the ambiguity is affected by your problem domain: if we were writing an event-registration app, this name would again be ambiguous.
In general, choose names that would make it easy for a colleague to correctly guess an object’s identity.
Posted 2 days back at
Posted about 21 hours back atPosted 4 days back atPosted 4 days back atPosted 4 days back atPosted 4 days back atPosted 4 days back atPosted 4 days back at
SHOULDA BEEN GONE
Posted about 10 hours back at GIANT ROBOTS SMASHING INTO OTHER GIANT ROBOTS - HomeWe haven’t been taking pull requests on shoulda-matchers as much as we shoulda, but it’s back in the spotlight now. Shoulda’s been gone … but it’s back.
<iframe frameborder="0" height="315" src="https://www.youtube.com/embed/CNXDCHHjEvs?rel=0" width="420"></iframe>
Here are the new features in shoulda-matchers 1.1.0:
- A NEWS file so you can track new hottness in REAL TIME
- shoulda-matchers’ very first dependency: ActiveSupport >= 3.0.0. This was an implicit dependency for a while, but now it’s official.
- An
only_integeroption forvalidates_numericality_of- A
query_the_databasematcher, so that you can doit { should query_the_database(4.times).or_less }- Database column primality is correctly checked
- The flash matcher can check specific keys using
[], like so:it { should set_the_flash[:alert].to("Bad username") }- A
validates_confirmation_ofmatcher:it { should validate_confirmation_of(:password) }- A
serializematcher:it { should serialize(:details).as(Hash).as_instance_of(Hash) }- A
have_sent_emailmatcher can now checkreply_to: it { should have_sent_email.reply_to([user, other]) }- An
accept_nested_attributesmatcherIf you filed a pull request and we didn’t take a look, please re-submit or ping me on Github. We’d love to hear from you.
Posted about 23 hours back at