<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:blogger='http://schemas.google.com/blogger/2008' xmlns:georss='http://www.georss.org/georss' xmlns:gd="http://schemas.google.com/g/2005" xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-5825798647577501834</id><updated>2026-08-10T23:45:06.196-07:00</updated><category term="LMS"/><category term="Web 2.0"/><category term="eLearning"/><category term="education"/><title type='text'>The Other Brian Whitmer</title><subtitle type='html'>Yeah, so there&#39;s this like &quot;super chef&quot; guy whose name is Brian Whitmer.  That&#39;s not me.  Sorry.  Me?  I&#39;ll be talking about improving eLearning and my coding discoveries that happen along the way. &lt;a href=&quot;https://twitter.com/whitmer&quot;&gt;&lt;img src=&quot;https://upload.wikimedia.org/wikipedia/sco/thumb/9/9f/Twitter_bird_logo_2012.svg/1267px-Twitter_bird_logo_2012.svg.png&quot; width=&quot;20&quot; valign=&quot;middle&quot;&gt;&lt;/a&gt;</subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://brianwhitmer.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5825798647577501834/posts/default?redirect=false'/><link rel='alternate' type='text/html' href='http://brianwhitmer.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><link rel='next' type='application/atom+xml' href='http://www.blogger.com/feeds/5825798647577501834/posts/default?start-index=26&amp;max-results=25&amp;redirect=false'/><author><name>Brian Whitmer</name><uri>http://www.blogger.com/profile/00009042638644799674</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjuU9fLl8xHMXUGHbywzQI6WumY7z2W7ZL1iBvxzleBCeBQzIoZ5hnhALV9oSHTQs3iWNRFbTiyADkUEIENiZawHyzWZBxIq3JzvCsTANyrGx-fD1nDmk4ax2BIakeg/s1600/71c13439beedf6c35c53acb0976d97c6'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>29</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>25</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-5825798647577501834.post-4399706891850234976</id><published>2020-02-07T15:18:00.001-08:00</published><updated>2020-02-07T15:23:44.064-08:00</updated><title type='text'>Instructure&#39;s Acquisition is Not What I&#39;m Worried About</title><content type='html'>It&#39;s interesting how quickly and how slowly the world of edtech moves. I left Instructure at the beginning of 2015 to work on speech-generating software for people with disabilities. Some people tell me I shouldn&#39;t care anymore, or that I don&#39;t deserve to have an opinion anymore. That&#39;s cool, I get that, I just can&#39;t seem to stop worrying about what happens to this Little Company that Could. So here we are. There are probably, like, five of you reading this. I hope you had a pleasant week :-).&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhjKoaBykrj3vmDSSNsRG9vcms_Q-40WqSbWyw6lTFR8ryHfopfMZSfC3Vstwnw37g8FUdJp0S5pKZoFgyPU_i5BbJMVU3aMU4qel6nWAwlUtywmaJgiY9lkR3G3dIyPpaqxV54v49mNLs/s1600/Picture1.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;694&quot; data-original-width=&quot;931&quot; height=&quot;238&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhjKoaBykrj3vmDSSNsRG9vcms_Q-40WqSbWyw6lTFR8ryHfopfMZSfC3Vstwnw37g8FUdJp0S5pKZoFgyPU_i5BbJMVU3aMU4qel6nWAwlUtywmaJgiY9lkR3G3dIyPpaqxV54v49mNLs/s320/Picture1.png&quot; width=&quot;320&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;
&lt;h3&gt;
Growing Up Edu&lt;/h3&gt;
I was injected with a healthy dose of edu idealism when Devlin Daley and I, fresh out of college, met with CIOs and instructional technologists from around 20 universities and community colleges, and I like to think it&#39;s done a lot to shape my mentality around technology. If nothing else, it&#39;s been incorporated into this weird mashup of I-don&#39;t-know-much and here&#39;s-how-awesome-it-should-be that realtors, contractors and consultants all stopped bothering trying to wrap their heads around eventually. I&#39;m kind of a mess :-).&lt;br /&gt;
&lt;br /&gt;
I believe that technologists should find and implement interesting and valuable solutions to existing problems, and that there should be compensation available for their work. It&#39;s pretty simple and naive, but it&#39;s how I think things should work. Not all good ideas get compensated, and not all problems are well-defined, but there you have it.&lt;br /&gt;
&lt;br /&gt;
I believe that that&#39;s what we shot for when we started Instructure. There were clear problems with the LMS, and we had the right timing, background and lack of baggage to introduce a compelling solution. People were willing to pay for that solution because they believed it would improve their effectiveness or productivity.&lt;br /&gt;
&lt;h3&gt;
Spinning Plates Don&#39;t Stay Up on Their Own&lt;/h3&gt;
Neither Devlin or I wanted to actually run the company, so we brought in others at different levels who did, which was undoubtedly a good idea. Some of our new business-heads had different motivations, which is fine, but it meant that as the company grew we had people in leadership roles who never really understood what it was that got people excited about Canvas. They knew people thought it was a game-changer, but they didn&#39;t understand or didn&#39;t care about the intricacies of the edtech market. Software-company-as-a-generic-machine is a mentality that starts with investors and trickles its way down into all the seams. Sales is sales, support is support, you plug in the right pieces and out comes the revenue.&lt;br /&gt;
&lt;br /&gt;
For us, it seemed like the only place where this broke down was around product strategy. We couldn&#39;t seem to empower the product team enough to drive a strong strategy and ended up chasing revenue or headlines. We won some great deals (and headlines) early on, so it&#39;s not like it was a complete loss, and it&#39;d be easy to blame our shifting tides of product focus things on the edtech market and its idealism or lack of savvy or privacy-mindedness or corporate sensitivity, but I was over product in those days so, you know, my bad.&lt;br /&gt;
&lt;br /&gt;
I believe that this product problem was part of an issue that&#39;s still showing up today with Instructure, and it affects the company strategy in general. It has to do with bolt-on acquisitions and not-invented-here syndrome. It has to do with chasing the dollar instead of earning the dollar. It has to do with forgetting to strategically ignore ROI. It has to do with how nobody gets fired for following the Silicon Valley playbook.&lt;br /&gt;
&lt;h3&gt;
Finding the Right Playbook&lt;/h3&gt;
The hard truth is that when you bring on an institutional investor, they don&#39;t really care what you&#39;re already doing, they&#39;re only looking at upside because they&#39;re there to optimize their return going forward. Some investors do this hyper-short-term, and mess up their companies down the line. Some apply healthy pressure and are more patient as long as they&#39;re still confident they can beat the return they&#39;d get from other investment strategies. Either way, they see each company as a revenue opportunity, not a feel-good story to tell their grandchildren.&lt;br /&gt;
&lt;br /&gt;
This isn&#39;t inherently bad. They get their money after the company makes money, and the company makes money when people are excited enough about it to give it new money. So investors look for patterns of behavior that worked well in other situations and apply them once again. Accelerate revenue by entering a new market or increasing walletshare for existing customers. Improve margins by paring down R&amp;amp;D and shifting resources away from established product lines. Bring in an executive layer that already has experience handling issues at the upcoming stage of the company&#39;s growth. It&#39;s a sort of standard operating procedure you can start from to make sure you&#39;re not accidentally veering off in a weird direction. Sometimes you may want to veer, but if not then it&#39;s the &quot;safe&quot; route because it&#39;s so well-trodden. Once companies get big enough you don&#39;t need investors suggesting this stuff anymore because the corporate executive team has already been trained in how it all works.&lt;br /&gt;
&lt;br /&gt;
Except it doesn&#39;t all just work. Personally I&#39;m not a huge fan of any of the above strategies, but that&#39;s ok, they&#39;re really just business decisions. They can succeed or not based on what happens underneath and around them. That&#39;s where I think Instructure has been struggling, though. It&#39;s not that the broad strokes are all wrong-headed, but they won&#39;t succeed just because they&#39;re what you&#39;re supposed to do. At a high level things at Instructure don&#39;t seem particularly deliberate or concerted so much as just, what you&#39;re supposed to be doing, and I think people are starting to notice.&lt;br /&gt;
&lt;br /&gt;
Unfortunately, I think this has been going on a lot longer than people realize. Before I left there was already hand-wringing around &quot;why can&#39;t we just build the next SpeedGrader?&quot; ironically mixed with &quot;let&#39;s shift resources over to new projects&quot; and &quot;we have too many bugs so we&#39;re going to pause new development for a while and address stability&quot;. It&#39;s hard not to fall into a routine of medium-term hype-chasing and putting out fires, which I think comes from that business-for-business&#39;-sake mentality. I&#39;m way too much of a product person so I never actually think a product is &quot;done&quot; (it&#39;s a personal problem :-)), but it&#39;s especially hard for me to see untapped potential in a product -- even one that doesn&#39;t have justifiable revenue upside.&lt;br /&gt;
&lt;br /&gt;
I believe that Instructure worked so well in the early days because we accidentally instilled in everyone an urgency and empowerment to think of ways to make things better, even if it was less efficient. Some people come by it naturally, some focus on their own little domain, but the outliers were the ones there to just &quot;do my job&quot;. We drove home how much we needed top to bottom ears to the ground, and we absorbed and obsessed over all that feedback so we could throw all sorts of unique ideas against the wall and build the ones that stuck. I&#39;ve watched that kind of whittle away over time as people got roasted for sticking their necks out, and deadlines and parity and we-can-build-and-sell-one-of-those started trumping that&#39;s-interesting-how-could-we-improve-that.&lt;br /&gt;
&lt;h3&gt;
Keep Canvas Weird&lt;/h3&gt;
Look, none of this is particularly ground-breaking. &quot;Founder says company needs to stop being all corporatey and focus on what made them great in the good old days. Nothing to see here, move along.&quot; You could say I&#39;m just drawing from the playbook of what founders did in the past, we all play our part and the pattern repeats itself. I won&#39;t get my feelings hurt, I&#39;ll just chalk this post up to catharsis or something. I just can&#39;t &lt;i&gt;not&lt;/i&gt; say something so long as I think my saying something has a chance to turn at least a couple heads back toward the idea of solving interesting problems.&lt;br /&gt;
&lt;br /&gt;
It&#39;s not like nothing good has happened. The Canvas API has solidified, mastery-based courses can grow into something cool, and I&#39;m interested to see how the new Analytics views develop. But Canvas can do a lot more. Did you know the original version of Canvas has a feed reader where students could register their personal blogs and then submit homework to their classes just by posting with the right hashtag? Or that we originally had an embed code you could drop in your HTML to allow access to grades, homework submissions and discussion boards from an arbitrary web site? Or that we mostly-completed a heuristic-based tool that would highlight outlier students based on activity and participation in that specific class? Or that we half-wrote a tool for auto-assigning students to groups based on same- or different-mindedness based on a teacher-created survey?&lt;br /&gt;
&lt;br /&gt;
I can tell you exactly why none of those projects stuck, and maybe they all sound like terrible ideas to you. But as Instructure has become more streamlined and optimized, it&#39;s harder for me to envision where in the company those types of ideas can even germinate. When business pressures are applied, everything naturally moves toward the well-trodden path, where it will see less resistance. This is a big part of why most big companies just copy each other&#39;s features, or end up buying their way to innovation, there&#39;s literally nowhere left for the interesting solutions to get enough oxygen.&lt;br /&gt;
&lt;br /&gt;
Typically innovation still happens at large companies only when someone high up has gained enough social capital to just do what they want, or when the company makes a deliberate decision to shield some groups from the business scrutiny of optimization. I&#39;m not confident that Instructure has been set up to accomplish that kind of innovation for quite a while. Even back when I was wrapping up my time, the teams that had enough freedom to do anything more than incremental development and refactoring were pretty minimal. I would be surprised if things have improved on the Canvas side.&lt;br /&gt;
&lt;h3&gt;
What Now?&lt;/h3&gt;
I don&#39;t believe Instructure has lost its soul. I think people still get jazzed about working there. I think customers are still generally happy with Canvas. I think Canvas is a valuable contribution to education. But I don&#39;t think customers are looking to Instructure anymore for the Next Cool Thing. And I do worry the company&#39;s open floor plan is shifting from &quot;I can walk info wherever it needs to go&quot; to &quot;I have a great view outside but it&#39;s kind of noisy in here&quot;. I worry that Canvas is about as good as it&#39;s going to get, which bums me out since we never managed to tweak things enough to convert the edupunks (personal problem again). There are a lot of forces tugging on the company anymore, and it&#39;s hard for me to see how adding another return-focused investor is going to do anything to improve the existing product (indeed, Michael Feldstein argues that Instructure&#39;s problem is that it needs more breadth, not more Canvas Cowbell). But those are primarily business decisions, they can end up good or bad depending on how you handle them. For me (and, I would argue, for edtech customers), I care much less about percent ownerships or the size of Instructure&#39;s product portfolio than I do about the current (not historical) impact of the products in that portfolio.&lt;br /&gt;
&lt;br /&gt;
Again, I&#39;m not here proclaiming all is lost, woe is my old company. I think there&#39;s a course correction in order, but nothing terribly drastic. There are still great people at Instructure trying to make good things happen for educators and learners, and there are great customers who want to share their insights to keep improving on a strong foundation. But nobody asked for SpeedGrader, it showed up because we had the latitude to throw it against the wall. If there were a way to shift back to that old style, where business-heads make sure things stay smooth and maintained, but while also letting enough people get all weird solving compelling problems for educators and learners, I think you&#39;d see a &quot;next SpeedGrader&quot; show up of its own accord. And maybe the portfolio would grow too, who knows? But it wouldn&#39;t be expansion for revenue&#39;s sake, it would be building interesting things and figuring out how the industry is willing to compensate for them. My druthers would be allocating resources based on social impact as opposed to revenue, but I understand if that&#39;s a (ahem) bridge too far.&lt;br /&gt;
&lt;br /&gt;
It&#39;s true that growth is slowing for Canvas, so from a business perspective that means there&#39;s less value to be had investing there. Unless, of course, people become dissatisfied or disillusioned and move to a different product -- but frankly there&#39;s not anyone doing drastically better in the space so the current risk is small. Canvas wouldn&#39;t be the first LMS to fester all fat and happy, though, and you can&#39;t ramp down and up R&amp;amp;D and expect it to remain effective. There are interesting problems I wish Canvas already had solutions implemented for. Some of them have been sitting in the Feature Request queue for years. There are going to be new problems that Canvas could grow to solve. I wish I was more confident people inside the company will be empowered to create the solutions.&lt;br /&gt;
&lt;br /&gt;
I hope Instructure can find a way to keep solving interesting problems in education, I still don&#39;t see anybody else in a better position to provide a major influence on educational technology. I&#39;m confident that the industry will continue to compensate them for their work as long as they do.</content><link rel='replies' type='application/atom+xml' href='http://brianwhitmer.blogspot.com/feeds/4399706891850234976/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/5825798647577501834/4399706891850234976' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5825798647577501834/posts/default/4399706891850234976'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5825798647577501834/posts/default/4399706891850234976'/><link rel='alternate' type='text/html' href='http://brianwhitmer.blogspot.com/2020/02/instructures-acquisition-is-not-what-im.html' title='Instructure&#39;s Acquisition is Not What I&#39;m Worried About'/><author><name>Brian Whitmer</name><uri>http://www.blogger.com/profile/00009042638644799674</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjuU9fLl8xHMXUGHbywzQI6WumY7z2W7ZL1iBvxzleBCeBQzIoZ5hnhALV9oSHTQs3iWNRFbTiyADkUEIENiZawHyzWZBxIq3JzvCsTANyrGx-fD1nDmk4ax2BIakeg/s1600/71c13439beedf6c35c53acb0976d97c6'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhjKoaBykrj3vmDSSNsRG9vcms_Q-40WqSbWyw6lTFR8ryHfopfMZSfC3Vstwnw37g8FUdJp0S5pKZoFgyPU_i5BbJMVU3aMU4qel6nWAwlUtywmaJgiY9lkR3G3dIyPpaqxV54v49mNLs/s72-c/Picture1.png" height="72" width="72"/><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5825798647577501834.post-1019819088898528046</id><published>2018-07-17T12:55:00.001-07:00</published><updated>2018-07-18T11:26:09.208-07:00</updated><title type='text'>Dear Instructure: Please Don&#39;t Become the Next Blackboard</title><content type='html'>I was classically trained on the five-paragraph essay and took my fair share of AP classes, so &quot;compare and contrast&quot; is like a reflex for me. When I read Michael Feldstein&#39;s article on&amp;nbsp;&lt;a href=&quot;https://mfeldstein.com/canvas-surpasses-blackboard-learn-in-us-market-share/&quot;&gt;Canvas taking Blackboard&#39;s spot on the LMS totem pole&lt;/a&gt;, it got my gears spinning. If Instructure is finally taking top shelf, what are we going to do to not become exactly what we set out to fix in the first place?&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://media.giphy.com/media/12kQczfejiVQxW/giphy.gif&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;327&quot; data-original-width=&quot;400&quot; height=&quot;261&quot; src=&quot;https://media.giphy.com/media/12kQczfejiVQxW/giphy.gif&quot; width=&quot;320&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;
&lt;br /&gt;
Instructure is working on new leadership in marketing, sales, product, operations -- oh, and we&#39;ve also got a&amp;nbsp;&lt;a href=&quot;https://www.prnewswire.com/news-releases/instructure-appoints-software-industry-veteran-dan-goldsmith-as-president-300644227.html&quot;&gt;new President&lt;/a&gt;. Maybe a little history lesson isn&#39;t such a bad idea (&lt;a href=&quot;https://www.youtube.com/watch?v=dCIP3x5mFmw&quot;&gt;here&#39;s quick refresher of how we got started&lt;/a&gt;). My goal here is to say, &quot;hey, here&#39;s a list of things we should all keep an eye on so we don&#39;t go all you-didn&#39;t-learn-anything-President-Coin-from-Hunger-Games.&quot; Back in the day I used to take some time in every onboarding helping new hires to catch the vision of why we were different and to understand the Instructure Way. So if you like you can consider this your old-school onboarding indoctrination session.&lt;br /&gt;
&lt;br /&gt;
(It&#39;s probably worth noting that I can&#39;t help but say &quot;we&quot; even though I&#39;m not at all involved in Instructure anymore, other than the occasional lunch with my old coworkers. It&#39;s hard to let go, I guess. see: footnote)&lt;br /&gt;
&lt;br /&gt;
&lt;h3&gt;
1. Focus on the User, not the Dollar (It&#39;s Okay, the Dollar Will Still Show Up)&lt;/h3&gt;
We showed up on the edtech scene in 2008, and people were more than happy to not just give us the time of day, but to unload their frustrations with Blackboard -- and ideas for new hotness they were afraid they&#39;d never see. Blackboard was really stinking it up from what we could tell. We crashed their user&#39;s conference in Vegas after a few years and told everybody we were the anti-Blackboard. We didn&#39;t need a better value prop than that. Just &quot;not Blackboard&quot; and a bunch of t-shirts was enough to get people excited.&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg1kdGtWewm5CCm-iXDBxkX7gkzOxDQLIM95LBEbkUshEUZuzNWGTiE61FRhSnvTZp_4anIxIQC8-LFoDOVm-4ojKorH2ChRylFxWv2CM_6MBZe-tbLo9q6P-2-D7LhJfV9nZ6g53MTIdo/s1600/canvas-t-shirt-is-this-your-lms.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;251&quot; data-original-width=&quot;346&quot; height=&quot;231&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg1kdGtWewm5CCm-iXDBxkX7gkzOxDQLIM95LBEbkUshEUZuzNWGTiE61FRhSnvTZp_4anIxIQC8-LFoDOVm-4ojKorH2ChRylFxWv2CM_6MBZe-tbLo9q6P-2-D7LhJfV9nZ6g53MTIdo/s320/canvas-t-shirt-is-this-your-lms.png&quot; width=&quot;320&quot; /&gt;&lt;/a&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgzY5Wl3FwOAYEctLSYYuSAqGR7esYgkOggXh21eq2N6oCK2BmEjEEQqfgg2PwB5IuX96eQl_EtOd2eRQ5ogvecbOsf1UyAs0Q3dWvE8gSPusdJ6xTnwmXaL3zpbqD8AFHT-ctF1YqfIgE/s1600/canvas-t-shirt-cheat.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;300&quot; data-original-width=&quot;300&quot; height=&quot;200&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgzY5Wl3FwOAYEctLSYYuSAqGR7esYgkOggXh21eq2N6oCK2BmEjEEQqfgg2PwB5IuX96eQl_EtOd2eRQ5ogvecbOsf1UyAs0Q3dWvE8gSPusdJ6xTnwmXaL3zpbqD8AFHT-ctF1YqfIgE/s200/canvas-t-shirt-cheat.png&quot; width=&quot;200&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;
&lt;br /&gt;
Mind you, we had a lot more than that going for us. Blackboard and D2L have continually had a hard time figuring out what makes us better. That&#39;s probably partly because *we* had a hard time explaining what made us better. All the &quot;easy to use&quot;, &quot;end-user-oriented&quot; claims felt like hackneyed platitudes. The truth is what we built was a fresh take on the LMS, starting with students and teachers and grand instructional design ideas instead of with administration and management. Devlin Daley and I were fresh out of college, we felt the pain on the student side and as TAs, and we picked the brains of every teacher we could find.&lt;br /&gt;
&lt;br /&gt;
What was so different about Instructure is that we said &quot;teaching and learning is hard enough without technology getting in the way&quot; and we meant it. There were a hundred little fibbly bits that we coded into the product, not because they were on the top of someone&#39;s feature list or because they&#39;d close a deal, but because they were the right thing to do. We gave teachers permission to make their own content public, we gave students ownership over any files they uploaded, we made sure that there was a rational way to get to any piece of course content, we let people set their own email addresses, etc. etc. Sometimes this caused problems because we still had customers&amp;nbsp;&lt;a href=&quot;https://mfeldstein.com/dammit-lms/&quot;&gt;pushing from the management side&lt;/a&gt;, but almost always we fenagled a workaround that didn&#39;t compromise on &quot;making teaching and learning easier&quot;. And even though nobody calls out those little finishes in their &quot;why we chose Instructure&quot; blog posts, they are a major part of our &quot;different&quot; approach, and they help close deals.&lt;br /&gt;
&lt;br /&gt;
So yeah, that&#39;s gotcha number one. Are we still the student/teacher advocate? Nobody pays us to do that, and plenty of decision-makers push us to give it up, but we&#39;ve got this in our DNA and we can keep it up. The edubloggers that would function as our checks and balances have mostly written off the LMS entirely, so that leaves it on us. Keep an eye on it or you&#39;ll find people getting less excited about our products, but without a clear reason why.&lt;br /&gt;
&lt;br /&gt;
&lt;h3&gt;
2. Keep Solving Interesting Problems&lt;/h3&gt;
Blackboard&#39;s user conferences had a reputation when we showed up. They threw a great party, everyone said so. But people also said that they made a lot of noise to hide the fact that nothing interesting was actually going on with the product. Merging Blackboard and WebCT into a single company could not have been fun or easy, so they had a valid excuse, but at the end of the day interesting things just weren&#39;t happening.&lt;br /&gt;
&lt;br /&gt;
Instructure is also known for&amp;nbsp;&lt;a href=&quot;https://youtu.be/8aZcejxw0n4?t=1m50s&quot;&gt;throwing a great party&lt;/a&gt;. InstructureCon has always been a blast, with great swag, surprise performances, and a fun theme (I better see some&amp;nbsp;&lt;a href=&quot;https://www.canvaslms.com/news/instructurecon/&quot;&gt;Greatest Showman references&lt;/a&gt;&amp;nbsp;this year or I&#39;ll be sorely disappointed). But it&#39;s also been a place to grow a strong community and to introduce people to the latest and greatest in Canvas.&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;iframe allowfullscreen=&quot;&quot; class=&quot;YOUTUBE-iframe-video&quot; data-thumbnail-src=&quot;https://i.ytimg.com/vi/Afa_tKBJvJ0/0.jpg&quot; frameborder=&quot;0&quot; height=&quot;266&quot; src=&quot;https://www.youtube.com/embed/Afa_tKBJvJ0?feature=player_embedded&quot; width=&quot;320&quot;&gt;&lt;/iframe&gt;&lt;/div&gt;
&lt;br /&gt;
&lt;br /&gt;
Innovation isn&#39;t easy, and it doesn&#39;t come just at an annual user&#39;s conference. You can&#39;t just suddenly show up and say, &quot;look! Innovation!&quot; which plenty of people got at Instructure. Devlin and I made a great combo getting this stone rolling because we weren&#39;t straight execution (despite my misplaced best efforts) and we weren&#39;t just grand ideas, we had room for both, and it was awesome to see that keep going. You have to be&amp;nbsp;&lt;a href=&quot;http://brianwhitmer.blogspot.com/2014/11/on-dangers-of-prioritization.html&quot;&gt;deliberate about allowing new ideas to develop&lt;/a&gt;&amp;nbsp;or you&#39;ll end up too demand-driven. Nobody asked for SpeedGrader, or a fully-public API, or an LTI app ecosystem. We have a great head-start with our&amp;nbsp;&lt;a href=&quot;http://brianwhitmer.blogspot.com/2014/04/open-is-not-afterthought.html&quot;&gt;strategy of openness&lt;/a&gt;, but watching some other companies, I&#39;m surprised with how quickly &quot;open&quot; can die on the vine if you don&#39;t keep on it.&lt;br /&gt;
&lt;br /&gt;
&lt;h3&gt;
3. Don&#39;t Rob the Cash Cow to Pay the Pied Piper (And Don&#39;t Mix Metaphors)&lt;/h3&gt;
When we talked to schools about their beefs with Blackboard, people kept saying Blackboard was focusing on too many things. Multiple times we heard &quot;I mean, they&#39;re even running on-campus payment systems and swipe cards! It&#39;s no wonder they&#39;re not doing anything new with their LMS.&quot; Me, I&#39;m more pragmatic. I get that you need multiple revenue sources, especially if you want to grow. Sometimes they don&#39;t make much sense to outsiders.&lt;br /&gt;
&lt;br /&gt;
Instructure has had the Canvas product for a lot of years. After a bit we tweaked it for K-12. Then we did some work to get it ready for international. Then we introduced Bridge and Arc. Then we bought Practice and added Gauge. Then we started expanding our HCM suite. That&#39;s a lot of pots to stir, so you have to pay close attention if you want to do it right.&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://thumbs.gfycat.com/ObeseInfamousIntermediateegret-max-1mb.gif&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;184&quot; data-original-width=&quot;240&quot; src=&quot;https://thumbs.gfycat.com/ObeseInfamousIntermediateegret-max-1mb.gif&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;
&lt;br /&gt;
Investors ask a lot about the breakdown of our R&amp;amp;D and marketing investments. Are we putting everything into Bridge and ignoring Canvas? Are we giving international the attention it needs? Can we add a new product without jeopardizing our existing product quality? There are plenty of easy, reassuring bizspeak hush puppies, but the questions themselves are worth thinking hard about.&lt;br /&gt;
&lt;br /&gt;
Are we solving interesting problems in all the markets we&#39;re going after? If we&#39;re not doing anything interesting then what are we doing? We have some great products, and I&#39;m confident we don&#39;t need to start milking any of them as a legacy product just to siphon cash off into our next growth target. Maybe that would be a good use of funds, but it&#39;s frankly not enough, none of our products are *that* legacy. If we&#39;re going to add new products to our repertoire, then let&#39;s definitely make them awesome, we&#39;ve got the ability to keep doing that. If we don&#39;t have the bandwidth to keep making all the things awesomer, then we have too many things going on, investor pressures be darned. But hey, the good news is that we have enough employees that people should be able to be innovating just about everywhere.&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://cpb-us-e1.wpmucdn.com/sites.northwestern.edu/dist/c/214/files/2015/06/instcon3-1jea9x1.jpg&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;496&quot; data-original-width=&quot;800&quot; height=&quot;247&quot; src=&quot;https://cpb-us-e1.wpmucdn.com/sites.northwestern.edu/dist/c/214/files/2015/06/instcon3-1jea9x1.jpg&quot; width=&quot;400&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;br /&gt;
The red flag for me will be if we don&#39;t see innovations being discussed at InstructureCon. It&#39;s a bit of a coal-mine-canary for continued investment in our existing customer base. We can sell complementary products for more walletshare, and we can expand into new markets, but we have to be really careful.&amp;nbsp;We don&#39;t want to move all the Risk pieces over to Asia and leave Europe covered in little onesies.&lt;br /&gt;
&lt;br /&gt;
This one is particularly tricky, because it&#39;d be easy to justify by saying &quot;we&#39;re still investing heavily in Canvas&quot;, when really most of that &quot;investment&quot; was&amp;nbsp;just ongoing support and maintenance. I&#39;m more interested in the breakdown of the&amp;nbsp;&lt;i&gt;innovation&lt;/i&gt;&amp;nbsp;budget, and, like I said, the best external proxy I can think of is InstructureCon announcements. There&#39;s a lot of interesting work we&#39;ve been a part of, so keep an eye on what makes it to the surface. We&#39;ve had some great years and some meh years as far as innovation goes. Don&#39;t let the conference get all hollow and stuff, and don&#39;t pretend to be excited about &quot;innovative&quot; iterative enhancements. People will notice. Customers know when they&#39;re being pandered to, and lipservice is transparent and boring. Keep the awesome going, instead.&lt;br /&gt;
&lt;br /&gt;
&lt;h3&gt;
4. Make Sure People Still Like Hanging Out With Us&lt;/h3&gt;
This is getting long and a bit rambling, but stay with me. I&#39;ll put a cute unicorn at the end. The biggest gotcha, and the one I really don&#39;t have any visibility into anymore, is company culture. From the outside, Blackboard of 2008 felt stuffy and overbearing. The D2L lawsuit didn&#39;t exactly help that image. People didn&#39;t like talking to tech support, they felt like they were getting nickel and dimed on upsells, and nobody would have called them &quot;cool&quot;. That&#39;s in spite of the pockets of earnestness we early Canvasites saw when we made a surprise visit to Blackboard&#39;s new corporate offices. There were people at the company trying to do the right things for the right reasons, but it just wasn&#39;t breaking to the surface.&lt;br /&gt;
&lt;br /&gt;
Let&#39;s not get to that point, eh? We built an awesome company that didn&#39;t take itself too seriously, where everyone was genuine and genuinely trying to make things better. Everyone knew we needed to get to the root issue before crafting a solution, and that every touch point with our customers needed to be an impactful one. We weren&#39;t a company that hired young single dudes to squeeze extra work out of them with catered dinners and ultimate frisbee. But we also weren&#39;t a company where people took three-hour lunches and tried to beat the commute home. We worked hard because we felt we were doing something important. We had an open floor plan because private office jockeying is a joke. We made our panda pinata be the office receptionist by hooking it up to a speaker with text-to-speech. We came up with goofy meeting room names because it was fun to watch people in expensive suits file into a room called Battletoads. We didn&#39;t take all that stuff seriously because we we were too busy trying to make a difference where it mattered.&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEixH8BuvMPLgQxMEGIEOExyUoUG-9LkQrpy4z7m_mFQbmo4ii0uAsPjfSbdZj56llH_LcUvYSAiFwUafi2lrGUU4dy7Vmwz0ONwD6I5zztyO5WsKvOmAKiT_Qrt_oqpW2S7rwAM8c_LOHo/s1600/instructure.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;413&quot; data-original-width=&quot;550&quot; height=&quot;150&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEixH8BuvMPLgQxMEGIEOExyUoUG-9LkQrpy4z7m_mFQbmo4ii0uAsPjfSbdZj56llH_LcUvYSAiFwUafi2lrGUU4dy7Vmwz0ONwD6I5zztyO5WsKvOmAKiT_Qrt_oqpW2S7rwAM8c_LOHo/s200/instructure.png&quot; width=&quot;200&quot; /&gt;&lt;/a&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj1Z1dnq-zTg5w_d1-pOQFDYZVlORLtxYq6clHZ5I6o2gqD9ES1-VE2g7Wa8d47gQIYIXH6qXfTvwvY34mcjx15ZYVfRDhmjBaJZ0DoIgLbHIAJmTHH29fPkW60UkjfFTVXMLeoiDa_IWU/s1600/instructure-300x214.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;214&quot; data-original-width=&quot;300&quot; height=&quot;142&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj1Z1dnq-zTg5w_d1-pOQFDYZVlORLtxYq6clHZ5I6o2gqD9ES1-VE2g7Wa8d47gQIYIXH6qXfTvwvY34mcjx15ZYVfRDhmjBaJZ0DoIgLbHIAJmTHH29fPkW60UkjfFTVXMLeoiDa_IWU/s200/instructure-300x214.png&quot; width=&quot;200&quot; /&gt;&lt;/a&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhQ8nXngtkZRjE4dJLfz0XJrFqVVdSUPUZx_5SAIhJT7qCUabtWK4RsVlFi_qp-k-D69gsIoGrmzYmiGAuv9Mg1HVfJCzfQCv8AI2sz_aonlmeUZP7cGSHeYFt7O7f5J19v7qBKwkuFSkw/s1600/INSTRUCTURE_logo-gray-white.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;627&quot; data-original-width=&quot;1200&quot; height=&quot;104&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhQ8nXngtkZRjE4dJLfz0XJrFqVVdSUPUZx_5SAIhJT7qCUabtWK4RsVlFi_qp-k-D69gsIoGrmzYmiGAuv9Mg1HVfJCzfQCv8AI2sz_aonlmeUZP7cGSHeYFt7O7f5J19v7qBKwkuFSkw/s200/INSTRUCTURE_logo-gray-white.png&quot; width=&quot;200&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
Obviously you have to grow up along the way (that panda receptionist could be&amp;nbsp;&lt;i&gt;rude&lt;/i&gt;), but we never have to lose the passion that draws people to work for Instructure because, hey, it seems like an awesome place where people are doing awesome things. When the new hires I&#39;ve talked to have still felt that vibe, it made me happy, let&#39;s not lose that. We didn&#39;t always get everything right (ask Ryan Shaw how many times he had to re-merge master into the SpeedGrader branch before it was ready, or Sunny Washington about inter-departmental lunch invitations), but we did get a lot right. We were extremely lucky with our timing, I&#39;ll be the first to tell anybody. But it would be a gross oversimplification to assume that the only reason we&#39;re doing a &quot;Canvas:Blackboard&quot; exercise thing right now is because we showed up with cloud-plus-modern-web right at Blackboard&#39;s weak point. Who we are bleeds into everything we do.&lt;br /&gt;
&lt;h3&gt;
Keep Doing Awesome&lt;/h3&gt;
I haven&#39;t kept the best count of how many early employees are still at Instructure, it&#39;s been ten years and people move on. I like to believe that the culture transfer has been happening seamlessly all along. We&#39;ve changed offices six times, we&#39;ve shuffled through plenty of execs, but I hope Instructure is still the awesome place to work that it used to be. I&#39;m actually very confident that with the right energy we can keep doing awesome things all over the place, just like we have in the past. I hope people are emotionally invested and trying to make a difference for education. I hope that people on the ground working their heels off to do the &quot;right&quot; thing in spite of the all inevitable corporate pressures to not bother, can be proud of the end result. If that remains true, then I&#39;d say we&#39;ve earned our place at the top of the list.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
You made it! Here&#39;s your reward:&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjz6pD9UD7oOGjYIksWbduUCVD1EnWBRjM_YPIU4Qttbppkk4kY7oIdBuujB1D1MLddksN1rAl3bvVWXkLAoGjtER6RA36FmRFyZeJS20cSf_MWoUBJaigd9LrbLwnfJBrLK0UD6a73Mcg/s1600/cute-unicorn-wallpapers-lilly-singh-Favim.com-3606495.png&quot; imageanchor=&quot;1&quot; style=&quot;clear: right; display: inline !important; margin-bottom: 1em; margin-left: 1em;&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;475&quot; data-original-width=&quot;500&quot; height=&quot;190&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjz6pD9UD7oOGjYIksWbduUCVD1EnWBRjM_YPIU4Qttbppkk4kY7oIdBuujB1D1MLddksN1rAl3bvVWXkLAoGjtER6RA36FmRFyZeJS20cSf_MWoUBJaigd9LrbLwnfJBrLK0UD6a73Mcg/s200/cute-unicorn-wallpapers-lilly-singh-Favim.com-3606495.png&quot; width=&quot;200&quot; /&gt;&lt;/a&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjtxXiwtar_37dw6DjGjrg6xk0sTnwxNBQw6SkZqKM51ZlY28MltaKusxaxFX9gZanzjHf0SdBv1kd50ogHLPHc9XvWn8TW-zQ5GyBi5p-CJIq8f1PhPw3Fn6lUm7vr5e3YBxj9RRaNSFU/s1600/ap%252C550x550%252C12x12%252C1%252Ctransparent%252Ct.u3.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;550&quot; data-original-width=&quot;550&quot; height=&quot;200&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjtxXiwtar_37dw6DjGjrg6xk0sTnwxNBQw6SkZqKM51ZlY28MltaKusxaxFX9gZanzjHf0SdBv1kd50ogHLPHc9XvWn8TW-zQ5GyBi5p-CJIq8f1PhPw3Fn6lUm7vr5e3YBxj9RRaNSFU/s200/ap%252C550x550%252C12x12%252C1%252Ctransparent%252Ct.u3.png&quot; width=&quot;200&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Ooh, bonus gotcha for the road. Blackboard Ultra is still not really a thing. I&#39;m sure there are plenty of internal Instructure jokes about it. But turning a ship that large is hard, and with private equity on your back and ongoing reorgs I get why it&#39;s taking so long. It may be asking too much to try to get Canvas through the next technology wave (blockchain-based LMS, anyone?), but please let&#39;s don&#39;t promise a product years before it&#39;s ready. Personally, I don&#39;t think you need to promise new features unless they&#39;re imminent, just release the things when they&#39;re ready to run amok, but that&#39;s more an opinion. This market isn&#39;t heated enough that you need to get the jump on anybody, just do awesome stuff and share it when it&#39;s ready, I say.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Footnote: Somebody somewhere is probably going to call me overly simplistic or naive. That&#39;s fair, ex-founders and their rose-colored glasses is probably a meme somewhere. I&#39;ve seen Instructure change and evolve a lot, and hopefully people will agree that I took the changes in stride, I didn&#39;t keep pining for the good old days every time we moved up a rung on the corporatiness ladder, progress means you lose a bit but you gain more. But maybe I&#39;m all negatively nostalgic, I&#39;m obviously not the best judge. I doubt there&#39;s a shortage of castaway founders shaking their heads over the grand insights nobody is asking them for anymore. Whatever, this is getting too introspective to actually be productive. Let&#39;s focus, here.</content><link rel='replies' type='application/atom+xml' href='http://brianwhitmer.blogspot.com/feeds/1019819088898528046/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/5825798647577501834/1019819088898528046' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5825798647577501834/posts/default/1019819088898528046'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5825798647577501834/posts/default/1019819088898528046'/><link rel='alternate' type='text/html' href='http://brianwhitmer.blogspot.com/2018/07/dear-instructure-please-dont-become.html' title='Dear Instructure: Please Don&#39;t Become the Next Blackboard'/><author><name>Brian Whitmer</name><uri>http://www.blogger.com/profile/00009042638644799674</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjuU9fLl8xHMXUGHbywzQI6WumY7z2W7ZL1iBvxzleBCeBQzIoZ5hnhALV9oSHTQs3iWNRFbTiyADkUEIENiZawHyzWZBxIq3JzvCsTANyrGx-fD1nDmk4ax2BIakeg/s1600/71c13439beedf6c35c53acb0976d97c6'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg1kdGtWewm5CCm-iXDBxkX7gkzOxDQLIM95LBEbkUshEUZuzNWGTiE61FRhSnvTZp_4anIxIQC8-LFoDOVm-4ojKorH2ChRylFxWv2CM_6MBZe-tbLo9q6P-2-D7LhJfV9nZ6g53MTIdo/s72-c/canvas-t-shirt-is-this-your-lms.png" height="72" width="72"/><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5825798647577501834.post-2146536311285634504</id><published>2015-03-12T10:59:00.000-07:00</published><updated>2015-03-12T11:17:21.885-07:00</updated><title type='text'>Please Don&#39;t Bash the Aggregator</title><content type='html'>The Internet is made up of a bunch of disaggregated units that we call web sites or apps. Every unit can provide its own diversity of opinion, tone, arguments, activities, etc. Each unit has its own strategy for styling and interaction, its own bugs and awesomeness, its own security policy and often its own terms of use. Each unit can be physically situated anywhere in the network (the idea that we need everything in &quot;the cloud&quot; is really just based on corporate convenience). We typically use one of four popular rendering engines to access the loosely-connected units, and it&#39;s all kicked off by typing an obscure code into an empty text box. It&#39;s actually kind of a miracle that anything meaningful ever happens there.&lt;br /&gt;
&lt;br /&gt;
Nobody exclusively uses the disaggregated Internet. If you&#39;re using browser bookmarks or a feed reader or an LMS or email or a search engine or social network then you&#39;re using at least one of what I&#39;m calling an &lt;b&gt;aggregator&lt;/b&gt;. Aggregators collect items either automatically, or based on user input, and group them in a way that makes it easier for the user to handle.&lt;br /&gt;
&lt;h3&gt;
Disaggregation Pros and Cons&lt;/h3&gt;
&lt;table cellpadding=&quot;0&quot; cellspacing=&quot;0&quot; class=&quot;tr-caption-container&quot; style=&quot;float: right; margin-left: 1em; text-align: right;&quot;&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: center;&quot;&gt;&lt;span style=&quot;clear: right; margin-bottom: 1em; margin-left: auto; margin-right: auto;&quot;&gt;&lt;a href=&quot;http://umw.domains/&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;http://bavatuesdays.com/files/2013/08/9516686867_043ea0be0c_z.jpg&quot; height=&quot;236&quot; width=&quot;320&quot; /&gt;&lt;/a&gt;&lt;/span&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;tr-caption&quot; style=&quot;text-align: center;&quot;&gt;&lt;a href=&quot;http://umw.domains/&quot;&gt;Disaggregation is an unsung hero of the web.&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
A &lt;b&gt;completely disaggregated&lt;/b&gt; Internet would have every person with their own web site for which you would punch in their unique address to check in with or communicate with them. There is nothing inherently wrong with &lt;a href=&quot;http://umw.domains/&quot;&gt;strong disaggregation&lt;/a&gt;,&amp;nbsp;I&#39;m actually a big fan of it. In my mind I envision everyone&#39;s home router having a built-in web server with their own Dropbox, Calendar, etc. (I think that&#39;ll be the next great evolution of the Internet, but now I&#39;m getting off-topic).&lt;br /&gt;
&lt;br /&gt;
The problem with a completely disaggregated Internet is that, by itself, the motivation to access any one unit is relatively low. I like Bob, but I really don&#39;t need to see what&#39;s going on in his life or check if he&#39;s messaged me all that often, so I&#39;ll probably only visit his disaggregated unit of the Internet when he tells me there&#39;s something waiting for me there. Now if I lump Bob, Fran and my other coworkers together, the motivation to check for communication with them *as a group* becomes more valuable. So we figure out a way to aggregate all of our interactions into one web site. Many web sites work as internal repositories, collecting items crafted or imported by site users and presenting them for other users to see. These internal aggregators are what I&#39;m calling &lt;b&gt;silos&lt;/b&gt;. Silos act primarily on the assumption that what you want is on the current web site, you don&#39;t need to go somewhere else to find it (they also typically underserve some percentage of their users by catering to the massive majority).&lt;br /&gt;
&lt;h3&gt;
The LMS vs. Disaggregation&lt;/h3&gt;
&lt;table cellpadding=&quot;0&quot; cellspacing=&quot;0&quot; class=&quot;tr-caption-container&quot; style=&quot;float: right; margin-left: 1em; text-align: right;&quot;&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: center;&quot;&gt;&lt;a href=&quot;http://img4.wikia.nocookie.net/__cb20141122213848/harrypotter/images/5/5a/B4C31M1.jpg&quot; imageanchor=&quot;1&quot; style=&quot;clear: right; margin-bottom: 1em; margin-left: auto; margin-right: auto;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;http://img4.wikia.nocookie.net/__cb20141122213848/harrypotter/images/5/5a/B4C31M1.jpg&quot; height=&quot;143&quot; width=&quot;320&quot; /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;tr-caption&quot; style=&quot;text-align: center;&quot;&gt;Walled gardens are no fun.&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
The LMS is traditionally seen as a silo. Instructors build learning resources, start discussions, distribute assessments, etc. inside a single web site. Learners use the web site because they have no choice if they want to graduate, and spend hours learning to navigate an interface that they&#39;ll never use again once they&#39;re done with school. The inherent bias of &quot;everything important in a single place&quot; discourages discovery outside the LMS and prevents the learner from getting comfortable with the disaggregated power of the Internet. It also discourages experimentation by instructors because they are stuck with whatever features their particular LMS deems valuable. One strong argument for this silo model is its convenience for the institution.&lt;br /&gt;
&lt;br /&gt;
And hey, if you want to &lt;a href=&quot;http://moreorlessbunk.net/teaching/lms-aol/&quot;&gt;bash the LMS as a silo&lt;/a&gt; I&#39;m all for it, I&#39;ll stand next to you and join in. But we do a disservice if we pretend that the LMS story stops there. We need to look at the alternatives to the LMS as a silo. Some teachers say just ditch the LMS and use your own disaggregated web site with a couple other modern web tools linked up. I ask them about cognitive load for the learner, having to jump around to all those different web sites and logins. Some tell me it hasn&#39;t been a problem for their web-native learners. That&#39;s cool for them, but the learners I talk to hate -- like really HATE -- jumping around the web trying to remember where their homework or lecture slides are. And maybe if you had only one instructor doing the disaggregate thing it could work, but with a full courseload of web-hopping I&#39;d get stabby too. Learners pine for an aggregator. So do administrators, for very different but justifiable reasons. Instructors do too, it turns out. Learners submitting homework on their personal blogs is great until you have to start pasting URLs and switching tabs to get it all graded with feedback. So we circle back to the LMS silo, as if silo is the only way to get aggregation.&lt;br /&gt;
&lt;br /&gt;
http://www.educause.edu/visuals/shared/er/extras/2014/ReclaimingInnovation/default.html&lt;br /&gt;
&lt;h3&gt;
Learning Aggregation&lt;/h3&gt;
&lt;table align=&quot;center&quot; cellpadding=&quot;0&quot; cellspacing=&quot;0&quot; class=&quot;tr-caption-container&quot; style=&quot;float: right; margin-left: 1em; text-align: right;&quot;&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: center;&quot;&gt;&lt;a href=&quot;http://kirkhamsystems.com/wp-content/uploads/google-reader-closed-featured-570x270.jpg&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: auto; margin-right: auto;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;http://kirkhamsystems.com/wp-content/uploads/google-reader-closed-featured-570x270.jpg&quot; height=&quot;151&quot; width=&quot;320&quot; /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;tr-caption&quot; style=&quot;text-align: center;&quot;&gt;My favorite aggregator, RIP :-(&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
Un-siloed aggregation isn&#39;t impossible, of course. We need to do a better job of teasing apart the aggregator and the silo, because they don&#39;t have to be the same thing even though sometimes they are. Silos are self-referencing, internal aggregators (Facebook, AOL, LMS, etc.) but there are also great &lt;b&gt;external aggregators&lt;/b&gt;&amp;nbsp;(feed readers, search engines, etc.) that collect without lock-in. Email is probably the best example of external aggregation. I can host my email on any number of services or run my own, and there&#39;s a well-defined protocol for notifying other units of a new item that may be of interest to them (email is slightly different in that the actual item gets passed around, not a link or snippet). An external aggregator is a jumping-off point that gives a higher-level view without trying to force lock-in, and the LMS, it turns out, can be a powerful external aggregator.&lt;br /&gt;
&lt;br /&gt;
When we started Instructure almost seven years ago we&#39;d been thoroughly indoctrinated by &lt;a href=&quot;http://opencontent.org/blog/&quot;&gt;David Wiley&lt;/a&gt;, &lt;a href=&quot;http://jaredstein.org/&quot;&gt;Jared Stein&lt;/a&gt; and company on the merits of disaggregation. We started our LMS by drawing everything up completely &lt;a href=&quot;http://www.educause.edu/visuals/shared/er/extras/2014/ReclaimingInnovation/default.html&quot;&gt;user-centric and disaggregated&lt;/a&gt; (e.g. Google Spreadsheets or equivalent for the gradebook, SurveyMonkey or equivalent for the quizzes, etc.), then looking at what made the most sense to pull back in for the sake of user experience. Everything that got folded back in was done in a way that it could be swapped for an alternative if desired. We splattered the site with RSS feeds (and RSS aggregators), notification policies, URL submissions and user-defined connections. We made it easy to pull in or link to other web sites, and when we discovered LTI we kind of went crazy implementing the heck out of it. We built a whole bunch of integration points that, while they &lt;a href=&quot;http://mfeldstein.com/dammit-lms/&quot;&gt;weren&#39;t showing up on RFPs&lt;/a&gt;, were still the right thing to do.&lt;br /&gt;
&lt;br /&gt;
We were trying to build an LMS as an aggregator. A jumping-off point for the rest of the web. A &lt;b&gt;learning platform &lt;/b&gt;-- not &quot;platform&quot; the &quot;open&quot;-like buzzword that at this point just means &quot;thing on the Internet&quot;, but &quot;platform&quot; the jumping-off point and a place to get an idea of what&#39;s going on in at a higher level. I&#39;d say we&#39;ve had mixed degrees of success making Canvas a learning platform. Some parts of Canvas are still too locked-in for my liking (and I&#39;m excited for the potential of xAPI and Caliper), but in general it&#39;s the best example I&#39;ve come across for learning aggregation.&lt;br /&gt;
&lt;br /&gt;
Incidentally that&#39;s also why we&#39;ve pushed so hard for LTI. &lt;a href=&quot;https://www.eduappcenter.com/docs/basics/index&quot;&gt;LTI&lt;/a&gt; is an integration standard, and while the UX of launching third-party apps from a consistent wrapper is nice, the real value is in not having to log in to or paste the URL for another web site as a disruption of the learning flow, and in being able to pass useful information back to the aggregator. Two-way communication, just like the Canvas APIs.&lt;br /&gt;
&lt;h3&gt;
Therefore, What?&lt;/h3&gt;
This post is like half of a book long at this point so I&#39;ll stop. Just know that &quot;LMS&quot; doesn&#39;t have to mean &quot;silo.&quot; To me, when you say &quot;the LMS is a silo&quot; you&#39;re not helping. I&#39;d much rather hear &quot;the LMS is silo but *should be* an aggregator&quot; because it&#39;s more productive. I also think it&#39;s becoming more of a reality, and though I doubt we&#39;ll ever get all the way to the other end of the spectrum, we have plenty more room to move in the aggregator direction. The Internet *needs* aggregators to function, and they provide some serious value that we all benefit from every day. So let&#39;s not throw them out with the bathwater that is the LMS silo.</content><link rel='replies' type='application/atom+xml' href='http://brianwhitmer.blogspot.com/feeds/2146536311285634504/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/5825798647577501834/2146536311285634504' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5825798647577501834/posts/default/2146536311285634504'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5825798647577501834/posts/default/2146536311285634504'/><link rel='alternate' type='text/html' href='http://brianwhitmer.blogspot.com/2015/03/please-dont-bash-aggregator.html' title='Please Don&#39;t Bash the Aggregator'/><author><name>Brian Whitmer</name><uri>http://www.blogger.com/profile/00009042638644799674</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjuU9fLl8xHMXUGHbywzQI6WumY7z2W7ZL1iBvxzleBCeBQzIoZ5hnhALV9oSHTQs3iWNRFbTiyADkUEIENiZawHyzWZBxIq3JzvCsTANyrGx-fD1nDmk4ax2BIakeg/s1600/71c13439beedf6c35c53acb0976d97c6'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5825798647577501834.post-8939661439244749053</id><published>2014-11-13T12:10:00.000-08:00</published><updated>2014-11-17T12:31:46.157-08:00</updated><title type='text'>On the Dangers of Prioritization</title><content type='html'>So you&#39;re running your little software startup, and things are going great. You&#39;ve got some really happy users who are finding bugs and suggesting new ideas, and more customers are starting to come on board. You&#39;ve hired some folks to help keep things moving along, and they&#39;re excited to help out. You&#39;re still stressed out of your mind, but at least there are other people now to help share the load.&lt;br /&gt;
&lt;span style=&quot;text-align: center;&quot;&gt;&lt;br /&gt;&lt;/span&gt;
&lt;br /&gt;
&lt;table cellpadding=&quot;0&quot; cellspacing=&quot;0&quot; class=&quot;tr-caption-container&quot; style=&quot;float: right; margin-left: 1em; text-align: right;&quot;&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgs1xp-EVRlx8Gn5VYq_9YKa0Si875ZyICo5JbBKm4gY-8azc5KcoWMvNYGMQwlQcI8vU71zXk-DLZlmKRsT5Ec1DGBoAiqioS26Z71Q_aaJkpajQL3ZhlDqfnJvIn80EozIzYIuNFr-B8/s1600/priorities.png&quot; imageanchor=&quot;1&quot; style=&quot;clear: right; margin-bottom: 1em; margin-left: auto; margin-right: auto;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;320&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgs1xp-EVRlx8Gn5VYq_9YKa0Si875ZyICo5JbBKm4gY-8azc5KcoWMvNYGMQwlQcI8vU71zXk-DLZlmKRsT5Ec1DGBoAiqioS26Z71Q_aaJkpajQL3ZhlDqfnJvIn80EozIzYIuNFr-B8/s320/priorities.png&quot; width=&quot;260&quot; /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;tr-caption&quot; style=&quot;text-align: center;&quot;&gt;Prioritization is hard.&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;span style=&quot;text-align: center;&quot;&gt;When it comes to developing your product, you&#39;ve got a pretty good idea of what needs to be built when because you&#39;re basically talking to every customer and employee on a regular basis. There&#39;s a file somewhere that you half-heartedly maintain and call &quot;the roadmap&quot;, but if someone asked you &quot;what should we work on next?&quot; there&#39;s a 50% chance your response wouldn&#39;t be anywhere on that document, things are moving too quickly.&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
At some point people start talking about your brain as a single point of failure, and you realize they&#39;re right. So you use your bug tracker to document new features, and everyone feels a little better knowing as least the general ideas are written down somewhere. You all agree that this is progress, and part of growing into an actual organization.&lt;br /&gt;
&lt;br /&gt;
What happens next could come from a couple different places. Your sales or support groups start wanting to know when new features are coming. They&#39;re probably not so much concerned about specific dates as they are a general order of priority. Or your development group wants to start doing research leading up to the development of new features. Or your customers want to inject their perspective into your timeline. Or one of your early hires thinks you&#39;re not giving enough attention to the cool new thing you talked about six months ago. However it happens -- and it will happen because it&#39;s a healthy part of your company&#39;s growth -- the main point is that someone, somewhere, pressures you to create an ordered, prioritized list of things you will build or fix.&lt;br /&gt;
&lt;br /&gt;
There are all sorts of legitimate concerns with roadmaps, from time commitments to public visibility to levels of granularity, and I&#39;m not talking about those concerns right now. I&#39;m talking about the danger of development prioritization. And specifically, prioritization by algorithm or committee.&lt;br /&gt;
&lt;br /&gt;
Don&#39;t misunderstand me, priorities are important and valuable. Someone (probably multiple someones) will sit down and label all your bugs and features with tags like &quot;on fire&quot;, &quot;must have&quot;, &quot;nice to have&quot;, &quot;affects everyone&quot;, &quot;customer-specific&quot;, etc. Then you&#39;re going to say, &quot;clearly we need to start with the emergencies affecting everyone, work through the must-haves, and eventually get to the nice-to-haves.&quot; It&#39;ll be a huge relief knowing that you&#39;ve defined a heuristic that others can use to make informed decisions, and that you&#39;re no longer the blocker on all development everywhere. Plus, it&#39;ll sound perfectly rational to prioritize work based on the number of users affected and the degree of impact it will have on affected users.&lt;br /&gt;
&lt;br /&gt;
It&#39;ll also be wrong.&lt;br /&gt;
&lt;br /&gt;
Okay, not wrong, but definitely insufficient. Once you give up control of development to that algorithm or committee, you lose something significant. One of the most important characteristics of a founder is that they have the freedom to build something that few if any other people think is important enough to build. And guess what? You just gave that up without even realizing it. Or maybe you did realize it, but you just don&#39;t see how there could be any alternative. Obviously you making all the decisions by the seat of your pants won&#39;t scale, and you don&#39;t really trust anyone else enough to pass that liberty on unrestricted. What else were you supposed to do?&lt;br /&gt;
&lt;br /&gt;
Well, if you think your product has a sufficient level of disruption already baked in, then I guess you&#39;re good to go. If not then you&#39;ve got a problem. Not only will bugs keep creeping in to (rightly) steal priority, but so will deal-breaking features and incremental enhancements. How can you justify wasting time on a moonshot-maybe when you have concrete evidence that the standard features you&#39;re missing are a serious customer acquisition impediment or opportunity? Moonshots don&#39;t survive prioritization algorithms.&lt;br /&gt;
&lt;br /&gt;
You can argue that you&#39;ve got a sufficiently innovative team, and everyone will see and recognize the value of innovation. But the ROI on innovation is hard to quantify, and it&#39;s inherently higher-risk, which a growing company is (justifiably) getting less and less excited about. I&#39;ve seen lots of dev priority lists in lots of different styles, and the only time I&#39;ve seen them not have this problem is when they were the hazy unmaintainable kind owned by a single individual.&lt;br /&gt;
&lt;br /&gt;
&lt;table cellpadding=&quot;0&quot; cellspacing=&quot;0&quot; class=&quot;tr-caption-container&quot; style=&quot;float: right; margin-left: 1em; text-align: right;&quot;&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: center;&quot;&gt;&lt;a href=&quot;http://i.imgur.com/pmRVgPd.jpg&quot; imageanchor=&quot;1&quot; style=&quot;clear: right; margin-bottom: 1em; margin-left: auto; margin-right: auto;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;http://i.imgur.com/pmRVgPd.jpg&quot; height=&quot;218&quot; width=&quot;320&quot; /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;tr-caption&quot; style=&quot;text-align: center;&quot;&gt;George Bailey makes it look so easy.&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
There&#39;s also a deeper problem. Once you have development priorities, who exactly is going to be out there looking for the innovations? When there was just you, 100% of the company was searching for magic, in a way rather aimlessly. The first couple hires were still after it, but gradually the percentage of energy being put into outside-the-lines ideas will shrink. And the smaller it gets, the more work it is to maintain culturally against the increasingly structured to-do list. You can flex your founder muscles and force some ideas through, but as time goes on that will feel more and more against the grain. Without intervention, at some point you may lift your head and realize you&#39;re thinking about this stuff completely differently than the rest of the company.&lt;br /&gt;
&lt;br /&gt;
So what are you supposed to do? This is why 20% time has such a great appeal. Or a separate dev team that works on crazy prototypes. Or the hackathons where developers can spend a couple days on whatever they want. Or a founder that people just leave alone to work on whatever they want. Those are examples of people saying, &quot;our system is flawed but it&#39;s not clear how to fix it, so let&#39;s just set aside some bandwidth outside of our broken system to try to compensate for its flaws.&quot;&lt;br /&gt;
&lt;br /&gt;
And guess what? That&#39;s the best &lt;i&gt;I&#39;ve&lt;/i&gt; seen, anyway. We&#39;ve tried all of those things in one form or another at Instructure, and they&#39;ve each made their own dent. But if there&#39;s a silver bullet for the prioritization-innovation conflict I&#39;d love to hear about it (other than keeping the company small, but that limits your bandwidth for other reasons). Maybe innovation-squashing is just an innate characteristic of prioritization.&lt;br /&gt;
&lt;br /&gt;
The fact is, I don&#39;t think truly innovative ideas are the kind that show up on a roadmap. In my experience they&#39;ve come out of left field when you&#39;re working on really important other-stuff, so there&#39;s a huge risk of them being brushed off. It&#39;s not the kinds of things you find by hunkering down and singularly looking for the next big thing. By the time they show up on a roadmap they probably seem obvious, but they&#39;ll never get that way on their own. They start out as little sparks that need some oxygen to become a flame, and then to be identified for what they are and given some attention and kindling to grow. And that just doesn&#39;t happen when everyone is busy working on the day-to-day.&lt;br /&gt;
&lt;br /&gt;
You have to figure out a way (that works for your company, because I&#39;m betting it will be unique to your company) to repeatedly jostle your employees out of their routine enough so they think differently, and also feel a desire to bring up their ideas (on-boarding indoctrination is one trick we&#39;ve used to help calibrate there). Once a quarter won&#39;t cut it, it has to be a repeatable thing because it often takes a couple strikes to get lit -- but not too repeatable or it just becomes fake or part of the routine. And it shouldn&#39;t be just for developers, ideas come from anyone connected enough to pick up a trend. Then you need product-oriented people who explore these sessions and pull the separate-but-related sparks into the start of a bonfire.&lt;br /&gt;
&lt;br /&gt;
It&#39;s not a trivial thing I&#39;m talking about, but it&#39;s a big part of why large companies stop innovating, innovation just doesn&#39;t get the legitimate air-time it requires. I&#39;m not convinced that scheduling weekly &quot;out-of-the-box time&quot; is the right approach, but I haven&#39;t actually seen many other strategies in the wild. I have this hazy vision of monthly &quot;off-kilter pitches&quot; that get approved as incubation projects, but it&#39;s not concrete and I&#39;ve never tried it, so I can&#39;t endorse it. You&#39;re essentially looking to give everyone both time *and* empowerment, to get the percent of employees working on innovation back up as high as you can get it. So whatever way works best for you. I think that&#39;s possible without losing the value of your prioritization, but I also think prioritization will eclipse innovation if you&#39;re not actively avoiding that outcome.</content><link rel='replies' type='application/atom+xml' href='http://brianwhitmer.blogspot.com/feeds/8939661439244749053/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/5825798647577501834/8939661439244749053' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5825798647577501834/posts/default/8939661439244749053'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5825798647577501834/posts/default/8939661439244749053'/><link rel='alternate' type='text/html' href='http://brianwhitmer.blogspot.com/2014/11/on-dangers-of-prioritization.html' title='On the Dangers of Prioritization'/><author><name>Brian Whitmer</name><uri>http://www.blogger.com/profile/00009042638644799674</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjuU9fLl8xHMXUGHbywzQI6WumY7z2W7ZL1iBvxzleBCeBQzIoZ5hnhALV9oSHTQs3iWNRFbTiyADkUEIENiZawHyzWZBxIq3JzvCsTANyrGx-fD1nDmk4ax2BIakeg/s1600/71c13439beedf6c35c53acb0976d97c6'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgs1xp-EVRlx8Gn5VYq_9YKa0Si875ZyICo5JbBKm4gY-8azc5KcoWMvNYGMQwlQcI8vU71zXk-DLZlmKRsT5Ec1DGBoAiqioS26Z71Q_aaJkpajQL3ZhlDqfnJvIn80EozIzYIuNFr-B8/s72-c/priorities.png" height="72" width="72"/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5825798647577501834.post-3375845842734852893</id><published>2014-06-09T10:22:00.000-07:00</published><updated>2014-06-09T10:22:48.280-07:00</updated><title type='text'>Customers Can Ruin Your Vision, But They Don&#39;t Have To (Part 2)</title><content type='html'>&lt;a href=&quot;http://brianwhitmer.blogspot.com/2014/04/customers-can-ruin-your-vision-but-they.html&quot;&gt;This is a link to Part 1&lt;/a&gt;, and probably fits better for earlier-stage companies/products.&lt;br /&gt;
&lt;br /&gt;
&lt;table cellpadding=&quot;0&quot; cellspacing=&quot;0&quot; class=&quot;tr-caption-container&quot; style=&quot;float: right; margin-left: 1em; text-align: right;&quot;&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: center;&quot;&gt;&lt;a href=&quot;http://img1.wikia.nocookie.net/__cb20131106213953/starwars/images/d/d6/Yoda_SWSB.png&quot; imageanchor=&quot;1&quot; style=&quot;clear: right; margin-bottom: 1em; margin-left: auto; margin-right: auto;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;http://img1.wikia.nocookie.net/__cb20131106213953/starwars/images/d/d6/Yoda_SWSB.png&quot; height=&quot;320&quot; width=&quot;278&quot; /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;tr-caption&quot; style=&quot;font-size: 13px; text-align: center;&quot;&gt;Product people, like Jedi masters, play&lt;br /&gt;the long game, they do.&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
When you get bigger the problems shift. It&#39;s been amazing to watch Instructure move from stage to stage, and it was usually very obvious when we&#39;d hit a new stage because the internal dialog adjusted to new topics -- getting the product out there, attracting new customers, building innovative features, fixing bugs to scaling out, etc. all in different amounts at each stage.&lt;br /&gt;
&lt;br /&gt;
Anyway. Once you start to grow your company you&#39;re going to be dealing with more customers, which means more opinions and more requests and demands. Thanks to the Internet (thanks, Internet!) it&#39;s possible to gather more feedback from your customers and potential customers than you can possibly know what to do with*. And the frustrated ones will happily give it to you in droves.&lt;br /&gt;
&lt;br /&gt;
That&#39;s not inherently a bad thing, but it definitely can be. It&#39;s really easy to get frustrated when you have a vocal minority of customers demanding a feature or a change that doesn&#39;t match your long-term vision. I have another blog post brewing on how product people need to play the long game, but suffice it to say a good product person will hear feature requests that make them nervous about what direction those changes will inevitably take them. Blowing off the requests sounds like a bad idea though, and vision-selling doesn&#39;t always work because there are perfectly reasonable (read: not-hypothetical, like you&#39;re cute little long-term vision thingy) justifications for the change.&lt;br /&gt;
&lt;br /&gt;
The fact is, once you move beyond the early adopters you&#39;re by definition entering a customer base that is less forgiving of you-not-having-what-they&#39;re-used-to-having. You&#39;ll see increased pressure to implement things that aren&#39;t part of your vision. Parity with legacy systems is a really big deal for the less-risk-averse customer majority that is trying to convince their users that migrating to a new system is a good idea, and won&#39;t ruin their lives forever. A healthy vision is re-evaluated constantly so go ahead and take those opportunities to stop and re-evaluate. But if it still doesn&#39;t match then what do you do?&lt;br /&gt;
&lt;br /&gt;
I&#39;ve seen a couple things work well for us at Instructure.&lt;br /&gt;
&lt;br /&gt;
The first approach is to go down a level in your discussion. Stepping back and saying &quot;what are you really trying to accomplish&quot; can be super valuable, and should really be the first tool in a product person&#39;s belt anyway. Sometimes you can redirect the customer&#39;s energy in a more exciting direction (like with BYU-Hawaii in the&amp;nbsp;&lt;a href=&quot;http://brianwhitmer.blogspot.com/2014/04/customers-can-ruin-your-vision-but-they.html&quot;&gt;early days&lt;/a&gt;), and other times you can at least find a compromise that you&#39;re both ok with.&lt;br /&gt;
&lt;br /&gt;
Wharton, for example, didn&#39;t want us to show final grades inside of Canvas because they had another system that kept their official grades and they didn&#39;t want students getting confused. But keeping students informed is a major part of our vision, and being able to see how they were faring in their courses throughout the semester felt really important to us. We pushed and they pushed and we were getting nowhere. So we stepped back and discovered that the vocabulary was the real issue. If we could call it something other than &quot;final grade&quot; in the interface then they&#39;d be fine with keeping it. That was loads better than the custom-JavaScript-to-hide-final-grades-just-for-Wharton path that had been proposed before.&lt;br /&gt;
&lt;br /&gt;
The second approach is plain old vision-selling. Ideally you&#39;ll be able to sell them on your long-term vision and they&#39;ll say &quot;that sounds better, let&#39;s do that&quot;. Sometimes that&#39;s just a short email, but more often it&#39;s getting on the phone or (better yet) meeting them in person. The point is to actually convert the person, not to get them to shut up, so make sure you&#39;re including them in the decision, giving them a peek at the future. And if you&#39;re doing that why not also get their feedback on it? If they feel attached to the future because they had a part in it, there&#39;s the chance they&#39;ll not only stop pressuring you to change, but even help evangelize for your vision.&lt;br /&gt;
&lt;br /&gt;
We&#39;ve turned multiple critics into evangelists this way (not in some manipulative way, don&#39;t get me wrong. We legitimately included them in the discussion and they legitimately got excited about it), and when it works it tends to work really well. But make sure you&#39;re actually going to follow through on what you discussed/promised or you&#39;ll be worse than where you started.&lt;br /&gt;
&lt;br /&gt;
The third approach only works if it&#39;s a project you intend on doing eventually, and the problem is prioritization. Basically you say, &quot;ok, is this more or less important than X, Y and Z that we&#39;re already working on?&quot; Don&#39;t ask unless you&#39;re willing to adjust your priorities based on the response, but it&#39;s ok to make customers think hard about what&#39;s most important. It&#39;s actually usually pretty insightful to watch that process from the sidelines.&lt;br /&gt;
&lt;br /&gt;
Our client services department had the idea to start maintaining a top-10 request list early-on. This gave us a very helpful point of reference to compare priorities. If you&#39;re planning on doing both things eventually, then it seems like a great idea for your customers to help prioritize the things you&#39;re building for them, and it has the added benefit of showing them why their new feature isn&#39;t getting the attention they&#39;d like it to. Many times the response was, &quot;you&#39;re right, X is more important. I&#39;ll go help my noisy faculty member understand why we&#39;re not doing that.&quot;&lt;br /&gt;
&lt;br /&gt;
Internal prioritization is important too. You need to have your whole team on board with the list of things you&#39;re going to build, because if a salesperson really wants a certain deal or an executive hears a noisy frustration while visiting a customer, you&#39;ll often hear about that need in a disproportionate way. Even your web forums will be skewed and can be used as fodder by the enterprising employee to get their pet feature implemented. But a strong priority lets you rationally step back and say, &quot;ok, but is that really more important than the ability for people to log in?&quot;&lt;br /&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
Sometimes you just can&#39;t come to a resolution. One school wanted to prevent students changing their default email address in order to keep everything on controlled systems. We assured them that their students are coming to their campus with already-established email workflows, and a new address quite often would just be a black hole. Or they&#39;d just forward their emails and the data would leak out anyway. But their legal department wouldn&#39;t budge on the requirement. I lost track of that thread and I can&#39;t actually remember how that one turned out. Maybe we made a cheat sheet showing the students how to set up email forwarding.&lt;br /&gt;
&lt;br /&gt;
I&#39;m pretty sure this list isn&#39;t exhaustive, and these don&#39;t always work, but they&#39;re some of the ways we&#39;ve tried to address the conflict between vision and a growing customer base with diverse needs. At the end of the day the product you&#39;re building should be something that attracts new customers but also continues to excite your existing customers. If your vision isn&#39;t heading straight down that path then it&#39;s probably going to be a bumpy ride. But more times than you might think it&#39;s possible to get customers on board with your vision one way or another, which ends up being a win for everyone. A good product balances happily between customer-defined and company-defined. Your customers aren&#39;t stupid or malicious, but they shouldn&#39;t build your product alone -- and neither should you.&lt;br /&gt;
&lt;br /&gt;
&lt;i&gt;* It&#39;s worth noting that open discussion forums are tricky things. I highly recommend them because of the insight they can provide, but they need to have a very clear purpose in mind. We implemented a &quot;Feature Request Forum&quot; where we want people to suggest ideas for way to continually improve Canvas. It was a really great idea, and has been super valuable at times. However, we didn&#39;t do the best job defining purpose, and since it&#39;s significantly easier to suggest a feature than to implement it, the list got huge and started filling up with &quot;why haven&#39;t you built this yet, it&#39;s been sitting here for three years!&quot; flameage. The goal was never to Build All the Things, so we clearly had a misunderstanding. We wanted a place where we could discuss the best way to implement new features and also hear crazy ideas we might not have thought of. We&#39;re gradually reworking our forums to get to that point but it takes a lot longer to transition there than to be explicit and clear from the get-go.&lt;/i&gt;</content><link rel='replies' type='application/atom+xml' href='http://brianwhitmer.blogspot.com/feeds/3375845842734852893/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/5825798647577501834/3375845842734852893' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5825798647577501834/posts/default/3375845842734852893'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5825798647577501834/posts/default/3375845842734852893'/><link rel='alternate' type='text/html' href='http://brianwhitmer.blogspot.com/2014/06/customers-can-ruin-your-vision-but-they.html' title='Customers Can Ruin Your Vision, But They Don&#39;t Have To (Part 2)'/><author><name>Brian Whitmer</name><uri>http://www.blogger.com/profile/00009042638644799674</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjuU9fLl8xHMXUGHbywzQI6WumY7z2W7ZL1iBvxzleBCeBQzIoZ5hnhALV9oSHTQs3iWNRFbTiyADkUEIENiZawHyzWZBxIq3JzvCsTANyrGx-fD1nDmk4ax2BIakeg/s1600/71c13439beedf6c35c53acb0976d97c6'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5825798647577501834.post-7762713712983808001</id><published>2014-04-22T09:53:00.002-07:00</published><updated>2014-04-23T08:03:18.475-07:00</updated><title type='text'>Customers Can Ruin Your Vision, But They Don&#39;t Have To (Part 1)</title><content type='html'>Hi entrepreneur, I guess this one&#39;s for you.&lt;br /&gt;
&lt;br /&gt;
When you take a brand new idea and decide to make it into a reality, just about anything is possible. You have an unadulterated image in your mind of the ideal customer who will love exactly the thing you want to build. Of course your opinions will be seen as visionary and spot-on. How could you not know what you&#39;re talking about? (Side note: founder hubris is one of the reasons a &lt;a href=&quot;http://brianwhitmer.blogspot.com/2010/05/story-of-instructure.html&quot;&gt;Product Validation Tour&lt;/a&gt; is so important)&lt;br /&gt;
&lt;br /&gt;
&lt;table cellpadding=&quot;0&quot; cellspacing=&quot;0&quot; class=&quot;tr-caption-container&quot; style=&quot;float: right; margin-left: 1em; text-align: right;&quot;&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: center;&quot;&gt;&lt;a href=&quot;http://img1.wikia.nocookie.net/__cb20120508071134/marveldatabase/images/a/a4/Vision_(Earth-616)_00.png&quot; imageanchor=&quot;1&quot; style=&quot;clear: right; margin-bottom: 1em; margin-left: auto; margin-right: auto;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;http://img1.wikia.nocookie.net/__cb20120508071134/marveldatabase/images/a/a4/Vision_(Earth-616)_00.png&quot; height=&quot;320&quot; width=&quot;284&quot; /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;tr-caption&quot; style=&quot;text-align: center;&quot;&gt;It&#39;s important to have a strong vision. Here&#39;s hoping &lt;br /&gt;
&lt;a href=&quot;http://screenrant.com/avengers-2-age-ultron-paul-bettany-vision/&quot;&gt;Paul Bettany&lt;/a&gt; can pull it off (too obscure a reference?).&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
Then one day you finally get a real customer (for Instructure it was BYU-Hawaii, and we drank mango nectar and wore leis to celebrate). They&#39;re your first customer ever, so you take a picture of their check and you listen very closely to what they have to say. They are well aware of their position of influence and push you hard to implement their pet features because holy cow why wouldn&#39;t you?&lt;br /&gt;
&lt;br /&gt;
This is your first big test of vision (second if you count the product validation tour, but if you did that right it wasn&#39;t much of a test, more a collaboration). For us, we told our #1 that we were aiming high, and while we were grateful for their business, we needed to make sure we were implementing things that worked for at least 80% of our customers. They cheekily responded that they were 100% of our customers :-P, so what was the big deal? BYU-Hawaii is not the bad guy in this story, by the way. Customers aren&#39;t bad guys.&lt;br /&gt;
&lt;br /&gt;
This was the Test of The Special, and it&#39;s a tricky one to handle. The Special is the extra feature that doesn&#39;t really fit into your vision, but which at least some of your customers are telling you they need in order to do business. If you want to build a consulting gig then embrace the Special. If you want to build scalable software then the Special is very dangerous. Not evil, just dangerous. Especially early-on.&lt;br /&gt;
&lt;br /&gt;
When your product is young it should have a very well-defined trajectory. That whole founder hubris thing, where you know exactly who you&#39;re serving and what you&#39;re giving them and what features you&#39;re going to add when, that&#39;s actually kind of important. You make darn sure it&#39;s valid and that there are enough early adopters to get some critical mass (ahem, PVT), but then you stick to it. If at this point you&#39;re already spinning off into side-projects and Specials, then you&#39;ve got a vision problem, and you&#39;re going to end up wherever someone else pushes you. There&#39;s a verse in the Bible that covers this nicely, actually:&lt;br /&gt;
&lt;br /&gt;
&lt;blockquote class=&quot;tr_bq&quot;&gt;
&quot;For he that wavereth is like a wave of the sea driven with the wind and tossed.&quot; -&lt;a href=&quot;https://www.lds.org/scriptures/nt/james/1.6?lang=eng&quot;&gt;James 1:6&lt;/a&gt;&lt;/blockquote&gt;
&lt;table cellpadding=&quot;0&quot; cellspacing=&quot;0&quot; class=&quot;tr-caption-container&quot; style=&quot;float: right; text-align: right;&quot;&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: center;&quot;&gt;&lt;a href=&quot;http://i2.listal.com/image/1703312/500full.jpg&quot; imageanchor=&quot;1&quot; style=&quot;clear: right; margin-bottom: 1em; margin-left: auto; margin-right: auto;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;http://i2.listal.com/image/1703312/500full.jpg&quot; height=&quot;240&quot; width=&quot;320&quot; /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;tr-caption&quot; style=&quot;text-align: center;&quot;&gt;Adding extra appendages can be dangerous.&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;br /&gt;
Know where you&#39;re going. If you build a third arm that you&#39;re not excited about but that you think your customer might need to be happy, remember that you&#39;re going to be maintaining that arm for the rest of forever. If it glitches, you have to stop working on your laser-guided vision processing chip and go rewire that stupid arm. Maybe you can&#39;t get out of building it, because maybe your vision could use some adjusting, and if that&#39;s the case then be very clear with everyone (especially internally) that the change you&#39;re making is a reshuffling of priorities, and that other things are going to slip but that this is important enough to do it anyway. In the future you&#39;ll get big and changing directions will be hard enough on its own, but for now you should introduce a little artificial friction toward change because it will force everyone to stop and say, is this really the right move for us?&lt;br /&gt;
&lt;br /&gt;
If you decide to build it you&#39;d better figure out a way to make it an awesome part of your vision. Because if you&#39;re not excited about it, your team won&#39;t be either, and it&#39;ll be a second-class citizen in your system and your customers will notice and resent you for it and you&#39;ll be worse off than if you&#39;d never built it in the first place.&lt;br /&gt;
&lt;br /&gt;
For us, the thing BYU-Hawaii was asking for was a video discussion board. Some other edtech tools would let you create either a text &lt;i&gt;or&lt;/i&gt; video/audio board. BYU-Hawaii needed video discussions as part of whatever LMS they were using -- and for good reason, their distance ed program was serving students on different islands, regions, and continents with all sorts of bandwidth constraints and time zones. But we couldn&#39;t afford to maintain two different discussion tools, and frankly it felt gross and weird to have multiple tools that served almost the same purpose.&lt;br /&gt;
&lt;br /&gt;
So we had the aforementioned chat with BYU-Hawaii. Sorry, we&#39;re not building two discussion systems. We didn&#39;t want to blow them off completely, so we talked to them about the plans we had for discussions and also grading. We outlined our vision with them and said, &quot;there&#39;s got to be a way we can fold this into our vision that is as exciting for us as it is for you.&quot; This was a critical piece of their educational process, so it wasn&#39;t something we could lay away for future work, which meant it needed to be something we could get stoked enough about right now that we were willing to delay something else to make it happen.&lt;br /&gt;
&lt;br /&gt;
We batted some ideas around and in the end what we proposed to them was a audio/video widget that could be used to drop media into text-based discussions as well as other parts of the system. After talking to BYU-Hawaii we looked for how we could fold their need into our vision since it wasn&#39;t going away, and it turned out we were actually really excited about the prospect of &quot;video-everywhere&quot; to improve the learning experience, it had just been a little farther down the path. Implementing it was going to take longer than they wanted, but they now saw the vision and agreed with it, and there were some feature-parity elements they were willing to let slide to help make it happen, so it worked out nicely for everyone.&lt;br /&gt;
&lt;br /&gt;
If we had just built what BYU-Hawaii was asking for we would have been taking a very large step down the path that we resented other edtech companies for taking. Subpar one-off features is pretty standard fare in edtech, and the whole reason we started Instructure was to not be That Guy. It wouldn&#39;t have ruined us as a company I don&#39;t think, multiple discussion types would have been a bother and not particularly innovative (video-everywhere, it turns out, is now a huge value proposition for people thinking about switching to Canvas, because it&#39;s so tightly integrated and easy to leverage), but we would have survived. Just not with the same vision.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;table cellpadding=&quot;0&quot; cellspacing=&quot;0&quot; class=&quot;tr-caption-container&quot; style=&quot;float: right; margin-left: 1em; text-align: right;&quot;&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgcErUPcxp2lIR-6Xtmg0kxvMldapaCSkz5u6Q_wtqCnuYetPYwqh06QHRUGr8UjGMcnNYWfHwTlwzEwx_-iUZD_SH9lhdxf7q6bM8109XR7fpIdZSHHqkqNQ-JR8HPLmBQjSZE2lg2cyQ/s1600/Screen+Shot+2014-04-22+at+9.51.44+AM.png&quot; imageanchor=&quot;1&quot; style=&quot;clear: right; margin-bottom: 1em; margin-left: auto; margin-right: auto;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgcErUPcxp2lIR-6Xtmg0kxvMldapaCSkz5u6Q_wtqCnuYetPYwqh06QHRUGr8UjGMcnNYWfHwTlwzEwx_-iUZD_SH9lhdxf7q6bM8109XR7fpIdZSHHqkqNQ-JR8HPLmBQjSZE2lg2cyQ/s1600/Screen+Shot+2014-04-22+at+9.51.44+AM.png&quot; height=&quot;168&quot; width=&quot;320&quot; /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;tr-caption&quot; style=&quot;text-align: center;&quot;&gt;Sometimes the solution is 12 moves away, but it&#39;s there.&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
The point is, you HAVE to start with a strong vision, and think hard about any time you&#39;re asked to stray from that vision. It may be ok, but it may not. And you have to get creative. At the end of the day a strong product visionary will look at customer demands and trace out in their mind a variation that could fit in with the existing vision. Maybe it&#39;s right there ready to go, maybe it&#39;s a few steps down the path. But somebody at your company should bet getting a rush out of trying to find that overlap, and then helping customers see how their needs can serve the &quot;greater good&quot; as you head toward that awesome thing of the future you started out building in the first place. And most of the time you should still probably say &quot;no&quot;. Figure out where it might fit, then decide if it&#39;s worth it. BYU-Hawaii is one of the examples where we adjusted course, but those were the rare exceptions.</content><link rel='replies' type='application/atom+xml' href='http://brianwhitmer.blogspot.com/feeds/7762713712983808001/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/5825798647577501834/7762713712983808001' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5825798647577501834/posts/default/7762713712983808001'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5825798647577501834/posts/default/7762713712983808001'/><link rel='alternate' type='text/html' href='http://brianwhitmer.blogspot.com/2014/04/customers-can-ruin-your-vision-but-they.html' title='Customers Can Ruin Your Vision, But They Don&#39;t Have To (Part 1)'/><author><name>Brian Whitmer</name><uri>http://www.blogger.com/profile/00009042638644799674</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjuU9fLl8xHMXUGHbywzQI6WumY7z2W7ZL1iBvxzleBCeBQzIoZ5hnhALV9oSHTQs3iWNRFbTiyADkUEIENiZawHyzWZBxIq3JzvCsTANyrGx-fD1nDmk4ax2BIakeg/s1600/71c13439beedf6c35c53acb0976d97c6'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgcErUPcxp2lIR-6Xtmg0kxvMldapaCSkz5u6Q_wtqCnuYetPYwqh06QHRUGr8UjGMcnNYWfHwTlwzEwx_-iUZD_SH9lhdxf7q6bM8109XR7fpIdZSHHqkqNQ-JR8HPLmBQjSZE2lg2cyQ/s72-c/Screen+Shot+2014-04-22+at+9.51.44+AM.png" height="72" width="72"/><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5825798647577501834.post-5521744343701038912</id><published>2014-04-02T12:51:00.002-07:00</published><updated>2014-04-02T12:51:35.836-07:00</updated><title type='text'>Open is Not an Afterthought</title><content type='html'>&lt;table cellpadding=&quot;0&quot; cellspacing=&quot;0&quot; class=&quot;tr-caption-container&quot; style=&quot;float: right; margin-left: 1em; text-align: right;&quot;&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: center;&quot;&gt;&lt;a href=&quot;http://fnrad.com/wp-content/uploads/watermelon-mouth-and-teeth-open-carving-900x600.jpg&quot; imageanchor=&quot;1&quot; style=&quot;clear: right; margin-bottom: 1em; margin-left: auto; margin-right: auto;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;http://fnrad.com/wp-content/uploads/watermelon-mouth-and-teeth-open-carving-900x600.jpg&quot; height=&quot;213&quot; width=&quot;320&quot; /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;tr-caption&quot; style=&quot;font-size: 13px; text-align: center;&quot;&gt;I will make this one day&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
Open source, open API, open communication, open content, open platform, open roadmap, open door policy. Open got thrown around as a buzzword pretty hard a few years ago so I can understand if you&#39;re turned off by it, but I for one still think it&#39;s really important.&lt;br /&gt;
&lt;br /&gt;
If you&#39;re a developer, product manager, entrepreneur, etc. wondering if you should make your &quot;thing&quot; more open, yes you should figure out how to open it -- even just a little bit -- right away. You probably should have been thinking about it a year ago. Open (like accessibility, incidentally) isn&#39;t really something you tack on after-the-fact, it&#39;s a whole lot easier in young projects. And for me it hasn&#39;t typically been something that happened naturally. You usually have to fight for it.&lt;br /&gt;
&lt;br /&gt;
Open is great for a lot of reasons. It gives your team something not-hidden that they can feel pride in, it forces you to think about the *real* reasons why you&#39;re doing something, and of course it lets others build on top of your stuff. Open is about the unexpected leverage that someone else finds without your help. In my experience those discoveries typically happen later than you expect them to, but obviously not at all unless you first open things up. And in the end they&#39;re big success stories for you and your users.&lt;br /&gt;
&lt;br /&gt;
Example time.&lt;br /&gt;
&lt;table cellpadding=&quot;0&quot; cellspacing=&quot;0&quot; class=&quot;tr-caption-container&quot; style=&quot;float: right; margin-left: 1em; text-align: right;&quot;&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: center;&quot;&gt;&lt;a href=&quot;https://www.law.upenn.edu/livewhale/content/images/7/13018_canvas.png&quot; imageanchor=&quot;1&quot; style=&quot;clear: right; margin-bottom: 1em; margin-left: auto; margin-right: auto;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;200&quot; src=&quot;https://www.law.upenn.edu/livewhale/content/images/7/13018_canvas.png&quot; width=&quot;200&quot; /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;tr-caption&quot; style=&quot;font-size: 13px; text-align: center;&quot;&gt;Our logo is open in the middle.&lt;br /&gt;Coincidence? Mostly.&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;br /&gt;
The only reason Canvas has an open API is because we decided we should have one. When we started building an iPhone app&amp;nbsp;&lt;a href=&quot;http://voice.instructure.com/blog/bid/147409/Canvas-for-iOS&quot;&gt;back in 2011&lt;/a&gt;&amp;nbsp;we decided the app would only use public API endpoints -- if they didn&#39;t exist, we&#39;d write them. Later we extended that rule to new features in Canvas proper as well. It didn&#39;t provide short-term benefits other than maybe code hygiene and it took more effort to build third-party-consumable endpoints. But now we have somewhere around a million third-party API calls per day from lockdown browsers, portfolio and analytics tools, alternative gradebooks, badging apps, and other neat projects. People enjoy building on top of Canvas because they can just create something cool, no babysitting required.&lt;br /&gt;
&lt;br /&gt;
When we first started building Canvas we really wanted it to be open source. It was important to me and Devlin as developers for many (some admittedly naive) reasons. Every investor we talked to would get hung up on that bullet point, though. How would we make money off people running the codebase locally? Were we going to offer support contracts? Were we a SaaS company or a support company? We eventually conceded, assuming they knew something we didn&#39;t, only to circle back and find a business reason for &quot;going&quot;&amp;nbsp;&lt;a href=&quot;https://www.youtube.com/watch?v=dCIP3x5mFmw&quot;&gt;open source in 2011&lt;/a&gt;&amp;nbsp;(side note: our&amp;nbsp;&lt;a href=&quot;https://github.com/instructure/canvas-lms/commit/8b8173dcc907d3a3ace327fb68aabd5e2d6f73fb&quot;&gt;initial commit message&lt;/a&gt;&amp;nbsp;was an easter egg that no one ever caught. Too subtle?).&lt;br /&gt;
&lt;br /&gt;
We also have always worked to have an open relationship with our customers and users. Back when we were still piloting with a couple dozen teachers, we decided that we were going to include our customers deeply in product strategy. It made sense to us because it&#39;s what we&#39;d already been doing with our &lt;a href=&quot;http://brianwhitmer.blogspot.com/2010/05/story-of-instructure.html&quot;&gt;Product Validation Tour&lt;/a&gt; of a Metro and a slide deck. With every new customer we sat down and talked through problems, sometimes finding creative (read: wonky) workarounds to just get things done. We were straight with them about our shortcomings and our future plans, and expected them to be honest with us about their needs vs. wants. Now it&#39;s a foregone conclusion that our client services teams will work *with* customers to find solutions to problems, and I love it.&lt;br /&gt;
&lt;br /&gt;
The &quot;open&quot; bullet point I&#39;m most proud of though is the open architecture we&#39;re still building. When I first heard about LTI (an interoperability standard in edtech) I got really really excited about the promise it offered and threw together&amp;nbsp;&lt;a href=&quot;https://github.com/instructure/canvas-lms/commit/9d131ea836d72c8dec821f7f0232b21ca1eabcbb&quot;&gt;a Canvas implementation&lt;/a&gt;&amp;nbsp;as quick as I could. Nobody really cared back then, and it was obvious pretty quickly that LTI didn&#39;t quite hit the dream Devlin and I were&amp;nbsp;&lt;a href=&quot;http://brianwhitmer.blogspot.com/2008/08/mashable-one-stop-shop.html&quot;&gt;talking about back in 2008&lt;/a&gt;&amp;nbsp;(we bandied the idea around&amp;nbsp;&lt;a href=&quot;http://www.educause.edu/ero/article/envisioning-post-lms-era-open-learning-network&quot;&gt;with Jon Mott in 2009&lt;/a&gt;&amp;nbsp;too), where LMS components like discussions or gradebook could be replaced with alternatives. So we started&amp;nbsp;&lt;a href=&quot;https://www.eduappcenter.com/docs/extensions/index&quot;&gt;extending LTI&lt;/a&gt;&amp;nbsp;to get it to where, combined with our open API, you really could swap out whole features in Canvas. Now when edtech startups decide to integrate with an LMS they come to Instructure first because it&#39;s the easiest integration (plus our documentation is slick).&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://www.apertus.org/sites/default/files/bart_os.gif&quot; imageanchor=&quot;1&quot; style=&quot;clear: right; float: right; margin-bottom: 1em; margin-left: 1em;&quot;&gt;&lt;br /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;table cellpadding=&quot;0&quot; cellspacing=&quot;0&quot; class=&quot;tr-caption-container&quot; style=&quot;float: right; text-align: right;&quot;&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: center;&quot;&gt;&lt;a href=&quot;https://www.apertus.org/sites/default/files/bart_os.gif&quot; imageanchor=&quot;1&quot; style=&quot;clear: right; margin-bottom: 1em; margin-left: auto; margin-right: auto;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;223&quot; src=&quot;https://www.apertus.org/sites/default/files/bart_os.gif&quot; width=&quot;320&quot; /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;tr-caption&quot; style=&quot;font-size: 13px; text-align: center;&quot;&gt;Why did he write on his head?&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;br /&gt;
This is starting to sound like a brag-fest, sorry. My point is, every single time Instructure took a step toward openness, it was premeditated. And there were naysayers. And the business value was unclear. And we did it anyway. And in the end it definitely paid off. We&#39;ve often had to win over new people at Instructure to the value of open, and we still do sometimes. But once they experience it for themselves then they&#39;re usually on board after that.&lt;br /&gt;
&lt;br /&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
I&#39;m a believer in open because I&#39;ve seen the difference it&#39;s made at Instructure. Frankly, if your company can&#39;t get over what might happen should you open up your code/content/API/platform/communication then you either have the wrong kind of competitive advantage or you&#39;re not valuing your users as much as you should. People who think lock-in is the same as customer stickiness aren&#39;t in it to improve the user experience. Opening up doesn&#39;t provide immediate returns. But gradually it wins over a few early adopters, then a few more, and then things really get interesting when you start to find those exciting ideas that someone else came up with. Ideas that make a difference that wouldn&#39;t have been possible without being open.&lt;/div&gt;
</content><link rel='replies' type='application/atom+xml' href='http://brianwhitmer.blogspot.com/feeds/5521744343701038912/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/5825798647577501834/5521744343701038912' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5825798647577501834/posts/default/5521744343701038912'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5825798647577501834/posts/default/5521744343701038912'/><link rel='alternate' type='text/html' href='http://brianwhitmer.blogspot.com/2014/04/open-is-not-afterthought.html' title='Open is Not an Afterthought'/><author><name>Brian Whitmer</name><uri>http://www.blogger.com/profile/00009042638644799674</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjuU9fLl8xHMXUGHbywzQI6WumY7z2W7ZL1iBvxzleBCeBQzIoZ5hnhALV9oSHTQs3iWNRFbTiyADkUEIENiZawHyzWZBxIq3JzvCsTANyrGx-fD1nDmk4ax2BIakeg/s1600/71c13439beedf6c35c53acb0976d97c6'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5825798647577501834.post-1990986641719316556</id><published>2014-02-04T22:40:00.002-08:00</published><updated>2014-02-04T22:40:32.517-08:00</updated><title type='text'>Instructional Design is Not Interface Design</title><content type='html'>&lt;table cellpadding=&quot;0&quot; cellspacing=&quot;0&quot; class=&quot;tr-caption-container&quot; style=&quot;float: right; margin-left: 1em; text-align: right;&quot;&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: center;&quot;&gt;&lt;a href=&quot;http://netdna.webdesignerdepot.com/uploads/2013/03/featured_cp@wdd2x.jpg&quot; imageanchor=&quot;1&quot; style=&quot;clear: left; margin-bottom: 1em; margin-left: auto; margin-right: auto;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;http://netdna.webdesignerdepot.com/uploads/2013/03/featured_cp@wdd2x.jpg&quot; height=&quot;182&quot; width=&quot;320&quot; /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;tr-caption&quot; style=&quot;text-align: center;&quot;&gt;Note that neither is really about picking good colors.&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
Designing good interfaces is about finding elegant solutions to problems. It&#39;s about understanding what users want to accomplish so intimately that when you show them your solution the beauty goes unnoticed. It&#39;s about building an interface that lets the real work can happen unhindered. You shouldn&#39;t have to think about the interface you&#39;re using, it should get completely out of the way.&lt;br /&gt;
&lt;br /&gt;
Which in educational technology is actually kind of a problem. I didn&#39;t realize it was an issue until a few years ago. I used to tell people that instructional design and interface design are at their core the same thing. That was pretty naive on my part, but it was based more on practical observations than graduate-level research, so I don&#39;t feel too bad about it. At the end of the day what I saw most instructional designers doing was helping people build learning experiences that were intuitive for learners to work through. Get rid of weird navigation, structure the content with a natural flow, don&#39;t use ugly fonts. Stuff like that. Building an intuitive, elegant workflow that doesn&#39;t trip people up and lets them focus on what they&#39;re trying to accomplish. Learning interface design.&lt;br /&gt;
&lt;br /&gt;
&lt;table cellpadding=&quot;0&quot; cellspacing=&quot;0&quot; class=&quot;tr-caption-container&quot; style=&quot;float: right; text-align: right;&quot;&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhGp_OBssFvfYxF4T-1_MWrGGle-BL8Z0NNhGR3Xr2W-xrIeVdMJuGApD8UDSKXYmuysU45XYJu479Pr9-uEip8QCQNZmHB76OMZLbgwXvrRepGFkV72YZWeU-LM_Jbne50o2_Z4-TTpBo/s1600/Screen+Shot+2014-02-04+at+11.34.51+PM.png&quot; imageanchor=&quot;1&quot; style=&quot;clear: right; margin-bottom: 1em; margin-left: auto; margin-right: auto;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhGp_OBssFvfYxF4T-1_MWrGGle-BL8Z0NNhGR3Xr2W-xrIeVdMJuGApD8UDSKXYmuysU45XYJu479Pr9-uEip8QCQNZmHB76OMZLbgwXvrRepGFkV72YZWeU-LM_Jbne50o2_Z4-TTpBo/s1600/Screen+Shot+2014-02-04+at+11.34.51+PM.png&quot; height=&quot;196&quot; width=&quot;320&quot; /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;tr-caption&quot; style=&quot;text-align: center;&quot;&gt;Image searching for &quot;instructional design&quot; is disheartening.&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
The problem with this perspective didn&#39;t become apparent until I had a little more experience under my belt. We were doing a redesign of some components in Canvas, and the designers showed me their ideas, and when I objected to their designs they were legitimately baffled as to why I didn&#39;t agree with them. What they were proposing was focused so completely on streamlining the user&#39;s (learner&#39;s) experience that it was actually going to negatively impact the learning experience.&lt;br /&gt;
&lt;br /&gt;
See, learning is different than learning management (don&#39;t get me started on &quot;LMS&quot;, it&#39;s a term I&#39;ve always hated but never bothered to change). If you&#39;re just&amp;nbsp;&lt;i&gt;managing&lt;/i&gt; your learning experience then yes, by all means, focus completely on optimization. Log in, get stuff done and close that browser tab as quickly as possible. But if instead you&#39;re trying to facilitate &lt;i&gt;learning&lt;/i&gt;&amp;nbsp;then you need to be concerned with more than just saving someone time. Learning requires conflict, it involves running up against differing opinions and joining unexpected discussions and trying to overlay acquired knowledge in new and possibly confusing arenas. None of that is very clean or streamlined.&lt;br /&gt;
&lt;br /&gt;
Good instructional design isn&#39;t about getting to the nugget of information and then getting out without too many clicks, even if that is most of what I&#39;d seen early-on working with schools. Really good instructional design would actually try to surface social interactions that would be beneficial for the learner to engage in -- even if they weren&#39;t intending to participate in them when they first logged in. Even if they weren&#39;t really in the mood. Even if it meant&amp;nbsp;&lt;i&gt;noticing&lt;/i&gt;&amp;nbsp;the interface.&lt;br /&gt;
&lt;br /&gt;
&lt;table align=&quot;center&quot; cellpadding=&quot;0&quot; cellspacing=&quot;0&quot; class=&quot;tr-caption-container&quot; style=&quot;float: right; margin-left: 1em; text-align: right;&quot;&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: center;&quot;&gt;&lt;a href=&quot;http://webpages.scu.edu/ftp/kljensen/Raw%20Images/Conflict%20photo.png&quot; imageanchor=&quot;1&quot; style=&quot;clear: right; margin-bottom: 1em; margin-left: auto; margin-right: auto;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;http://webpages.scu.edu/ftp/kljensen/Raw%20Images/Conflict%20photo.png&quot; height=&quot;216&quot; width=&quot;320&quot; /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;tr-caption&quot; style=&quot;text-align: center;&quot;&gt;Calvin taught me a lot about learning in social settings.&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
It&#39;s not about forcing a learner to post at least once in the discussion board in order to get a grade, but it should be about exposing them to the experiences they mightn&#39;t pursue on their own that will help them deepen or solidify their understanding. Maybe in a perfect world all learners would see this as part of their successful learning workflow, in which case you could fall back to arguing that instructional design and interface design have the same goal, but that&#39;s not the case today. A good learning interface can&#39;t take just the learner&#39;s immediate interests into consideration, or it will miss the bigger picture completely.&lt;br /&gt;
&lt;br /&gt;
Anyway, something to think about if you&#39;re ever in the business of designing educational technology.</content><link rel='replies' type='application/atom+xml' href='http://brianwhitmer.blogspot.com/feeds/1990986641719316556/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/5825798647577501834/1990986641719316556' title='10 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5825798647577501834/posts/default/1990986641719316556'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5825798647577501834/posts/default/1990986641719316556'/><link rel='alternate' type='text/html' href='http://brianwhitmer.blogspot.com/2014/02/instructional-design-is-not-interface.html' title='Instructional Design is Not Interface Design'/><author><name>Brian Whitmer</name><uri>http://www.blogger.com/profile/00009042638644799674</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjuU9fLl8xHMXUGHbywzQI6WumY7z2W7ZL1iBvxzleBCeBQzIoZ5hnhALV9oSHTQs3iWNRFbTiyADkUEIENiZawHyzWZBxIq3JzvCsTANyrGx-fD1nDmk4ax2BIakeg/s1600/71c13439beedf6c35c53acb0976d97c6'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhGp_OBssFvfYxF4T-1_MWrGGle-BL8Z0NNhGR3Xr2W-xrIeVdMJuGApD8UDSKXYmuysU45XYJu479Pr9-uEip8QCQNZmHB76OMZLbgwXvrRepGFkV72YZWeU-LM_Jbne50o2_Z4-TTpBo/s72-c/Screen+Shot+2014-02-04+at+11.34.51+PM.png" height="72" width="72"/><thr:total>10</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5825798647577501834.post-3792479172226388830</id><published>2013-12-20T09:25:00.000-08:00</published><updated>2014-02-02T16:15:41.439-08:00</updated><title type='text'>Should Everyone Learn to Code?</title><content type='html'>This is a repost of a &lt;a href=&quot;http://learning.instructure.com/2013/12/should-everyone-learn-to-code/&quot;&gt;post I wrote for Instructure&#39;s Keep Learning blog&lt;/a&gt;. I had a couple other paragraphs that got cut out that I&#39;ll slip in here as well. Enjoy!&lt;br /&gt;
&lt;br /&gt;
Should computer programming be standard curriculum? This question seems to &lt;a href=&quot;http://business.time.com/2012/06/08/codecademy-founder-why-everyone-should-learn-programming/&quot;&gt;come&lt;/a&gt; &lt;a href=&quot;http://www.slate.com/articles/technology/future_tense/2013/08/everybody_does_not_need_to_learn_to_code.html&quot;&gt;up&lt;/a&gt; &lt;a href=&quot;http://www.huffingtonpost.com/john-pavley/learning-to-code_b_3337098.html&quot;&gt;every&lt;/a&gt; &lt;a href=&quot;http://www.linkedin.com/today/post/article/20130716014745-7374576-why-you-need-to-know-code-and-how-you-can-learn-in-a-month&quot;&gt;few&lt;/a&gt; &lt;a href=&quot;http://www.forbes.com/sites/anthonykosner/2012/10/06/learn-to-code-1-does-everybody-really-need-to-program/&quot;&gt;months&lt;/a&gt;, and it came up again for me a few weeks ago, so I thought I’d take a crack at it. I’m a programmer by training, and I spent two years in a computer science research lab, so I have some inherent biases, but I’m also a dad who’s very concerned with how my kids are shaped by what they learn in school, so hopefully my input is useful.&lt;br /&gt;
&lt;br /&gt;
&lt;h3&gt;
On The One Hand …&lt;/h3&gt;
&lt;br /&gt;
Of course everyone should learn to code. Just like everyone should learn to change a leaky pipe or a flat tire, and to multiply decimals, and to manage their finances, and to present a compelling argument in front of a group of people. You don’t learn to code just so you can be a professional coder.&lt;br /&gt;
&lt;br /&gt;
To me, learning isn’t so much about developing skills as it is about having the contextual understanding to make sense of the world around you. We try to reduce observed chaos by finding mental models that match reality as closely as possible. When we understand something it’s less scary and more predictable—and predictability is empowering. When our culture can’t function without software, but for most people that software is still a voodoo art, it’s high time we gave more people the context to know what’s going on.&lt;br /&gt;
&lt;br /&gt;
A &lt;a href=&quot;http://www.codinghorror.com/blog/2012/05/please-dont-learn-to-code.html&quot;&gt;common argument&lt;/a&gt; against everyone learning to program is that there will be more bad programmers in the world. Sure. Just like there are at least five bad, self-declared plumbers on my street. And while they may not know their limits exactly, none of them try to tackle industrial plumbing projects that are clearly out of their league. It’s not the end of the world if newbie programmers cut their teeth on hobby projects and don’t write perfect code.&lt;br /&gt;
&lt;br /&gt;
Programmers have the whole world at their fingertips. A programmer can ply their trade in anything from medicine to finance to farming. As a programmer, I can answer my own questions, almost without fail. I can write a quick script and see if my new idea will really make things more efficient or not. And, just as importantly, I can recognize which of my questions are tractable and which aren’t. That’s hugely empowering, and it means I can be more productive than many other people in similar situations.&lt;br /&gt;
&lt;br /&gt;
&lt;h3&gt;
On The Other Hand …&lt;/h3&gt;
&lt;br /&gt;
Saying everyone needs to code just because every industry needs coders is like saying everyone needs to know accounting or law. People should be able to manage their own finances and understand a basic legal contract on their own, sure, but not much more than that. It’d be great if everyone had all those skill sets, but that’s not reasonable to expect. It’s not such a bad thing if “code” lives in the same realm for most people as “legalese” and “accountant-speak.” There’s a limit to how deep you should need to go into any non-essential subject. Remember, most programmers can’t code in binary or assembly and can’t solder their own circuits. Maybe the typical software user’s expertise can stop at power user rather than armchair coder—which would still be a huge step forward.&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjTfKn9ZWiRG4UxzJEVYh_ij052Phl92rhGme2H1cgi2H-yOYsZiWBi8NL9CRN6yAuFcwSPfvonBVjYkjG0XRMNRzjMtJn25wyOEDHP72L_bGtztoYOj282ejMmJpvO-sXNFetWyy_ncek/s1600/207823.strip.sunday.gif&quot; imageanchor=&quot;1&quot; style=&quot;clear: left; float: left; margin-bottom: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjTfKn9ZWiRG4UxzJEVYh_ij052Phl92rhGme2H1cgi2H-yOYsZiWBi8NL9CRN6yAuFcwSPfvonBVjYkjG0XRMNRzjMtJn25wyOEDHP72L_bGtztoYOj282ejMmJpvO-sXNFetWyy_ncek/s1600/207823.strip.sunday.gif&quot; height=&quot;178&quot; width=&quot;400&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
There’s also the concern about creating a generation of same-mindedness. Studying computer theory isn’t a trivial endeavor, and quite frankly, ends up rewiring your brain in some very noticeable ways. Most programmers have a very similar perspective on how the world works and how to tackle problems. Maybe they’ve found the optimal mindset, but maybe not. I would be reluctant to raise up an entire generation of students to have that particular perspective without some serious thought first.&lt;br /&gt;
&lt;br /&gt;
&lt;h3&gt;
Therefore, What?&lt;/h3&gt;
&lt;br /&gt;
I want to take this argument, “everyone should learn to code,” and tweak it. The goal of teaching everyone to program shouldn’t be to make everyone a programmer. That’s just silly. I work at a software company, and I’d say that at best one-third of the people in our office would benefit from having coding skills. There are many jobs that will still need to be filled, and just as many skill sets outside of programming that are going to be important for the foreseeable future.&lt;br /&gt;
&lt;br /&gt;
I think everyone deserves a contextual understanding of how the world around them functions. I think everyone should learn to code—a little bit. I don’t think everyone needs to know the ins and outs of JavaScript or Python or Java or whatever. Even more importantly, I don’t think everyone needs to know (or ought to know) decision trees, binary search, complexity classes, or tail recursion. But I think everyone deserves to know:&lt;br /&gt;
&lt;br /&gt;
How the Internet works (and that it’s not the same thing as a web browser)&lt;br /&gt;
&lt;br /&gt;
How to craft a set of instructions that drive a system (for Codecademy, Lego Mindstorms, Scratch, or whatever)&lt;br /&gt;
&lt;br /&gt;
How to tinker and troubleshoot (to help overcome the fear of breaking things, which is a legitimate, but crippling factor in tech adoption)&lt;br /&gt;
&lt;br /&gt;
And also maybe (but maybe not) a couple other things:&lt;br /&gt;
&lt;br /&gt;
How to break down a complex problem into smaller, more manageable sets of problems&lt;br /&gt;
&lt;br /&gt;
How to test the correctness and robustness of a solution to a problem&lt;br /&gt;
&lt;br /&gt;
I guess you could say I think everyone doesn’t need to intimately know how to code, but everyone should learn how coding works, and how to use it to solve the problem at hand.&lt;br /&gt;
&lt;br /&gt;
Where does that need to happen? It doesn’t need to be a full-year class. I’d love to see a mandatory introductory class in high school that covered things like computer programming, electronics (&lt;a href=&quot;http://www.kickstarter.com/projects/joylabs/makey-makey-an-invention-kit-for-everyone&quot;&gt;this&lt;/a&gt; type of &lt;a href=&quot;http://www.kickstarter.com/projects/electroninks/circuit-scribe-draw-circuits-instantly?ref=category&quot;&gt;stuff&lt;/a&gt;), and other applied STEM topics (sort of a modern shop class). It doesn’t sound unreasonable, and it would be a great jumping-off point for those that do discover a passion for coding or any number of related areas.&lt;br /&gt;
&lt;br /&gt;
&lt;h3&gt;
The End&lt;/h3&gt;
&lt;br /&gt;
&lt;h3&gt;
Extras: More on why not everyone should learn to code&lt;/h3&gt;
&lt;br /&gt;
This is the stuff that got cut out. The concern was that it made the argument against a little too strong and lengthy, but this is something I think about a lot so I&#39;ve added it here I guess for my own selfish purposes.&lt;br /&gt;
&lt;br /&gt;
As a Computer Science student in college, I had my brain very literally rewired. I can vividly remember walking around campus talking to myself, moving and twisting imaginary figures in front of me as I tried to make sense of finite state machines, …, and …. I’m not sure if I didn’t think the same way after that, or if I always thought a little bit differently, but I came out of that education with a very distinct perspective on how the world works.&lt;br /&gt;
&lt;br /&gt;
There is no doubt in my mind that most programmers have a similar mental model for the world, and a similar approach to tackling projects. Part of it is that sense of empowerment I talked about earlier, but part of comes from seeing everything as a set of differently-sized algorithms with a well-defined problem and a testable, possibly inevitable solution. It comes out in the typical programmer’s style of humor, their language, their approach to meetings, etc. There are TV shows that target nerd culture, and there’s a rising trend in media for the nerd-hero that fits a very distinct persona.&lt;br /&gt;
&lt;br /&gt;
All of these things concern me. I suppose it sounds elitist to say “I don’t want more people in the workforce just like me,” but that’s exactly how I feel. Is the programmer mindset the *right* way to tackle the problems of the future, or is it just *one* way? As a programmer myself I don’t think I’m the best person to be answering that question. One of the problems with a data-driven mindset is that you are inevitably drawn to answer the questions that can be effectively measured, not necessarily the questions that can lead to the right solution.&lt;br /&gt;
&lt;br /&gt;
If we decide it’s worthwhile to train up an entire generation of learners to start thinking a certain way, what does that do to our population’s cognitive diversity? I don’t actually know, but I don’t think we should try it without at least thinking really hard about it first.</content><link rel='replies' type='application/atom+xml' href='http://brianwhitmer.blogspot.com/feeds/3792479172226388830/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/5825798647577501834/3792479172226388830' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5825798647577501834/posts/default/3792479172226388830'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5825798647577501834/posts/default/3792479172226388830'/><link rel='alternate' type='text/html' href='http://brianwhitmer.blogspot.com/2013/12/should-everyone-learn-to-code.html' title='Should Everyone Learn to Code?'/><author><name>Brian Whitmer</name><uri>http://www.blogger.com/profile/00009042638644799674</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjuU9fLl8xHMXUGHbywzQI6WumY7z2W7ZL1iBvxzleBCeBQzIoZ5hnhALV9oSHTQs3iWNRFbTiyADkUEIENiZawHyzWZBxIq3JzvCsTANyrGx-fD1nDmk4ax2BIakeg/s1600/71c13439beedf6c35c53acb0976d97c6'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjTfKn9ZWiRG4UxzJEVYh_ij052Phl92rhGme2H1cgi2H-yOYsZiWBi8NL9CRN6yAuFcwSPfvonBVjYkjG0XRMNRzjMtJn25wyOEDHP72L_bGtztoYOj282ejMmJpvO-sXNFetWyy_ncek/s72-c/207823.strip.sunday.gif" height="72" width="72"/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5825798647577501834.post-501662228029213319</id><published>2013-04-29T10:27:00.000-07:00</published><updated>2013-08-22T09:38:42.711-07:00</updated><title type='text'>A Better YouTube App Using LTI</title><content type='html'>&lt;br /&gt;
&lt;div class=&quot;p1&quot;&gt;
&lt;br class=&quot;Apple-interchange-newline&quot; /&gt;
K, so&lt;a href=&quot;http://brianwhitmer.blogspot.com/2012/12/lti-authentication.html&quot;&gt;&amp;nbsp;I promised to revisit&lt;/a&gt;&amp;nbsp;the LTI workflow and how I think it&#39;s broken -- also how we fixed it in Canvas. Here&#39;s that revisit, as promised.&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;table align=&quot;center&quot; cellpadding=&quot;0&quot; cellspacing=&quot;0&quot; class=&quot;tr-caption-container&quot; style=&quot;margin-left: auto; margin-right: auto; text-align: center;&quot;&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;&lt;a href=&quot;https://encrypted-tbn2.gstatic.com/images?q=tbn:ANd9GcQAMcHElzIvqc8Dozkfa52AFmMLkONHSim31YyMdRQRZgQHVEyxvA&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: auto; margin-right: auto;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://encrypted-tbn2.gstatic.com/images?q=tbn:ANd9GcQAMcHElzIvqc8Dozkfa52AFmMLkONHSim31YyMdRQRZgQHVEyxvA&quot; /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;tr-caption&quot; style=&quot;font-size: 13px;&quot;&gt;This is backwards, like LTI. Also like LTI, it&#39;s crafty in the middle.&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div class=&quot;p1&quot;&gt;
In standard LTI there are two possible workflows:&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div class=&quot;p1&quot;&gt;
1. Admin-installed, reusable launch. In this case someone high up installs an LTI app that teachers can use in their courses. The launch URL is generic, so when teachers add links to the app within their course material they then have to launch the app and go through an initial selection process.&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div class=&quot;p1&quot;&gt;
This is backwards from what most people want to do. Nobody says, &quot;hey, I want to add YouTube to my course! I&#39;ll figure out which video later…&quot; It makes a lot more sense to pick the specific YouTube video you want and add *that* to your content.&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div class=&quot;p1&quot;&gt;
Which brings us to…&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div class=&quot;p1&quot;&gt;
2. Admin/teacher-installed, specific launch. The alternative is to specify when adding the resource what URL to launch. LTI allows for domain-level matching, so you can still have the admin install the app with a valid key and secret, and then teachers need to insert content-specific links that match this domain.&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div class=&quot;p1&quot;&gt;
This is also an awkward workflow, albeit a little better. Essentially this is saying, &quot;hey, I want to add a YouTube video to my course! I&#39;ll go over to YouTube, find the right video, copy the link and paste it here&quot;. Still not terribly elegant.&lt;/div&gt;
&lt;div class=&quot;p1&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div class=&quot;p1&quot;&gt;
Which is why we&#39;ve built some content extensions to LTI to support The Right Workflow. Using our extensions, the admin installs the app with a key and secret, and when the teacher goes to add a link to content from that app, a selection dialog appears that lets them browse/search content within that app, pick it, and have the linking part automatically taken care of. Now we can say &quot;hey, I want to add a YouTube video to my course! I&#39;ll just open up this handy YouTube picker and find the video I want&quot;.&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div class=&quot;p1&quot;&gt;
&lt;br /&gt;
&lt;iframe allowfullscreen=&quot;&quot; frameborder=&quot;0&quot; height=&quot;315&quot; src=&quot;http://www.youtube.com/embed/-3TGCBK3ryo?rel=0&quot; width=&quot;420&quot;&gt;&lt;/iframe&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div class=&quot;p1&quot;&gt;
Here&#39;s how it works.&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div class=&quot;p1&quot;&gt;
LTI launches come standard with a parameter I haven&#39;t mentioned before called launch_presentation_return_url. Basically when the LTI app has done doing its thing it can redirect the iframe to this URL and the LMS should know at that point that the app is done and do something about it (probably redirect to another page or close down the iframe).&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div class=&quot;p1&quot;&gt;
All I&#39;ve done is define some additional parameters which can be added to this return redirect that will tell the LMS that the user picked some content (we also send over a couple additional parameters to give the app some hints about what the user is expecting). The docs are here, but basically you look for selection_directive, and we have shortcuts for easily embedded links, images, lti launches and iframes, and for everything else it uses oembed.&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div class=&quot;p1&quot;&gt;
As far as an implementation goes, we&#39;re talking about this:&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div class=&quot;p4&quot;&gt;
&lt;pre&gt;# Handle POST requests to the endpoint &quot;/lti_launch&quot;
post &quot;/lti_launch&quot; do
  # do magical YouTube-y stuff  
  if params[&#39;selection_directive&#39;]
    # all the JavaScript needs to know is the redirect URL, it can take care of the rest
    render(&#39;selection_specific_page&#39;, params[&#39;launch_presentation_return_url&#39;])
  else
    return &quot;This app doesn&#39;t support standard LTI launches, only content selection launches&quot;
  end
end
&lt;/pre&gt;
&lt;div class=&quot;p6&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div class=&quot;p7&quot;&gt;
for the server. The JavaScript code changes as well to support the selection redirect:&lt;br /&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div class=&quot;p6&quot;&gt;
&lt;pre&gt;// Remember the return_url so we know where to send the user once selection is complete
var returnUrl = decodeURIComponent(location.href.match(/return_url=([^&amp;amp;#]+)/)[1]);
if(!returnUrl) {
  returnUrl = &quot;http://www.example.com&quot;;
  alert(&quot;No valid return URL provided! This tool will not work correctly!&quot;);
}
    
function returnVideo(video_id) {
  var url = &quot;https://www.youtube.com/watch?v=&quot;  + video_id;
  returnUrl = returnUrl + (returnUrl.match(/\?/) ? &quot;&amp;amp;&quot; : &quot;?&quot;) + &quot;embed_type=url&amp;amp;title=Video&amp;amp;text=Video&amp;amp;url=&quot; + encodeURIComponent(url);
  location.href = returnUrl;
}
&lt;/pre&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div class=&quot;p7&quot;&gt;
Now it doesn&#39;t even require an LTI launch for the student to access the data (which seemed silly for YouTube anyway), just an LTI launch by the teacher at setup-time, then the tool returns a YouTube iframe and the LMS takes care of inserting it in the right place. We use this approach in Canvas to add buttons to the WYSIWYG editor, add options for homework submissions, and as an option in the module builder, but we&#39;ll be adding it more places in the future.&lt;/div&gt;
&lt;div class=&quot;p6&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div class=&quot;p7&quot;&gt;
You may not have noticed, but we&#39;re now ignoring the LTI credentials like we did in the first example. It turns out that if your app only does content selection and doesn&#39;t support standard LTI, there&#39;s nothing that needs to be persisted to the database, and there&#39;s nothing to protect for an open app like a YouTube searcher.&lt;i&gt;&amp;nbsp;If you&#39;re still allowing standard LTI launches or if your content is protected, you should definitely still confirm the LTI signature using a preset key and secret.&lt;/i&gt;&lt;/div&gt;
&lt;div class=&quot;p6&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div class=&quot;p7&quot;&gt;
&lt;a href=&quot;https://github.com/whitmer/youtube_lti_better&quot;&gt;Sinatra app course code available here.&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;
</content><link rel='replies' type='application/atom+xml' href='http://brianwhitmer.blogspot.com/feeds/501662228029213319/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/5825798647577501834/501662228029213319' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5825798647577501834/posts/default/501662228029213319'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5825798647577501834/posts/default/501662228029213319'/><link rel='alternate' type='text/html' href='http://brianwhitmer.blogspot.com/2013/04/a-better-youtube-app-using-lti.html' title='A Better YouTube App Using LTI'/><author><name>Brian Whitmer</name><uri>http://www.blogger.com/profile/00009042638644799674</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjuU9fLl8xHMXUGHbywzQI6WumY7z2W7ZL1iBvxzleBCeBQzIoZ5hnhALV9oSHTQs3iWNRFbTiyADkUEIENiZawHyzWZBxIq3JzvCsTANyrGx-fD1nDmk4ax2BIakeg/s1600/71c13439beedf6c35c53acb0976d97c6'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://img.youtube.com/vi/-3TGCBK3ryo/default.jpg" height="72" width="72"/><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5825798647577501834.post-888567192764547650</id><published>2012-12-28T10:50:00.000-08:00</published><updated>2012-12-28T10:50:46.880-08:00</updated><title type='text'>LTI Authentication</title><content type='html'>Last post I wrote a &lt;a href=&quot;http://brianwhitmer.blogspot.com/2012/12/building-youtube-lti-app.html&quot;&gt;short tutorial on how to build an LTI app&lt;/a&gt;, with a YouTube search app as the example. The thing I left out of that example was signature validation. Validating the request&#39;s signature is how you can make sure that app launches are happening only from trusted sources, and how you can use LTI for automatically logging in app users. Authentication is important and if you&#39;re building a production-worthy LTI app you should definitely include this.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;table align=&quot;center&quot; cellpadding=&quot;0&quot; cellspacing=&quot;0&quot; class=&quot;tr-caption-container&quot; style=&quot;margin-left: auto; margin-right: auto; text-align: center;&quot;&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjWiDgq6oqbG2e1HrxlxTiEeHBR0RyK9CjMQ-D_m9m1FoIyCS3v4NRa81TxgH8q_hMT8ksrRaAiiAkN1cjrriGMMgf5y3y9s4Jbt2MABZwva3XRi29cD_EaIwheWzJdXkg_epgpvL18y_4/s1600/JohnsSignature.jpg&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: auto; margin-right: auto;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;214&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjWiDgq6oqbG2e1HrxlxTiEeHBR0RyK9CjMQ-D_m9m1FoIyCS3v4NRa81TxgH8q_hMT8ksrRaAiiAkN1cjrriGMMgf5y3y9s4Jbt2MABZwva3XRi29cD_EaIwheWzJdXkg_epgpvL18y_4/s320/JohnsSignature.jpg&quot; width=&quot;320&quot; /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;tr-caption&quot; style=&quot;text-align: center;&quot;&gt;Graphology is the analysis of signatures and handwriting. It tells us that John Hancock had trouble sleeping and liked ponies.&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;br /&gt;
LTI authentication is based on OAuth 1.0&#39;s signature validation. LTI is primarily a one-way identity assertion, where the learning platform tells the app details about the current user&#39;s identity and context. The learning platform and the app are responsible to come up with a consumer key and shared secret out-of-band (more on that in a minute). The attributes come across as form POST parameters, and the signature is sent across as an additional parameter.&lt;br /&gt;
&lt;br /&gt;
Side note: Wherever possible you should &lt;b&gt;serve your app over https instead of http&lt;/b&gt;. Some learning platforms like Canvas render all pages over SSL and users will get security warnings when trying to launch non-SSL apps.&lt;br /&gt;
&lt;br /&gt;
The signature is generated, &lt;a href=&quot;http://oauth.net/core/1.0/#signing_process&quot;&gt;as with OAuth 1.0&lt;/a&gt;, by sorting all the request parameters, adding the consumer key, a timestamp and a nonce, and hashing them together using the shared secret. There are either&lt;a href=&quot;https://lti-examples.heroku.com/code.html&quot;&gt; LTI or OAuth libraries&lt;/a&gt; for many common languages, so hopefully you don&#39;t have to write this code yourself, but if you do &lt;a href=&quot;http://oauth.googlecode.com/svn/code/javascript/example/signature.html&quot;&gt;here&#39;s a handy page for checking your signature generation&lt;/a&gt;. In practice your code will look something like the following (&lt;a href=&quot;http://brianwhitmer.blogspot.com/2012/12/building-youtube-lti-app.html&quot;&gt;read my last post&lt;/a&gt; if this doesn&#39;t look familiar):&lt;br /&gt;
&lt;br /&gt;
&lt;pre&gt;# Handle POST requests to the endpoint &quot;/lti_launch&quot;
post &quot;/lti_launch&quot; do
  config = find_config(params[&#39;oauth_consumer_key&#39;])
  if !config
    return &quot;Invalid launch - no configuration found for that key&quot;
  end
  provider = IMS::LTI::ToolProvider.new(config.key, config.secret, params)
  if !provider.valid_request?(request)
    return &quot;Invalid launch - signature does not match&quot;
  end
  
  # do magical YouTube-y stuff 
end
&lt;/pre&gt;
&lt;br /&gt;
Side note: there are a few (optional) cases where the app may also pass messages back to the learning platform (&lt;a href=&quot;https://canvas.instructure.com/doc/api/file.assignment_tools.html&quot;&gt;grade passback&lt;/a&gt;, for example). In these cases the app will use the same signing process as the learning platform.&lt;br /&gt;
&lt;br /&gt;
User data comes across as POST parameters. Some parameters are required, many are optional and can be configured within the learning platform. &lt;a href=&quot;https://lti-examples.heroku.com/code.html#params&quot;&gt;Here&#39;s a list of the expected parameters&lt;/a&gt;, though additional custom parameters can also be sent. If your app has its own login system you can use this data to match users up with their existing logins, or to auto-create a user account in your system matching the data provided (some tools ask new users to create a login on first launch before continuing, I encourage people to make that an optional step after-the-fact to make things easier on the end-user). Our YouTube app doesn&#39;t care about identity at all, so we can ignore identity for now.&lt;br /&gt;
&lt;br /&gt;
The only trick left is generating a consumer key and shared secret, and sharing them between the app and the learning platform. In practice, the app typically generates the key and secret, and it&#39;s the end-user&#39;s responsibility to copy the key and secret from a page within the app and paste them into a form within the learning platform. On the learning platform&lt;em style=&quot;background-color: white; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; margin: 0px; padding: 0px;&quot;&gt;–&lt;/em&gt;side the app will be configured by an institution admin, a department admin, or possibly an individual instructor, and the same key will be used to launch the app for any learners or instructors within that unit. Sometimes the key is the user&#39;s login or some known identifier, but often it&#39;s a large unique string just like the shared secret.&lt;br /&gt;
&lt;br /&gt;
&lt;table align=&quot;center&quot; cellpadding=&quot;0&quot; cellspacing=&quot;0&quot; class=&quot;tr-caption-container&quot; style=&quot;margin-left: auto; margin-right: auto; text-align: center;&quot;&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgcBlrTa1bgZIE2L-7g-u22aRu3lKKU6D0xYa9QIQDmITAOfV4mHe-KCOeoLUrOclL380FE4laIUcoJ3VeqtetlwVxXFybvKeNvGyRG4wKERKxlhdHlHMrWK3x0KvUE_sfS75sTUxrCtLU/s1600/Screen+Shot+2012-12-28+at+9.51.42+AM.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: auto; margin-right: auto;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;243&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgcBlrTa1bgZIE2L-7g-u22aRu3lKKU6D0xYa9QIQDmITAOfV4mHe-KCOeoLUrOclL380FE4laIUcoJ3VeqtetlwVxXFybvKeNvGyRG4wKERKxlhdHlHMrWK3x0KvUE_sfS75sTUxrCtLU/s400/Screen+Shot+2012-12-28+at+9.51.42+AM.png&quot; width=&quot;400&quot; /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;tr-caption&quot; style=&quot;text-align: center;&quot;&gt;Example of key and secret being provided by the app.&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;br /&gt;
&lt;table align=&quot;center&quot; cellpadding=&quot;0&quot; cellspacing=&quot;0&quot; class=&quot;tr-caption-container&quot; style=&quot;margin-left: auto; margin-right: auto; text-align: center;&quot;&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh3ahellCZJOf6g8Ry_WzOZlYl6h27hBfqexhJw7O-qce0UIuv1eCVa14wHZcmo3V6dDHMZYSTdZ_HDsCR5_64JNSS2GQzFd0Ix1q7krIAlAFvtToR7Zjzuof7eV1g3Lt9fqfQY-_-tokY/s1600/Screen+Shot+2012-12-28+at+9.53.14+AM.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: auto; margin-right: auto;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;241&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh3ahellCZJOf6g8Ry_WzOZlYl6h27hBfqexhJw7O-qce0UIuv1eCVa14wHZcmo3V6dDHMZYSTdZ_HDsCR5_64JNSS2GQzFd0Ix1q7krIAlAFvtToR7Zjzuof7eV1g3Lt9fqfQY-_-tokY/s400/Screen+Shot+2012-12-28+at+9.53.14+AM.png&quot; width=&quot;400&quot; /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;tr-caption&quot; style=&quot;text-align: center;&quot;&gt;Example of pasting the key and secret within the learning platform&#39;s app configuration tool.&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;br /&gt;
Remember: the key is fine to share publicly, but &lt;b&gt;the secret should be protected&lt;/b&gt;, since anyone who knows the secret (and key) can impersonate the learning platform to the app. If you&#39;re going to do something like hashing the key to generate the secret, it&#39;s a very good idea to add some randomness.&lt;br /&gt;
&lt;br /&gt;
&lt;table align=&quot;center&quot; cellpadding=&quot;0&quot; cellspacing=&quot;0&quot; class=&quot;tr-caption-container&quot; style=&quot;margin-left: auto; margin-right: auto; text-align: center;&quot;&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgqdeDaa1eG-1P_zMEQHnsCrWJAv06ecayREZDNtKuAtX-C3PIWez_ASGJ32pqXRKDeOLkZIqKAj9PW5Sof0PHGAm1x-hW-WgjQzIt43wiwikkSaPLJrlYe3N5JyCeBfyI7HLByQcmQKe8/s1600/secret_safe.jpg&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: auto; margin-right: auto;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;180&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgqdeDaa1eG-1P_zMEQHnsCrWJAv06ecayREZDNtKuAtX-C3PIWez_ASGJ32pqXRKDeOLkZIqKAj9PW5Sof0PHGAm1x-hW-WgjQzIt43wiwikkSaPLJrlYe3N5JyCeBfyI7HLByQcmQKe8/s320/secret_safe.jpg&quot; width=&quot;320&quot; /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;tr-caption&quot; style=&quot;text-align: center;&quot;&gt;Shared secrets should be kept secret. They should be kept safe.&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;br /&gt;
For our YouTube app we&#39;ll just add a small command-line script that can be used to generate a new key and secret by hand:&lt;br /&gt;
&lt;br /&gt;
&lt;pre&gt;config = generate_config()
print &quot;== New Configuration ==&quot;
print &quot;consumer key:  &quot; + config.key
print &quot;shared secret: &quot; + config.secret
&lt;/pre&gt;
&lt;br /&gt;
The reason you need authentication for LTI should be clear, it&#39;s how the app can verify that users are coming from a trusted source into the app, and can be considered an alternative to a username and password&lt;em style=&quot;background-color: white; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; margin: 0px; padding: 0px;&quot;&gt;–&lt;/em&gt;style login. Even for a simple YouTube app like our example, which completely ignores all user information, it&#39;s important because each app placement within the learning platform is going to end up persisting information to your datastore once a video is selected, and without signature validation it would be easy for a malicious party to launch and run your app millions of times and stuff your datastore with junk placements. There&#39;s a more elegant approach that gets around this issue using an extension to LTI that I built for Canvas, but I&#39;ll cover that in another post.&lt;br /&gt;
&lt;br /&gt;
&lt;a href=&quot;https://github.com/whitmer/youtube_lti_signed&quot;&gt;Sinatra app source code available here.&lt;/a&gt;</content><link rel='replies' type='application/atom+xml' href='http://brianwhitmer.blogspot.com/feeds/888567192764547650/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/5825798647577501834/888567192764547650' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5825798647577501834/posts/default/888567192764547650'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5825798647577501834/posts/default/888567192764547650'/><link rel='alternate' type='text/html' href='http://brianwhitmer.blogspot.com/2012/12/lti-authentication.html' title='LTI Authentication'/><author><name>Brian Whitmer</name><uri>http://www.blogger.com/profile/00009042638644799674</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjuU9fLl8xHMXUGHbywzQI6WumY7z2W7ZL1iBvxzleBCeBQzIoZ5hnhALV9oSHTQs3iWNRFbTiyADkUEIENiZawHyzWZBxIq3JzvCsTANyrGx-fD1nDmk4ax2BIakeg/s1600/71c13439beedf6c35c53acb0976d97c6'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjWiDgq6oqbG2e1HrxlxTiEeHBR0RyK9CjMQ-D_m9m1FoIyCS3v4NRa81TxgH8q_hMT8ksrRaAiiAkN1cjrriGMMgf5y3y9s4Jbt2MABZwva3XRi29cD_EaIwheWzJdXkg_epgpvL18y_4/s72-c/JohnsSignature.jpg" height="72" width="72"/><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5825798647577501834.post-8271087810413231689</id><published>2012-12-08T16:04:00.000-08:00</published><updated>2012-12-08T16:04:20.139-08:00</updated><title type='text'>Building a YouTube LTI app</title><content type='html'>If you didn&#39;t know, &lt;a href=&quot;https://lti-examples.heroku.com/&quot;&gt;I&#39;m a fan of LTI&lt;/a&gt;. What is &lt;a href=&quot;http://www.imsglobal.org/toolsinteroperability2.cfm&quot;&gt;LTI&lt;/a&gt;? It&#39;s a cross-platform standard in edtech for what essentially amounts to Facebook apps for learning. Like Bejeweled Blitz running within Facebook, you now have Quizlet flashcards running with a course web site. It&#39;s pretty slick, and it makes it a lot easier to build apps that work in different learning platforms.&lt;br /&gt;
&lt;br /&gt;
&lt;table align=&quot;center&quot; cellpadding=&quot;0&quot; cellspacing=&quot;0&quot; class=&quot;tr-caption-container&quot; style=&quot;margin-left: auto; margin-right: auto; text-align: center;&quot;&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: center;&quot;&gt;&lt;a href=&quot;http://poppyonakite.com/wp-content/uploads/2012/02/blt.jpg&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: auto; margin-right: auto;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;225&quot; src=&quot;http://poppyonakite.com/wp-content/uploads/2012/02/blt.jpg&quot; width=&quot;320&quot; /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;tr-caption&quot; style=&quot;text-align: center;&quot;&gt;LTI was originally called BLTI, which always made me hungry.&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;br /&gt;
Anyway. I thought I&#39;d start sharing some examples of LTI apps and how they could be built. I&#39;ll start with an app to embed YouTube videos within course content. The server code is ruby-esque pseudocode which hopefully is grok-able. I&#39;ve included an actual ruby app at the end as well for reference.&lt;br /&gt;
&lt;div&gt;
&lt;br /&gt;
For this example I&#39;ll use the standard LTI workflow (Canvas has what I think is a cleaner workflow, but it&#39;s not officially supported right now. I&#39;ll cover that in another post). With LTI, the teacher or administrator sets up an LTI app. They specify a &lt;code&gt;launch URL&lt;/code&gt;, a &lt;code&gt;consumer key&lt;/code&gt; and a &lt;code&gt;shared secret&lt;/code&gt;. Then when anyone clicks a link to access the app, it will be loaded in an iframe within the platform. In our case, the teacher would add one or more YouTube App placeholders to their course content. Then the teacher would go to each of these placeholders and specify which YouTube video to associate with each placement. Students who launch the app after it is set up will just see the selected YouTube video.&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;iframe allowfullscreen=&#39;allowfullscreen&#39; webkitallowfullscreen=&#39;webkitallowfullscreen&#39; mozallowfullscreen=&#39;mozallowfullscreen&#39; width=&#39;320&#39; height=&#39;266&#39; src=&#39;https://www.youtube.com/embed/l3QHXM4aMuA?feature=player_embedded&#39; frameborder=&#39;0&#39;&gt;&lt;/iframe&gt;&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;object class=&quot;BLOGGER-youtube-video&quot; classid=&quot;clsid:D27CDB6E-AE6D-11cf-96B8-444553540000&quot; codebase=&quot;http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=6,0,40,0&quot; data-thumbnail-src=&quot;http://i.ytimg.com/vi/p90sFDD_K9s/0.jpg&quot; height=&quot;266&quot; width=&quot;320&quot;&gt;&lt;param name=&quot;movie&quot; value=&quot;http://www.youtube.com/v/p90sFDD_K9s?version=3&amp;f=user_uploads&amp;c=google-webdrive-0&amp;app=youtube_gdata&quot; /&gt;&lt;param name=&quot;bgcolor&quot; value=&quot;#FFFFFF&quot; /&gt;&lt;param name=&quot;allowFullScreen&quot; value=&quot;true&quot; /&gt;&lt;embed width=&quot;320&quot; height=&quot;266&quot;  src=&quot;http://www.youtube.com/v/p90sFDD_K9s?version=3&amp;f=user_uploads&amp;c=google-webdrive-0&amp;app=youtube_gdata&quot; type=&quot;application/x-shockwave-flash&quot; allowfullscreen=&quot;true&quot;&gt;&lt;/embed&gt;&lt;/object&gt;&lt;/div&gt;
&lt;br /&gt;
&lt;br /&gt;
App &quot;launches&quot; happen when a user accesses the app from its placement within the learning platform. A launch consists of a client-side form post with an iframe or new tab as the form target. A bunch of data gets sent as POST parameters, including an OAuth-style signature derived from the parameters, key and secret. For simplicity (and since we&#39;re just dealing with public videos and don&#39;t care if the user is actually authenticated) we&#39;re going to ignore signature verification this time around. In a production environment I&#39;d add the check or someone could potentially stuff your database with garbage data.&lt;br /&gt;
&lt;br /&gt;
&lt;pre&gt;# Handle POST requests to the endpoint &quot;/lti_launch&quot;
post &quot;/lti_launch&quot; do
  # do magical YouTube-y stuff
end
&lt;/pre&gt;
&lt;br /&gt;
The only values we&#39;re going to worry about are &lt;code&gt;resource_link_id&lt;/code&gt; and &lt;code&gt;tool_consumer_instance_guid&lt;/code&gt;. The combination of these values should give us a globally unique identifier that we can use to remember this &quot;launch&quot;. We&#39;ll call this the &lt;code&gt;placement_id&lt;/code&gt;, and since any launch from the same placement will result in the same &lt;code&gt;placement_id&lt;/code&gt;, we can use it to remember which video the teacher picked for this placement. If the teacher adds multiple YouTube App placeholders to their course, each placeholder will launch with a different &lt;code&gt;resource_link_id&lt;/code&gt; (&lt;code&gt;tool_consumer_instance_guid&lt;/code&gt; is an extra precaution in case platforms use the same link id) and result in a different&amp;nbsp;&lt;code&gt;placement_id&lt;/code&gt;.&lt;br /&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;pre&gt;# Handle POST requests to the endpoint &quot;/lti_launch&quot;
post &quot;/lti_launch&quot; do
  placement_id = params[&#39;resource_link_id&#39;] + 
      params[&#39;tool_consumer_instance_guid&#39;]
  placement = find_placement(placement_id)
  if placement
    redirect_to &quot;https://youtube.com/embed/&quot;  + placement.video_id
  else
    # use a cookie-based session to remember placement permission
    session[&quot;can_set_&quot; + placement_id] = true

    # let the user pick the video to use for this placement&lt;/pre&gt;
&lt;pre&gt;    redirect_to (&quot;/youtube_search.html?placement_id=&quot; + placement_id)
&lt;/pre&gt;
&lt;pre&gt;  end
end
&lt;/pre&gt;
&lt;br /&gt;
Now we need to build the YouTube video selection page. I like jQuery, and YouTube supports jsonp, so the querying part is actually pretty easy. For the sake of simplicity we&#39;re going to build an &quot;I&#39;m feeling lucky&quot; YouTube searcher that just assumes the first result is the one you want.&lt;br /&gt;
&lt;br /&gt;
&lt;pre&gt;&amp;lt;html&amp;gt;
  &amp;lt;body&amp;gt;
  &amp;lt;h1&amp;gt;YouTube Searcher&amp;lt;/h1&amp;gt;
  &amp;lt;p&amp;gt;Search for a YouTube video below. The first result
  is what will be shown whenever anyone loads this app.
  &amp;lt;/p&amp;gt;
  &amp;lt;form id=&quot;form&quot;&amp;gt;
    &amp;lt;input type=&quot;text&quot; name=&quot;query&quot; id=&quot;query&quot;/&amp;gt;
    &amp;lt;button type=&quot;submit&quot;&amp;gt;I&#39;m Feeling Lucky&amp;lt;/button&amp;gt;
  &amp;lt;/form&amp;gt;
  &amp;lt;script src=&quot;//ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.min.js&quot;&amp;gt;&amp;lt;/script&amp;gt;
  &amp;lt;script&amp;gt;
    // Remember the placement_id so we can persist one a video is found
    var placement_id = location.href.match(/placement_id=([^&amp;amp;#]+)/)[1];
    
    // AJAX call to remember the placement for future launches
    function rememberVideo(video_id) {
      $.ajax({
        url: &quot;/set_video&quot;,
        type: &#39;POST&#39;,
        data: {
          placement_id: placement_id,
          video_id: video_id
        },
        success: function(data) {
          if(data.success) {
            alert(&quot;Video set! Redirecting now...&quot;);
            location.href = &quot;https://www.youtube.com/embed/&quot; + video_id;
          } else {
            alert(&quot;There was a problem setting the video.&quot;);
          }
        },
        dataType: &#39;json&#39;
      });
    }
    
    // JSONP call to search for YouTube videos
    function findVideo(query) {
      // YouTube API endpoint.
      var url = &quot;https://gdata.youtube.com/feeds/api/videos?v=2&amp;amp;q=&quot;;&lt;/pre&gt;
&lt;pre&gt;      url = url + query + &quot;&amp;amp;orderby=relevance&amp;amp;alt=json-in-script&quot;;&lt;/pre&gt;
&lt;pre&gt;      $.ajax({
        url: url,
        success: function(data) {
          // Grad the *first* video and use that one.
          // If you wanted to list the videos instead this would be the place to
          // iterate through the results. The attribute names are... different, 
          // but you can find thumbnails, descriptions, durations, etc.
          var video_id = data.feed.entry[0].id[&#39;$t&#39;].match(/\w+$/)[0];
          rememberVideo(video_id);
        },
        dataType: &#39;jsonp&#39;
      });
    }
    
    // When the user submits the search form, trigger the JSONP lookup
    $(&quot;#form&quot;).submit(function(event) {
      event.preventDefault();
      findVideo($(&quot;#query&quot;).val());
    });
  &amp;lt;/script&amp;gt;
  &amp;lt;/body&amp;gt;
&amp;lt;/html&amp;gt;&lt;/pre&gt;
&lt;br /&gt;
We also need a server-side piece to persist the placement_id-to-video mapping to the db.&lt;br /&gt;
&lt;br /&gt;
&lt;pre&gt;# Handle POST requests to the endpoint &quot;/set_video&quot;
post &quot;/set_video&quot; do
  if session[&quot;can_set_&quot; + params[&#39;placement_id&#39;]]
    create_placement(params[&#39;placement_id&#39;], params[&#39;video_id&#39;])
    return &#39;{&quot;success&quot;: true}&#39;&lt;/pre&gt;
&lt;pre&gt;  else&lt;/pre&gt;
&lt;pre&gt;    return &#39;{&quot;success&quot;: false}&#39;
  end
end
&lt;/pre&gt;
&lt;br /&gt;
Now the first person to launch the YouTube app after it&#39;s been placed will see the search interface that will let them specify which video to show, and anyone who launches the app after that will get redirected to the selected video.&lt;br /&gt;
&lt;br /&gt;
&lt;a href=&quot;https://github.com/whitmer/youtube_lti&quot;&gt;Sinatra app source code available here&lt;/a&gt;.</content><link rel='replies' type='application/atom+xml' href='http://brianwhitmer.blogspot.com/feeds/8271087810413231689/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/5825798647577501834/8271087810413231689' title='14 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5825798647577501834/posts/default/8271087810413231689'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5825798647577501834/posts/default/8271087810413231689'/><link rel='alternate' type='text/html' href='http://brianwhitmer.blogspot.com/2012/12/building-youtube-lti-app.html' title='Building a YouTube LTI app'/><author><name>Brian Whitmer</name><uri>http://www.blogger.com/profile/00009042638644799674</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjuU9fLl8xHMXUGHbywzQI6WumY7z2W7ZL1iBvxzleBCeBQzIoZ5hnhALV9oSHTQs3iWNRFbTiyADkUEIENiZawHyzWZBxIq3JzvCsTANyrGx-fD1nDmk4ax2BIakeg/s1600/71c13439beedf6c35c53acb0976d97c6'/></author><thr:total>14</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5825798647577501834.post-8916605584906646071</id><published>2010-08-14T21:17:00.000-07:00</published><updated>2010-08-14T21:27:02.831-07:00</updated><title type='text'>uninitialized constant Jammit::Routes</title><content type='html'>This post is mostly just for me (because I know someday this is going to happen again and I&#39;m going to search for this error string), but maybe somebody else will find it useful too.  I just switched ruby environments and I couldn&#39;t run my rails project anymore, it failed with the error &quot;uninitialized constant Jammit::Routes&quot;.&lt;br /&gt;&lt;br /&gt;It routes.rb we&#39;ve included the line &quot;Jammit::Routes.draw(map)&quot; for jammit routes, and that fails for some reason.  Last time it took me forever to figure out why, but eventually I found that (for me, anyway) there was a problem with the closure-compiler-0.3.2 gem.  It checks if you&#39;re on Windows and if so, it checks if you have ruby 1.9 installed or not.  If you do it requires &#39;open3&#39; and if you don&#39;t requires &#39;win32/open3&#39;.  I don&#39;t want to deal with all the mess of getting &#39;win32/open3&#39; into our bundler bundle, and I don&#39;t actually need closure-compiler to work since I can&#39;t deploy from my box anyway, so I just changed the &quot;lib/closure/popen.rb&quot; file in the gem to not require &#39;win32/open3&#39; and everything&#39;s happy again.</content><link rel='replies' type='application/atom+xml' href='http://brianwhitmer.blogspot.com/feeds/8916605584906646071/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/5825798647577501834/8916605584906646071' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5825798647577501834/posts/default/8916605584906646071'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5825798647577501834/posts/default/8916605584906646071'/><link rel='alternate' type='text/html' href='http://brianwhitmer.blogspot.com/2010/08/uninitialized-constant-jammitroutes.html' title='uninitialized constant Jammit::Routes'/><author><name>Brian Whitmer</name><uri>http://www.blogger.com/profile/00009042638644799674</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjuU9fLl8xHMXUGHbywzQI6WumY7z2W7ZL1iBvxzleBCeBQzIoZ5hnhALV9oSHTQs3iWNRFbTiyADkUEIENiZawHyzWZBxIq3JzvCsTANyrGx-fD1nDmk4ax2BIakeg/s1600/71c13439beedf6c35c53acb0976d97c6'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5825798647577501834.post-5433015090000313815</id><published>2010-05-21T11:29:00.000-07:00</published><updated>2010-05-24T10:47:32.891-07:00</updated><title type='text'>The Story of Instructure</title><content type='html'>For the curious at heart, here&#39;s a little color around how I ended up co-founding an educational software company called &lt;a href=&quot;http://www.instructure.com&quot;&gt;Instructure&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;In 2008 I was a grad student at Brigham Young University, just finishing up my Master&#39;s in Human-Computer Interaction.  One of my last classes was a Software Business class taught through the C.S. department with a visiting professor, and the idea of the class was to pretend like you were doing a startup, do all the market research, put together a plan and &quot;pitch&quot; at the end of the semester.  Devlin Daley and myself ended up in a group (we&#39;d taken usability classes together before) and sort of decided not to pretend.  Devlin had always been the entrepreneurial type, and I&#39;ll confess it didn&#39;t take much for me to catch the bug, either.  We didn&#39;t have to look far for a legitimate opportunity.&lt;br /&gt;&lt;br /&gt;BYU used Blackboard as their LMS, and we were so frustrated with the product both as students and as TA&#39;s, that we decided to poke around that market a little more.  We were baffled when we failed to find anybody that we considered pushing the boundaries of education.  Usually in a healthy market you have some one product that&#39;s really driving innovation, but in the LMS market we didn&#39;t feel like anyone was doing that.  Plus, education was something I could really get excited about.  I realized I already had tons of ideas for how online learning could be improved, and I started itching to implement them.&lt;br /&gt;&lt;br /&gt;So we dug deeper, looked at the size of the market, the way contracts were signed, why innovation seemed to have stagnated, etc. and realized there was a legitimate opportunity for someone to step in and disrupt things.&lt;br /&gt;&lt;br /&gt;So we did.  We started jotting down what we thought was busted, how we thought the system should look -- and then we did the very hard thing that I think a lot more startups should do.  Instead of starting to write code, which both of us loved doing, we took all our ideas and built them into a mocked-up version of the product in PowerPoint.  Then we started calling schools.  We would cold-call the CTO, CIO or the head of Instructional Design and tell them we were a new company who wanted to show our thoughts on the future of the LMS and get their feedback as well.&lt;br /&gt;&lt;br /&gt;We had a very favorable response, and met with eighteen universities over the summer of 2008 including UCLA, Berkeley, UNLV, UVU, Westminster and USC.  Everyone loved what we were doing and gave us great feedback.  After each school we&#39;d write down a ton of notes, re-work the PowerPoint and go at it again.  We learned a TON and ended up with a very compelling product.&lt;br /&gt;&lt;br /&gt;After that we found an angel investor who funded us enough to start development and, well, haven&#39;t stopped for a breath since then.  We now have a team of eight, a few contracts under our belt, and a bunch more on the way.  I&#39;m having all sorts of fun integrating with big-name web tools, building new approaches to education problems, and designing simple but effective interactions for teachers and students.  It&#39;s been a blast, and I don&#39;t see that changing in the near future.&lt;br /&gt;&lt;br /&gt;Good times :-).</content><link rel='replies' type='application/atom+xml' href='http://brianwhitmer.blogspot.com/feeds/5433015090000313815/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/5825798647577501834/5433015090000313815' title='5 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5825798647577501834/posts/default/5433015090000313815'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5825798647577501834/posts/default/5433015090000313815'/><link rel='alternate' type='text/html' href='http://brianwhitmer.blogspot.com/2010/05/story-of-instructure.html' title='The Story of Instructure'/><author><name>Brian Whitmer</name><uri>http://www.blogger.com/profile/00009042638644799674</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjuU9fLl8xHMXUGHbywzQI6WumY7z2W7ZL1iBvxzleBCeBQzIoZ5hnhALV9oSHTQs3iWNRFbTiyADkUEIENiZawHyzWZBxIq3JzvCsTANyrGx-fD1nDmk4ax2BIakeg/s1600/71c13439beedf6c35c53acb0976d97c6'/></author><thr:total>5</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5825798647577501834.post-8321228337710425960</id><published>2009-11-19T16:30:00.000-08:00</published><updated>2009-11-19T16:43:08.733-08:00</updated><title type='text'>Google&#39;s Crowdsourcing the Training Set</title><content type='html'>In all the Google news today, one piece that hasn&#39;t gotten much attention is the &lt;a href=&quot;http://bit.ly/1afjkq&quot;&gt;YouTube speech recognition tool&lt;/a&gt;.  There&#39;s a hidden bit of genius in Google&#39;s implementation of this easy captioning tool for YouTube videos (which, by the way, will rock for educational accessibility purposes).  Right now it&#39;s only turned on for a few trusted sites, but Google is looking to beef up its speech recognition classifier even more by gathering auto tracks from all its YouTube videos.  This is actually a much richer dataset than the Goog-411 could provide (or even Google Voice voicemails, really).&lt;br /&gt;&lt;br /&gt;&lt;object width=&quot;425&quot; height=&quot;344&quot;&gt;&lt;param name=&quot;movie&quot; value=&quot;http://www.youtube.com/v/kTvHIDKLFqc&amp;color1=0xb1b1b1&amp;color2=0xcfcfcf&amp;hl=en_US&amp;feature=player_embedded&amp;fs=1&quot;&gt;&lt;/param&gt;&lt;param name=&quot;allowFullScreen&quot; value=&quot;true&quot;&gt;&lt;/param&gt;&lt;param name=&quot;allowScriptAccess&quot; value=&quot;always&quot;&gt;&lt;/param&gt;&lt;embed src=&quot;http://www.youtube.com/v/kTvHIDKLFqc&amp;color1=0xb1b1b1&amp;color2=0xcfcfcf&amp;hl=en_US&amp;feature=player_embedded&amp;fs=1&quot; type=&quot;application/x-shockwave-flash&quot; allowfullscreen=&quot;true&quot; allowScriptAccess=&quot;always&quot; width=&quot;425&quot; height=&quot;344&quot;&gt;&lt;/embed&gt;&lt;/object&gt;&lt;br /&gt;&lt;br /&gt;That&#39;s not the genius part, though.  The real genius is Google&#39;s &quot;automatic caption timing&quot;, where you type in the textual version of your video and YouTube will automatically chunk it up into caption blocks based on what it can decipher from the video.  Adding captions is now a cakewalk, so why wouldn&#39;t you do it?&lt;br /&gt;&lt;br /&gt;Let me say that again, another way.  Google has found a way to motivate people to, of their own free will, send in textual versions of their audio tracks.  An accurate textual representation of the audio a machine learning algorithm is going to try to classify as, well, text.  They just won themselves a huge, presumably fairly accurate, training set for speech-to-text translation, donated by some not-insignificant subset of YouTube&#39;s giant population who will want captions on their videos.&lt;br /&gt;&lt;br /&gt;Google Voice voicemails may actually spit out something legible in the near future.</content><link rel='replies' type='application/atom+xml' href='http://brianwhitmer.blogspot.com/feeds/8321228337710425960/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/5825798647577501834/8321228337710425960' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5825798647577501834/posts/default/8321228337710425960'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5825798647577501834/posts/default/8321228337710425960'/><link rel='alternate' type='text/html' href='http://brianwhitmer.blogspot.com/2009/11/googles-crowdsourcing-training-set.html' title='Google&#39;s Crowdsourcing the Training Set'/><author><name>Brian Whitmer</name><uri>http://www.blogger.com/profile/00009042638644799674</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjuU9fLl8xHMXUGHbywzQI6WumY7z2W7ZL1iBvxzleBCeBQzIoZ5hnhALV9oSHTQs3iWNRFbTiyADkUEIENiZawHyzWZBxIq3JzvCsTANyrGx-fD1nDmk4ax2BIakeg/s1600/71c13439beedf6c35c53acb0976d97c6'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5825798647577501834.post-4903436613506632608</id><published>2009-07-28T11:44:00.000-07:00</published><updated>2009-07-28T12:13:24.417-07:00</updated><title type='text'>Ruby ERB and output_buffer</title><content type='html'>I just ran into this little frustration and thought others might, too.  I have some template files that I need evaluated, and recently I wanted to add in some new functionality similar to the content_for method used in Rails templates, but in my own special way.  I don&#39;t want them just rendered like Rails controllers because I don&#39;t need all that overhead for what are really some pretty small template files.&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;The funny thing about Rails is that if you try to go off the beaten path, everyone will ask why you&#39;re bothering to wander off, and shouldn&#39;t you just stay where it&#39;s comfortable?  Probably 95% of the time they&#39;re right (and 3% of the rest of the time you realize six months later that they were probably right), but there are cases where it&#39;s useful to do something a little different (I think).&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Anyway, most of the posts I saw on using ERB talked about its scary voodoo magic internals that aren&#39;t worth delving into.  So I didn&#39;t.  I had what I thought was a pretty basic problem, as follows:&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;I defined a method &lt;span class=&quot;Apple-style-span&quot;  style=&quot;font-family:&#39;courier new&#39;;&quot;&gt;my_method &lt;/span&gt;that I wanted to call from within the templates which, for starters, I just wanted to assign to an instance variable.  So I wrote:&lt;/div&gt;&lt;div&gt;&lt;span class=&quot;Apple-style-span&quot;   style=&quot;font-family:-webkit-monospace;font-size:100%;&quot;&gt;&lt;span class=&quot;Apple-style-span&quot;  style=&quot; white-space: pre;font-size:13px;&quot;&gt;&lt;span class=&quot;Apple-style-span&quot;   style=&quot;font-family:Georgia;font-size:130%;&quot;&gt;&lt;span class=&quot;Apple-style-span&quot;  style=&quot; white-space: normal;font-size:16px;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;pre&gt;def my_method(name, &amp;amp;block)&lt;br /&gt; res = yield&lt;br /&gt; self.instance_variable_set(&quot;@value_#{name}&quot;.to_sym, res.to_s.strip)&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;def parse!(template)&lt;br /&gt; b = binding&lt;br /&gt; self.body = ERB.new(template, 0, &quot;%&lt;&gt;&quot;).result(b)&lt;br /&gt; self.value_a = @value_a&lt;br /&gt; self.body&lt;br /&gt;end&lt;br /&gt;&lt;/pre&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Looked good to me, pretty simple.  But if I passed in the template:&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;pre&gt;Start Template&lt;br /&gt; &amp;lt;% my_method :a do %&amp;gt;&lt;br /&gt; value for a&lt;br /&gt; &amp;lt;% end %&amp;gt;&lt;br /&gt;End Template&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;div&gt;then I&#39;d get:&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;pre&gt;== value for self.body ==&lt;br /&gt;Start Template&lt;br /&gt;value for a&lt;br /&gt;End Template&lt;br /&gt;&lt;br /&gt;== value for self.value_a ==&lt;br /&gt;Start Template&lt;br /&gt;value for a&lt;br /&gt;&lt;/pre&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;This is what is generally considered bad, and not correct.  I messed around with things for a while and got nowhere.  Then I dug into how Rails was evaluating templates and its &lt;span class=&quot;Apple-style-span&quot;  style=&quot;font-family:&#39;courier new&#39;;&quot;&gt;content_for&lt;/span&gt; method.  ActionView::Base has an accessor called &lt;span class=&quot;Apple-style-span&quot;  style=&quot;font-family:&#39;courier new&#39;;&quot;&gt;output_buffer&lt;/span&gt; being used by CaptureHelper (where &lt;span class=&quot;Apple-style-span&quot;  style=&quot;font-family:&#39;courier new&#39;;&quot;&gt;content_for &lt;/span&gt;is defined) in a way I couldn&#39;t understand at first.  &lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;When you call &lt;span class=&quot;Apple-style-span&quot;  style=&quot;font-family:&#39;courier new&#39;;&quot;&gt;content_for&lt;/span&gt;, part of its process is to store the value of &lt;span class=&quot;Apple-style-span&quot;  style=&quot;font-family:&#39;courier new&#39;;&quot;&gt;output_buffer &lt;/span&gt;as &lt;span class=&quot;Apple-style-span&quot;  style=&quot;font-family:&#39;courier new&#39;;&quot;&gt;old_output_buffer&lt;/span&gt;, then call its &lt;span class=&quot;Apple-style-span&quot;  style=&quot;font-family:&#39;courier new&#39;;&quot;&gt;yield &lt;/span&gt;and finally re-set &lt;span class=&quot;Apple-style-span&quot;  style=&quot;font-family:&#39;courier new&#39;;&quot;&gt;output_buffer &lt;/span&gt;to its original value.  Weird, but at least it was a start.  So I blindly added &lt;span class=&quot;Apple-style-span&quot;  style=&quot;font-family:&#39;courier new&#39;;&quot;&gt;attr_accessor :output_buffer&lt;/span&gt; to my class and hoped for the best.  &lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;No love.  I dug around a little more and found the rest of the trick.  One of the arguments for ERB.new is the name of the local variable to use to store the string buffer used in the ERB evaluation.  I&#39;d never used that before because I didn&#39;t care, but if I set that value to &quot;@output_buffer&quot; then everything works magically.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;So the new code is:&lt;/div&gt;&lt;div&gt;&lt;pre&gt;&lt;br /&gt;&lt;/pre&gt;&lt;pre&gt;def my_method(name, &amp;amp;block)&lt;br /&gt; old_buffer, @output_buffer = @output_buffer, &#39;&#39;&lt;br /&gt; res = yield&lt;br /&gt; self.instance_variable_set(&quot;@value_#{name}&quot;.to_sym, res.to_s.strip)&lt;br /&gt; @output_buffer = old_buffer&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;def parse!(template)&lt;br /&gt; b = binding&lt;br /&gt; self.body = ERB.new(template, 0, &quot;%&lt;&gt;&quot;, &quot;@output_buffer&quot;).result(b)&lt;br /&gt; self.value_a = @value_a&lt;br /&gt; self.body&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div&gt;And suddenly everything works like a champ.  Happy sigh.&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://brianwhitmer.blogspot.com/feeds/4903436613506632608/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/5825798647577501834/4903436613506632608' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5825798647577501834/posts/default/4903436613506632608'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5825798647577501834/posts/default/4903436613506632608'/><link rel='alternate' type='text/html' href='http://brianwhitmer.blogspot.com/2009/07/ruby-erb-and-outputbuffer.html' title='Ruby ERB and output_buffer'/><author><name>Brian Whitmer</name><uri>http://www.blogger.com/profile/00009042638644799674</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjuU9fLl8xHMXUGHbywzQI6WumY7z2W7ZL1iBvxzleBCeBQzIoZ5hnhALV9oSHTQs3iWNRFbTiyADkUEIENiZawHyzWZBxIq3JzvCsTANyrGx-fD1nDmk4ax2BIakeg/s1600/71c13439beedf6c35c53acb0976d97c6'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5825798647577501834.post-8598699294844105291</id><published>2009-06-04T14:36:00.000-07:00</published><updated>2009-06-04T14:57:52.822-07:00</updated><title type='text'>Google Wave Limitations</title><content type='html'>&lt;a href=&quot;http://wave.google.com/&quot;&gt;&lt;img style=&quot;margin: 0px auto; display: block; text-align: center; cursor: pointer; width: 200px; height: 200px;&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi2QE76zpH7ljBCl_l99w5pRtbIgaqb4yuJ0nFFEWBfIioB5tFx5HI1tUMXhZ-N5ucaIcNWov9o8leIJkv4DTgjb-hdmygajNdv9Mt5wIM7dTCbE8rsG21IMFC-Ifbm84WtsEXE1PIc488/s200/wavelogo.png&quot; alt=&quot;&quot; id=&quot;BLOGGER_PHOTO_ID_5343592199580305778&quot; border=&quot;0&quot; /&gt;&lt;/a&gt;Don&#39;t get me wrong.  I dig(g?) the Wave.  I think it&#39;s got some great potential to really disrupt things in a much-needed way.  But I&#39;m still skeptical.  I&#39;ve tried to figure out what I can about Wave given that I don&#39;t even have a sandbox account yet, and now I want to share my thoughts.  So here&#39;s what I think Wave doesn&#39;t do:&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;font-weight: bold;&quot;&gt;Wave Will Replace Blogs&lt;/span&gt;&lt;br /&gt;&lt;img style=&quot;margin: 0pt 10px 3px 0pt; float: left; cursor: pointer; width: 122px; height: 122px;&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj_08QzFAIp0IjKopGuKhZ0IsFpCX_Igg0nE0zUlcieUpeq25gMsarJ5Q6ZhhnAhJ7wiziyum-nuS_HVODPUaMTjBAlNP2yT0huOLNIZ4TObP_Lw7MnqrFdeWgvr8ODF8qsUFrLkPsbn4s/s200/icon_blogger.gif&quot; alt=&quot;&quot; id=&quot;BLOGGER_PHOTO_ID_5343590159802233330&quot; border=&quot;0&quot; /&gt;If you&#39;re interested in Wave, you&#39;ve probably &lt;a href=&quot;http://wave.google.com/&quot;&gt;already seen the Wave video&lt;/a&gt;.  One of the examples in the video shows embedding waves as blog posts, so you get real-time comments from visitors.  The thing they gloss over in the demo is that, as Wave stands right now, anyone who joins that wave has permissions to edit anything -- the original blog post, or anyone else&#39;s comments.  It&#39;s like making your blog a public wiki instead of a set of authored posts.  In the extreme case you&#39;ve got almighty blog spam potential, but even in the realistic case there&#39;s potential for editing other people&#39;s comments.&lt;br /&gt;&lt;br /&gt;You could technically write a &quot;read-only-enforcy&quot; robot that keeps reverting segments of the wave if anyone else edits them, but, well, that smells funny.  I expect that someday Wave will add &lt;a href=&quot;http://code.google.com/apis/wave/guide.html&quot;&gt;wavelets&lt;/a&gt; with limited editability, but that doesn&#39;t solve everything.&lt;br /&gt;&lt;br /&gt;One issue that will be addressed as this all evolves is how much are users expected to monitor the development of waves they&#39;re subscribed to?  Is it as important as responding to a new email?  How easy is it to recognize and dismiss minor edits?  If I&#39;m still part of a wave is it assumed I endorse it?  There&#39;s some haziness that the system will have to define for itself as it develops.&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;font-weight: bold;&quot;&gt;Wave Will Replace Facebook&lt;/span&gt;&lt;br /&gt;&lt;img style=&quot;margin: 0pt 10px 3px 0pt; float: left; cursor: pointer; width: 120px; height: 120px;&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhxilUQw_3I3FJ2iva5Iquasu6Ca5Hi4FYA7tJQdMdHwwP6Wh0T7mg_Cu_g6kLx0HHG4l8veY1pSu9da4lZ133NecDJrfFEvYplA3w2JyEZYyMCl1ap-1Yt8f4JlWnbCU0WUB4SN_YBFsU/s200/facebook-icon.png&quot; alt=&quot;&quot; id=&quot;BLOGGER_PHOTO_ID_5343591254012999842&quot; border=&quot;0&quot; /&gt;Or Twitter, for that matter.  This isn&#39;t going to happen, because of one simple but significant feature in Wave: the &quot;unread&quot; feature.  Facebook&#39;s stream and Twitter&#39;s feeds are very much about real-time.  You don&#39;t comment on old tweets, and Facebook doesn&#39;t really make it easy to &quot;catch-up&quot; on old items.  There&#39;s no indication of what you might have missed between visits, and that changes the medium.  Things like Email, Feed Readers -- or Wave, for that matter, make sure to highlight any items that have seen activity.  I think that implies a sense of importance to each message, and for me anyway, I feel weird clicking any kind of &quot;clear all&quot; button.  What did I just dismiss?  Whose question did I just unintentionally ignore?  In Wave&#39;s case, was the latest edit a change in spelling or an important question that needs addressing?  I don&#39;t feel that urgency at all with Twitter of Facebook.  Interesting how taking away that &quot;unread&quot; feature completely changes the nature of the service.&lt;br /&gt;&lt;br /&gt;Anyway, I think that because of the way Wave is organized and its coming from an email background, it won&#39;t do well replacing services that are more real-time, if only because they actually mark all those changes and encourage you to review them.&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;font-weight: bold;&quot;&gt;Wave Will Replace the LMS&lt;/span&gt;&lt;br /&gt;&lt;img style=&quot;margin: 0pt 10px 3px 0pt; float: left; cursor: pointer; width: 80px; height: 100px;&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiSDa9E2eCWcdydsQYqoFoVijP1sN2Zgbk5kSIyibR2IZhmSZ3RKpDStDdXGqIsQLGHEakT3n0mX1DdPE-YLa3X-A1Yx2TL2ZvNSntbY8CTMvCB0vEgK0e6gMCIuZu7TfpQ2uOmy0CU7v4/s200/logo.png&quot; alt=&quot;&quot; id=&quot;BLOGGER_PHOTO_ID_5343590663422243426&quot; border=&quot;0&quot; /&gt;I won&#39;t talk much about this, because I think it&#39;s been hit already.  &lt;a href=&quot;http://mfeldstein.com/does-google-wave-mean-the-end-of-the-lms/&quot;&gt;Michael Feldstein made some good points&lt;/a&gt; (especially the part about how it&#39;s silly to put much stock in the death-tolls of the LMS from people who aren&#39;t even using them anymore).  &lt;a href=&quot;http://www.dr-chuck.com/csev-blog/000630.html&quot;&gt;Dr. Chuck adds some other points&lt;/a&gt; about authorization and the inherent de-normalization of waves.&lt;br /&gt;&lt;br /&gt;For my part I&#39;ll just say I think you &lt;span style=&quot;font-style: italic;&quot;&gt;could&lt;/span&gt; write an LMS on top of Wave, but there&#39;d be some serious robottage going on behind the scenes to make everything play nice, and I think the decentralized nature of Waves make it too disjointed on its own.  That said, I think &lt;a href=&quot;http://www.instructure.com/&quot;&gt;a future-looking LMS&lt;/a&gt; could seriously benefit from harnessing waves for things like group projects, peer reviews, or maybe even assessment.  That&#39;s what I&#39;ll be working on -- if Google ever gives me my sandbox account, that is.</content><link rel='replies' type='application/atom+xml' href='http://brianwhitmer.blogspot.com/feeds/8598699294844105291/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/5825798647577501834/8598699294844105291' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5825798647577501834/posts/default/8598699294844105291'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5825798647577501834/posts/default/8598699294844105291'/><link rel='alternate' type='text/html' href='http://brianwhitmer.blogspot.com/2009/06/google-wave-limitations.html' title='Google Wave Limitations'/><author><name>Brian Whitmer</name><uri>http://www.blogger.com/profile/00009042638644799674</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjuU9fLl8xHMXUGHbywzQI6WumY7z2W7ZL1iBvxzleBCeBQzIoZ5hnhALV9oSHTQs3iWNRFbTiyADkUEIENiZawHyzWZBxIq3JzvCsTANyrGx-fD1nDmk4ax2BIakeg/s1600/71c13439beedf6c35c53acb0976d97c6'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi2QE76zpH7ljBCl_l99w5pRtbIgaqb4yuJ0nFFEWBfIioB5tFx5HI1tUMXhZ-N5ucaIcNWov9o8leIJkv4DTgjb-hdmygajNdv9Mt5wIM7dTCbE8rsG21IMFC-Ifbm84WtsEXE1PIc488/s72-c/wavelogo.png" height="72" width="72"/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5825798647577501834.post-2615585089242804450</id><published>2009-05-12T15:09:00.000-07:00</published><updated>2009-05-12T15:26:26.525-07:00</updated><title type='text'>jQuery UI :tabbable -- what the?</title><content type='html'>This week I&#39;ve been working on adding some basic accessibility tweaks to our site.  Instead of starting from scratch, I&#39;ve been peeking at the &lt;a href=&quot;http://jqueryui.com/&quot;&gt;jQuery UI&lt;/a&gt; code, because I know those guys have been working with the &lt;a href=&quot;http://www.w3.org/WAI/intro/aria.php&quot;&gt;ARIA &lt;/a&gt;blokes to &quot;accessibleize&quot; jQuery UI.  I think that&#39;s greate for everybody, by the way, for specifically this reason.  Instead of having just the specs alone, I can study the standards and also look at how some real-world coders have implemented those standards.&lt;br /&gt;&lt;br /&gt;Anyway, the trick I wanted to duplicate was the dialog&#39;s auto-focus trick.  When a jQuery UI dialog pops up it automatically shifts tab focus to the first element in the dialog that can receive focus, which is nice for accessibility because then even a non-visual user&#39;s attention is brought to the dialog.  I could have thrown together a quick selector that checks for the first anchor, input element or whatever, but like I said, I wanted to see what they&#39;d done.&lt;br /&gt;&lt;br /&gt;I snuck into the source, and noticed they&#39;re using a selector filter called &quot;:tabbable&quot; to select the elements that, I assumed, was capable of being tabbed to.  A quick Google search and I found nothing -- hence this post.&lt;br /&gt;&lt;br /&gt;Apparently jQuery UI is adding two very useful (for accessibility purposes, anyway) selector filters to the jQuery selector engine, &quot;:focusable&quot; and &quot;:tabbable&quot;.  Here&#39;s the code:&lt;br /&gt;&lt;br /&gt;&lt;pre style=&quot;overflow: auto;&quot;&gt;//Additional selectors&lt;br /&gt;$.extend($.expr[&#39;:&#39;], {&lt;br /&gt;  data: function(elem, i, match) {&lt;br /&gt;    return !!$.data(elem, match[3]);&lt;br /&gt;  },&lt;br /&gt;&lt;br /&gt;  focusable: function(element) {&lt;br /&gt;    var nodeName = element.nodeName.toLowerCase(),&lt;br /&gt;      tabIndex = $.attr(element, &#39;tabindex&#39;);&lt;br /&gt;    return (/input|select|textarea|button|object/.test(nodeName)&lt;br /&gt;      ? !element.disabled&lt;br /&gt;      : &#39;a&#39; == nodeName || &#39;area&#39; == nodeName&lt;br /&gt;        ? element.href || !isNaN(tabIndex)&lt;br /&gt;        : !isNaN(tabIndex))&lt;br /&gt;      // the element and all of its ancestors must be visible&lt;br /&gt;      // the browser may report that the area is hidden&lt;br /&gt;      &amp;amp;&amp;amp; !$(element)[&#39;area&#39; == nodeName ? &#39;parents&#39; : &#39;closest&#39;](&#39;:hidden&#39;).length;&lt;br /&gt;  },&lt;br /&gt;&lt;br /&gt;  tabbable: function(element) {&lt;br /&gt;    var tabIndex = $.attr(element, &#39;tabindex&#39;);&lt;br /&gt;    return (isNaN(tabIndex) || tabIndex &gt;= 0) &amp;amp;&amp;amp; $(element).is(&#39;:focusable&#39;);&lt;br /&gt;  }&lt;br /&gt;});&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;:focusable selects the list of elements that are inherently focusable, i.e. anchor tags, input elements, form elements that aren&#39;t disabled, or elements that have a defined &quot;tabindex&quot; attribute.  :tabbable is a subset of this list, only including those :focusable elements that have tabindex &gt;= 0.  You can set an element to have tabindex=&quot;-1&quot; and it will be focusable, but won&#39;t show up anywhere in the page&#39;s tab order, hence it&#39;s not tabbable.&lt;br /&gt;&lt;br /&gt;Anyway, cool stuff.  If you use this you&#39;ll probably want to check &quot;:visible&quot; as well.</content><link rel='replies' type='application/atom+xml' href='http://brianwhitmer.blogspot.com/feeds/2615585089242804450/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/5825798647577501834/2615585089242804450' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5825798647577501834/posts/default/2615585089242804450'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5825798647577501834/posts/default/2615585089242804450'/><link rel='alternate' type='text/html' href='http://brianwhitmer.blogspot.com/2009/05/jquery-ui-tabbable-what.html' title='jQuery UI :tabbable -- what the?'/><author><name>Brian Whitmer</name><uri>http://www.blogger.com/profile/00009042638644799674</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjuU9fLl8xHMXUGHbywzQI6WumY7z2W7ZL1iBvxzleBCeBQzIoZ5hnhALV9oSHTQs3iWNRFbTiyADkUEIENiZawHyzWZBxIq3JzvCsTANyrGx-fD1nDmk4ax2BIakeg/s1600/71c13439beedf6c35c53acb0976d97c6'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5825798647577501834.post-2306644285274773924</id><published>2009-01-27T17:00:00.001-08:00</published><updated>2009-01-27T17:37:38.835-08:00</updated><title type='text'>Are rounded corners THAT hard to implement?</title><content type='html'>So Microsoft has just announced their first (and probably only) &lt;a href=&quot;http://blog.wired.com/business/2009/01/more-details-ab.html&quot;&gt;release candidate of Internet Explorer 8&lt;/a&gt;.  For those in the not-know, release candidates fit somewhere between betas and final releases, most often leaning closer to the final release.  It&#39;s a last chance to make sure there&#39;s nothing seriously wrong before actually releasing the product.&lt;br /&gt;&lt;br /&gt;IE8&#39;s supposed to add a bunch of new features, while not changing the actual interface much at all.  If you look at the list of new features for IE8, it&#39;s pretty much a smattering of a bunch of little cool things -- no real direction, just a bunch of little cool things.  They have web snippets, some new accessibility events, a safe JSON parser, etc. etc.  I&#39;m fine with all that, I&#39;d actually really love for every browser to get a JSON parser and improved accessibility.  My beef is what they don&#39;t have.&lt;br /&gt;&lt;br /&gt;Rounded corners.&lt;br /&gt;&lt;br /&gt;Most other major browsers (Firefox, Safari, Chrome) have support for those friendly little curves on the edges of your layout boxes.  Microsoft, however, has said they&#39;re basically not expanding their CSS support at all, just sticking with the CSS 2.1 that they already complies with.  I guess they did say it&#39;s &quot;high on the wish list&quot; and to expect it in the next version, but my complaint is, how hard is it really to implement rounded corners?  I mean, they could seriously have had one intern working on it for a few months and he probably could have managed rounded corners in CSS.&lt;br /&gt;&lt;br /&gt;What&#39;s the big deal, you may ask.  Who cares about rounded corners anyway?  Well.  If you were to ask a web designer, what&#39;s the most-awkwardly-hacked-on layout feature in today&#39;s web pages, they&#39;d almost definitely say it&#39;s rounded corners.  There are so many &quot;workarounds&quot; for the rounded corner problem it&#39;s not even funny.  Most of them use tables and CSS -- insert cringe here -- to get around the problem, but that&#39;s like using toothpaste to fill the holes in your walls.  It technically works, but it&#39;s really not the right tool for the job.  Not to mention how much it can bork with accessibility and semantic meaning.&lt;br /&gt;&lt;br /&gt;Anyway, everyone knows that anywhere from 30-90% of a web site&#39;s users are on IE, so until Microsoft implements rounded corners we&#39;re stuck in nastyland.  I&#39;m a little frustrated with Microsoft over this one, actually.  They had the opportunity to save thousands of web sites from code nastification currently happening in the name of aesthetics, and they just didn&#39;t bother.  I seriously doubt it would have taken THAT much effort, and even an unfinished implementation (say, we only do up to 10 pixel rounding, for example) would have been good enough for me.  Honestly, you shouldn&#39;t have to make a table or write twenty lines of CSS (or both) just to get some non-square navigation tabs at the top of your page.</content><link rel='replies' type='application/atom+xml' href='http://brianwhitmer.blogspot.com/feeds/2306644285274773924/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/5825798647577501834/2306644285274773924' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5825798647577501834/posts/default/2306644285274773924'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5825798647577501834/posts/default/2306644285274773924'/><link rel='alternate' type='text/html' href='http://brianwhitmer.blogspot.com/2009/01/are-rounded-corners-that-hard-to.html' title='Are rounded corners THAT hard to implement?'/><author><name>Brian Whitmer</name><uri>http://www.blogger.com/profile/00009042638644799674</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjuU9fLl8xHMXUGHbywzQI6WumY7z2W7ZL1iBvxzleBCeBQzIoZ5hnhALV9oSHTQs3iWNRFbTiyADkUEIENiZawHyzWZBxIq3JzvCsTANyrGx-fD1nDmk4ax2BIakeg/s1600/71c13439beedf6c35c53acb0976d97c6'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5825798647577501834.post-3213484662060925877</id><published>2009-01-02T10:01:00.000-08:00</published><updated>2009-01-02T11:48:37.686-08:00</updated><title type='text'>jQuery 1.3 delegation</title><content type='html'>This post will most likely be useful only to me, but I&#39;m extremely excited about the new version of jQuery that&#39;s coming out, and I wanted to put down some of its new features before I forget, and to make sure I understand them completely.  If you aren&#39;t familiar with javascript event delegation, this probably won&#39;t mean a lot to you (&lt;a href=&quot;http://www.robertnyman.com/2008/05/04/event-delegation-with-javascript/&quot;&gt;here&#39;s a quick tutorial&lt;/a&gt;).&lt;br /&gt;&lt;br /&gt;I went poking around in &lt;a href=&quot;http://dev.jquery.com/changeset/5990&quot;&gt;the jQuery &lt;/a&gt;&lt;a href=&quot;http://dev.jquery.com/changeset/5987&quot;&gt;revisions &lt;/a&gt;because I haven&#39;t found hardly any details on what exactly is changing with the new version (other than speedups and such, but those don&#39;t excited me nearly as much as other people -- probably because I tend to write my code for the speed of &quot;right now&quot; instead of for a future version, so if something is changing from slow to fast, I&#39;m probably not using it anyway).  There&#39;s some good stuff going into this new version.&lt;br /&gt;&lt;br /&gt;And more than just &lt;a href=&quot;http://github.com/jeresig/sizzle/tree/master&quot;&gt;Sizzle&lt;/a&gt;, which I&#39;m not going to spend any time on.&lt;br /&gt;&lt;br /&gt;So I&#39;ve been using the &lt;a href=&quot;http://code.google.com/p/reglib/&quot;&gt;jQuery event delegation plugin&lt;/a&gt; on my most recent project, and it works nicely, but there are a few problems.  First is that your selectors have to match on the target of the event, not an ancestor.  So if I have a list of &quot;div.child&quot;s inside of a &quot;div.parent&quot;, I call:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;$(&quot;div.parent&quot;).delegate(&#39;click&#39;, &#39;div.child&#39;, function(e) { });&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;to watch for clicks on any of the div.child&#39;s.  The problem here is that if I have an image tag inside of the div.child, and the user clicks on the image instead of the whitespace in the div, then the delegation plugin won&#39;t trigger the event.  I actually did a quick rewrite of the plugin on my own to check against parents as well, changing:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;return this.bind(type, function(event) {&lt;br /&gt;   var target = $(event.target);&lt;br /&gt;   if (target.is(delegate)) {&lt;br /&gt;       return handler.apply(target, arguments);&lt;br /&gt;   }&lt;br /&gt;});&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;to:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;return this.bind(type, function(event) {&lt;br /&gt;   var target = $(event.target);&lt;br /&gt;   if (target.is(delegate)) {&lt;br /&gt;       return handler.apply(target, arguments);&lt;br /&gt;   }&lt;br /&gt;   var $container = $(this);&lt;br /&gt;   var $parent_target = null;&lt;br /&gt;   target.parents().each(function() {&lt;br /&gt;       if($(this).is(delegate)) {&lt;br /&gt;           $parent_target = $(this);&lt;br /&gt;           return false;&lt;br /&gt;       }&lt;br /&gt;       if($(this)[0] == $container[0]) {&lt;br /&gt;           return false;&lt;br /&gt;       }&lt;br /&gt;   });&lt;br /&gt;   if($parent_target) {&lt;br /&gt;       return handler.apply($parent_target, arguments);&lt;br /&gt;   }&lt;br /&gt;});&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Problem solved -- for me, anyway.  But the better news is that jQuery&#39;s new delegation mechanism takes care of this for you!  &lt;a href=&quot;http://dev.jquery.com/changeset/5987&quot;&gt;It&#39;s got a .closest method&lt;/a&gt; that matches on the element or its closest matching ancestor.  Pretty vital, if you ask me, for any actually usable delegation system.  In that case you could replace my code with:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;return this.bind(type, function(event) {&lt;br /&gt;   var closest = $(event.target).closest(delegate);&lt;br /&gt;   if (closest.length &gt; 0) {&lt;br /&gt;       return handler.apply(closest, arguments);&lt;br /&gt;   }&lt;br /&gt;});&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;So that&#39;s cool, and it contented me for a while, but then I ran into another problem: bubbling.  Normal user events bubble just fine, but jQuery also lets you trigger artificial events using .click, .submit, or .trigger(type) methods -- these don&#39;t bubble.  At least, they didn&#39;t used to.  &lt;a href=&quot;http://www.ejohn.org/&quot;&gt;Resig &lt;/a&gt;&lt;a href=&quot;http://dev.jquery.com/changeset/5988&quot;&gt;fixed that as well&lt;/a&gt; in the new version, for which I am extremely grateful.  Hours of conniving workarounds were wasted, but I can handle that.&lt;br /&gt;&lt;br /&gt;As it turns out, I may still be using the delegation plugin, as enhanced by the new changes in jQuery 1.3.  I wasn&#39;t entirely sure how&lt;a href=&quot;http://dev.jquery.com/changeset/5990&quot;&gt; jQuery&#39;s new .live and .die functions&lt;/a&gt; behaved, so I didn&#39;t know how applicable they&#39;d be, but &lt;a href=&quot;http://ejohn.org/&quot;&gt;John Resig&lt;/a&gt; himself left a nice comment on &lt;a href=&quot;http://ajaxian.com/archives/jquery-13-beta-sizzling-and-feature-testing&quot;&gt;Ajaxian&#39;s post&lt;/a&gt;:&lt;br /&gt;&lt;br /&gt;&lt;blockquote&gt;We’re not using the name ‘delegate’ because it isn’t normal event delegation (not to mention that there are already a number of delegate plugins using that name). Typically when someone wants to do full delegation they also want to specify the root element - e.g.: $(”#someroot”).delegate(”div”, “click”, someFn); We wanted to provide something that was much simpler than normal delegation but still leave room for people to write their own full delegation code/plugins.&lt;/blockquote&gt;&lt;br /&gt;What he means about it not being &quot;normal event delegation&quot; is that jQuery&#39;s .live and .die methods don&#39;t let you specify who you&#39;re delegating to.  It&#39;s always a the document (root) level.  So if I call:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;$(&quot;div.child&quot;).live(&#39;click&#39;, function(e) { });&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;(which, by the way, would be the appropriate way to listen for clicks on any div.child&#39;s in the document) then it always bubbles all the way up to the document.  What if you just want to catch clicks on div.child&#39;s that are inside a &quot;div.parent&quot;?  Not possible with .live and .die.  That&#39;s ok, though, because I&#39;m willing to bet most people won&#39;t care, and if nothing else this addition offers a great starting point for those new to event delegation.  This is a great piece of functionality, and the fact that it handles both inner-element events and triggered-event bubbling makes me a very happy programmer.&lt;br /&gt;&lt;br /&gt;As a side note, you can kill all delegated functions of a given type with:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;$(&quot;div.child&quot;).die(&#39;click&#39;);&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;or just a specific function with:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;$(&quot;.div.child&quot;).die(&#39;click&#39;, function_to_stop_calling);&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Resig is calling this a &lt;a href=&quot;http://brandonaaron.net/docs/livequery/&quot;&gt;livequery&lt;/a&gt;/&lt;a href=&quot;http://stilbuero.de/jquery/delegate/&quot;&gt;event delegation&lt;/a&gt; hybrid, although it&#39;s really more delegation than anything.  I think the reasoning there is that more people know of and use livequery than the delegation plugins, so it&#39;s more familiar, and in fact the syntax is more like livequery than delegation -- although honestly there&#39;s not that much difference between the two.  Either way, it&#39;s a great addition to a great library, and a useful inclusion of a great new feature in web programming.</content><link rel='replies' type='application/atom+xml' href='http://brianwhitmer.blogspot.com/feeds/3213484662060925877/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/5825798647577501834/3213484662060925877' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5825798647577501834/posts/default/3213484662060925877'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5825798647577501834/posts/default/3213484662060925877'/><link rel='alternate' type='text/html' href='http://brianwhitmer.blogspot.com/2009/01/jquery-13-delegation.html' title='jQuery 1.3 delegation'/><author><name>Brian Whitmer</name><uri>http://www.blogger.com/profile/00009042638644799674</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjuU9fLl8xHMXUGHbywzQI6WumY7z2W7ZL1iBvxzleBCeBQzIoZ5hnhALV9oSHTQs3iWNRFbTiyADkUEIENiZawHyzWZBxIq3JzvCsTANyrGx-fD1nDmk4ax2BIakeg/s1600/71c13439beedf6c35c53acb0976d97c6'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5825798647577501834.post-6764064335106347834</id><published>2008-12-15T10:26:00.000-08:00</published><updated>2008-12-15T10:55:48.084-08:00</updated><title type='text'>jQuery events: setting a property that has only a getter</title><content type='html'>I ran into a new problem in jQuery the other day, and I couldn&#39;t find a good solution for it.  Hence, a new post in the hopes of helping out the next individual.&lt;br /&gt;&lt;br /&gt;In case you didn&#39;t know, I&#39;m working on a modern learning management system for Instructure.  Good stuff, but I can&#39;t spill too many beans yet.  Sorry. &lt;br /&gt;&lt;br /&gt;Anyway, as part of that I need a good javascript WYSIWYG editor (love to do just &lt;a href=&quot;http://en.wikipedia.org/wiki/WYSIWYM&quot;&gt;WYSIWYM&lt;/a&gt;, but I don&#39;t think it&#39;s general enough for all faculty) and I&#39;ve settled on &lt;a href=&quot;http://tinymce.moxiecode.com/&quot;&gt;TinyMCE &lt;/a&gt;for the time being -- mostly because they&#39;ve actually got some accessibility functionality baked in.  I&#39;ve written a jQuery wrapper around it for all the features I need to get at (because let&#39;s face it, TinyMCE&#39;s API is NOT intuitive, and I&#39;d prefer to touch it as little as possible), but I also need to capture key events so I can treat the &quot;escape&quot; key like a cancel click.  Sadly, TinyMCE uses iframes and eats up javascript events before you can get to them.&lt;br /&gt;&lt;br /&gt;No problem, TinyMCE&#39;s API lets you catch key and mouse events and do what you will with them.  To make things simple I&#39;m listening for key events on all form text elements, so I just want to take TinyMCE&#39;s key event and pretend like it got called on the textarea that TinyMCE replaced.  jQuery has a .trigger method that lets you call events as if they happened on the selection, so I just pass the event TinyMCE gives me into jQuery.&lt;br /&gt;&lt;br /&gt;Bzzzt!  Firefox throws an error, &quot;setting a property that has only a getter&quot;.  Blast.  I futz around with it for a bit, can&#39;t solve it, so I finally muster the courage to dive into jQuery code and figure out what the problem is.  The error&#39;s being thrown because the jQuery trigger method asks you to specify the event type (&quot;keydown&quot;, &quot;mouseup&quot;, etc.) and then sets the event.type property to make sure it&#39;s the right type.  Problem is, javascript native events don&#39;t let you SET the event type, only get it.  Hence the error.&lt;br /&gt;&lt;br /&gt;Double-blast.  Okay, so now what?  I dig a little deeper (like I said before, no good documentation that I could find on this) to see what jQuery&#39;s doing with events.  When jQuery catches an event, it wraps it in a jQuery event object to make things happy (and you can set the event.type property on this wrapped object to your heart&#39;s content).  So if I just wrap the event, problem solved.  I realized I should probably do this anyway, because while the only error I hit was setting an unsettable property, there&#39;s probably other kinks I don&#39;t want to deal with.&lt;br /&gt;&lt;br /&gt;So how do you wrap events?  Turns out it&#39;s pretty easy.  Instead of:&lt;br /&gt;&lt;br /&gt;&lt;blockquote&gt;if(e.type == &#39;keydown&#39;) {&lt;br /&gt;    $(&quot;selection&quot;).trigger(e.type, e);&lt;br /&gt;}&lt;br /&gt;&lt;/blockquote&gt;&lt;br /&gt;You use:&lt;br /&gt;&lt;br /&gt;&lt;blockquote&gt;if(e.type == &#39;keydown&#39;) {&lt;br /&gt;     $(&quot;selection&quot;).trigger(e.type, $.event.fix(e));&lt;br /&gt;}&lt;br /&gt;&lt;/blockquote&gt;&lt;br /&gt;That&#39;s if you have &quot;$&quot; as an alias for jQuery.  Otherwise you&#39;d call jQuery.event.fix(e) to get the wrapped object.&lt;br /&gt;&lt;br /&gt;Also, I&#39;m actually using triggerHandler instead of trigger.  Trigger just fires the event, while triggerHandler triggers everything except the default behavior (that way I&#39;m not initiating a keydown on the textarea and inadvertently adding text).&lt;br /&gt;&lt;br /&gt;Problem solved!</content><link rel='replies' type='application/atom+xml' href='http://brianwhitmer.blogspot.com/feeds/6764064335106347834/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/5825798647577501834/6764064335106347834' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5825798647577501834/posts/default/6764064335106347834'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5825798647577501834/posts/default/6764064335106347834'/><link rel='alternate' type='text/html' href='http://brianwhitmer.blogspot.com/2008/12/jquery-events-setting-property-that-has.html' title='jQuery events: setting a property that has only a getter'/><author><name>Brian Whitmer</name><uri>http://www.blogger.com/profile/00009042638644799674</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjuU9fLl8xHMXUGHbywzQI6WumY7z2W7ZL1iBvxzleBCeBQzIoZ5hnhALV9oSHTQs3iWNRFbTiyADkUEIENiZawHyzWZBxIq3JzvCsTANyrGx-fD1nDmk4ax2BIakeg/s1600/71c13439beedf6c35c53acb0976d97c6'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5825798647577501834.post-7537670307009785056</id><published>2008-11-14T18:48:00.000-08:00</published><updated>2008-11-14T20:25:11.526-08:00</updated><title type='text'>Universities and OpenID</title><content type='html'>Today&#39;s &lt;a href=&quot;http://www.edtechpost.ca/wordpress/2008/11/14/best-password-recovery/&quot;&gt;post by Scott Leslie&lt;/a&gt; got me thinking about universities and their identity systems.  The issue Scott brought up was getting all these web services to play nice with the university&#39;s system.  Teachers are getting tired of the lack of functionality that&#39;s available from their LMS (I have some &lt;a href=&quot;http://brianwhitmer.blogspot.com/2008/08/mashable-one-stop-shop.html&quot;&gt;thoughts on that, too&lt;/a&gt;), so they&#39;re turning to services elsewhere that provide better features, better interaction and more flexibility.  I can&#39;t say as I blame them.  I heard that at a recent web usability conference the presenter referred to Blackboard as, essentially, the &lt;span style=&quot;font-style: italic;&quot;&gt;anti-interface&lt;/span&gt;.  So sure, use the tools that are actually useful, and education actually benefits.&lt;br /&gt;&lt;br /&gt;That&#39;s great and all, but it leaves the students in a bit of a lurch.  That smattering of web services aren&#39;t integrated.  Like at all.  Suddenly a student needs accounts with Blogger, WordPress, the local wiki, Google Docs, etc. etc. etc.  And then they have to link up with everyone else to make things work.  Day one of class turns into a mass sign-up, sync-up session.  That&#39;s not a great place to be.  Scott put it aptly when he said “those nasty web 2.0 tools won’t single sign-on to my campus login system, so what are we to do?”&lt;br /&gt;&lt;br /&gt;Well!  OpenID is a pretty cool idea that just might help out.  I&#39;m not going to go into specifics, because I&#39;d probably embarass myself if I did, but the basic jist of OpenID is having a common means of authenticating users across multiple sites.  In other words, accomplishing a single sign-on, single identity for the whole web.  That way when you go to OpenID-enabled site X, instead of having to create a new username and password, you say &quot;dude, I totally already have an account at this OpenID site.  I&#39;ll just use that account.&quot;  Then site X says, &quot;oh, my bad.  Lemme just go check and make sure,&quot; and then &quot;hey OpenID site, you ever heard of this dude?&quot;  Your OpenID site finishes up with a &quot;heck yeah&quot; and you&#39;re signed in.  Once you&#39;ve signed in once with your OpenID site, you&#39;re good to go for that browser session.  You can log in at sites X, Y and Z without registering or even putting in your password.  Cool beans.&lt;br /&gt;&lt;br /&gt;The best news?  Sites are actually starting to accept OpenID.  You can use Scribd, WordPress, Plaxo, Blogger, Disqus, etc. with a single identifier.  Right now.&lt;br /&gt;&lt;br /&gt;So here&#39;s my thought:  Why not make your university an OpenID provider?  Schools aren&#39;t going to pass their login off to someone else (any time soon, anyway), but I can&#39;t think of a reason for them not to share that login at other sites.  Let students clump all their school-related accounts into one  It would be a great thing for &lt;a href=&quot;http://en.wikipedia.org/wiki/Edupunk&quot;&gt;&lt;/a&gt;&lt;a href=&quot;http://www.chrislott.org/&quot;&gt;these &lt;/a&gt;&quot;edupunk&quot; &lt;a href=&quot;http://www.jonmott.com/blog/&quot;&gt;folks&lt;/a&gt;, if nothing else.  Besides, I really like the idea of an OpenID account being tied to something more concrete than just a web site somewhere.  It... feels... very natural to cluster related accounts around a single global id.</content><link rel='replies' type='application/atom+xml' href='http://brianwhitmer.blogspot.com/feeds/7537670307009785056/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/5825798647577501834/7537670307009785056' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5825798647577501834/posts/default/7537670307009785056'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5825798647577501834/posts/default/7537670307009785056'/><link rel='alternate' type='text/html' href='http://brianwhitmer.blogspot.com/2008/11/universities-and-openid.html' title='Universities and OpenID'/><author><name>Brian Whitmer</name><uri>http://www.blogger.com/profile/00009042638644799674</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjuU9fLl8xHMXUGHbywzQI6WumY7z2W7ZL1iBvxzleBCeBQzIoZ5hnhALV9oSHTQs3iWNRFbTiyADkUEIENiZawHyzWZBxIq3JzvCsTANyrGx-fD1nDmk4ax2BIakeg/s1600/71c13439beedf6c35c53acb0976d97c6'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5825798647577501834.post-2288762689093750244</id><published>2008-11-05T16:27:00.000-08:00</published><updated>2008-11-05T17:09:23.410-08:00</updated><title type='text'>How to use django filters in python code</title><content type='html'>Okay, so django is pretty nice.  It&#39;s a great web framework with a very straightforward templating engine, and I&#39;m sad to be leaving it for Rails-land for the time being.  One of the nice things about django is the &lt;a href=&quot;http://docs.djangoproject.com/en/dev/ref/templates/builtins/&quot;&gt;set of included template tags and variable filters&lt;/a&gt;.  You can define blocks of code that can then be overwritten by templates that inherit the given template, and you can very easily format your data in view-specific ways.  The variable filters in particular come in handy.  Very often.&lt;br /&gt;&lt;br /&gt;In fact, there are times when it would be nice to be able to use those filters outside of django template code.  In the true spirit of &lt;a href=&quot;http://www.google.com/url?sa=t&amp;amp;source=web&amp;amp;ct=res&amp;amp;cd=1&amp;amp;url=http%3A%2F%2Fen.wikipedia.org%2Fwiki%2FDon%2527t_repeat_yourself&amp;amp;ei=Kj0SSbT_LImMsAOm4q3BAg&amp;amp;usg=AFQjCNHbd1Tlapfbw-ez3fqqI1cnJXhKkA&amp;amp;sig2=TI9D5YcQV8wMlf7hGosA8A&quot;&gt;DRY&lt;/a&gt;, I don&#39;t want to recreate django&#39;s date filter, file size formatter, &lt;a href=&quot;http://www.djangosnippets.org/snippets/43/&quot;&gt;slugify tool&lt;/a&gt;, etc.&lt;br /&gt;&lt;br /&gt;So how do you use django filters in plain old python?  Turns out it&#39;s pretty easy:&lt;br /&gt;&lt;pre&gt;&lt;span class=&quot;p&quot;&gt;&lt;br /&gt;def process_data():&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;k&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;django.template&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;defaultfilters&lt;/span&gt;&lt;br /&gt; page_title = &quot;How to use django filters in python code&quot;&lt;br /&gt; page_slug = defaultfilters.slugify(page_title)&lt;br /&gt; # page_slug == &quot;how-to-use-django-filters-in-python-code&quot;&lt;br /&gt;&lt;br /&gt; file_size = 123456789&lt;br /&gt; file_size_display = defaultfilters.filesizeformat(file_size)&lt;br /&gt; # file_size_display == &quot;117.7 MB&quot;&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;And there you have it.  Good stuff.  If you don&#39;t want to keep typing &quot;defaultfilters&quot; you can alias it, of course.&lt;br /&gt;&lt;pre&gt;&lt;span class=&quot;k&quot;&gt;&lt;br /&gt;from&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;django.template&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;defaultfilters as filters&lt;/span&gt;&lt;br /&gt;page_slug = filters.slugify(page_title)&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;You can call any filter from the &lt;a href=&quot;http://docs.djangoproject.com/en/dev/ref/templates/builtins/#built-in-filter-reference&quot;&gt;built-in list&lt;/a&gt; this way.  The first argument is the value upon which to perform the filter, the second argument is (optionally) the string argument used as additional information for some formats.  So&lt;br /&gt;&lt;pre&gt;&lt;span class=&quot;cp&quot;&gt;&lt;br /&gt;{{&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;date&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;:&quot;D d M Y&quot;&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;}}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;becomes&lt;br /&gt;&lt;pre&gt;&lt;span class=&quot;cp&quot;&gt;&lt;br /&gt;defaultfilters.date(value, &quot;D d M Y&quot;)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt; Pretty straightforward stuff.  Obviously this only works for the default filters.  If you&#39;ve added any more filters, you should know already where they&#39;re located and how to call them.</content><link rel='replies' type='application/atom+xml' href='http://brianwhitmer.blogspot.com/feeds/2288762689093750244/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/5825798647577501834/2288762689093750244' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5825798647577501834/posts/default/2288762689093750244'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5825798647577501834/posts/default/2288762689093750244'/><link rel='alternate' type='text/html' href='http://brianwhitmer.blogspot.com/2008/11/how-to-use-django-filters-in-python.html' title='How to use django filters in python code'/><author><name>Brian Whitmer</name><uri>http://www.blogger.com/profile/00009042638644799674</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjuU9fLl8xHMXUGHbywzQI6WumY7z2W7ZL1iBvxzleBCeBQzIoZ5hnhALV9oSHTQs3iWNRFbTiyADkUEIENiZawHyzWZBxIq3JzvCsTANyrGx-fD1nDmk4ax2BIakeg/s1600/71c13439beedf6c35c53acb0976d97c6'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5825798647577501834.post-491031194129805381</id><published>2008-10-18T10:45:00.000-07:00</published><updated>2008-10-18T11:21:39.126-07:00</updated><title type='text'>Fickle Finances and Software Startups</title><content type='html'>&lt;span style=&quot;;font-family:arial;font-size:100%;&quot;  &gt;Too true, too true.  I ran into Paul Graham&#39;s post on &lt;a href=&quot;http://www.paulgraham.com/badeconomy.html&quot;&gt;startups in a bad economy&lt;/a&gt; via &lt;a href=&quot;http://www.windley.com/archives/2008/10/start_your_business_now.shtml&quot;&gt;Phil Windley&#39;s blog&lt;/a&gt;, and I very much agree with what was said, there:&lt;br /&gt;&lt;/span&gt;&lt;blockquote  style=&quot;font-family:arial;&quot;&gt;&lt;span style=&quot;font-size:100%;&quot;&gt;&lt;br /&gt;&quot;&lt;/span&gt;&lt;span style=&quot;font-size:100%;&quot;&gt;The economic situation is apparently so grim that some experts fear we may be in for a stretch as bad as the mid seventies.&lt;br /&gt;&lt;br /&gt;&quot;When Microsoft and Apple were founded.&lt;br /&gt;&lt;br /&gt;&quot;Someone who thinks &#39;I better not start a startup now, because the economy is so bad&#39; is making the same mistake as the people who thought during the Bubble &#39;all I have to do is start a startup, and I&#39;ll be rich.&#39;&quot;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;/blockquote&gt;&lt;span style=&quot;;font-family:arial;font-size:100%;&quot;  &gt;On the nose, I&#39;d say!  We&#39;ve been batting this idea around as we talk about eLearning technology.  The fact of the matter is, no matter how bad the economy gets, schools are still going to use an LMS because, well, they need it.  They can&#39;t ask their faculty to go back to paper grading, and they can&#39;t suddenly drop their distance learning programs.  In some ways it makes our product even more viable because it&#39;s a better return on investment.  You don&#39;t have to keep paying on top for all the plugins and features that make the product actually viable.  But in general, web services aren&#39;t going to be the first thing to go in a budget cut.&lt;br /&gt;&lt;br /&gt;The same vein goes for a lot of web technology.  Companies still need software to manage their customers and to mine their data, even with a bad economy.  People aren&#39;t going to stop using email.  They&#39;re not going to stop using Facebook or watching movies on Hulu or Netflix online or whatever.  They actually might do it more because it&#39;s cheaper than going out.  I think it&#39;s fair to say that in general it would take quite a financial sucker-punch for people to cancel their Internet service altogether.  They may even be looking for &lt;span style=&quot;font-style: italic;&quot;&gt;new &lt;/span&gt;opportunities and experiences online.  Now, people may be reluctant to add &lt;span style=&quot;font-style: italic;&quot;&gt;more &lt;/span&gt;monthly fees, so in that sense maybe there&#39;s an issue.  But at the same time, if you really are doing a startup &lt;span style=&quot;font-style: italic;&quot;&gt;right now&lt;/span&gt; then you&#39;re probably offering a free beta for the next little while anyway.  And products for companies, all you need to do is hit a meaningful ROI and you&#39;re home free.&lt;br /&gt;&lt;br /&gt;Phil summarized the sentiment quite well, I thought:&lt;br /&gt;&lt;/span&gt;&lt;blockquote  style=&quot;font-family:arial;&quot;&gt;&lt;span style=&quot;font-size:100%;&quot;&gt;&lt;br /&gt;&quot;Actually, he doesn&#39;t necessarily think starting in bad times is better than good times, just that there&#39;s nothing special about good times when it comes to starting high-tech businesses&quot;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;/blockquote&gt;&lt;span style=&quot;;font-family:arial;font-size:100%;&quot;  &gt;Phil and Paul both get the idea pretty clearly.  The technology sector is less sensitive to (or maybe just slower at reacting to) financial upheavals.  In the end it still boils down to having a good idea and doing a good job putting it forward.&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;;font-family:verdana;font-size:100%;&quot;  &gt;&lt;/span&gt;&lt;blockquote  style=&quot;font-family:arial;&quot;&gt;&lt;span style=&quot;font-size:100%;&quot;&gt;&lt;blockquote&gt;&lt;/blockquote&gt;&lt;br /&gt;&quot;If we&#39;ve learned one thing from funding so many startups, it&#39;s that they succeed or fail based on the qualities of the founders.  The economy has some effect, certainly, but as a predictor of success it&#39;s rounding error compared to the founders.&lt;br /&gt;&lt;br /&gt;&quot;If you&#39;re worried about threats to the survival of your company, don&#39;t look for them in the news.  Look in the mirror... &lt;/span&gt;&lt;span style=&quot;font-size:100%;&quot;&gt;If you&#39;re the right sort of person, you&#39;ll win even in a bad economy. And if you&#39;re not, a good economy won&#39;t save you.&quot;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;/blockquote&gt;&lt;span style=&quot;;font-family:verdana;font-size:100%;&quot;  &gt;&lt;/span&gt;</content><link rel='replies' type='application/atom+xml' href='http://brianwhitmer.blogspot.com/feeds/491031194129805381/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/5825798647577501834/491031194129805381' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5825798647577501834/posts/default/491031194129805381'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5825798647577501834/posts/default/491031194129805381'/><link rel='alternate' type='text/html' href='http://brianwhitmer.blogspot.com/2008/10/fickle-finances-and-software-startups.html' title='Fickle Finances and Software Startups'/><author><name>Brian Whitmer</name><uri>http://www.blogger.com/profile/00009042638644799674</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjuU9fLl8xHMXUGHbywzQI6WumY7z2W7ZL1iBvxzleBCeBQzIoZ5hnhALV9oSHTQs3iWNRFbTiyADkUEIENiZawHyzWZBxIq3JzvCsTANyrGx-fD1nDmk4ax2BIakeg/s1600/71c13439beedf6c35c53acb0976d97c6'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5825798647577501834.post-5541392979069278474</id><published>2008-08-25T13:55:00.000-07:00</published><updated>2008-09-03T11:04:08.417-07:00</updated><title type='text'>The Mashable One-Stop Shop</title><content type='html'>So... interesting meeting yesterday, it really got me thinking.  We&#39;ve been on the road this week talking to a bunch of schools, and one meeting in particular sparked the pontifical juices.  It was a rough discussion.  Funny how rejection always makes you think harder than success.&lt;br /&gt;&lt;br /&gt;See, there&#39;s a lot of talk right now about student-centered learning, about putting the student in the driver&#39;s seat of their education.  The LMS, instead of just dispersing static information, needs to be a springboard to new resources and innovative learning techniques.  Great rhetoric, although I find it interesting that we&#39;re talking about totally transforming the nature of the LMS when I&#39;ve yet to see &lt;a href=&quot;http://mfeldstein.com/blackboard-inc-analysis-part-2-financial-performance/trackback/&quot;&gt;even the most successful LMS&#39;s&lt;/a&gt; take advantage of basic things like AJAX requests and in-page edits.  But that&#39;s another story.  As is the issue of &lt;a href=&quot;http://www.academiccommons.org/commons/review/moodle-and-social-constructionism&quot;&gt;moderate vs. extreme constructivism&lt;/a&gt;.  Anyway.&lt;br /&gt;&lt;br /&gt;Web 2.0 services keep showing up, and educators are finally starting to take note (well, some of them anyway) of their potential for learning.  There&#39;s a natural push from the innovators to leverage these new technologies in education, and that means including them in the LMS somehow.  Maybe even &lt;span style=&quot;font-style: italic;&quot;&gt;replacing&lt;/span&gt; an established feature of the LMS.  That&#39;s a big change from how things have worked in the past.  Traditional LMS&#39;s are a one-stop shop.  They have their version of a standard list of features, and that&#39;s about it.  You can add new functionality with plugins, but replacing say, the discussion board, could only happen by throwing a new link somewhere else in the course structure -- confusing faculty and students in the process.  That leaves you stuck with whatever the LMS offers, there&#39;s no chance to search for best of breed on your standard feature set.&lt;br /&gt;&lt;br /&gt;Solution?  The impression I got from yesterday&#39;s meeting is that you make the LMS into a mash-up.  It becomes a skeleton that doesn&#39;t offer the features itself, it links to other services that offer the features.  Let the teachers decide for themselves.   Taken to the extreme, when the teacher first sets up the course they pick from a drop-down list of discussion boards, group messaging systems, gradebooks, file repositories, content management systems, etc.   The LMS just keeps student data secure and brings all the resources into one place.  That&#39;s really just one step up from what the innovators are doing right now -- WordPress for their announcements, MediaWiki for their assignments, and Google Groups for their discussions.  All that plus a single point of entry.&lt;br /&gt;&lt;br /&gt;While I do see the utility of heading in that direction (and also the challenge of integrating with all those services), I think there&#39;s a bigger jump involved than a lot of instructional techs are acknowledging.   It&#39;s funny, really, because I&#39;ve described the future of the LMS in almost exactly the same words that I heard yesterday, although I had a slightly different image in mind.  I just don&#39;t see the LMS becoming quite that... fleshless.  I&#39;m not sure that&#39;s the right functionality to offer to or require of the faculty.&lt;br /&gt;&lt;br /&gt;It&#39;s totally awesome to say the LMS should let faculty use WordPress or Blogger or whatever for their announcements, MediaWiki or DocuWiki or whatever for course content, Google Groups or Disqus or whatever for communication, MicroGrade Online or Google Spreadsheets or whatever for their gradebook, YouTube or TeacherTube or iTunesU for their video, etc. But most teachers aren&#39;t savvy enough to have&lt;span style=&quot;font-style: italic;&quot;&gt; &lt;/span&gt;a preference.  I&#39;d even go so far as to say they don&#39;t &lt;span style=&quot;font-style: italic;&quot;&gt;want&lt;/span&gt; to have to have a preference.  They don&#39;t want to (or don&#39;t have time to) go set up accounts at different sites and manage student permissions for every course.  They want to have one option for each feature, they want it to be easy and seamless, and they even want it to look the same as everything else so they don&#39;t get confused.  And that&#39;s actually not a bad thing.  Most people just want a single tool that does its job without much fuss or fiddle.  It&#39;s only the rare power user that wants to tinker.  You do have to give the power users freedom to innovate, though, or you&#39;ll get left in the dust by the competition.&lt;br /&gt;&lt;br /&gt;That&#39;s why I think an LMS needs to play both fields: they need to offer flexible options for the power users, but also either integrate deeply with or include their own version of all the major components.  Then you can throw in some settings that cover most standard alternatives.  For example, students could use the integrated blog, but the LMS could also allow Blogger and WordPress URLs instead.  A teacher could export their course calendar to Google Calendar -- or maybe the teacher could even import their Google Calendar into the LMS instead.  Or the teacher could just use the standard calendar if they like.  Likewise a teacher could use the included wiki and file system to build up a repository of learning objects, or point to some external content management system that housed their objects.  It shouldn&#39;t matter to the LMS which approach they take.  By keeping these sort of approaches in mind, I definitely think it&#39;s possible to create a one-stop shop that&#39;s also mashable.  It lets the evolution happen more gradually (and realistically) while still letting the innovators keep pushing the front edge.&lt;br /&gt;&lt;br /&gt;The &lt;span style=&quot;font-style: italic;&quot;&gt;real&lt;/span&gt; trick would be in finding a way to integrate with new services &lt;span style=&quot;font-style: italic;&quot;&gt;as they appear&lt;/span&gt; instead of having to wait for the LMS vendor to catch up and recognize the service themselves.  Educational software, though important, doesn&#39;t have enough of a commanding presence to motivate new services to integrate with it, so the responsibility will probably stay with the LMS to do the integrating.  Again, that&#39;s another story.</content><link rel='replies' type='application/atom+xml' href='http://brianwhitmer.blogspot.com/feeds/5541392979069278474/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/5825798647577501834/5541392979069278474' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5825798647577501834/posts/default/5541392979069278474'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5825798647577501834/posts/default/5541392979069278474'/><link rel='alternate' type='text/html' href='http://brianwhitmer.blogspot.com/2008/08/mashable-one-stop-shop.html' title='The Mashable One-Stop Shop'/><author><name>Brian Whitmer</name><uri>http://www.blogger.com/profile/00009042638644799674</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjuU9fLl8xHMXUGHbywzQI6WumY7z2W7ZL1iBvxzleBCeBQzIoZ5hnhALV9oSHTQs3iWNRFbTiyADkUEIENiZawHyzWZBxIq3JzvCsTANyrGx-fD1nDmk4ax2BIakeg/s1600/71c13439beedf6c35c53acb0976d97c6'/></author><thr:total>0</thr:total></entry></feed>