Kyle Brandt, a system administrator, asks Should Developers have Access to Production?
A question that comes up again and again in web development companies is:"Should the developers have access to the production environment, and if they do, to what extent?"
My view on this is that as a whole they should have limited access to production. A little disclaimer before I attempt to justify this view is that this standpoint is in no way based on the perceived quality or attitude of the developers -- so please don't take it this way.
This is a tricky one for me to answer, because, well, I'm a developer. More specifically, I'm one of the developers Kyle is referring to. How do I know that? Because Kyle works for our company, Stack Overflow Internet Services Incorporated©®™. And Kyle is a great system administrator. How do I know that? Two reasons:
From my perspective, the whole point of the company is to talk about what we're doing. Getting things done is important, of course, but we have to stop occasionally to write up what we're doing, how we're doing it, and why we're even doing it in the first place -- including all our doubts and misgivings and concerns. If we don't, we're cheating ourselves, and you guys, out of something much deeper. Yes, writing about what we're doing and explaining it to the community helps us focus. It lets our peers give us feedback. But most importantly of all, it lets anyone have the opportunity to learn from our many, many mistakes … and who knows, perhaps even the occasional success.
That's basically the entire philosophy behind our Stack Exchange Q&A network, too. Let's all talk about this stuff in public, so that we can teach each other how to get better at whatever the heck it is we love to do.
(Sometimes I get the feeling this idea makes my co-founder nervous, which I continually struggle to understand. If we don't walk the walk, why are we even doing this? But I digress.)
The saga of System Administrators versus Programmers is not a new one; I don't think I've ever worked at any company where these two factions weren't continually battling with each other in some form. It's truly an epic struggle, but to understand it, you have to appreciate that both System Administrators and Programmers have different, and perhaps complementary, supernatural powers.
Programmers are like vampires. They're frequently up all night, paler than death itself, and generally afraid of being exposed to daylight. Oh yes, and they tend think of themselves (or at least their code) as immortal.
System Administrators are like werewolves. They may look outwardly ordinary, but are incredibly strong, mostly invulnerable to stuff that would kill regular people -- and prone to strange transformations during a moon "outage".
Let me be very clear that just as Kyle respects programmers, I have a deep respect for system administrators:
Although there is certainly some crossover, we believe that the programming community and the IT/sysadmin community are different beasts. Just because you're a hotshot programmer doesn't mean you have mastered networking and server configuration. And I've met a few sysadmins who could script circles around my code. That's why Server Fault gets its own domain, user profiles, and reputation system.
Different "beasts" indeed.
Anyway, if you're looking for a one size fits all answer to the question of how much access programmers should have to production environments, I'm sorry, I can't give you one. Every company is different, every team is different. I know, it's a sucky answer, but it depends.
However, as anyone who has watched the latest season of True Blood (or, God help us all, the Twilight Eclipse movie) can attest, there are ways for vampires and werewolves to work together. In a healthy team, everyone feels their abilities are being used and not squandered.
On our team, we're all fair-to-middling sysadmins. But there are a million things to do, and having a professional sysadmin means we can focus on the programming while the networking, hardware, and operational stuff gets a whole lot more TLC and far better (read: non-hacky) processes put in place. We're happy to refocus our efforts on what we're expert at, and let Kyle put his skills to work in areas that he's expert at. Now, that said, we don't want to cede full access to the production servers -- but there's a happy middle ground where our access becomes infrequent and minor over time, except in the hopefully rare event of an all hands on deck emergency.
The art of managing vampires and werewolves, I think, is to ensure that they spend their time not fighting amongst themselves, but instead, using those supernatural powers together to achieve a common goal they could not otherwise. In my experience, when programmers and system administrators fight, it's because they're bored. You haven't given them a sufficiently daunting task, one that requires the full combined use of their unique skills to achieve.
Remember, it's not vampires versus werewolves. It's vampires and werewolves.
| [advertisement] JIRA Studio - SVN hosting, issue tracking, CI and Google Apps integration. Free trial » |
Like any self-respecting geek, I'm mostly an indoor enthusiast.
But on those unfortunate occasions when I am compelled -- for reasons entirely beyond my control -- to leave the house, I do so fully armed with my crucial utility belt items. Yes, you heard me, I transform from the geeky Bruce Wayne to the gosh-darned Batman!
At least, that's how I like to think of it.
I've been talking about this every-day carry stuff for quite a while now. The 2010 edition of my personal utility belt is mostly subtle tweaks, but I daresay it's the best one yet.
The art of every-day carry must go on. What you see here is the contents of my pocket:
Rest assured, everything here is carefully selected with the appropriate levels of monomaniacal attention to detail. For this weight and size, I don't think you can do better. (And don't think I've forgotten about optimizing my wallet, either. Oh no. Quite the contrary.)
However, I have to add a special category this year for the other must-have EDC utility belt item: the smartphone. What self-respecting superhero would leave the house these days without their smartphone? I'm not religious about it, but I use and rather like the iPhone 4, and I'm continually amazed how many things it does that I used to carry separate items for:
Smartphones really are the ultimate gadget. The list of functions is already enormous, and I'm sure I'm leaving out a few other things that you can do with a modern smartphone.
In a pinch, I could conceivably drop the AAA LED flashlight and the USB flash drive from my EDC kit and substitute the smartphone. Not exactly, mind you, but it's getting closer every year. At this rate, Apple could introduce a flip-out blade on the iPhone 7 and reduce my entire EDC kit to one item.
Anyway, that's what's on my utility belt in 2010. What's on yours?
| [advertisement] JIRA Studio - Hosted software development suite. Build better software. Faster. Free trial » |
On a recent airplane flight, I happened to catch the movie Groundhog Day. Again.
If you aren't familiar with this classic film, the premise is simple: Bill Murray, somehow, gets stuck reliving the same day over and over.
It's been at least 5 years since I've seen Groundhog Day. I don't know if it's my advanced age, or what, but it really struck me on this particular viewing: this is no comedy. There's a veneer of broad comedy, yes, but lurking just under that veneer is a deep, dark existential conundrum.
It might be amusing to relive the same day a few times, maybe even a few dozen times. But an entire year of the same day -- an entire decade of the same day -- everything happening in precisely, exactly the same way? My back of the envelope calculation easily ran to a decade. But I was wrong. The director, Harold Ramis thinks it was actually 30 or 40 years.
I think the 10-year estimate is too short. It takes at least 10 years to get good at anything, and alloting for the down time and misguided years [Phil] spent, it had to be more like 30 or 40 years [spent reliving the same day].
We only see bits and pieces of the full experience in the movie, but this time my mind began filling in the gaps. Repeating the same day for decades plays to our secret collective fear that our lives are irrelevant and ultimately pointless. None of our actions -- even suicide, in endless grisly permutations -- ever change anything. What's the point? Why bother? How many of us are trapped in here, and how can we escape?
This is some dark, scary stuff when you really think about it.
You want a prediction about the weather, you're asking the wrong Phil.I'll give you a winter prediction.
It's gonna be cold,
it's gonna be gray,
and it's gonna last you for the rest of your life.
Comedy, my ass. I wanted to cry.
But there is a way out: redemption through repetition. If you have to watch Groundhog Day a few times to appreciate it, you're not alone. Indeed, that seems to be the whole point. Just ask Roger Ebert:
"Groundhog Day" is a film that finds its note and purpose so precisely that its genius may not be immediately noticeable. It unfolds so inevitably, is so entertaining, so apparently effortless, that you have to stand back and slap yourself before you see how good it really is.Certainly I underrated it in my original review; I enjoyed it so easily that I was seduced into cheerful moderation. But there are a few films, and this is one of them, that burrow into our memories and become reference points. When you find yourself needing the phrase This is like "Groundhog Day" to explain how you feel, a movie has accomplished something.
There's something delightfully Ouroboros about the epiphanies and layered revelations in repeated viewings of a movie that is itself about (nearly) endless repetition.
Which, naturally, brings me to A/B testing. That's what Phil spends most of those thirty years doing. He spends it pursuing a woman, technically, but it's how he does it that is interesting:
Rita: This whole day has just been one long setup.Phil: It hasn't.
Rita: And I hate fudge!
Phil: [making a mental list] No white chocolate. No fudge.
Rita: What are you doing? Are you making some kind of list? Did you call my friends and ask what I like and what I don't like? Is this what love is for you?
Phil: This is real. This is love.
Rita: Stop saying that! You must be crazy.
Phil doesn't just go on one date with Rita, he goes on thousands of dates. During each date, he makes note of what she likes and responds to, and drops everything she doesn't. At the end he arrives at -- quite literally -- the perfect date. Everything that happens is the most ideal, most desirable version of all possible outcomes on that date on that particular day. Such are the luxuries afforded to a man repeating the same day forever.
This is the purest form of A/B testing imaginable. Given two choices, pick the one that "wins", and keep repeating this ad infinitum until you arrive at the ultimate, most scientifically desirable choice. Your marketing weasels would probably collapse in an ecstatic, religious fervor if they could achieve anything even remotely close to the level of perfect A/B testing depicted in Groundhog Day.
But at the end of this perfect date, something impossible happens: Rita rejects Phil.
Phil wasn't making these choices because he honestly believed in them. He was making these choices because he wanted a specific outcome -- winning over Rita -- and the experimental data told him which path he should take. Although the date was technically perfect, it didn't ring true to Rita, and that made all the difference.
That's the problem with A/B testing. It's empty. It has no feeling, no empathy, and at worst, it's dishonest. As my friend Nathan Bowers said:
A/B testing is like sandpaper. You can use it to smooth out details, but you can't actually create anything with it.
The next time you reach for A/B testing tools, remember what happened to Phil. You can achieve a shallow local maximum with A/B testing -- but you'll never win hearts and minds. If you, or anyone on your team, is still having trouble figuring that out, well, the solution is simple.
Just watch Groundhog Day again.
| [advertisement] JIRA Studio - Hosted software development suite. Build better software. Faster. Free trial » |
Remember that Scene in Star Trek IV where Scotty tried to use a Mac Plus?
Using a mouse or keyboard to control a computer? Don't be silly. In the future, clearly there's only one way computers will be controlled: by speaking to them.
There's only one teeny-tiny problem with this magical future world of computers we control with our voices.
It doesn't work.
Despite ridiculous, order of magnitude increases in computing power over the last decade, we can't figure out how to get speech recognition accuracy above 80% -- when the baseline human voice transcription accuracy rate is anywhere from 96% to 98%!
In 2001 recognition accuracy topped out at 80%, far short of HAL-like levels of comprehension. Adding data or computing power made no difference. Researchers at Carnegie Mellon University checked again in 2006 and found the situation unchanged. With human discrimination as high as 98%, the unclosed gap left little basis for conversation. But sticking to a few topics, like numbers, helped. Saying “one” into the phone works about as well as pressing a button, approaching 100% accuracy. But loosen the vocabulary constraint and recognition begins to drift, turning to vertigo in the wide-open vastness of linguistic space.
As Robert Fortner explained in Rest in Peas: The Unrecognized Death of Speech Recognition, after all these years, we're desperately far away from any sort of universal speech recognition that's useful or practical.
Now, we do have to clarify that we're talking about universal recognition: saying anything to a computer, and having it reliably convert that into a valid, accurate text representation. When you constrain the voice input to a more limited vocabulary -- say, just numbers, or only the names that happen to be in your telephone's address book -- it's not unreasonable to expect a high level of accuracy. I tend to think of this as "voice control" rather than "voice recognition".
Still, I think we're avoiding the real question: is voice control, even hypothetically perfect voice control, more effective than the lower tech alternatives? In my experience, speech is one of the least effective, inefficient forms of communicating with other human beings. By that, I mean ...
I am by no means against talking with my fellow human beings. I have a very deep respect for those rare few who are great communicators in the challenging medium of conversational speech. Though we've all been trained literally from birth how to use our voices to communicate, voice communication remains filled with pitfalls and misunderstandings. Even in the best of conditions.
So why in the world -- outside of a disability -- would I want to extend the creaky, rickety old bridge of voice communication to controlling my computer? Isn't there a better way?
Robert's post contains some examples in the comments from voice control enthusiasts:
in addition to extremely accurate voice dictation, there are those really cool commands, like being able to say something like "search Google for Balloon Boy" or something like that and having it automatically open up your browser and enter the search term -- something like this is accomplished many times faster than a human could do it. Or, being able to total up a column of numbers in Microsoft Excel by saying simply "total this column" and seeing the results in a blink of an eye, literally.
That's funny, because I just fired up the Google app on my iPhone, said "balloon boy" into it, and got .. a search for "blue boy". I am not making this up. As for the Excel example, total which column? Let's assume you've dealt with the tricky problem of selecting what column you're talking about with only your voice. (I'm sorry, was it D5? B5?) Wouldn't it be many times faster to click the toolbar icon with your mouse, or press the keyboard command equivalent, to sum the column -- rather than methodically and tediously saying the words "sum this column" out loud?
I'm also trying to imagine a room full of people controlling their computers or phones using their voices. It's difficult enough to get work done in today's chatty work environments without the added burden of a floor full of people saying "zoom ... enhance" to their computers all day long. Wouldn't we all end up hoarse and deaf?
Let's look at another practical example -- YouTube's automatic speech recognition feature. I clicked through to the first UC Berkeley video with this feature, clicked the CC (closed caption) icon, and immediately got .. this.
"Light exerts force on matter". But according to Google's automatic speech recognition, it's "like the search for some matter". Unsurprisingly, it does not get better from there. You'd be way more confused than educated if you had to learn this lecture from the automatic transcription.
Back when Joel Spolsky and I had a podcast together, a helpful listener suggested using speech recognition to get a basic podcast transcript going. Everything I knew about voice recognition told me this wouldn't help, but harm. What's worse: transcribing everything by hand, from scratch -- or correcting every third or fourth word in an auto-generated machine transcript? Maybe it's just me, but the friction of the huge error rate inherent in the machine transcript seems far more intimidating than a blank slate human transcription. The humans may not be particularly efficient, but they all add value along the way -- collective human judgment can editorially improve the transcript, by removing all the duplication, repetition, and "ums" of a literal, by-the-book transcription.
In 2004, Mike Bliss composed a poem about voice recognition. He then read it to voice recognition software on his PC, and rewrote it as recognized.
|
a poem by Mike Bliss like a baby, it listens it can't discriminate it tries to understand it reflects what it thinks you say it gets it wrong... sometimes sometimes it gets it right. One day it will grow up, like a baby, it has potential will it go to work? will it turn to crime? you look at it indulgently. you can't help loving it, can you? |
a poem by like myth like a baby, it nuisance it can't discriminate it tries to oven it reflects lot it things you say it gets it run sometimes sometimes it gets it right won't day it will grow bop Ninth a baby, it has provincial will it both to look? will it the two crime? you move at it inevitably you can't help loving it, cannot you? |
The real punchline here is that Mike re-ran the experiment in 2008, and after 5 minutes of voice training, the voice recognition got all but 2 words of the original poem correct!
I suspect that's still not good enough in the face of the existing simpler alternatives. Remember handwriting recognition? It was all the rage in the era of the Apple Newton.
It wasn't as bad as Doonesbury made it out to be. I learned Palm's Graffiti handwriting recognition language and got fairly proficient with it. More than ten years later, you'd expect to see massively improved handwriting recognition of some sort in today's iPads and iPhones and iOthers, right? Well, maybe, if by "massively improved" you mean "nonexistent".
While it still surely has its niche uses, I personally don't miss handwriting recognition. Not even a little. And I can't help wondering if voice recognition will go the same way.
| [advertisement] JIRA 4 - Simplify bug tracking for everyone involved. Get started from $10 for 10 users » |
After we created Stack Overflow, some people were convinced we had built a marginally better mousetrap for asking and answering questions. The inevitable speculation began: can we use your engine to build a Q&A site about {topic}? Our answer was Stack Exchange. Pay us $129 a month (and up), and you too can create a hosted Q&A community on our engine -- for whatever topic you like!
Well, I have a confession to make: my heart was never in Stack Exchange. It was a parallel effort in a parallel universe only tangentially related to my own. There's a whole host of reasons why, but if I had to summarize it in a sentence, I'd say that money is poisonous to communities. That $129/month doesn't sound like much -- and it isn't -- but the commercial nature of the enterprise permeated and distorted everything from the get-go.
(fortunately, the model is changing with Stack Exchange 2.0, but that's a topic for another blog post.)
Yes, Stack Overflow Internet Services Incorporated©®™ is technically a business, even a venture capital backed business now -- but I didn't co-found it because I wanted to make money. I co-founded it because I wanted to build something cool that made the internet better. Yes, selfishly for myself, of course, but also in conjunction with all of my fellow programmers, because I know none of us is as dumb as all of us.
Nobody is participating in Stack Overflow to make money. We're participating in Stack Overflow because …
I don't care how much you pay me, you'll never be able to recreate the incredibly satisfying feeling I get when demonstrating mastery within my community of peers. That's what we do on Stack Overflow: have fun, while making the internet one infinitesimally tiny bit better every day.
So is it any wonder that some claim Stack Overflow is more satisfying than their real jobs? Not to me.
If this all seems like a bunch of communist hippie bullcrap to you, I understand. It's hard to explain. But there is quite a bit of science documenting these strange motivations. Let's start with Dan Pink's 2009 TED talk.
Dan's talk centers on the candle problem. Given the following three items …
… how can you attach the candle to the wall?
It's not a very interesting problem on its own -- that is, until you try to incentivize teams to solve it:
Now I want to tell you about an experiment using the candle problem by a scientist from Princeton named Sam Glucksberg. Here's what he did.To the first group, he said, "I'm going to time you to establish norms, averages for how long it typically takes someone to solve this sort of problem."
To the second group, he said, "If you're in the top 25 percent of the fastest times you get five dollars. If you're the fastest of everyone we're testing here today you get 20 dollars." (This was many years ago. Adjusted for inflation, it's a decent sum of money for a few minutes of work.)
Question: How much faster did this group solve the problem?
Answer: It took them, on average, three and a half minutes longer. Three and a half minutes longer. Now this makes no sense, right? I mean, I'm an American. I believe in free markets. That's not how it's supposed to work. If you want people to perform better, you reward them. Give them bonuses, commissions, their own reality show. Incentivize them. That's how business works. But that's not happening here. You've got a monetary incentive designed to sharpen thinking and accelerate creativity -- and it does just the opposite. It dulls thinking and blocks creativity.
It turns out that traditional carrot-and-stick incentives are only useful for repetitive, mechanical tasks. The minute you have to do anything even slightly complex that requires even a little problem solving without a clear solution or rules -- those incentives not only don't work, they make things worse!
Pink eventually wrote a book about this, Drive: The Surprising Truth About What Motivates Us.
There's no need to read the book; this clever ten minute whiteboard animation will walk you through the main points. If you view only one video today, view this one.
The concept of intrinsic motivation may not be a new one, but I find that very few companies are brave enough to actually implement them.
I've tried mightily to live up to the ideals that Stack Overflow was founded on when building out my team. I don't care when you come to work or what your schedule is. I don't care where in the world you live (provided you have a great internet connection). I don't care how you do the work. I'm not going to micromanage you and assign you a queue of task items. There's no need.
If you want to build a ship, don't drum up the men to gather wood, divide the work and give orders. Instead, teach them to yearn for the vast and endless sea.
– Antoine de Saint Exupéry
Because I know you yearn for the vast and endless sea, just like we do.
| [advertisement] JIRA 4 - Simplify bug tracking for everyone involved. Get started from $10 for 10 users » |
When I first chose my own adventure, I didn't know what working remotely from home was going to be like. I had never done it before. As programmers go, I'm fairly social. Which still means I'm a borderline sociopath by normal standards. All the same, I was worried that I'd go stir-crazy with no division between my work life and my home life.
Well, I haven't gone stir-crazy yet. I think. But in building Stack Overflow, I have learned a few things about what it means to work remotely -- at least when it comes to programming. Our current team encompasses 5 people, distributed all over the USA, along with the team in NYC.
My first mistake was attempting to program alone. I had weekly calls with my business partner, Joel Spolsky, which were quite productive in terms of figuring out what it was we were trying to do together -- but he wasn't writing code. I was coding alone. Really alone. One guy working all by yourself alone. This didn't work at all for me. I was unmoored, directionless, suffering from analysis paralysis, and barely able to get motivated enough to write even a few lines of code. I rapidly realized that I'd made a huge mistake in not having a coding buddy to work with.
That situation rectified itself soon enough, as I was fortunate enough to find one of my favorite old coding buddies was available. Even though Jarrod was in North Carolina and I was in California, the shared source code was the mutual glue that stuck us together, motivated us, and kept us moving forward. To be fair, we also had the considerable advantage of prior history, because we had worked together at a previous job. But the minimum bar to work remotely is to find someone who loves code as much as you do. It's … enough. Anything else on top of that -- old friendships, new friendships, a good working relationship -- is icing that makes working together all the sweeter. I eventually expanded the team in the same way by adding another old coding buddy, Geoff, who lives in Oregon. And again by adding Kevin, who I didn't know, but had built amazing stuff for us without even being asked to, from Texas. And again by adding Robert, in Florida, who I also didn't know, but spent so much time on every single part of our sites that I felt he had been running alongside our team the whole way, there all along.
The reason remote development worked for us, in retrospect, wasn't just shared love of code. I picked developers who I knew -- I had incontrovertible proof -- were amazing programmers. I'm not saying they're perfect, far from it, merely that they were top programmers by any metric you'd care to measure. That's why they were able to work remotely. Newbie programmers, or competent programmers who are phoning it in, are absolutely not going to have the moxie necessary to get things done remotely -- at least, not without a pointy haired manager, or grumpy old team lead, breathing down their neck. Don't even think about working remotely with anyone who doesn't freakin' bleed ones and zeros, and has a proven track record of getting things done.
While Joel certainly had a lot of high level input into what Stack Overflow eventually became, I only talked to him once a week, at best (these calls were the genesis of our weekly podcast series). I had a strong, clear vision of what I wanted Stack Overflow to be, and how I wanted it to work. Whenever there was a question about functionality or implementation, my team was able to rally around me and collectively make decisions we liked, and that I personally felt were in tune with this vision. And if you know me at all, you know I'm not shy about saying no, either. We were able to build exactly what we wanted, exactly how we wanted.
Bottom line, we were on a mission from God. And we still are.
So, there are a few basic ground rules for remote development, at least as I've seen it work:
This is all well and good when you have a remote team size of three, as we did for the bulk of Stack Overflow development. And all in the same country. Now we need to grow the company, and I'd like to grow it in distributed fashion, by hiring other amazing developers from around the world, many of whom I have met through Stack Overflow itself.
But how do you scale remote development? Joel had some deep seated concerns about this, so I tapped one of my heroes, Miguel de Icaza -- who I'm proud to note is on our all-star board of advisors -- and he was generous enough to give us some personal advice based on his experience running the Mono project, which has dozens of developers distributed all over the world.
At the risk of summarizing mercilessly (and perhaps too much), I'll boil down Miguel's advice the best I can. There are three tools you'll need in place if you plan to grow a large-ish and still functional remote team:
We're currently experimenting with Campfire, but whatever floats your boat and you can get your team to consistently use, will work. Chat is the most essential and omnipresent form of communication you have when working remotely, so you need to make absolutely sure it's functioning before going any further.
We're using Google Groups and although it's old school in spades, it works plenty well for this. You can get the emails as they arrive, or view the archived list via the web interface. One word of caution, however. Every time you see something arrive in your inbox from the mailing list you better believe, in your heart of hearts, that it contains useful information. The minute the mailing list becomes just another "whenever I have time to read that stuff", noise engine, or distraction from work … you've let someone cry wolf too much, and ruined it. So be very careful. Noisy, argumentative, or useless things posted to the mailing list should be punishable by death. Or noogies.
As much as I love ASCII, sometimes faceless ASCII characters just aren't enough to capture the full intentions and feelings of the human being behind them. When you find yourself sending kilobytes of ASCII back and forth, and still are unsatisfied that you're communicating, you should instill a reflexive habit of "going voice" on your team.
Never underestimate the power of actually talking to another human being. I know, I know, the whole reason we got into this programming thing was to avoid talking to other people, but bear with me here. You can't be face to face on a remote team without flying 6 plus hours, and who the heck has that kind of time? I've got work I need to get done! Well, the next best thing to hopping on a plane is to fire up Skype and have a little voice chat. Easy peasy. All that human nuance which is totally lost in faceless ASCII characters (yes, even with our old pal *<:-)) will come roaring back if you regularly schedule voice chats. I recommend at least once a week at an absolute minimum; they don't have to be long meetings, but it sure helps in understanding the human being behind all those awesome checkins.
Nobody hates meetings and process claptrap more than I do, but there is a certain amount of process you'll need to keep a bunch of loosely connected remote teams and developers in sync.
Every Monday, as in somebody's-got-a-case-of-the, each team should produce a brief, summarized rundown of:
This doesn't have to be (and in fact shouldn't be) a long report. The briefer the better, but do try to capture all the useful highlights. Mail this to the mailing list every Monday like clockwork. Now, how many "teams" you have is up to you; I don't think this needs to be done at the individual developer level, but you could.
Any time you conduct what you would consider to be a "meeting" with someone else, take minutes! That is, write down what happened in bullet point form, so those remote team members who couldn't be there can benefit from -- or at least hear about -- whatever happened.
Again, this doesn't have to be long, and if you find taking meeting minutes onerous then you're probably doing it wrong. A simple bulleted list of sentences should suffice. We don't need to know every little detail, just the big picture stuff: who was there? What topics were discussed? What decisions were made? What are the next steps?
Both of the above should, of course, be mailed out to the mailing list as they are completed so everyone can be notified. You do have a mailing list, right? Of course you do!
If this seems like a lot of jibba-jabba, well, that's because remote development is hard. It takes discipline to make it all work, certainly more discipline than piling a bunch of programmers into the same cubicle farm. But when you imagine what this kind of intellectual work -- not just programming, but anything where you're working in mostly thought-stuff -- will be like in ten, twenty, even thirty years … don't you think it will look a lot like what happens every day right now on Stack Overflow? That is, a programmer in Brazil helping a programmer in New Jersey solve a problem?
If I have learned anything from Stack Overflow it is that the world of programming is truly global. I am honored to meet these brilliant programmers from every corner of the world, even if only in a small way through a website. Nothing is more exciting for me than the prospect of adding international members to the Stack Overflow team. The development of Stack Overflow should be reflective of what Stack Overflow is: an international effort of like-minded -- and dare I say totally awesome -- programmers. I wish I could hire each and every one of you. OK, maybe I'm a little biased. But to me, that's how awesome the Stack Overflow community is.
I believe remote development represents the future of work. If we have to spend a little time figuring out how this stuff works, and maybe even make some mistakes along the way, it's worth it. As far as I'm concerned, the future is now. Why wait?
| [advertisement] Atlassian Starter Day - Learn how startups like Boxee and Pandora broke through. Sign-up today » |
We're currently in the midst of a CSS Zen Garden type excerise on our family of Q&A websites, which I affectionately refer to as "the Trilogy":
(In case you were wondering, yes, meta is the Star Wars Holiday Special.)
These sites all run the same core engine, but the logo, domain, and CSS "skin" that lies over the HTML skeleton is different in each case:
|
|
|
|
|
|
They are not terribly different looking, it's true, but we also want them to be recognizable as a family of sites.
We're working with two amazing designers, Jin Yang and Nathan Bowers, who are helping us whip the CSS and HTML into shape so they can produce a set of about 10 different Zen Garden designs. As new sites in our network get democracied into being, these designs will be used as a palette for the community to choose from. (And, later, the community will decide on a domain name and logo as well.)
Anyway, I bring this up not because my pokemans, let me show you them, but because I have to personally maintain four different CSS files. And that number is only going to get larger. Much larger. That scares me a little.
Most of all, what I've learned from this exercise in site theming is that CSS is kind of painful. I fully support CSS as a (mostly) functional user interface Model-View-Controller. But even if you have extreme HTML hygiene and Austrian levels of discipline, CSS has some serious limitations in practice.
Things in particular that bite us a lot:
In short, CSS violates the living crap out of the DRY principle. You are constantly and unavoidably repeating yourself.
That's why I'm so intrigued by two Ruby gems that attempt to directly address the deficiencies of CSS.
1. Less CSS
/* CSS */
#header {
-moz-border-radius: 5;
-webkit-border-radius: 5;
border-radius: 5;
}
#footer {
-moz-border-radius: 10;
-webkit-border-radius: 10;
border-radius: 10;
}
|
// LessCSS
.rounded_corners (@radius: 5px) {
-moz-border-radius: @radius;
-webkit-border-radius: @radius;
border-radius: @radius;
}
#header {
.rounded_corners;
}
#footer {
.rounded_corners(10px);
}
|
2. SASS
/* CSS */
.content_navigation {
border-color: #3bbfce;
color: #2aaebd;
}
.border {
padding: 8px;
margin: 8px;
border-color: #3bbfce;
}
|
// Sass !blue = #3bbfce !margin = 16px .content_navigation border-color = !blue color = !blue - #111 .border padding = !margin / 2 margin = !margin / 2 border-color = !blue |
As you can see, in both cases we're transmogrifying CSS into a bit more of a programming language, rather than the static set of layout rules it currently exists as. Behind the scenes, we're generating plain vanilla CSS using these little dynamic languages. This could be done at project build time, or even dynamically on every page load if you have a good caching strategy.
I'm not sure how many of these improvements CSS3 will bring, never mind when the bulk of browsers in the world will support it. But I definitely feel that the core changes identified in both Less CSS and SASS address very real pain points in practical CSS use. It's worth checking them out to understand why they exist, what they bring to the table, and how you could possibly adopt some of these strategies in your own CSS and your favorite programming language.
| [advertisement] Atlassian Starter Day - Learn how startups like Boxee and Pandora broke through. Sign-up today » |
I have what I would charitably describe as a hate-hate relationship with email. I desperately try to avoid sending email, not just for myself, but also in the code I write.
Despite my misgivings, email is the cockroach of communication mediums: you just can't kill it. Email is the one method of online contact that almost everyone -- at least for that subset of "everyone" which includes people who can bear to touch a computer at all -- is guaranteed to have, and use. Yes, you can make a fairly compelling case that email is for old stupid people, but let's table that discussion for now.
So, reluctantly, we come to the issue of sending email through code. It's easy! Let's send some email through oh, I don't know, let's say ... Ruby, courtesy of some sample code I found while browsing the Ruby tag on Stack Overflow.
require 'net/smtp'
def send_email(to, subject = "", body = "")
from = "my@email.com"
body= "From: #{from}\r\nTo: #{to}\r\nSubject: #{subject}\r\n\r\n#{body}\r\n"
Net::SMTP.start('192.168.10.213', 25, '192.168.0.218') do |smtp|
smtp.send_message body, from, to
end
end
send_email "foo@example.com", "title", "body goes here"
There's a bug in this code, though. Do you see it?
Just because you send an email doesn't mean it will arrive. Not by a long shot. Bear in mind this is email we're talking about. It was never designed to survive a bitter onslaught of criminals and spam, not to mention the explosive, exponential growth it has seen over the last twenty years. Email is a well that has been truly and thoroughly poisoned -- the digital equivalent of a superfund cleanup site. The ecosystem around email is a dank miasma of half-implemented, incompletely supported anti-spam hacks and workarounds.
Which means the odds of that random email your code just sent getting to its specific destination is .. spotty. At best.
If you want email your code sends to actually arrive in someone's AOL mailbox, to the dulcet tones of "You've Got Mail!", there are a few things you must do first. And most of them are only peripherally related to writing code.
1. Make sure the computer sending the email has a Reverse PTR record
What's a reverse PTR record? It's something your ISP has to configure for you -- a way of verifying that the email you send from a particular IP address actually belongs to the domain it is purportedly from.
Not every IP address has a corresponding PTR record. In fact, if you took a random sampling of addresses your firewall blocked because they were up to no good, you'd probably find most have no PTR record - a dig -x gets you no information. That's also apt to be true for mail spammers, or their PTR doesn't match up: if you do a dig -x on their IP you get a result, but if you look up that result you might not get the same IP you started with.That's why PTR records have become important. Originally, PTR records were just intended as a convenience, and perhaps as a way to be neat and complete. There still are no requirements that you have a PTR record or that it be accurate, but because of the abuse of the internet by spammers, certain conventions have grown up. For example, you may not be able to send email to some sites if you don't have a valid PTR record, or if your pointer is "generic".
How do you get a PTR record? You might think that this is done by your domain registrar - after all, they point your domain to an IP address. Or you might think whoever handles your DNS would do this. But the PTR record isn't up to them, it's up to the ISP that "owns" the IP block it came from. They are the ones who need to create the PTR record.
A reverse PTR record is critical. How critical? Don't even bother reading any further until you've verified that your ISP has correctly configured the reverse PTR record for the server that will be sending email. It is absolutely the most common check done by mail servers these days. Fail the reverse PTR check, and I guarantee that a huge percentage of the emails you send will end up in the great bit bucket in the sky -- and not in the email inboxes you intended.
2. Configure DomainKeys Identified Mail in your DNS and code
What's DomainKeys Identified Mail? With DKIM, you "sign" every email you send with your private key, a key only you could possibly know. And this can be verified by attempting to decrypt the email using the public key stored in your public DNS records. It's really quite clever!
The first thing you need to do is generate some public-private key pairs (one for every domain you want to send email from) via OpenSSL. I used a win32 version I found. Issue these commands to produce the keys in the below files:
$ openssl genrsa -out rsa.private 1024 $ openssl rsa -in rsa.private -out rsa.public -pubout -outform PEM
These public and private keys are just big ol' Base64 encoded strings, so plop them in your code as configuration string resources that you can retrieve later.
Next, add some DNS records. You'll need two new TXT records.
The first TXT DNS record is the global DomainKeys policy and contact email.
The second TXT DNS record is the public base64 key you generated earlier, as one giant unbroken string. Note that the "selector" part of this record can be anything you want; it's basically just a disambiguating string.
Almost done. One last thing -- we need to sign our emails before sending them. In any rational world this would be handled by an email library of some kind. We use Mailbee.NET which makes this fairly painless:
smtp.Message = dk.Sign(smtp.Message,
null, AppSettings.Email.DomainKeyPrivate, false, "selector");
3. Set up a SenderID record in your DNS
To be honest, SenderID is a bit of a "nice to have" compared to the above two. But if you've gone this far, you might as well go the distance. SenderID, while a little antiquated and kind of.. Microsoft/Hotmail centric.. doesn't take much additional effort.
SenderID isn't complicated. It's another TXT DNS record at the root of, say, example.com, which contains a specially formatted string documenting all the allowed IP addresses that mail can be expected to come from. Here's an example:
"v=spf1 a mx ip4:10.0.0.1 ip4:10.0.0.2 ~all"
You can use the Sender ID SPF Record Wizard to generate one of these for each domain you send email from.
That sucked. How do I know all this junk is working?
I agree, it sucked. Email sucks; what did you expect? I used two methods to verify that all the above was working:
Received-SPF: pass Authentication-Results: ... spf=pass ... dkim=pass
If you see that, then the Reverse PTR and DKIM signing you set up is working. Google provides excellent diagnostic feedback in their email server headers, so if something isn't working, you can usually discover enough of a hint there to figure out why.
SPF check: pass DomainKeys check: fail DKIM check: pass Sender-ID check: pass SpamAssassin check: ham
You want to pass SPF, DKIM, and Sender-ID. Don't worry about the DomainKeys failure, as I believe it is spurious -- DKIM is the "newer" version of that same protocol.
Yes, the above three steps are quite a bit of work just to send a lousy email. But I don't send email lightly. By the time I've reached the point where I am forced to write code to send out email, I really, really want those damn emails to arrive. By any means necessary.
And for those who are the unfortunate recipients of these emails: my condolences.
| [advertisement] JIRA Studio - SVN hosting, issue tracking, CI and Google Apps integration. Free trial » |
As far as I'm concerned, you can never be too rich, too thin, or have too much screen space. By "screen", I mean not just large monitors, but multiple large monitors. I've been evangelizing multiple monitors since the dark days of Windows Millennium Edition:
If you're a long time reader you're probably sick of hearing about this stuff by now, but something rather wonderful has happened since I last wrote about it:
If you're only using one monitor, you are cheating yourself out of potential productivity. Two monitors is a no-brainer. It's so fundamental that I included it as a part of the Programmer's Bill of Rights.But you can do better.
As good as two monitors is, three monitors is even better. With three monitors, there's a "center" to focus on. And 50% more display area. While there's certainly a point of diminishing returns for additional monitors, I think three is the sweet spot. Even Edward Tufte, in the class I recently attended, explicitly mentioned multiple monitors. I don't care how large a single display can be; you can never have enough desktop space.
Normally, to achieve three monitors, you have to either:
- Buy an exotic video card that has more than 2 monitor connections.
- Install a second video card.
Fortunately, that is no longer true. I was excited to learn that the latest ATI video cards have gone from two to three video outputs. Which means you can now achieve triple monitors with a single video card upgrade! They call this "eyefinity", but it's really just shorthand for "raising the standard from two display outputs to three".
But, there is a (small) catch. The PC ecosystem is in the middle of shifting display output standards. For evidence of this, you need look no further than the back panel of one of these newfangled triple display capable ATI video cards:
It contains:
I suspect part of this odd connector layout is due to space restrictions (DVI is awfully chunky), but I've always understood DisplayPort to be the new, improved DVI connector for computer monitors, and HDMI to be the new, improved s-video/component connector for televisions. Of course these worlds are blurring, as modern high-definition TVs make surprisingly effective computer monitors, too.
Anyway, since all my monitors have only DVI inputs, I wasn't sure what to do with the other output. So I asked on Super User. The helpful answers led me to discover that, as I suspected, the third output has to be DisplayPort. So to connect my third monitor, I needed to convert DisplayPort to DVI, and there are two ways:
I ended up going with the active converter, which has mixed reviews, but it's worked well for me over the last few weeks.
Note that this adapter requires USB power, and given the spotty results others have had with it, some theorize that it needs quite a bit of juice to work reliably. I plugged it into my system's nearby rear USB ports which do tend to deliver more power (they're closer to the power supply, and have short cable paths). Now, I have gotten the occasional very momentary black screen with it, but nothing severe enough to be a problem or frequent enough to become a pattern. If you have DisplayPort compatible monitors, of course, this whole conversion conundrum is a complete non-issue. But DisplayPort is fairly new, and even my new-ish LCD monitors don't support it yet.
The cool thing about this upgrade, besides feeding my video card addiction, is that I was able to simplify my hardware configuration. That's always good. I went from two video cards to one, which means less power consumption, simpler system configuration, and fewer overall driver oddities. Basically, it makes triple monitors -- dare I say it -- almost a mainstream desktop configuration. How could I not be excited about that?
I was also hoping that Nvidia would follow ATI's lead here and make three display outputs the standard for all their new video cards, too, but sadly that's not the case. It turns out their new GTX 480 fails in other ways, in that it's basically the Pentium 4 of video cards -- generating ridiculous amounts of heat for very little performance gain. Based on those two facts, I am comfortable endorsing ATI wholeheartedly at this point. But, do be careful, because not all ATI cards support triple display outputs (aka "eyefinity"). These are the ones that I know do:
Unless you're a gamer, there's no reason to care about anything other than the least expensive model here, which will handily crush any 2D or 3D desktop GUI acceleration needs you might have. As an addict, of course I bought the high end model and it absolutely did not disappoint -- more than doubling my framerates in the excellent game Battlefield: Bad Company 2 over the GTX 280 I had before.
I'm excited that a triple monitor setup is now, thanks to ATI, so easily attainable for desktop users -- as long as you're aware of the DisplayPort caveat I discussed above. I'd encourage anyone who is even remotely interested in the (many) productivity benefits of a triple monitor setup to seriously consider an ATI video card upgrade.
| [advertisement] JIRA Studio - Hosted software development suite. Build better software. Faster. Free trial » |
Writing code? That's the easy part. Getting your application in the hands of users, and creating applications that people actually want to use -- now that's the hard stuff.
I've been a long time fan of Krug's book Don't Make Me Think. Not just because it's a quick, easy read (and it is!) -- but because it's the most concise and most approachable book I've ever found to teach the fundamental importance of usability. As far as I'm concerned, if you want to help us make the software industry a saner place, the first step is getting Don't Make Me Think in the hands of as many of your coworkers as you can. If you don't have people that care about usability on your project, your project is doomed.
Beyond getting people over the hurdle of at least paging through the Krug book, and perhaps begrudgingly conceding that this usability stuff matters, the next challenge is figuring out how to integrate usability testing into your project. It's easy to say "Usability is Important!", but you have to walk the walk, too. I touched on some low friction ways to get started in Low-Fi Usability Testing. That rough outline is now available in handy, more complete book form -- Rocket Surgery Made Easy: The Do-It-Yourself Guide to Finding and Fixing Usability Problems.
Don't worry, Krug's book is just as usable as his advice. It's yet another quick, easy read. Take it from the man himself:
If you're wondering what the beginner's "how do I boil water?" recipe for software project usability is, stop reading this post and get a copy of Rocket Surgery Made Easy. Now.
One of the holy grails of usability testing is eyetracking -- measuring where people's eyes look as they use software and web pages. Yes, there are clever JavaScript tools that can measure where users move their pointers, but that's only a small part of the story. Where the eye wanders, the pointer may not, and vice-versa. But, who has the time and equipment necessary to conduct an actual eyetracking study? Almost nobody.
That's where Eyetracking Web Usability comes in.
Eyetracking Web Usability is chock full of incredibly detailed eyetracking data for dozens of websites. Even though you (probably) can't afford to do real eyetracking, you can certainly use this book as a reference. There is enough variety in UI and data that you can map the results, observations, and explanations found here to what your project is doing.
This particular book is rather eyetracking specific, but it's just the latest entry in a whole series on usability, and I recommend them all highly. These books are a fount of worthwhile data for anyone who works on software and cares about usability, from one of the most preeminent usability experts on the web.
Usability isn't really cheap or easy. It's an endless war, with innumerable battlegrounds, stretching all the way back to the dawn of computing. But these books, at least, are cheap and easy in the sense that they give you some basic training in fighting the good (usability) fight. That's the best I can do, and it's all I'd ask from anyone else I work with.
| [advertisement] JIRA Studio - Hosted software development suite. Build better software. Faster. Free trial » |
Need to hire a really great programmer? Want a job that doesn't drive you crazy? Visit the Joel on Software Job Board: Great software jobs, great people.
We’ve been opening new Stack Exchanges left and right on a variety of topics. In almost every case, the Stack Exchange appears to duplicate the content of an existing community. For example, our WordPress answers site (now in beta) covers the exact same material as WordPress.org’s existing forums.
This is nothing new to us at Stack Overflow, which purported to cover the exact same material as hundreds (if not thousands) of other programming sites. There’s no rule that says that there needs to be exactly one Q&A website per topic.
There is, however, a compelling case for the Stack Exchange technology. WordPress.org’s forums don’t have voting, so you have to read through every answer and decide for yourself which one might solve your problem. They don’t have reputation, so there’s no way to see whether you’re getting an answer from someone who knows what they’re talking about. They don’t have wiki-style editing, so collaboration is impossible. You have to log on to ask or answer a question, so the burden of participation is higher. Stack Overflow is simply better than traditional forums, which is why it largely replaced proprietary forums. I remember hours of discussion with John Resig and the folks at jQuery who couldn’t decide whether to replace the jQuery Google Group with a forum or with a Stack Exchange. Ultimately it didn’t matter that much, because most of the jQuery Q&A activity happens on Stack Overflow anyway.
One day, the features that are standard on Stack Exchange will be copied everywhere. Until then, we’ll keep churning out new sites.
Need to hire a really great programmer? Want a job that doesn't drive you crazy? Visit the Joel on Software Job Board: Great software jobs, great people.
Sometimes I think a pretty good business model would be to copy the applications that 37signals makes, but make them more complex. More features, more promises—generally, just more complicated.
Here’s the video from a talk I gave at the Business of Software conference last year:
I’ll be speaking again at this year’s conference in Boston, October 4th-6th.
Need to hire a really great programmer? Want a job that doesn't drive you crazy? Visit the Joel on Software Job Board: Great software jobs, great people.
We launched three new Stack Exchange sites this week!
We’ll have three more for you next week, too.
Need to hire a really great programmer? Want a job that doesn't drive you crazy? Visit the Joel on Software Job Board: Great software jobs, great people.
“We decided that individually-branded sites felt more authentic and trustworthy. We thought that letting every Stack Exchange site have its own domain name, visual identity, logo, and brand would help the community feel more coherent. After all, nobody wants to say that they live in Housing Block 2938TC. They want to live in Colonial Manor. Never mind the connotation of, well, colonies.”
Need to hire a really great programmer? Want a job that doesn't drive you crazy? Visit the Joel on Software Job Board: Great software jobs, great people.
Want to know how to export mail from Gmail? Or delete your Facebook account? Or send giant files via email?
Well, the new Web Applications Stack Exchange is for you. It’s a part of the Stack Exchange network, so it has the clean, elegant design that made Stack Overflow a phenomenal success.
The newest member of the Stack Exchange Network is the first one to go through the community site-creation process called Area 51. There are more great sites in the pipeline, but they have to demonstrate that they can reach critical mass or we won’t create them.
Need to hire a really great programmer? Want a job that doesn't drive you crazy? Visit the Joel on Software Job Board: Great software jobs, great people.
Neil has posted a video of Don Norman (most famous for his book The Design of Everyday Things) speaking at the Business of Software conference last year in San Francisco.
“Imagine you’re on the first slide of your powerpoint presentation and want to move to the next slide. Your remote control has two buttons. They are unmarked, but one button points up and one button points down.
“Which button do you press?”
It turns out half the people press up, half the people press down, and everybody thinks their choice is obvious. It’s a great talk.
The early bird discount for the Business of Software 2010 (Boston, October 4-6) saves you $400, but it expires this week, so this is the right time to sign up for my favorite conference.
Need to hire a really great programmer? Want a job that doesn't drive you crazy? Visit the Joel on Software Job Board: Great software jobs, great people.
Here's how most folks use the Web. You get a link in email, Twitter, Facebook, IM, whatever and you open it in a new tab.
Then, at some point in your copious free time, and possibly while reading other more pressing things, you'll read these 43 tabs, right? Even better, some of the articles are 8 pages long so you'll load up pages 1-4 and 6 and you don't even know why.
Then, maybe your browser crashes or your system reboots or something locks up or you get confused as to why you wanted to read that in the first place.
This is not cool and I refuse to use the web in this way anymore. Here's what I do.
Consider this new workflow. You'll either Read It Now or Read It Later.
Whenever you find something long that you KNOW you want to read but you just don't have time now, don't open a tab. Save it to Instapaper. I've got a bookmarklet for Instapaper in my bookmark bar on all my computers in all my browsers. This important, hence the bold.
If it's not setup on all your machines in any browser where you might find content, you'll fall back to old habits and not use it. Take the 10 minutes and do it. The bookmarklet even works from within Google Reader. Anywhere you find stuff you want to read later. You can even have your Instapaper queue sent over to your Kindle if it makes you happy.
Lets say I see this article by Phil Haack tweeted. I visit the page and while it looks interesting, he's SO loquacious and I'm busy now. I'll read it later.
I'll click "Read Later" in my bookmarks bar, and I see this notification.
Fast forward some hours. I've got time and I've collected a few interesting bits that I'm looking forward to reading. I visit Instapaper and see this:
There's the articles I've saved lately, with new ones first. It knows what I've read, what I've starred and what's been articled.
Here's an interesting bit, while I can click the link for Phil and visit his site, I don't. I'll click "Text" for Phil's article using a filter. The Instapaper filter is a lot like Readability (more on that later) in that it removes the non-content parts of the article. It also adds a little bar at the top where I can select between readable fonts, change the width, font size and line spacing. Everything here is focused on text and making the content I'm consuming more soluble.
I can of course also read from my phone (I'm working on a Windows Phone 7 version) or whatever device makes me happy. It's the same queue.
Sometimes I want to read something right now, but the site I'm looking at is just too busy. Recently I wanted to read this article on overclocking my motherboard. However the site looked like Las Vegas.
I have another bookmarklet called Readability.
There it is...
And as Rob Conery likes to say pressing it "is like closing the car windows while driving on the freeway."
I find that the simple introduction of these two tools, Instapaper for Reading Later and Readability for Reading Now not only allow me to consume and collect MORE information than before, but I'm slightly less stressed out while I'm doing it. Goodbye 43 tabs.
I am broken, my friends. I've blogged before on:
Today I'm wearing a neck brace. Yes, I'm one of the "looks like they are suing someone" people. I hate those people and now I'm one of them.
I was totally fine, all was well, playing at the playground with 2 and 4 when I decided to do some chin-ups on the monkey bars. I can usually do ten good ones so I didn't think it was a big deal. I worked out like a fiend from age 15 to 25 so I thought I had some decent muscle maturity. Turns out that's not true and I'm tight as hell.
Sitting in front of a computer for the last 20+ years has broken me, my friends. I'm tense and some muscle in my neck ripped on chin-up #2 quite nicely. I dropped and haven't been able to move my head since Sunday. Now I'm doing physical therapy, chiropractic, exercises, stretching and generally being sad.
Fortunately Microsoft is pretty cool about this and only want to me to get my ass back to making money for the company get better, so they're getting me a desk that will be motorized and go up and down so I can sit AND stand while working.
I'm hoping this experience will be the kick in the head (and neck) that will get me back in shape. I'd hate it if I ran out of keystrokes.
Let this be a lesson to YOU, Dear Reader. Take breaks, stretch, make sure your desk area is setup ergonomically.
How do YOU keep your body, hands, back and neck from breaking down completely?
There's lots of info spread around on how to install various older versions of Ubuntu under various older versions of Virtual PC, but I didn't find any referring to the newish Ubuntu 10.4 and VPC on Win 7.
I did now find some useful command-line parameters in this blog post from Mark Wilson. I'm trying to make this post as complete as possible. If you have new or update or better info that is specific to the new changes in Ubuntu 10.4, let me know.
Here's what I did.
When you create a Hard Drive, create a Fixed one rather than a dynamic one. I find this is faster and can avoid some strange disk errors with Ubuntu and the VM. I saw some strangeness with dynamically expanding disks.
In the Settings for your VM, tell it that the DVD drive actually be the Ubuntu ISO that you downloaded.
Hit OK and start your VM.
IMPORTANT: When it starts booting, hit ESC when you see a blinking cursor, then you'll find yourself here. If you let it just boot without hitting ESC it'll start a bit, then give up.
Hit F6, then ESC. Then add vga=791 noreplace-paravirt at the end of the white command line so it looks like:
Hit Enter
You find yourself at a desktop...make sure that from Tools|Settings that your Network Card in the VM is attached to a REAL physical network card.
If you click in your VM, the mouse will be captured. You can get out with Ctrl+Alt+Left Arrow.
Double-Click Install Ubuntu and start the process using all the defaults.
Blah blah blah...
Wait a while...and IMPORTANT do not restart when it's done or you are screwed.
Instead, you need to make a few changes to make your new system bootable. Click "Continue Testing."
Now, go to the Places Menu in the top menu and click your File System. That will open up a disk browsing window with a GUID (yes, a GUID) in the title bar. You're going to need to type that, so get emotionally ready. You'll also want to rearrange the windows so you can open up a Terminal Window (from Applications, Accessories) and have the two near each other.
Now, open your Terminal. From Marks's blog, type:
sudo mount -o bind /dev /media/THATGUID/dev
sudo chroot /media/THATGUID/ /bin/bash
mount -t proc none /proc
nano /etc/default/grub
That last line will bring up a text editor.
From the text editor, change "quiet splash" to VGA=788 or one of the VGA codes from this table. Mark also recommends commenting outu GRUD_HIDDEN_TIMEOUT with a #. Oddly, while the codes for resolutions seem to work initially, X switches back to 800x600 when it starts.
| Depth | 800×600 | 1024×768 | 1152×864
|
1280×1024 | 1600×1200 |
| 8 bit | vga=771 | vga=773 | vga=353 | vga=775 | vga=796 |
| 16 bit | vga=788 | vga=791 | vga=355 | vga=794 | vga=798 |
| 24 bit | vga=789 | vga=792 | vga=795 | vga=799 |
Save with Ctrl-X, then run nano /etc/grub.d/10_linux from the terminal to edit one more file. Add noreplace-paravirt (remember that) after args="$4" like this:
Finally, run "update-grub" from the command line. NOW you can restart using the on-off button dealie on in the upper-right corner. I had to hit enter a few times in text mode to get it to finally restart. Ignore the error about Casper and just press enter.
At this point with Ubuntu 10.4 on Virtual PC:
Of course, using the Virtual Box virtualization tool works great with Ubuntu right out of the box and includes Virtual Additions that are custom to Linux and allow resizing, but I was (am) hoping to get this VPC thing working completely so I can stick with my one standard virtualization solution.
If you've solved any of these, specific to Ubuntu 10.4, then please let me know and I'll update this post.
UPDATE: Why my own MacGyver solution was brilliant in its horrible way, the folks over at World of VS have taken up the challenge and created a proper Visual Studio extension that you should use. I'll chat with them and get some details and maybe a write-up of how they did it. So, while I encourage you to enjoy my tale below, go get the World of VS Default Browser Switcher now!
I've heard and seen lots of complaints about how it's hard to set the default browser that Visual Studio launches when you launch a debug session for a website.
Folks spend time hunting around the Tools|Options dialog in Visual Studio looking for setting. They eventually realize it's not in there at all, but instead you have to right-click on an ASPX page within a Web Project and click "Browse With..."
From this dialog you can click Set Default, which is totally obvious, right my daimies? Um, no. This doesn't work for ASP.NET MVC people who use other view engines and might not even have a .ASPX file in their solution. Plus, it's slow and irritating. Sa da tay.
It IS interesting that I can add other browsers, like Google Chrome to this dialog via Add. Note that Google Chrome installs in C:\Users\Scott\appdata\Local\Google\Chrome\Application\chrome.exe which may not be c:\Program Files where you usually go hunting for these things.
Where is this browser information stored? That was my first question. Remember that your computer is NOT a black box. Even good programmers make this mistake and they "flip this switch and hope that light turns on" without confirming that the switch and the light are connected with good wire and they know how electricity works.
I can guess all day, or I can open up ProcMon and just see for myself. Seriously, learn how to use this freaking tool. You can flip light switches all day or you can just open up the wall and see the wires. If you know how to use Process Monitor competently, people of both sexes will immediately find you more attractive. It's true. I get all sorts of free Tacos and Chips when folks look can I run ProcMon like Keanu Reeves can look sad.
I fired ProcMon up set it to only show the devenv.exe process, and I took a chance and set 'contains browser' for the path. If this didn't work I'd open the flood gates and start sifting a bit. I could also have said 'highlight' things with the word browser if I liked.
I launch VS, open the Browse With dialog and sweet sassy mollassy. Look at all that good stuff.
Oh, fonts too small, let me zoom in.
Looks like we're reading values out of the registry at HKCU:\Software\Microsoft\VisualStudio\10.0\WebBrowser\ConfigTimestamp and...
...reading out of the browsers.xml file at C:\Users\Scott\AppData\Local\Microsoft\VisualStudio\10.0\browsers.xml.
What's in that file? I'm guessing XML with no schema, given it was probably 2003 when someone wrote this.
<?xml version="1.0"?>
<BrowserInfo>
<BrowserInfo>
<Browser>
<Name>Google Chrome</Name>
<Path>"C:\Users\Scott\AppData\Local\Google\Chrome\Application\chrome.exe"</Path>
<Resolution>0</Resolution>
<IsDefault>False</IsDefault>
</Browser>
</BrowserInfo>
</BrowserInfo>
I've seen folks attempt to change this with various extensions in Visual Studio and using automation calls within Visual Studio, but to the best of my knowledge, this feature has been in here for years and years and there's no way to get at it programmatically.
Interestingly as well, my first attempt at changing the browser programmatically consisted of this brilliance:
C:\Users\Scott\AppData\Local\Microsoft\VisualStudio\10.0>copy "browsers - firefox.xml" browsers.xml /y
1 file(s) copied.
But, it seems that those registry keys are serious and really used for something, because each time I opened Browse With... I found my changes thrown away, probably because VS isn't watching for file for change notification, but rather caching the file in memory.
Looks like a job for PowerShell (yes, I know can do this with batch files, but PowerShell is way batter, so nyah. Learn it.)
First I need to figure out what's going on in this registry. If I got to that key (by right-clicking the key within ProcMon and clicking Jump To), then right-click on the key in the Registry Editor I get:
Windows Registry Editor Version 5.00
[HKEY_CURRENT_USER\Software\Microsoft\VisualStudio\10.0\WebBrowser\ConfigTimestamp]
"CacheFilePath"="C:\\Users\\Scott\\AppData\\Local\\Microsoft\\VisualStudio\\10.0\\browsers.xml"
"CacheFileSizeBytes"=dword:000000e6
"CacheFileDateLastMod"=hex(b):6f,18,a4,ee,17,41,cb,01
"LastConfigurationTimestamp"=hex(b):00,26,aa,86,09,41,cb,01
Ok, so that's the location of the file we already know about, and looks like the file size in hex, as well as some magic goo for CacheFileDateLastMod and LastConfigurationTimestamp.
One at a time. The CacheFileSizeBytes is easy. Did you know that the Windows 7 calculator was quietly upgraded while you were out there not learning how to convert hex in your head? It's true! (Yes, you can also just look at the decimal value in the Registry, but again, this is more fun. Yes, you could always convert between Hex and Dec in calc.exe, but again, fun. What's your beef? ;) )
Click Dec(imal) and looks like 230 bytes, the size of my browser.xml file. What's the deal with those mod dates, though? They a probably a Windows file time, if they aren't ticks. Ticks are seconds since 1970-1-1 and a Windows FileTime is the number of 100-nanosecond ticks since 1601-1-1 rounded to the nearest millisecond. Why? Because 1601 was an awesome year. I mean, the Battle of Kinsale stopped the siege in Kinsale, Ireland, and famine killed half the Estonians. Sheesh, that was a horrible year! What were we thinking!?
Anyway, the easiest way to convert something you think might be a Date into a Date (and reason number 0x3b for you to finally learn PowerShell) is this line in PowerShell.
PS C:\> [DateTime]129268523480000000
Saturday, August 21, 0410 8:19:08 AM
Lemme do that again against a blue background with a screenshot so you really believe me.
Oh yes, I'm on a horse. Cool. Those are FileTimes. So, tappity tappity and here's a PowerShell script to check the current values and output them for testing.
cd C:\Users\Scott\AppData\Local\Microsoft\VisualStudio\10.0
$browsers = [xml](get-content 'browsers.xml')
$browsers.BrowserInfo.Browser.Name + " " + $browsers.BrowserInfo.Browser.Path
$regkey = "HKCU:\Software\Microsoft\VisualStudio\10.0\WebBrowser\ConfigTimestamp"
"LastConfigTimestamp: " + ([DateTime](get-itemproperty $regkey).LastConfigurationTimestamp).ToLocalTime()
"CacheFileDateLastMod: " + ([DateTime](get-itemproperty $regkey).CacheFileDateLastMod).ToLocalTime()
"CacheFileSizeBytes: " + (get-itemproperty $regkey).CacheFileSizeBytes
I'll go and develop and run this script in the PowerShell ISE (that's S for Scripting) that you already have on your computer. Freaky how Microsoft sneaks stuff like this on your machine. If you've got Windows 7, you're already got this.
I run Visual Studio and click Browse|With... a few times and watch the values change. Seems I need the SET to my GET script, so why not something like this. I've made copies of browsers.xml like browsers-chrome and browsers-firefox. You can do the same if you like.
cd C:\Users\Scott\AppData\Local\Microsoft\VisualStudio\10.0
copy '.\browsers - firefox.xml' .\browsers.xml
$regkey = "HKCU:\Software\Microsoft\VisualStudio\10.0\WebBrowser\ConfigTimestamp"
set-itemproperty $regkey -name LastConfigurationTimestamp -value (&{[DateTime]::Now.ToUniversalTime().ToFileTime()}) -type qword
set-itemproperty $regkey -name CacheFileDateLastMod -value (&{((dir .\browsers.xml).LastWriteTimeUtc).ToFileTime()}) -type qword
set-itemproperty $regkey -name CacheFileSizeBytes -value (&{(dir .\browsers.xml).Length}) -type dword
What I am doing in this script? I'm copying my browser xml over the main one AND I'm updating the TimeStamp to now to get Visual Studio to re-read the file. Visual Studio seems to be checking and triple checking and if the CacheFileDateLastMod and CacheFileSizeBytes don't reflect reality, it will freak out and just delete my file completely and rebuild a new browsers.xml from scratch. Paranoid.
You can go and fancy these scripts up with command-line parameters all you want because you're a better programmer than I, but I am all Save|As, baby. I have "UpdateDefaultBrowserToChrome.ps1" and, yes, wait for it, "UpdateDefaultBrowserToFireFox.ps1" and I sleep at night just fine, thank you very much.
I can right click on them on my desktop and select Run with PowerShell if I like.
But...still....it could be more awesome. Darn my parents and the work ethic they instilled in me as a small child.
You can run PowerShell scripts from the regular not-really-DOS command line like this if you like.
C:\Users\Scott\Desktop>powershell .\UpdateDefaultVSBrowserToChrome.ps1
I could even install PowerConsole and run these commands from INSIDE Visual Studio 2010 if I like and I want to rip a hole in the space time continuum. My, is that intellisense inside PowerShell inside Visual Studio? Double sun power!!!!
Still, this doesn't fit my mindless point and click mouse-like workflow. I'll go to Tools | External Tools and add two. Make sure you select the right PowerShell, which will be x86 even if you're on x64 so you correctly access the registry. I also checked Use Output window and added a single line of text at the bottom of each script.
Nice, but why not a toolbar?
Right click on any Toolbar, this Customize and add buttons for External Tools (in my case #6 and #7) and...
Which gives me this when I click:
And shows this in Browse With, showing me it worked:
Yay! Enjoy.
cd C:\Users\YOURNAME\AppData\Local\Microsoft\VisualStudio\10.0
copy '.\browsers - CUSTOMBROWSER.xml' .\browsers.xml
$regkey = "HKCU:\Software\Microsoft\VisualStudio\10.0\WebBrowser\ConfigTimestamp"
set-itemproperty $regkey -name LastConfigurationTimestamp -value (&{[DateTime]::Now.ToUniversalTime().ToFileTime()}) -type qword
set-itemproperty $regkey -name CacheFileDateLastMod -value (&{((dir .\browsers.xml).LastWriteTimeUtc).ToFileTime()}) -type qword
set-itemproperty $regkey -name CacheFileSizeBytes -value (&{(dir .\browsers.xml).Length}) -type dword
"Bam, son. Browser changed to CUSTOM BROWSER."
Scott talks to Jeff Wilcox, a Developer on the Silverlight Team about developing on Windows Phone 7. What kinds of performance can we expect from the phone? Jeff Wilcox shows Scott some tips and tricks on how to get the smoothest animations from your phone. Frame Rate Counters and more fun are explained!
NOTE: If you want to download our complete archives as a feed - that's all 228 shows, subscribe to the Complete MP3 Feed here.
Download: MP3 Full Show
Do also remember the complete archives are always up and they have PDF Transcripts, a little known feature that show up a few weeks after each show.
Telerik is our sponsor for this show.
Building quality software is never easy. It requires skills and imagination. We cannot promise to improve your skills, but when it comes to User Interface and developer tools, we can provide the building blocks to take your application a step closer to your imagination. Explore the leading UI suites for ASP.NET AJAX,MVC,Silverlight,Windows Formsand WPF. Enjoy developer tools like .NET reporting,ORM,Automated Testing Tools, TFS, and Content Management Solution. And now you can increase your productivity with JustCode, Telerik’s new productivity tool for code analysis and refactoring. Visitwww.telerik.com.
As I've said before this show comes to you with the audio expertise and stewardship of Carl Franklin. The name comes from Travis Illig, but the goal of the show is simple. Avoid wasting the listener's time. (and make the commute less boring)
Enjoy. Who knows what'll happen in the next show?
Scott talks to Mike Calvo, a Microsoft Lead Developer based out of Minnesota (!) about Expression SuperPreview. SuperPreview helps developers and designers with cross-browser CSS and HTML issues. How'd they build it and with what? What's inside? How does the cloud fit in and how do they support Safari?
I played with SuperPreview a bit last year, but started looking at it again last month when I noticed that version 4 has introduced support for Safari on Mac via a Cloud-based Remote Service.
I fired up Expression SuperPreview 4, and saw this:
Then I signed up:
Which enabled Mac Safari for this initial beta. I assume they'll add a pile of other browsers. If I don't see immediate browser support for ALynx, the Amiga port of Unix/VMS Lynx browser, then Microsoft sucks and they don't care about the little guy!
So now I can compare DOM layouts between Windows FireFox 3.6 (on the left) and Safari 4 Mac (on the right). You can also compare between browsers and PhotoShop comps.
More details on how this works in this episode of the podcast!
NOTE: If you want to download our complete archives as a feed - that's all 227 shows, subscribe to the Complete MP3 Feed here.
Download: MP3 Full Show
Links from the Show
Do also remember the complete archives are always up and they have PDF Transcripts, a little known feature that show up a few weeks after each show.
Telerik is our sponsor for this show.
Hanselminutes podcasts listeners can get $50 off any Telerik product this summer. All interested listeners should drop an email to podcast@telerik.com and mention the Hanselminutes promo and their sales team will reply with the special $50-off coupon code.
Building quality software is never easy. It requires skills and imagination. We cannot promise to improve your skills, but when it comes to User Interface and developer tools, we can provide the building blocks to take your application a step closer to your imagination. Explore the leading UI suites for ASP.NET AJAX,MVC,Silverlight,Windows Formsand WPF. Enjoy developer tools like .NET reporting,ORM,Automated Testing Tools, TFS, and Content Management Solution. And now you can increase your productivity with JustCode, Telerik’s new productivity tool for code analysis and refactoring. Visitwww.telerik.com.
As I've said before this show comes to you with the audio expertise and stewardship of Carl Franklin. The name comes from Travis Illig, but the goal of the show is simple. Avoid wasting the listener's time. (and make the commute less boring)
Enjoy. Who knows what'll happen in the next show?
My two-hundred-and-twenty-sixth podcast is up. Scott catches up with Pete Brown after they've both built their "Ultimate Developer PCs." Any regrets? What'd they learn and how you can learn from their mistakes and successes?
UPDATE: Pete and I did a Skype call with Joel Barsotti and he guided me in the overclocking process and I was able to easily take the 3.33Ghz Intel i7 processor I have to 4.0Ghz, a free 20% speed gain while staying on air cooling. I'm sure I could take it beyond but I don't want to compromise stability. Is a short overclocking show or article something you all are interested in?
NOTE: If you want to download our complete archives as a feed - that's all 225 shows,subscribe to the Complete MP3 Feed here.
Download: MP3 Full Show
Links from the Show
Do also remember the complete archives are always up and they have PDF Transcripts, a little known feature that show up a few weeks after each show.
Telerik is our sponsor for this show.
Hanselminutes podcasts listeners can get $50 off any Telerik product this summer. All interested listeners should drop an email to podcast@telerik.com and mention the Hanselminutes promo and their sales team will reply with the special $50-off coupon code.
Building quality software is never easy. It requires skills and imagination. We cannot promise to improve your skills, but when it comes to User Interface and developer tools, we can provide the building blocks to take your application a step closer to your imagination. Explore the leading UI suites for ASP.NET AJAX,MVC,Silverlight,Windows Formsand WPF. Enjoy developer tools like .NET reporting,ORM,Automated Testing Tools, TFS, and Content Management Solution. And now you can increase your productivity with JustCode, Telerik’s new productivity tool for code analysis and refactoring. Visitwww.telerik.com.
As I've said before this show comes to you with the audio expertise and stewardship of Carl Franklin. The name comes from Travis Illig, but the goal of the show is simple. Avoid wasting the listener's time. (and make the commute less boring)
Enjoy. Who knows what'll happen in the next show?
I'm not usually one of the "icon people." By that I mean, I don't collect icons, or change all the icons on my system to custom fancypants icons. But, I noticed today that I was using the Command Prompt alongside a Visual Studio Command Prompt (which is just a command prompt with the right path and environment set) as well as regular PowerShell as well as a PowerShell prompt with "VSVars32" set (again, just PowerShell with the right environment setup). However, their icons all look the same.
Seemed like a quick opportunity to edit a few icons and change my world. I went over and downloaded the most lovely Free Icon Editor I know of, IcoFX. I encourage you to donate to them because they are doing the world a wonderful service. I used their Extract command on cmd.exe, as well as devenv.exe and powershell.exe.
Disclaimer: I'm sure I'm breaking all sorts of international law or something by doing this. When the ninjas burst in and say "you can't use our icons for fun" I will likely deny having written this post. Back me up on this. I did this for me. This is not official Microsoft anything and you can't say it is. Who are you!? Stop calling me! Jimmy no live here! You no call back!
Aside: Here's the part I'm bummed about. It seems that the VS2010 icon editor is still stupid about alpha channels. I'm actually scandalized about the whole thing, but since I don't work on that team, I'll need to dig in to get more details. I would have liked to have done this all in VS.
OK, so now I've got all my icons loaded in IcoFX. I will edit them all and make a nice icon in one of the many resolutions that are available, even though technically I suppose for my use I just need 32x32 icons for the Windows 7 Taskbar and/or my desktop.
A little editing and resizing...seriously, this Icon Editor is a joy. Go now!
I saved these as vscommand.ico and vspowershell.ico and now I have these two nice icons on my desktop.
Now I pin the "Visual Studio Command Prompt" to the Taskbar, and it looks like this:
I even did a little one for the system menu, 'cause that's how I roll.
OK, so that's lovely.
However, when I'm in PowerShell, I'll sometimes switch my VSVars on by running the custom PowerShell VSVars script that I put in my Microsoft.PowerShell_profile.ps1. Remember this one from Chris Tavares?
function Get-Batchfile ($file) {
$cmd = "`"$file`" & set"
cmd /c $cmd | Foreach-Object {
$p, $v = $_.split('=')
Set-Item -path env:$p -value $v
}
}
function VsVars32($version = "10.0")
{
$key = "HKLM:SOFTWARE\Microsoft\VisualStudio\" + $version
$VsKey = get-ItemProperty $key
$VsInstallPath = [System.IO.Path]::GetDirectoryName($VsKey.InstallDir)
$VsToolsDir = [System.IO.Path]::GetDirectoryName($VsInstallPath)
$VsToolsDir = [System.IO.Path]::Combine($VsToolsDir, "Tools")
$BatchFile = [System.IO.Path]::Combine($VsToolsDir, "vsvars32.bat")
Get-Batchfile $BatchFile
[System.Console]::Title = "Visual Studio " + $version + " Windows Powershell"
//add a call to set-consoleicon as seen below...hm...!
}
Why not go completely over the top and combine this with Aaron Lerch's script for "Changing the Windows PowerShell Console Icon"? This way, when I call "vsvars32" I'll also change the Icon for my PowerShell. Crazy.
Here's Aaron's script with a few changes to make it a dot-sourced function and a couple typo fixes. This changes the system menu icon on the fly, but doesn't refresh the taskbar or ALT-TAB yet. Not sure if that's possible?
##############################################################################
## Script: Set-ConsoleIcon.ps1
## By: Aaron Lerch, tiny tiny mods by Hanselman
## Website: www.aaronlerch.com/blog
## Set the icon of the current console window to the specified icon
## Dot-Source first, like . .\set-consoleicon.ps1
## Usage: Set-ConsoleIcon [string]
## PS:1 > Set-ConsoleIcon "C:\Icons\special_powershell_icon.ico"
##############################################################################
$WM_SETICON = 0x80
$ICON_SMALL = 0
function Set-ConsoleIcon
{
param(
[string] $iconFile
)
[System.Reflection.Assembly]::LoadWithPartialName("System.Drawing") | out-null
$iconFile
# Verify the file exists
if ([System.IO.File]::Exists($iconFile) -eq $TRUE)
{
$icon = new-object System.Drawing.Icon($iconFile)
if ($icon -ne $null)
{
$consoleHandle = GetConsoleWindow
SendMessage $consoleHandle $WM_SETICON $ICON_SMALL $icon.Handle
}
}
else
{
Write-Host "Icon file not found"
}
}
## Invoke a Win32 P/Invoke call.
## From: Lee Holmes
## http://www.leeholmes.com/blog/GetTheOwnerOfAProcessInPowerShellPInvokeAndRefOutParameters.aspx
function Invoke-Win32([string] $dllName, [Type] $returnType,
[string] $methodName, [Type[]] $parameterTypes, [Object[]] $parameters)
{
## Begin to build the dynamic assembly
$domain = [AppDomain]::CurrentDomain
$name = New-Object Reflection.AssemblyName 'PInvokeAssembly'
$assembly = $domain.DefineDynamicAssembly($name, 'Run')
$module = $assembly.DefineDynamicModule('PInvokeModule')
$type = $module.DefineType('PInvokeType', "Public,BeforeFieldInit")
## Go through all of the parameters passed to us. As we do this,
## we clone the user's inputs into another array that we will use for
## the P/Invoke call.
$inputParameters = @()
$refParameters = @()
for($counter = 1; $counter -le $parameterTypes.Length; $counter++)
{
## If an item is a PSReference, then the user
## wants an [out] parameter.
if($parameterTypes[$counter - 1] -eq [Ref])
{
## Remember which parameters are used for [Out] parameters
$refParameters += $counter
## On the cloned array, we replace the PSReference type with the
## .Net reference type that represents the value of the PSReference,
## and the value with the value held by the PSReference.
$parameterTypes[$counter - 1] =
$parameters[$counter - 1].Value.GetType().MakeByRefType()
$inputParameters += $parameters[$counter - 1].Value
}
else
{
## Otherwise, just add their actual parameter to the
## input array.
$inputParameters += $parameters[$counter - 1]
}
}
## Define the actual P/Invoke method, adding the [Out]
## attribute for any parameters that were originally [Ref]
## parameters.
$method = $type.DefineMethod($methodName, 'Public,HideBySig,Static,PinvokeImpl',
$returnType, $parameterTypes)
foreach($refParameter in $refParameters)
{
$method.DefineParameter($refParameter, "Out", $null)
}
## Apply the P/Invoke constructor
$ctor = [Runtime.InteropServices.DllImportAttribute].GetConstructor([string])
$attr = New-Object Reflection.Emit.CustomAttributeBuilder $ctor, $dllName
$method.SetCustomAttribute($attr)
## Create the temporary type, and invoke the method.
$realType = $type.CreateType()
$realType.InvokeMember($methodName, 'Public,Static,InvokeMethod', $null, $null,
$inputParameters)
## Finally, go through all of the reference parameters, and update the
## values of the PSReference objects that the user passed in.
foreach($refParameter in $refParameters)
{
$parameters[$refParameter - 1].Value = $inputParameters[$refParameter - 1]
}
}
function SendMessage([IntPtr] $hWnd, [Int32] $message, [Int32] $wParam, [Int32] $lParam)
{
$parameterTypes = [IntPtr], [Int32], [Int32], [Int32]
$parameters = $hWnd, $message, $wParam, $lParam
Invoke-Win32 "user32.dll" ([Int32]) "SendMessage" $parameterTypes $parameters
}
function GetConsoleWindow()
{
Invoke-Win32 "kernel32" ([IntPtr]) "GetConsoleWindow"
}
It might also be interesting to make a ".Icon" property on System.Console using PowerShell's "Type Extensions" abilities. That way I could do[System.Console]::Icon = "something.ico", but I'll leave that as an exercise for the reader.
Remember, we never spoke.
Do you like a big pile of source code? Well, there is an imperial buttload of source in the Visual Studio 2010 and .NET Framework 4 Training Kit. It's actually a 178 meg download, which is insane. Perhaps start your download now and get it in the morning when you get up. It's extremely well put together and I say Kudos to the folks that did it. They are better people than I.
I like to explore it while watching TV myself and found myself looking through tonight. I checked my blog and while I thought I'd shared this with you before, Dear Reader, I hadn't. My bad, because it's pure gold. With C# and VB, natch.
Here's an outline of what's inside. I've heard of folks setting up lunch-time study groups and going through each section.
| C# 4 | Visual Basic 10 |
| F# | Parallel Extensions |
| Windows Communication Foundation | Windows Workflow |
| Windows Presentation Foundation | ASP.NET 4 |
| Windows 7 | Entity Framework |
| ADO.NET Data Services (OData) | Managed Extensibility Framework |
| Visual Studio Team System | RIA Services |
| Office Development |
I love using this kit in my talks, and used it a lot in my Lap Around .NET 4 talk.
There's Labs, Presentations, Demos, Labs and links to online Videos. It'll walk you step by step through loads of content and is a great starter if you're getting into what's new in .NET 4.
Here's a few of my favorite bits, and they aren't the parts you hear the marketing folks gabbing about.
Remember the old coding adage to "Assert Your Expectations?" Well, sometimes Debug.Assert is either inappropriate or cumbersome and what you really need is a method contract. Methods have names and parameters, and those are contracts. Now they can have conditions like "don't even bother calling this method unless userId is greater than or equal to 0 and make sure the result isn't null!
Code Contracts continues to be revised, with a new version out just last month for both 2008 and 2010. The core types that you need are included in mscorlib with .NET 4.0, but you do need to download the tools to see them inside Visual Studio. If you have VS Pro, you'll get runtime checking and VS Ultimate gets that plus static checking. If I have static checking and the tools I'll see a nice new tab in Project Properties:
I can even get Blue Squigglies for Contract Violations as seen below.
As a nice coincidence, you can go and download Chapter 15 of Jon Skeet's C# in Depth for free which happens to be on Code Contracts.
Here's a basic idea of what it looks like. If you have static analysis, you'll get squiggles on the lines I've highlighted as they are points where the Contract isn't being fulfilled. Otherwise you'll get a runtime ContractException. Code Contracts are a great tool when used in conjunction with Test Driven Development.
using System;
using System.Collections.Generic;
using System.Text;
using System.Diagnostics.Contracts;
namespace ContractsDemo
{
[ContractVerification(true)]
class Program
{
static void Main(string[] args)
{
var password = GetPassword(-1);
Console.WriteLine(password.Length);
Console.ReadKey();
}
#region Header
/// <param name="userId">Should be greater than 0</param>
/// <returns>non-null string</returns>
#endregion
static string GetPassword(int userId)
{
Contract.Requires(userId >= 0, "UserId must be");
Contract.Ensures(Contract.Result<string>() != null);
if (userId == 0)
{
// Made some code to log behavior
// User doesn't exist
return null;
}
else if (userId > 0)
{
return "Password";
}
return null;
}
}
}
I did a lot of COM Interop back in the day and it sucked. It wasn't fun and you always felt when you were leaving managed code and entering COM. You'd have to use Primary Interop Assemblies or PIAs and they were, well, PIAs. I talked about this a little bit last year in Beta 1, but it changed and got simpler in .NET 4 release.
Here's a nice little sample I use from the kit that gets the Processes on your system and then makes a list with LINQ of the big ones, makes a chart in Excel, then pastes the chart into Word.
If you've used Office Automation from managed code before, notice that you can say Range[] now, and not get_range(). You can call COM methods like ChartWizard with named parameters, and without including Type.Missing fifteen times. As an aside, notice also the default parameter value on the method.
static void GenerateChart(bool copyToWord = false)
{
var excel = new Excel.Application();
excel.Visible = true;
excel.Workbooks.Add();
excel.Range["A1"].Value2 = "Process Name";
excel.Range["B1"].Value2 = "Memory Usage";
var processes = Process.GetProcesses()
.OrderByDescending(p => p.WorkingSet64)
.Take(10);
int i = 2;
foreach (var p in processes)
{
excel.Range["A" + i].Value2 = p.ProcessName;
excel.Range["B" + i].Value2 = p.WorkingSet64;
i++;
}
Excel.Range range = excel.Range["A1"];
Excel.Chart chart = (Excel.Chart)excel.ActiveWorkbook.Charts.Add(
After: excel.ActiveSheet);
chart.ChartWizard(Source: range.CurrentRegion,
Title: "Memory Usage in " + Environment.MachineName);
chart.ChartStyle = 45;
chart.CopyPicture(Excel.XlPictureAppearance.xlScreen,
Excel.XlCopyPictureFormat.xlBitmap,
Excel.XlPictureAppearance.xlScreen);
if (copyToWord)
{
var word = new Word.Application();
word.Visible = true;
word.Documents.Add();
word.Selection.Paste();
}
}
You can also embed your PIAs in your assemblies rather than carrying them around and the runtime will use Type Equivalence to figure out that your embedded types are the same types it needs and it'll just work. One less thing to deploy.
The #1 reason, IMHO, to look at .NET 4 is the parallelism. I say this not as a Microsoft Shill, but rather as a dude who owns a 6-core (12 with hyper-threading) processor. My most favorite app in the Training Kit is ContosoAutomotive. It's a little WPF app that loads a few hundred thousand cars into a grid. There's an interface, ICarQuery, that a bunch of plugins implement, and the app foreach's over the CarQueries.
This snippet here uses the new System.Threading.Task stuff and makes a background task. That's all one line there, from StartNew() all the way to the bottom. It says, "do this chunk in the background." and it's a wonderfully natural and fluent interface. It also keeps your UI thread painting so your app doesn't freeze up with that "curtain of not responding" that one sees all the time.
private void RunQueries()
{
this.DisableSearch();
Task.Factory.StartNew(() =>
{
this.BeginTiming();
foreach (var query in this.CarQueries)
{
if (this.searchOperation.Token.IsCancellationRequested)
{
return;
}
query.Run(this.cars, true);
};
this.EndSequentialTiming();
}, this.searchOperation.Token).ContinueWith(_ => this.EnableSearch());
}
StartNew() also has a cancellation token that we check, in case someone clicked Cancel midway through, and there's a ContinueWith at the end that re-enables or disabled Search button.
Here's my system with the queries running. This is all in memory, generating and querying random cars.
And the app says it took 2.3 seconds. OK, what if I do this in parallel, using all the processors?
Here's the changed code. Now we have a Parallel.ForEach instead. Mostly looks the same.
private void RunQueriesInParallel()
{
this.DisableSearch();
Task.Factory.StartNew(() =>
{
try
{
this.BeginTiming();
var options = new ParallelOptions() { CancellationToken = this.searchOperation.Token };
Parallel.ForEach(this.CarQueries, options, (query) =>
{
query.Run(this.cars, true);
});
this.EndParallelTiming();
}
catch (OperationCanceledException) { /* Do nothing as we cancelled it */ }
}, this.searchOperation.Token).ContinueWith(_ => this.EnableSearch());
}
This code says "go do this in a background thread, and while you're there, parallelize this as you like." This loop is "embarrassingly parallel." It's a big for loop over 2 million cars in memory. No reason it can't be broken apart and made faster.
Here's the deal, though. It was SO fast, that Task Manager didn't update fast enough to show the work. The work was too easy. You can see it used more CPU and that there was a spike of load across 10 of the 12, but the work wasn't enough to peg the processors.
Did it even make a difference? Seems it was 5x faster and went from 2.389s to 0.4699 seconds. That's embarrassingly parallel. The team likes to call that "delightfully parallel" but I prefer "you're-an-idiot-for-not-doing-this-in-parallel parallel," but that was rejected.
Let's try something harder. How about a large analysis of Baby Names. How many Roberts born in the state of Washington over a 40 year period from a 500MB database?
Here's the normal single-threaded foreach version in Task Manager:
Here's the parallel version using 96% CPU.
And here's the timing. Looks like the difference between 20 seconds and under 4 seconds.
You can try this yourself. Notice the processor slider bar there at the bottom.
ProcessorsToUse.Minimum = 1;
ProcessorsToUse.Maximum = Environment.ProcessorCount;
ProcessorsToUse.Value = Environment.ProcessorCount; // Use all processors.
This sample uses "Parallel LINQ" and here's the two queries. Notice the "WithDegreeofParallelism."
seqQuery = from n in names
where n.Name.Equals(queryInfo.Name, StringComparison.InvariantCultureIgnoreCase) &&
n.State == queryInfo.State &&
n.Year >= yearStart && n.Year <= yearEnd
orderby n.Year ascending
select n;
parQuery = from n in names.AsParallel().WithDegreeOfParallelism(ProcessorsToUse.Value)
where n.Name.Equals(queryInfo.Name, StringComparison.InvariantCultureIgnoreCase) &&
n.State == queryInfo.State &&
n.Year >= yearStart && n.Year <= yearEnd
orderby n.Year ascending
select n;
The .NET 4 Training Kit has Extensibility demos, and Office Demos and SharePoint Demos and Data Access Demos and on and on. It's great fun and it's a classroom in a box. I encourage you to go download it and use it as a teaching tool at your company or school. You could do brown bags, study groups, presentations (there's lots of PPTs), labs and more.
Hope you enjoy it as much as I do.
My two-hundred-and-twenty-fifth podcast is up. Scott chats with Jason Dentler about NHibernate and their new 3.0 release. Jason is the author of the upcoming "NHibernate 3 Cookbook" from Packt Publishing. Is NHibernate hard and scary? Jason gets Scott up to speed and talks open source community.
NOTE: If you want to download our complete archives as a feed - that's all 225 shows,subscribe to the Complete MP3 Feed here.
Download: MP3 Full Show
Links from the Show
Do also remember the complete archives are always up and they have PDF Transcripts, a little known feature that show up a few weeks after each show.
Telerik is our sponsor for this show.
Hanselminutes podcasts listeners can get $50 off any Telerik product this summer. All interested listeners should drop an email to podcast@telerik.com and mention the Hanselminutes promo and their sales team will reply with the special $50-off coupon code.
Building quality software is never easy. It requires skills and imagination. We cannot promise to improve your skills, but when it comes to User Interface and developer tools, we can provide the building blocks to take your application a step closer to your imagination. Explore the leading UI suites for ASP.NET AJAX,MVC,Silverlight,Windows Formsand WPF. Enjoy developer tools like .NET reporting,ORM,Automated Testing Tools, TFS, and Content Management Solution. And now you can increase your productivity with JustCode, Telerik’s new productivity tool for code analysis and refactoring. Visitwww.telerik.com.
As I've said before this show comes to you with the audio expertise and stewardship of Carl Franklin. The name comes from Travis Illig, but the goal of the show is simple. Avoid wasting the listener's time. (and make the commute less boring)
Enjoy. Who knows what'll happen in the next show?
Bookmark and Share this page