tag:blogger.com,1999:blog-65797722402672883672024-02-07T07:48:35.419-05:00kwblogExperiments in Software EngineeringKevin Berridgehttp://www.blogger.com/profile/13759114853595462455noreply@blogger.comBlogger228125tag:blogger.com,1999:blog-6579772240267288367.post-64142083507585843872018-01-26T00:02:00.003-05:002018-01-26T00:02:43.453-05:00New Blog!After nearly 11 years I've finally built my own blog and am leaving this blog and Blogger behind. <br />
<br />
The new blog is at <a href="http://www.kevinberridge.com/">www.kevinberridge.com</a>, and I wrote about the switch in <a href="https://www.kevinberridge.com/posts/20180125-new-blog">the first post on the new blog</a>.<br />
<br />
It's been fun Blogger, thanks for everything.Kevin Berridgehttp://www.blogger.com/profile/13759114853595462455noreply@blogger.com0tag:blogger.com,1999:blog-6579772240267288367.post-86988525647068102312016-02-03T11:13:00.000-05:002016-02-03T11:13:03.847-05:00HG: What Changesets Are Not In This Tag?I still love Mercurial. You git people can pry it from my cold dead hands!<br />
<br />
Mercurial has a search feature called revsets (hg help revsets) which is a simple and powerful query language for searching the changeset history graph. I probably don't use it as often as I should, instead wasting time scrolling through the thg graph hunting for things or following branch lines. But I did use it today and thought I'd share.<br />
<br />
We have a release branch and we tag changesets with version numbers when we release. We're in a rather unusual period of chaos at the moment which had led to changesets on the release branch that had not been included in the last tagged release because the release was done from an anonymous head. As a result, it was hard to know exactly what changesets were not included in that tag. Enter revsets:<br />
<br />
hg sl -r "sort(branch(release) and not ancestors(tag-name) and not merge(), -rev)"<br />
<br />
This gets all changesets on the release branch which are <b>not</b> an ancestor of the given tag (AKA were not included in the release represented by that tag) and are <b>not</b> a merge changeset sorted by revision number descending.Kevin Berridgehttp://www.blogger.com/profile/13759114853595462455noreply@blogger.com0tag:blogger.com,1999:blog-6579772240267288367.post-20280156387497461962015-01-26T07:00:00.000-05:002015-01-26T07:00:03.954-05:00Why We Write TestsSoftware Testing is ubiquitous these days. It seems that every software development book has at least one section about testing. Every conference seems to have a testing track. And for what it's worth most of the developers I know are writing tests too. Not all of them, sadly, but most of them!<br />
<br />
But even with all this activity and talking around testing, I still find myself troubled by whether I'm using them "right." As simple as testing seems at first glance, it’s a big subject. There are all these contentious arguments about how it should be done. From what kinds of tests we should write, to when we should write them, to exactly how they should be written. It's easy to be overwhelmed by these details and lose sight of what is important, causing bad decisions to be made, or time to be wasted on issues that might not be so important in the big scheme of things.<br />
<br />
A clear understanding of the motivations of a technique, like testing, can keep the focus on what matters and can guide a good application of the technique to a specific scenario. And this can shed some light on why other people's opinions and practice might differ due to their different context.<br />
<br />
In the case of testing, I think we can summarize the motivations of the technique by asking a very simple question: why do we write tests?<br />
<br />
<h3>
<b>Why do we write tests?</b></h3>
To start with, I should be very clear that I'm talking about developers here. I am not talking about why a separate QA department might write tests. If you work in an environment with a separate test-writing QA department, it may change some of the algebra of how you approach testing, and certainly the QA people themselves will have very different motivations from the developers. But none of that will change the major motivations and benefits for why developers write tests. Which serves as a great example of why understanding the underpinning motivations is so important!<br />
<br />
OK great! So why do developers write tests?<br />
<br />
Because. Because people say we should. And for a lot of people, I think “because” is the only reason they’ve ever been given. But there are reasons, and chief among them is this:<br />
<blockquote class="tr_bq">
<div class="p1">
<b>"The true purpose of testing, just like the true purpose of design, is to reduce costs."</b><sup>1</sup></div>
</blockquote>
Testing, done well, makes software development take less time, thereby reducing the costs of development. But this is really surprising, isn't it? How could adding the work of testing possibly make development take less time? Especially given that the #1 excuse I hear for why people don't test is because they think they don't have time for it! Which does make sense, after all writing tests necessarily means writing more code. By some estimates up to 2 lines of test code for every 1 line of production code! That is a lot more code! And even given the fact that lines of code is a horrible metric, that still represents a significant amount of extra work.<br />
<br />
<h3>
How could testing reduce development cost?</h3>
There are, in fact, a lot of productivity benefits that developers derive from having and writing tests. I want to just quickly summarize a few of them before we get to the really big one. The first is this: "Fixing bugs early always lowers costs."<sup>1 </sup>When a developer is "in the zone" with some code, it takes significantly less time to track down and fix issues. So if tests can help us find issues when we're in the zone, that's a great time savings. And, of course, finding a bug before it gets into production is a HUGE time savings to the organization as a whole.<br />
<br />
The next reason is really simple. Automated tests can save you a lot of time and be more effective than manual tests alone. They don't replace manual tests, but automated tests can take some of the regression testing burden off of the manual testers, saving the whole team time. Plus automated tests can be run faster and more often, providing feedback more quickly. And you can also write automated tests for things that may be impossible to test manually, like error conditions, helping you find bugs earlier. <br />
<br />
Tests can also serve as documentation of code, helping us to understand existing code faster and to work with it more effectively. And along these same lines, tests can be used like an experiment to prove how some code <i>actually</i> works, saving on time spent mentally reasoning about how it <i>should</i> work and cutting straight to the chase.<br />
<br />
Another big and commonly cited reason is that writing tests helps cut down on the amount of time we spend debugging. Debugging is awful. Once you have to fire up a debugger there is absolutely no way to know how long you'll be at it. But people who write tests have experienced how much less time needs to be spent in the debugger. And the time that does need to be spent seems lessened partly because tests localize the area of code that might have the problem.<br />
<br />
All of these are ways that writing and having tests helps lower the costs of development. But probably the most important way tests help lower the cost of development is this: <b>confidence</b>. You might think we're talking about confidence in the correctness or quality of code, and that's part of it, but it's not the biggest part. The biggest part is actually that we have confidence to change the code! Why would this be so important?<br />
<br />
<h3>
Software rot</h3>
Software rot is the phenomenon where by code gets worse as time goes on. If you've worked for any kind of duration on a project you've doubtless experienced it. But why does our software rot like this? The simple answer is because we so often fail to refactor.<br />
<br />
Refactoring code is important, and yes, I know that this is not earth shattering news. But I feel like we often think of refactoring as this thing we do later. Like, once things get bad enough, we can always come back and refactor. But that's not right. That kind of thinking just makes software rot faster!<br />
<br />
When we have big changes to make, the need to refactor is obvious. But it's when the changes we're making are small that we really get into trouble! The small changes are the ones that we shoe horn into the code. "I'll just add an if statement here" we think, "It makes it work, what's the harm?" <br />
<br />
What's the harm? Software rot! That is software rot happening right before your eyes. Those seemingly small changes have a tendency to compound, rendering the code unintelligible. And in addition, surprisingly often, the small changes represent a major shift in the appropriate design. But even if we are aware of this, we ignore it. Why?<br />
<br />
We ignore it because we're trying to get the feature done so we can move on to the next thing. We're trying to be productive! Little realizing we are shooting ourselves in the foot. But we also ignore it because we think it's safer to change the code as little as possible. We have learned to avoid making "invasive" changes to code because we've seen even the simplest of changes break stuff. We've internalized this fear of change. And that's why we shoe horn in changes, but of course this inevitably leads to software rot!<br />
<br />
And rotten code just makes us more afraid, which leads us to shoe horn in more changes, leading to even more rotten code, and around and around we go!<br />
<br />
Which finally brings us back to confidence. What we need to break out of this destructive loop is the confidence to make those "invasive" code and design changes. Because if we don't have that confidence we wont make the kind of code changes that we absolutely need to make to prevent our code from rotting!<br />
<br />
<h3>
So, why do we write tests?</h3>
Because tests are the best and cheapest tool that we have to manage fear and replace it with confidence, so that we can and will refactor, so that our code doesn't rot, so that we can build software faster, indefinitely.<br />
<br />
When we have tests, we know we can change code. Because if something goes wrong, the tests will tell us right away. We can refactor constantly, working to keep the code as simple and communicative as possible at all times. If something goes wrong, the tests will tell us right away. We can shoe horn in changes, but then we can take that next critical step of refactoring the design to reflect it's new requirements! If something goes wrong, the tests will tell us right away. We can experiment with new names or new class structures and see what works best. If something goes wrong, the tests will tell us right away. We can truly live the Boy Scout rule, leaving code cleaner than it was when we found it. And if something goes wrong, the tests will tell us right away.<br />
<br />
And all of this will mean that our code is as intention revealing and simple as possible. And in a code base like that, we can quickly respond to new feature requests and surprising bugs. We can take on enhancements and incorporate new ideas that with a rotted code base we would probably have had to say no to. And that means not only are we delivering features and enhancements faster, we're building a better product too! This is the promise of tests, and it's the ultimate motivation for why developers write tests.<br />
<br />
<hr />
1. Practical Object-Oriented Design in RubyKevin Berridgehttp://www.blogger.com/profile/13759114853595462455noreply@blogger.com0tag:blogger.com,1999:blog-6579772240267288367.post-39572771813913369352014-10-01T12:54:00.000-04:002015-01-25T20:34:58.593-05:00Coming Soon To CodeMash: The Cartography of Testing<div>
Last year I had the amazing experience of giving my <a href="http://www.kevinberridge.com/2014/04/oop-youre-doing-it-completely-wrong.html" target="_blank">OOP: You're Doing It Completely Wrong</a> talk to a standing room only crowd at <a href="http://www.codemash.org/" target="_blank">CodeMash </a>(and later at Stir Trek). It was a crazy experience standing at the side of the room and watching people come in, my reaction going from, "oh this is a good crowd" to "wow, this a big crowd" to "holy crap!!!". </div>
<div style="font-family: Calibri; font-size: 11.0pt; margin: 0in;">
<br /></div>
<div style="margin: 0in;">
<div>
The idea for the OOP talk came from a question I found myself asking a lot, which was basically, "I know what objects are, but am I using them <i>right</i>"? Then I went and did a bunch of research and tried to coalesce all that into a coherent presentation of OO. So when I set out to think of a talk for this year I found myself starting in a similar place, but this time thinking about testing. The question is basically, "I know what tests are, but am I using them <i>right</i>?" Testing is such a big and contentious subject that I was pretty nervous to tackle it, but I like the idea that you should give the talk you wish you could attend. So I wrote it up, and CodeMash accepted it, and here's the abstract for my talk at CodeMash this year!</div>
<div>
<br /></div>
<span><b>The Cartography of Testing</b></span><br />
<span>Imagine diagramming your application like a map. The methods might be like cities and the classes like states. The more coupled two methods or classes are, the closer their cities or states may be to each other. Let's spread this map out before us and ask, "how do we best deploy our tests across this landscape"? There are many different kinds of test (unit, acceptance, etc.), each serving a different purpose. What mix of these will best cover the terrain? Well positioned tests can give us confidence in our code, document business rules, support refactoring, and make building new features easier. But poorly positioned tests can just as easily undermine all these goals. How do you find the right balance and test deployment strategy for your application's landscape? In this talk, we will look at the trade-offs in the different kinds of tests and survey recommendations for deploying them effectively.</span><br />
<span><br /></span>
<span>Hope to you see at the Kalahari in January!</span></div>
Kevin Berridgehttp://www.blogger.com/profile/13759114853595462455noreply@blogger.com0tag:blogger.com,1999:blog-6579772240267288367.post-13093763074884782552014-08-22T12:18:00.000-04:002015-01-25T20:55:31.664-05:00Unit Testing QuestionHi there. I have a question for you. I'm looking for some articles/papers/blogs/talks about Unit Testing at the right level of granularity. Could you send me some links?<br />
<br />
Let me try to explain what I mean. I've noticed that when you write what I'll call <a href="http://www.kevinberridge.com/2014/04/oop-youre-doing-it-completely-wrong.html">"good OO"</a> (for the sake of simplicity) you tend to end up with individual objects which on their own don't do that much. Instead the behavior that you care about emerges from the way in which the objects are composed together. And this poses an interesting problem for unit testing.<br />
<br />
If I define a unit as a single object, then I will write tests for each of those little objects and I'll mock/stub/fake out the collaborators. But since each object doesn't do much this means my tests do not end up describing the behavior of the system that I'm usually concerned with. These tests might also get in my way during new development or refactoring because the "low level" individual APIs are locked in by the tests.<br />
<br />
Alternatively, I could write tests that exercise the full composition of all the objects. These tests would be closer to describing the "end user" level behavior that I more likely care about. They are also more robust in the face of change as the lower level API can change without breaking these tests. But, they can also suffer from <a href="http://en.wikipedia.org/wiki/Cyclomatic_complexity" target="_blank">Cyclomatic complexity</a> problems because they are testing many levels of objects together.<br />
<br />
These last tests can be taken all the way to the edge of the application and written as Acceptance Tests that literally automate the web browser. Or they can be written like a regular unit test, but the "unit" is at a higher conceptual level, not just a single object.<br />
<br />
Finally, these are not mutually exclusive options. I could write both kinds of tests.<br />
<br />
So to loop back, my question for YOU is, have you seen any good resources that discuss this issue and make any recommendations? If so, I'd love a link, or, share your opinions on the issue. Thanks!Kevin Berridgehttp://www.blogger.com/profile/13759114853595462455noreply@blogger.com0tag:blogger.com,1999:blog-6579772240267288367.post-65886287415072917042014-05-21T13:40:00.003-04:002014-05-21T13:40:57.383-04:00Close old hg branches with powershellAnother silly post combining my two favorite tools: Mercurial and Powershell.<br />
<br />
If you use named branches as part of your development workflow you may occasionally forget to close a branch after you merge it back in. Or you might abandon a branch and never get back to it. And if you use sub repositories, sometimes it can be impossible to update back to those old revisions... And even if you don't get an error when you update back, it's still super slow to checkout all those old files just to mark the branch closed.<br />
<br />
To address all those issues, I just used this little powershell script:<br />
<pre>function closeoldbranch($branchname)
{
hg debugsetparent $branchname
hg branch $branchname
hg ci --close-branch -m "closes old branch"
}</pre>
I don't recommend that you make a habit of using this technique, but I did just get a lot of use out of it! So enjoy it, but be careful!Kevin Berridgehttp://www.blogger.com/profile/13759114853595462455noreply@blogger.com0tag:blogger.com,1999:blog-6579772240267288367.post-27996353490640440182014-04-10T22:39:00.000-04:002014-04-10T22:39:27.405-04:00OOP: You're Doing It Completely Wrong<iframe allowfullscreen="" frameborder="0" height="281" mozallowfullscreen="" src="//player.vimeo.com/video/91672848" webkitallowfullscreen="" width="500"></iframe> <br />
<a href="http://vimeo.com/91672848">OOP: You're Doing It Completely Wrong (Stir Trek Edition)</a>
<br />
<br />
This talk, "OOP: You're Doing It Completely Wrong", was first presented at CodeMash 2.0.1.4. in January to a standing room only crowd. It was the 2nd time I was fortunate enough to present at CodeMash and it was an absolute blast! The feedback I got was really encouraging and someone suggested I should submit it to other conferences and recommended Stir Trek. The video above is the recording of the talk as it was given at Stir Trek 2014 in April (to another standing room only crowd!).<br />
<br />
Here's the abstract:<br />
<blockquote class="tr_bq">
Chances are, most of us are primarily writing in Object Oriented Languages. But how many of us are truly doing Object Oriented Programming (OOP)? Objects are a powerful abstraction, but when all we do is write procedural code wrapped in classes we’re not realizing their benefits. That’s the tricky thing about OO, it’s easy to have Objects but still not be doing good OOP. This has led to a plethora of principles and patterns and laws, which are very valuable, but also easy to misunderstand and misapply. In this talk we’ll go back to the foundations of Objects, and take a careful look at what OO is really about and how our principles and patterns fit into the big picture. We’ll see why good OOP is important, and look at the mindset needed to design successful Objects. When we’re done, we’ll have a more nuanced understanding of what good OO is, what it can do for us, and when we should use it.</blockquote>
Between CodeMash and Stir Trek I had the time to really work through and reorganize the details of the talk, so I actually COMPLETELY rewrote it from the ground up for Stir Trek. And I will admit that I'm really proud of the result.<br />
<br />
This talk truly represents my (current) understanding of what makes OO powerful and how we should really think about it. It's VERY heavy on research and full of quotes and references. The CodeMash version was even more so. And that reflects my belief that we, as an industry, need to work on being a bit more scientific, especially when it comes to citing our references.<br />
<br />
I hope that you enjoy it, and I'd love to hear your thoughts!Kevin Berridgehttp://www.blogger.com/profile/13759114853595462455noreply@blogger.com0tag:blogger.com,1999:blog-6579772240267288367.post-82714901459318098892014-04-06T14:37:00.000-04:002014-04-06T14:37:34.525-04:00Visual Studio Shortcuts: The Complete GuideSo I was gonna do this whole series of posts breaking out useful shortcuts into categories in bite sized chunks. But that didn't happen cause I got bored with it. But I still think it's really useful. I have actually stopped using VSVIM and I just use VS's shortcuts now. The only thing I really miss is vim's hjkl and w and b movement keys (the arrow keys are so far away!). <br />
<br />
So, anyway, here's the big list of all the shortcut keys I have found useful and worth practicing. Each category is roughly sorted by utility. Hope it helps you too!<br />
<br />
<b>Editing:</b><br />
Ctrl+L: cuts the current line<br />
Ctrl+del: Join lines<br />
Shift+del: delete line<br />
Ctrl+C with nothing selected: copies current line<br />
Ctrl+F3: search for current select (like VIM *)<br />
Ctrl+Enter; Ctrl+Shift+Enter: insert blank line above/below current line<br />
Ctrl+Shift+W: select word (like VIM viw)<br />
Ctrl+K, S: surround with<br />
Ctrl+E, S: show white space<br />
Ctrl+U: to lower case<br />
Ctrl+Shift+U: to upper case<br />
Ctrl+Shift+down/up: move cursor to next highlighted identifier<br />
Ctrl+Shift+V: cycle clipboard ring<br />
Ctrl+up/down: moves the scrollbar<br />
Intellisense: use capital case to filter by camel case<br />
<br />
<b>Refactoring:</b><br />
Ctrl+R, R: rename<br />
Ctrl+R, M: extract method<br />
<br />
<b>Windows:</b><br />
Ctrl+,: navigate to window<br />
Ctrl+W, L: opens solution explorer<br />
Ctrl+F2: move to navigation bar (the class and method dropdowns)<br />
CUSTOM: Ctrl+W, ctrl+left/right arrow: move window to other tab group **Window.MovetoNextTabGroup/Window.MovetoPreviousTabGroup**<br />
CUSTOM: Ctrl+W, Ctrl+W: switch focus to other tab group **TabGroupJumper.Connect.JumpLeft, requires <a href="http://visualstudiogallery.msdn.microsoft.com/3e255015-41c3-47db-b25b-45e00c107875" target="_blank">TabGroupJumper extension</a>**<br />
Ctrl+W, E: opens error window<br />
Ctrl+K, T: opens call hierarchy window (like Find all References, but more)<br />
Ctrl+W, O: opens output window<br />
<br />
<b>Debugging:</b><br />
Ctrl+D, A: opens autos window<br />
Ctrl+D, I: opens immediate window<br />
Ctrl+D, C: opens callstack window<br />
<br />
<b>Misc:</b><br />
<a href="http://visualstudiogallery.msdn.microsoft.com/B08B0375-139E-41D7-AF9B-FAEE50F68392" target="_blank">Snippet designer extension</a>: makes it really easy to create snippets<br />
zencoding: comes with the <a href="http://vswebessentials.com/" target="_blank">Web Essentials extension</a>, allows you to quickly expand HTML tag structure ex: div.content<tab></tab><br />
<br />Kevin Berridgehttp://www.blogger.com/profile/13759114853595462455noreply@blogger.com0tag:blogger.com,1999:blog-6579772240267288367.post-30381103887170314492013-10-18T08:26:00.001-04:002013-10-18T08:26:29.711-04:00ETB: Editing: Just 3 Shortcuts for Dramatic Efficiency GainContinuing on the <a href="http://www.kevinberridge.com/2013/10/embracing-beast.html" target="_blank">Embracing The Beast (ETB)</a> series, this time we're going to dive into the text editor.<br />
<br />
If you edit at all like I used to, these 3 shortcut keys will save you a huge number of redundant keystrokes every single day. Yep, just learning 3 new shortcut keys.<br />
<br />
I'm not going to keep you waiting, here they are:<br />
<table style="width: 400px;">
<tbody>
<tr>
<th align="left">Shortcut</th>
<th align="left">Action</th>
</tr>
<tr>
<td>Ctrl+L</td>
<td>Cut current line</td>
</tr>
<tr>
<td>Ctrl+C (with NOTHING selected)</td>
<td>Copy current line</td>
</tr>
<tr>
<td>Ctrl+Enter</td>
<td>Insert blank line above</td>
</tr>
</tbody></table>
<br />
I have learned tons of new shortcut keys since I started this process, but these three are the most important. If you learn this and nothing else in this series, it will still be a marked improvement!<br />
<br />
Why? Let's take a look.<br />
<b><br /></b>
<b>Cut Current Line</b><br />
Like it says, this command cuts whatever line the cursor is on (meaning it copies it and deletes the line, including the carriage return). You can use this to easily move a line up or down, or to just delete a line. There is a command that deletes the line without cutting it (Shift+Del), but when you're just starting out it pays to limit the number of things you're learning all at once. Ctrl+L does the same thing that Shift+Del does, and <i>rarely</i> will the difference ever bite you. Start simple.<br />
<br />
"Cool man, but like, why is this such an efficiency improving short cut?"<br />
<br />
Glad you asked! Here's the sequence of keys I used to hit to do the same thing Ctrl+L does in one keystroke:<br />
<div>
<ol>
<li>End</li>
<li>Shift+Up</li>
<li>Ctrl+X</li>
</ol>
<div>
3 keystrokes when I could have used 1! Suppose you delete or move lines 100 times a day, which is probably crazy low. You would save 200 keystrokes. This paragraph is only 195 characters long.</div>
</div>
<div>
<br /></div>
<div>
Maybe that doesn't seem like a lot, but there is a hidden benefit here too; Ctrl+L is a single command that maps directly to a pretty high level action you wanted to take. It may be only 2 keystrokes better than the more manual way, but you don't have to busy yourself thinking about the micro steps required to move the cursor and highlight text. You just, BAM, do the action you want. End. Of. Story. Conceptual overhead here is much reduced! </div>
<div>
<br /></div>
<div>
<b>Copy Current Line</b></div>
<div>
I used to do this the same as above, except I'd Ctrl+C instead of Ctrl+X. But it turns out, if you just hit Ctrl+C when nothing is selected, VS will copy the entire line! Brilliant! </div>
<div>
<br /></div>
<div>
Suppose I copy half as many lines as I delete: 50/day =100 keys saved. This paragraph is 98 chars.</div>
<div>
<br /></div>
<div>
<b>Add Blank Line Above</b></div>
<div>
You might not think that you do this operation too often, but I think you'll be surprised. How many times do you write a block surrounded by {}? There are LOTS of ways you might do this, but the way I usually do it is I write the definition, the open {, and then the closing }, and now I want to go back up and type in the body, but I'm stuck below it!</div>
<div>
<br /></div>
<div>
Here's what I do:</div>
<div>
<ol>
<li>Up</li>
<li>End</li>
<li>Enter</li>
</ol>
<div>
That's 3 keystrokes again instead of just Ctrl+Enter! Interestingly, this is the one I'm having the hardest time training myself to take advantage of. That could be because how often I use it varies depending on what I'm coding, but I bet on a typical day I do this way more than I copy lines. Lets go with 200 times a day, for 400 keys saved. And you guessed it, this paragraph is 396 chars.</div>
</div>
<div>
<br /></div>
<div>
So with all three of these combined, and given my completely made up numbers, that's 700 keystrokes saved, every day, just by using these three shortcut keys, That's clearly a good thing, but the real benefit is in the fact that you're now communicating with your editor on a higher level than just cursor up and down.</div>
Kevin Berridgehttp://www.blogger.com/profile/13759114853595462455noreply@blogger.com0tag:blogger.com,1999:blog-6579772240267288367.post-60895363377793814332013-10-14T07:00:00.000-04:002013-10-14T07:00:08.807-04:00Embracing The Beast: Navigate ToNext up in the <a href="http://www.kevinberridge.com/2013/10/embracing-beast.html" target="_blank">Embracing The Beast</a> series is Navigate To.<br />
<br />
The Navigate To feature introduced in Visual Studio 2010 is the single most important feature they added that made it possible for me to work in Visual Studio without proclaiming my longing and desire for Vim at the top of my lungs every 5 minutes.<br />
<br />
The shortcut is Ctrl+, (Control Comma). But the shortcut is just the beginning of effectively using this thing.<br />
<div class="separator" style="clear: both; text-align: center;">
</div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj_veLP5Jk8uNh5rV1j3sm7Etmluh9EfGpEpKsBt9ZHzHauqJevFh_gF20r11aRQQHqSOiNXr8US1HEzOFLZKQabIYnaIzIKvpl-Wm0VwZKORWbmVsDJrfFv0xHJQSWN0nM7gRykD0WSLI/s1600/navigate-to.gif" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="419" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj_veLP5Jk8uNh5rV1j3sm7Etmluh9EfGpEpKsBt9ZHzHauqJevFh_gF20r11aRQQHqSOiNXr8US1HEzOFLZKQabIYnaIzIKvpl-Wm0VwZKORWbmVsDJrfFv0xHJQSWN0nM7gRykD0WSLI/s640/navigate-to.gif" width="640" /></a></div>
<br />
<b>What it searches</b><br />
Files, types, members, and variables.<br />
<br />
<b>Search string formats</b><br />
An <i><b>all lower case</b></i> search basically does a case-insensitive "contains" search, but it intelligently sorts the results preferring "Starts With" over "Contains". For example, if you search for "ext", you'll find things like Properties named "Extension" or Methods named "Extract" before you'll find Properties named "Text".<br />
<br />
But change your search string so that's it's <i><b>not all lower case</b></i>, "Ext", and now it does a case sensitive search which would still return "Extension" and "Extract" but not "Text".<br />
<br />
Make your search string <i><b>all upper case</b>, </i>and now it does a PascalCaseAware search! For example, search for "AVE" and it will match AbstractValidatorExtensions because of the PascalCase, and "AutoSave" because of the case insensitive contains match of "ave" in "Save". Unfortunately it returns the contains matches before the pascal case matches, so this can require a lot of pascal case characters before it will return the item you want at the top.<br />
<br />
Put <i><b>spaces between search terms</b></i> and it basically does an "and" search, but it's position independent. "auto save" will of course match "AutoSave", but so will "save auto"! Lest I mislead you, the matches don't have to be adjacent, "location incident" will match "AddLocationToSomeIncident".<br />
<br />
<b>Tips</b><br />
Suppose you are looking for a file, and you know part of its name and you know its a JavaScript file. Search for "partofname .js". The ".js" will bring .js files to the top of the results.<br />
<br />
Suppose you're looking for the Index view of an MVC controller. There are lots of Index views in your website I bet, so searching for just "index" isn't going to get you too far. Try this: "views partofcontrollername index". partofcontrollername just has to be a unique enough subset of the name of the controller to bring that folder to the top. This illustrates that Navigate To isn't just searching the file name, but the entire file path!<br />
<br />
If you have more Navigate To tips, I want to hear them! Comment below or <a href="http://twitter.com/kberridge" target="_blank">twitter at me</a>!Kevin Berridgehttp://www.blogger.com/profile/13759114853595462455noreply@blogger.com0tag:blogger.com,1999:blog-6579772240267288367.post-9121037706840077582013-10-08T08:41:00.000-04:002013-10-08T08:42:18.089-04:00Embracing The Beast: Where Do We Start?The Beast, as explained in the <a href="http://www.kevinberridge.com/2013/10/embracing-beast.html">first post</a>, is Visual Studio, and my objective is to finally really master it once and for all. What's the criteria for "master"? It's not a simple question because VS has so many different parts and features... Does mastering it mean you know when and how to use every single one of those features? Does mastering it mean you use it as fast and efficiently as possible? Where's a poor vim-loving-wanna-be-hippie-alt-dot-net-developer to start?<br />
<br />
There's two main related places I believe make the most sense to start, and that I believe will help drive out learning what other bells and whistles and sirens and synthesizers VS has to offer:<br />
<ol>
<li>Let go of the mouse</li>
<li>Touch fewer keys</li>
</ol>
<div>
That's it. Just those two things should give us a really solid start at becoming much faster and more efficient when coding in VS.</div>
<div>
<br /></div>
<div>
I'm guessing I don't really have to convince most of the people reading this that this is correct. But, you know, it's low hanging fruit, so I'm going for it anyway... Maybe you like the mouse. Maybe you read <a href="http://www.asktog.com/TOI/toi06KeyboardVMouse1.html">that one ancient article from the early Mac days that says using the mouse is actually more efficient than the keyboard</a>. OK. Tell me, how often do you save the file you are editing by:</div>
<div>
<ol>
<li>Grabing the mouse</li>
<li>Dragging waaaaaaaaaaaaaaaaaaaaaaay over (monitors are BIG these days) to the File menu, clicking it</li>
<li>Dragging down to the save item, clicking it</li>
</ol>
<div>
Or do you just hit Ctrl+S like 100,000 times subconsciously every time you stop to think about what to do next?</div>
</div>
<div>
<br /></div>
<div>
I thought so.</div>
<div>
<br /></div>
<div>
That's the thing about keyboard shortcuts, once you have practiced them to the point where they are <i>engrained in your muscle memory</i>, they are fast and require no thought and no time lag, allowing you to forget the physical steps of editing and focus on the more abstract ideas of what you are editing. But lets not skim over the most important part of that last sentence: practice! Real practice. The kind of practice familiar to most people who have played a musical instrument of some kind, which mainly consists of repetition, repetition, repeating yourself, doing it again, and again, repetition, slow repetition, fast repetition, and then more repetition. And if you didn't study music but instead spent your time going to sporting rehearsals (is that what they're called?), you probably experienced much the same thing.</div>
<div>
<br /></div>
<div>
So, if we are going to let go of the mouse, and touch fewer keys, we're going to have to practice shortcut keys. For me that practice usually looks like:</div>
<div>
<ol>
<li>Learning a new shortcut key</li>
<li>Writing it down</li>
<li>Trying it out a few times</li>
<li>Purposefully finding opportunities to use it</li>
<li>Paying close attention to my coding and if I miss a chance to use it,</li>
<li>leaning on undo</li>
<li>doing it again with the shortcut</li>
</ol>
<div>
Repeat, repeat, repeat, repeat, repeat. It's also important not to stretch yourself too thin all at once. Focus on a couple things at a time, work 'em to death, then do some other things, then go back to the first things again, etc. Some of this is going to be extra-curricular. Some of it can happen on the job. Some of it will slow you down a bit. It's OK, you're going to be happier for it soon. And it's not going to take as long as it feels like it does. I have no studies to prove this, I believe it on blind faith alone, and encourage you to take my word for it. We're software developers after all and that's how we do this.</div>
</div>
<div>
<br /></div>
<div>
OK, cool. So we need some shortcut keys to learn.</div>
<div>
<br /></div>
<div>
<b>The Basics</b></div>
<div>
These are the essentials, chances are anyone who's used VS for any amount of time knows these already, so let's get them out of the way.</div>
<div>
<br /></div>
<table style="width: 400pxpx;">
<tbody>
<tr><th align="left">Shortcut</th><th align="left">Action</th></tr>
<tr>
<td>F6 or Ctrl+Shift+B</td>
<td>Build</td>
</tr>
<tr>
<td>Ctrl+F4</td>
<td>Close Window</td>
</tr>
<tr>
<td>Ctrl+,</td>
<td>Navigate to</td>
</tr>
<tr>
<td>F5</td>
<td>Run</td>
</tr>
<tr>
<td>F9</td>
<td>Toggle Breakpoint</td>
</tr>
<tr>
<td>F10</td>
<td>Debugger Step Over</td>
</tr>
<tr>
<td>F11</td>
<td>Debugger Step Into</td>
</tr>
<tr>
<td>Ctrl+R, T</td>
<td>Run Tests</td>
</tr>
<tr>
<td>These you already know</td>
<td>cut, copy, paste, undo, redo, save</td>
</tr>
</tbody></table>
<br />
<div>
<b>Slightly Better Than Basic</b></div>
<div>
Moving a tiny bit up the scale toward shortcuts that are still bread and butter, but might be slightly less well known.</div>
<div>
<br /></div>
<table style="width: 400pxpx;">
<tbody>
<tr><th align="left">Shortcut</th><th align="left">Action</th></tr>
<tr>
<td>Shift+F5</td>
<td>Stop Debugging</td>
</tr>
<tr>
<td>Ctrl+E, C</td>
<td>Comment Selection</td>
</tr>
<tr>
<td>Ctrl+E, U</td>
<td>Uncomment Selection</td>
</tr>
<tr>
<td>Ctrl+M, M</td>
<td>Toggle Outlining</td>
</tr>
<tr>
<td>Ctrl+M, L</td>
<td>Toggle All Outlining</td>
</tr>
<tr>
<td>Ctrl+G</td>
<td>Go to Line</td>
</tr>
<tr>
<td>Shift+F6</td>
<td>Build Current Project Only</td>
</tr>
</tbody></table>
<br />
<div>
Learning shortcut keys isn't all there is to mastering an editor, but it's a big part, and it's certainly the first step. With these basics out of the way, we can move on to more interesting stuff.</div>
Kevin Berridgehttp://www.blogger.com/profile/13759114853595462455noreply@blogger.com0tag:blogger.com,1999:blog-6579772240267288367.post-61411830227814831322013-10-04T07:00:00.000-04:002013-10-04T07:00:06.938-04:00Embracing The Beast<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEil9GYz6-i9MLON5Hc-0_Bm6cv-NscF5TAS-B27nCdPU5OQ5QsA02TH_BjuC0rlYkDwSa4z-4CQcjvED_b4utPWu-t5qyMGxwJMDRTFaFPX-Jq7AtLFt0B0jmiaZcD9iETzn7lNx0NKwYY/s1600/vs+logo.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="111" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEil9GYz6-i9MLON5Hc-0_Bm6cv-NscF5TAS-B27nCdPU5OQ5QsA02TH_BjuC0rlYkDwSa4z-4CQcjvED_b4utPWu-t5qyMGxwJMDRTFaFPX-Jq7AtLFt0B0jmiaZcD9iETzn7lNx0NKwYY/s400/vs+logo.png" width="400" /></a></div>
The year was 2001, the language was VB, the editor was Visual Studio 6. It was the first time I used Visual Studio and, to be honest, I didn't give it any thought. Before that, I'd been developing in Turbo C and Brief. I really liked the <a href="http://en.wikipedia.org/wiki/Brief_(text_editor)">Brief</a> editor. It helped that my dad loved it and knew it pretty well too. In any case, it was the first editor I ever took the time to learn.<br />
<br />
Like your first language, your first editor molds your expectations. Brief was a keyboard driven, light weight, text focused editor. It was <i>brief</i>. And it had really really good (and <i>brief</i>) help. I no longer remember any of it's shortcut keys or even much about it's interface, but I still remember spending hours navigating through it's help like it was Wikipedia, "oh that sounds interesting." *click* "huh, what's that?" *click* "oooh! that sounds cool!" *click*.<br />
<br />
But I was working and schooling in the land of the beast now, so no more Brief. And compared to Brief, Visual Studio is a <i>BEAST</i>! Slow, mouse oriented, cluttered with tool windows sliding in and out from every direction, toolbars everywhere with countless incomprehensible icons. And no help.<br />
<br />
I think I did C++ in VS for a full year before I learned about the debugger, arguably VS's killer feature. Isn't the whole point of all this UI mouse driven stuff to make it more discoverable? It didn't work for me. It wasn't my expectation from my Brief days and with the really bad help, I had no way to learn it on my own. I finally learned it from one of my classmates, watching over their shoulder as they tried to fix a bug. My life changed that day: no more print statement debugging! <br />
<br />
I learned a lot of Visual Studio after that, but I never liked it, and I never found a good resource to help me learn more about it. I didn't feel bad about it, cause VS was still a slow, ugly, bloated beast. And, I seriously hated it so much I invested ALOT of time <a href="http://www.kevinberridge.com/2008/09/visual-studio-development.html">configuring Vim to do C# development completely outside of VS</a>.<br />
<br />
But that began to change about 3 years ago with VS 2010. It got faster and more usable in some key ways (though slower in others), and suddenly I found myself spending less time in Vim and more time in VS. It also helped that I was doing more web development than winforms or wpf development. Then with VS 2012, it got dramatically better still. I installed <a href="http://visualstudiogallery.msdn.microsoft.com/59ca71b3-a4a3-46ca-8fe1-0e90e3f79329">VsVim</a> and hardly switched into Vim at all anymore.<br />
<br />
It took awhile before I realized I really didn't hate Visual Studio anymore. And awhile longer after that before I realized, "Hey, I bet if I studied this thing the way I studied Vim back in the day, I could wring a lot of performance out of it". So I started paying attention to how I was using it, and I started researching VS tips, VS shortcuts, VS productivity. I haven't found one single good resource, but there's plenty of random blogs with scattered tips.<br />
<br />
Then this week, I took a big step. I turned off VsVim. **gasp!**<br />
<br />
So far, it's been a surprisingly good experience. Better than I was hoping. I'd like to write up some of what I'm learning here, much like the <a href="http://www.kevinberridge.com/2008/09/visual-studio-development.html">Vim series</a>. But I'm still working on ideas of how to present it. It's harder than with Vim, VS being such a beast and all...Kevin Berridgehttp://www.blogger.com/profile/13759114853595462455noreply@blogger.com0tag:blogger.com,1999:blog-6579772240267288367.post-89171684533244283992013-08-07T12:37:00.000-04:002013-08-07T12:37:04.135-04:00Powershell: Open Files Matching a SearchHave I ever mentioned how much I love Powershell?<br />
<br />
What do you do when you want to search a bunch of source files for a given string, and then open all the files that matched your search?<br />
<br />
First you have to be able to search a bunch of files, my earlier post <a href="http://www.kevinberridge.com/2008/06/powershell-grep.html">Powershell Grep</a> has you covered there. This outputs objects (a MatchInfo if you want to know) that list the files and lines that matched. If a file had multiple matching lines, it will be listed twice, so we need to do something about that. Then we'll need to assemble all the file paths and pass it into our favorite editor (Vim, <a href="http://www.kevinberridge.com/search/label/vim">no surprise there</a>).<br />
<br />
In Powershell V3 syntax the command is:<br />
<pre>gvim (grep SearchString | group-object Path).Name</pre>
In Powershell V2 syntax you have to use ForEach-Object:<br />
<pre>gvim (grep SearchString | group-object Path | %{ $_.Name })</pre>
If you're a programmer, especially if you're a .NET programmer, powershell is just so wonderfully intuitive (even if it is a bit verbose)!<br />
<br />
If you develop on the Windows platform and you haven't given Powershell a look yet, you really really should. I learned it by reading <a href="http://www.amazon.com/Windows-PowerShell-Action-Second-Edition/dp/1935182137">Windows Powershell In Action</a>, a book I really enjoyed for its brevity, good examples, and awesome asides about how and why certain design decisions were made in the language.Kevin Berridgehttp://www.blogger.com/profile/13759114853595462455noreply@blogger.com0tag:blogger.com,1999:blog-6579772240267288367.post-82401673612539055952013-06-04T11:45:00.000-04:002013-06-04T11:45:02.043-04:00Powershell: testing string length validationsEvery time I do this it makes me smile.<br />
<br />
If you write apps that have input fields that have max lengths that are validated, then occasionally you may need to test your validations. I used to do this by typing "this is a really really really long string that should break the validations" and the copying and pasting that over and over until I thought I'd gotten it long enough to exceed the max length.<br />
<br />
Now I just switch over to powershell (which I always have conveniently open and ready) and I type:<br />
<pre>"quite long" * 100 | clip.exe</pre>
<br />
<br />
"quite long" just happens to be exactly 10 characters long, so this generates a string which is 1000 characters long that looks like "quite longquite longquite long..." Piping that string to clip.exe saves it on your clipboard. Now just paste into the field you want to test and you're all set!Kevin Berridgehttp://www.blogger.com/profile/13759114853595462455noreply@blogger.com0tag:blogger.com,1999:blog-6579772240267288367.post-3129757692576310542013-04-13T17:13:00.000-04:002013-04-13T17:13:25.543-04:00Insight in Plastic Containers<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjxZWgxhvYJtAzx5efjQel1nHfi9IghqCPZ2EnLWgqU-V86Dit6ykpjTflwMRO9IcjtDSnZ8safQ6VMqnU703n4uQsEvt_a1UvQaI3_UAKbgoMowDict-z0ub3zx3wQvW-M2-ZwH9BuSPs/s1600/IMG_20130413_112550.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="345" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjxZWgxhvYJtAzx5efjQel1nHfi9IghqCPZ2EnLWgqU-V86Dit6ykpjTflwMRO9IcjtDSnZ8safQ6VMqnU703n4uQsEvt_a1UvQaI3_UAKbgoMowDict-z0ub3zx3wQvW-M2-ZwH9BuSPs/s640/IMG_20130413_112550.jpg" width="640" /></a></div>
<br />
Two simple small plastic containers. The one on the left is a considerably better design:<br />
<ul>
<li>They nest inside each other because of the tapered shape</li>
<li>The base of the container snaps into the top of the lid</li>
<li>The lids snap into each other</li>
</ul>
<div>
I love examples of good design like this, but that's not why I took this picture! </div>
<div>
<br /></div>
<div>
On the one on the left, see how the lid is facing down and the container fits on top of it, like this?</div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi4OUDFqCSyiibKGdj05XG6GSL7NlHMZvfxPTnlr3JCED0ZlLY1XdlW4wRhyEcaBQ9fQ4REr9RSJgg1A6NeGxRkBloK3DNJ1v5FZHEv8CE4fJ9hnphUdNLbv4lLGGovCsHJ8mz6cIbup-4/s1600/containers.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi4OUDFqCSyiibKGdj05XG6GSL7NlHMZvfxPTnlr3JCED0ZlLY1XdlW4wRhyEcaBQ9fQ4REr9RSJgg1A6NeGxRkBloK3DNJ1v5FZHEv8CE4fJ9hnphUdNLbv4lLGGovCsHJ8mz6cIbup-4/s1600/containers.png" /></a></div>
<div>
We have way more left-type containers and only a couple right-types. The right-types don't fit into each other, and the lids don't snap on the bottom, so there isn't any great way to store them. I usually just stuff 'em in the cabinet. But today I opened the cabinet door and noticed the lid on the right-type as in the photo:</div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi8LVRb8LE5fcjm8tHexUAjU9jP3UnhJN0E1ueeZfYlxdVtiwGvJJDEH2oMbScFX4Ac32NNYhLIr-If0pt6xJMN9xN16k17q0EZehvyfmkAVKXoMpICjqrVrU-Emzw2iAgCjHvJEYXFID4/s1600/containers+(1).png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi8LVRb8LE5fcjm8tHexUAjU9jP3UnhJN0E1ueeZfYlxdVtiwGvJJDEH2oMbScFX4Ac32NNYhLIr-If0pt6xJMN9xN16k17q0EZehvyfmkAVKXoMpICjqrVrU-Emzw2iAgCjHvJEYXFID4/s1600/containers+(1).png" /></a></div>
<div class="separator" style="clear: both; text-align: left;">
FLIPPED! It's facing up instead of down, and the container nests relatively nicely inside it. I couldn't help but smile at this! </div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
I have been fixated on the lids facing down because we have many more of the left-type containers, the idea of simply flipping the lid never occurred to me. It's wonderful to reflect on the insight of just flipping the lid around. A terribly simple idea that has been there all along, but I never saw it. </div>
<div>
<br /></div>
<div>
An admittedly silly example of lateral thinking... Or maybe it's not really lateral thinking, maybe it's just closed mindedness through familiarity. But in any case, when I saw it today it made me go "neat!"</div>
Kevin Berridgehttp://www.blogger.com/profile/13759114853595462455noreply@blogger.com0tag:blogger.com,1999:blog-6579772240267288367.post-82682715897809024632013-02-11T07:00:00.000-05:002013-02-20T12:11:03.600-05:00POODR's Duck Types<a href="http://www.amazon.com/gp/product/0321721330/ref=as_li_ss_il?ie=UTF8&camp=1789&creative=390957&creativeASIN=0321721330&linkCode=as2&tag=kwb04-20" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><img border="0" src="http://ws.assoc-amazon.com/widgets/q?_encoding=UTF8&ASIN=0321721330&Format=_SL160_&ID=AsinImage&MarketPlace=US&ServiceVersion=20070822&WS=1&tag=kwb04-20" /></a>
I recently read <a href="http://www.amazon.com/Practical-Object-Oriented-Design-Ruby-Addison-Wesley/dp/0321721330/">Practical Object-Oriented Design in Ruby</a> by Sandi Metz. It's a really wonderful book. I can say without any hesitation it has made me a much better Object-Oriented programmer. I honestly wish I could have read this 12 years ago when I was first learning an Object-Oriented language. <br />
<br />
Although the book is totally focused on Ruby, the OO practices it presents are easily applicable to other OO languages, including static languages like C#. This makes it one of those timeless books you can be happy to have on your shelf knowing it's not going to be outdated in a year. I highly recommend it!<br />
<br />
I intend to write a few posts highlighting some of the good ideas that struck me the most from this book, but in this post I just can't help but take a few shots at it's treatment of static vs. dynamic languages.<br />
<br />
My programming language lineage started by dabbling in C, then taking classes in C++, followed by Java, and finally C#. Most of the real world code I've written has been in static languages, and I've been programming professionally in C# for the last 8 years. This makes me a static language guy.<br />
<br />
When I learned ruby, about 5 years ago, I fell in love with it's clean syntax and amazing flexibility. I wrote a few simple tools in it for work, and I've written alot of rspec/capybara tests, plus I dabbled a bit with Rails. I feel I have a decent understanding of the language, but I'm by no means an expert and I definitely still think in classes and types.<br />
<br />
I tell you this to explain where I'm coming from. Static languages are what I know best and are what I'm used to. I'm not a dynamic language hater, I'm just comfortable with static langs. Which brings us back to POODR.<br />
<br />
POODR talks a lot of about "Duck Types" which are defined in the book as:<br />
<blockquote class="tr_bq">
Duck types are public interfaces that are not tied to any specific class. These across-class interfaces add enormous flexibility to your application by replacing costly dependencies on class with more forgiving dependencies on messages.</blockquote>
I was surprised at this definition because it describes the "Duck type" as being a <i>thing, </i>but in Ruby there is no thing that can represent this across-class-interface. Most treatments of duck typing from Rubyists I've seen usually just talk about how it's a feature of the dynamic nature of the language. They talk about "duck typing" but not "duck types."<br />
<br />
In C# we have <i>interfaces</i>, which can be used as explicitly defined duck types. The Dependency Inversion Principle and the Interface Segregation Principle are both trying to get you to use interfaces in this way, instead of just as <a href="http://www.kevinberridge.com/2012/02/header-interfaces-or-inverted.html">Header Interfaces</a>. It's good OO because it focuses on messages instead of types. As POODR says, "It's not what an object <i>is</i> that matters, it's what it <i>does</i>."<br />
<br />
I think there is a lot of power in Ruby's implicit "duck types," but I also think the lack of explicit interfaces is a serious liability, and I was very entertained by how many hoops POODR jumps through to try to work around this problem, all while trying to claim that it isn't a problem at all, and in fact, it's great!<br />
<br />
At the end of Chapter 5, there's a section that tries to convince you that Dynamic typing is better than Static typing. Unfortunately, it just builds up a straw man version of static typing to make it easier to tear down. What it leaves out is interfaces:<br />
<blockquote class="tr_bq">
Duck typing provides a way out of this trap. It removes the dependencies on class and thus avoids the subsequent type failures. It reveals stable abstractions on which your code can safely depend.</blockquote>
If statics langs didn't have interfaces, this might be true. But they do have interfaces! And worse, interfaces represent a significantly more stable abstraction that is dramatically safter to depend on than these invisible "duck types." POODR demonstrates this itself with examples where the "duck type" interface changes, but not all "implementers" of the interface are updated. There's no compiler to catch this. And standard TDD practices wont catch it either. Your tests will be green even though the system doesn't work. So you have to write manual tests that you can share across all the implementers to make sure the message names and parameters stay in sync. Nearly all of Chapter 9 is devoted to testing practices that simply wouldn't be needed if there was even just a rudimentary compiler that could verify just inheritance and interface implementations.<br />
<br />
The lack of explicit "duck types" just seems so problematic to me... Keeping them in sync is a chore, and a potential source of error. The worst kind of error too, because the same code may work in one context but break in another based on which "duck type" is used. <br />
<br />
Another problem I've run into is when trying to understand some code that takes in a "duck type", how do you figure out the full story of what will happen? How do you find all the implementers of that "duck type"? Just search your code base for one of the method names? Try to find every line of code that injects in a different duck type? <br />
<br />
Not being able to surface an explicit interface leaves you stuck in a situation where you have to infer the relationship between your objects by finding every usage of them. Seems like a lot more work, as well as being a recipe for tangled and confusing code.<br />
<br />
So what do you think Dynamic language people? Am I making a bigger deal out of the problems of dynamic typing just as Sandi made a bigger deal out of the problems of static typing? Is this just a lack of experience problem? Do you just not run into these issues that often in real world usage?<br />
<br />
<i>UPDATE 2/20/2013:</i><br />
<a href="http://www.infoq.com/presentations/Type-Functional-Design">Here's an interesting presentation by Michael Feathers</a> about the power of thinking about types during design. I felt like it had some relevance to the conversation here.Kevin Berridgehttp://www.blogger.com/profile/13759114853595462455noreply@blogger.com6tag:blogger.com,1999:blog-6579772240267288367.post-40326786870672069122013-02-04T07:00:00.000-05:002013-02-04T07:00:02.108-05:00In The Midst of Wonders<blockquote class="tr_bq">
"Where the uninformed and unenquiring eye perceives neither novelty nor beauty, he walks in the midst of wonders" - John Hershel, from <a href="http://www.goodreads.com/book/show/4371507-the-age-of-wonder">The Age of Wonder</a>, originally from A Preliminary Discourse on the Stud of Natural Philosophy</blockquote>
Kevin Berridgehttp://www.blogger.com/profile/13759114853595462455noreply@blogger.com0tag:blogger.com,1999:blog-6579772240267288367.post-88817950774899040182013-01-29T07:00:00.000-05:002013-01-29T07:00:04.791-05:00Custom and Example<blockquote class="tr_bq">
"I thus concluded that it is much more custom and example that persuade us than any certain knowledge, and yet inspite of this the voice of the majority does not afford a proof of any value in truths a little difficult to discover, because such truths are much more likely to have been discovered by one man than by a nation." - Rene Descartes, Discourse on Method and Meditations</blockquote>
Kevin Berridgehttp://www.blogger.com/profile/13759114853595462455noreply@blogger.com0tag:blogger.com,1999:blog-6579772240267288367.post-17153259539530979512013-01-24T08:19:00.002-05:002013-01-24T13:02:42.743-05:00The BasicsSome body I follow on twitter retweeted this tweet from <a href="http://agileotter.blogspot.com/">Tim Ottinger</a>:<br />
<blockquote class="twitter-tweet">
The reason for writing a function is not to reuse its code, but to name the operation it performs.<br />
— Tim Ottinger (@tottinge) <a href="https://twitter.com/tottinge/status/293776089099153408">January 22, 2013</a></blockquote>
My first pompous thought was something like, "how obvious." I was about to go back to work when a memory hit me out of no where. I remember very early in my career <i>F5-hacking</i> on some code and thinking about creating a method but worrying about not reusing it, or about someone else reusing it incorrectly, or about the extra lines of code the added syntax would add to my already 1000+ line Windows Form class.<br />
<br />
I remember programming like that. There was a time, not long ago, when I didn't think I should extract a method unless I meant to use it more than once! And it's weird because I don't remember having the epiphany that took me from where I was then to where I am now. I once thought A, I now think B, and I don't remember changing my mind. It's an interesting lesson in the way the mind works. And it reminded me that everyone was a newbie once, and that most likely, I still am a newbie I just haven't figured it out yet.<br />
<script async="" charset="utf-8" src="//platform.twitter.com/widgets.js"></script>
Kevin Berridgehttp://www.blogger.com/profile/13759114853595462455noreply@blogger.com2tag:blogger.com,1999:blog-6579772240267288367.post-25623108980710267042012-12-21T09:15:00.000-05:002012-12-21T09:15:33.314-05:00Slicing Concerns: ImplementationsIn <a href="http://www.kevinberridge.com/2012/12/slicing-concerns-and-naming-them.html">Slicing Concerns And Naming Them</a> I posed a question about how to go about separating different concerns while still maintaining a clean and relatable code base. Some interesting conversation resulted, and I wanted to follow up by investigating some of the different approaches to this problem that I'm aware of.<br />
<br />
<span style="font-family: Trebuchet MS, sans-serif; font-size: large;"><b>Inheritance
</b></span><br />
<pre class="prettyprint lang-cs">public class Task : ActiveRecord
{
public string Name { get; set; }
public int AssignedTo_UserId { get; set; }
public DateTime DueOn { get; set; }
}
public class NotificationTask : Task
{
public override void Save()
{
bool isNew = IsNewRecord;
base.Save();
if (isNew)
Email.Send(...);
}
}
public class TasksController : Controller
{
public ActionResult Create(...)
{
...
new NotificationTask {...}.Save();
...
}
public ActionResult CreateWithNoEmail(...)
{
...
new Task {...}.Save();
...
}
}
</pre>
This works, and the names are reasonable. But of course, inheritance can cause problems... I wont go into the composition over inheritance arguments as I assume this isn't the first time you've heard it!<br />
<br />
<span style="font-family: Trebuchet MS, sans-serif; font-size: large;"><b>Decorator
</b></span><br />
<pre class="prettyprint lang-cs">public class Task : ActiveRecord
{
public string Name { get; set; }
public int AssignedTo_UserId { get; set; }
public DateTime DueOn { get; set; }
}
public class NotificationTask
{
Task task;
public NotificationTask(Task t)
{
this.task = t;
}
public void Save()
{
bool isNew = t.IsNewRecord;
t.Save();
if (isNew)
Email.Send(...);
}
}
public class TasksController : Controller
{
public ActionResult CreateTask()
{
...
new NotificationTask(new Task {...}).Save();
...
}
}</pre>
This is not really the decorator pattern... At least not as defined by the GoF, but I have <a href="http://blog.codeclimate.com/blog/2012/10/17/7-ways-to-decompose-fat-activerecord-models/">seen it used this way often enough</a> that I don't feed too terrible calling it that. Really this is just a wrapper class. It's similar to the inheritance approach, except because it doesn't use inheritance, it opens us up to use inheritance on the Task for other reasons, and apply the email behavior to any kind of task.<br />
<br />
The naming is a bit suspect, because NotificationTask is not really a task, it just has a task. It implements only one of the task's methods. If we extracted an ITask interface we could make NotificationTask implement it and just forward all the calls. This would make it a task (and a decorator), but would also be crazy tedious.<br />
<br />
<span style="font-family: Trebuchet MS, sans-serif; font-size: large;"><b>Service
</b></span><br />
<pre class="prettyprint lang-cs">public class Task : ActiveRecord
{
public string Name { get; set; }
public int AssignedTo_UserId { get; set; }
public DateTime DueOn { get; set; }
}
public class CreatesTask
{
Task task;
public NotificationTask(Task t)
{
this.task = t;
}
public void Create()
{
t.Save();
Email.Send(...);
}
}</pre>
This service represents the standard domain behavior for creating a task. In an edge case where you needed a task but didn't want the email, you would just not use the service.<br />
<br />
The naming is pretty nice here, hard to be confused about what CreatesTask does... However, this path leads to a proliferation of <verb><noun> classes. In the small it's manageable, but as they accumulate, or as they start to call each other things get confusing. For example, if you know nothing about Task and you have to start working on it, would you know you should call the CreatesTask service? Would you know it exists? And would you be sure it was the correct service for you to be calling?<br />
<br />
<span style="font-family: Trebuchet MS, sans-serif; font-size: large;"><b>Dependency Injection</b></span><br />
<pre class="prettyprint lang-cs">public class Task : ActiveRecord
{
public string Name { get; set; }
public int AssignedTo_UserId { get; set; }
public DateTime DueOn { get; set; }
INotifier notifier;
public Task(INotifier notifier)
{
this.notifier = notifier;
}
public override void Save()
{
bool isNew = t.IsNewRecord;
t.Save();
if (isNew)
notifier.Send(...);
}
}
public class TasksController : Controller
{
public ActionResult Create(...)
{
...
new Task(new EmailNotifier()) { ... }.Save();
...
}
public ActionResult CreateWithNoEmail(...)
{
...
new Task(new NullNotifier()) { ... }.Save();
...
}
}
</pre>
I'm going to ignore all the complexity around the fact that this is an ActiveRecord object which the ActiveRecord framework will usually be responsible for new-ing up, which makes providing DI dependencies difficult if not impossible...<br />
<br />
The idea here is to pass in an INotifier, and then when you find yourself dealing with a task you'll build it with the notifier you want it to use. If you want no notification, you use the Null Object pattern and pass in an INotifier that doesn't do anything (called NullNotifier in the code example).<br />
<div>
<br /></div>
<div>
But this has the ORM-framework draw back I mentioned above. Plus it requires the code that is constructing the task to know what behavior the code that is going to save the task will require. Most of the time that's probably the same code, but if they aren't, you're out of luck.</div>
<br />
<span style="font-family: Trebuchet MS, sans-serif; font-size: large;"><b>Operational vs Data Classes</b></span><br />
<pre class="prettyprint lang-cs">public class TaskInfo
{
public string Name { get; set; }
public int AssignedTo_UserId { get; set; }
public DateTime DueOn { get; set; }
}
public class TaskList
{
public TaskInfo Create(TaskInfo t)
{
t.Save();
notifier.Send(...);
return t;
}
}</pre>
Here I've separated the data class from the operational class. I talked about this in the <a href="http://www.kevinberridge.com/2012/12/stratified-design.html">Stratified Design series of posts</a>. This separation hides ActiveRecord, giving us the control to define all of our operations independently of the database operations they may require. If we needed to save a task without sending an email we could just call TaskInfo.Save() directly from whatever mythical operation had that requirement. Or we could do some extract method refactorings on the Task.Create method to expose methods with just the behavior we need. Or we might extract another class. Naming is going to be hard for these refactorings, but at least we have options.<br />
<br />
If I missed anything, or if you see an important variation I didn't think of, please tell me about it! As always you can <a href="https://twitter.com/kberridge">talk to me on twitter</a>, and you can still <a href="https://gist.github.com/4318292">fork the original gist</a>.Kevin Berridgehttp://www.blogger.com/profile/13759114853595462455noreply@blogger.com1tag:blogger.com,1999:blog-6579772240267288367.post-50933307452768222632012-12-17T07:00:00.000-05:002013-08-20T22:18:23.461-04:00Slicing Concerns, And Naming ThemNaming is hard. Especially in OO. To name something, you have to understand it at it's deepest level. You must capture it's true essence. This is hard when you're giving a name to a thing that already exists, but it's orders of magnitude harder when you're simultaneously creating the thing out of thin air, and trying to decide what to call it. Which is after all what we do when we're designing code.<br />
<br />
The "essence of things" correlates closely with concepts like Separation of Concerns and the Single Responsibility Principle. You can slice any object into ever smaller concerns or responsibilities. You can slice it right down to it's constituent atoms! Many design problems, like tight coupling and loss of flexibility, are in large part due to having concerns and responsibilities defined at too high a level. Could this be so common simply because it's so hard to find names for the smaller concepts? It's frequently easy to see what those separate concepts may be, but terribly hard to think what to name them!<br />
<br />
Let's have an example:<br />
<script src="https://gist.github.com/4318292.js"></script>
This is entirely fictional code, but it's not so different from a lot of real code I've seen in the wild. And it illustrates this problem of slicing concerns very well.<br />
<br />
At first glance, it seems very simple. The domain has a Task concept which has a default due date (set in the constructor), and which sends a notification email after it's inserted (using an ActiveRecord hook). This very nicely and completely describes what a task is and how it behaves in our system. And the names make it very intuitive.<br />
<br />
Or do they? Is it really the case that <i>every single time</i> we insert a task in the database it should send an email? Unlikely. We should slice that behavior out and put it somewhere else:<br />
<pre class="prettyprint lang-cs">public class _WhatShouldThisBeCalled_
{
public class _WhatShouldThisBeCalled_(Task t)
{
t.Save();
Email.Send(t.AssignedTo_UserId, "New Task", "You have been assigned a new task");
}
}</pre>
This is an incredibly simple refactoring, but I have no idea what this class should be called. The method is a bit easier, it could be InsertAndNotify(Task t) or something similar. But what <i>is</i> this class? What <i>concern</i> does it represent?<br />
<br />
No, really, I'm actually asking you. What would you call it? <br />
<br />
Or how else would you write it? Maybe you'd do something like a fire an event and have someone hook it? How would they hook it? Maybe we need an EventAggregator? This is getting awfully complex for such a simple requirement!<br />
<br />
And it's not done, because it's not really so great that it defaults the DueOn date in the constructor. Is <b>every single task</b> really due tomorrow? Or is it just a certain kind of task, or tasks created in a certain way? And where will we put that code, what will it be called?<br />
<br />
I sincerely believe this is both a significant design problem, and a significant naming problem. I want to know how you'd tackle it. Please do leave a comment or <a href="https://twitter.com/kberridge">tell me on twitter</a> or even better, <a href="https://gist.github.com/4318292">fork the gist on github</a>!<br />
<br />
These concerns need to be separate! But what a cost we pay for it! The simple OO domain model of a Task has turned into something much less relatable. Either it's event driven spaghetti code with strange infrastructure objects like EventAggregators. Or it's a hodge-podge of service or command classes, none of which actually model a relatable thing... They only model functions, features, behaviors, use cases. Or maybe we try applying inheritance, and then we end up in a whole different world of confusing names and surprising behaviors. <br />
<br />
Can't we do better? Is there some way we can do the slicing of concerns we need but still maintain the modeling of real relatable things? Even if that <a href="http://www.kevinberridge.com/2012/11/encapsulation-youre-doing-it-wrong.html">may require a different way of thinking</a> or not using the design patterns that led us here (Active Record, in this case).Kevin Berridgehttp://www.blogger.com/profile/13759114853595462455noreply@blogger.com0tag:blogger.com,1999:blog-6579772240267288367.post-44039485270324837882012-12-14T07:00:00.000-05:002012-12-14T07:00:11.511-05:00The Fundamental Software Design ProblemThe most fundamental software design problem, that this the the most important problem which underlies all design decisions, is:<br />
<h3>
Choosing the right amount of abstraction</h3>
<br />
Say you're starting a brand new project that you don't have any previous experience with. What sort of architecture should we apply? We have a lot of choices, some listed here, ordered in increasing complexity:<br />
<ul>
<li>SmartUI</li>
<li>MVC w/ Active Record</li>
<li>Ports and Adapters</li>
<li>SOA</li>
<li>CQRS</li>
</ul>
<div>
For some problems just a glance is enough to know it needs a more abstract and complex solution. Equivalently, some problems quite clearly should be as simple as possible. But most problems lie somewhere in between. And generally there's really no way up front to know exactly where on the complexity scale it will lie.</div>
<div>
<br /></div>
<div>
Worse still, in a large enough application different portions of the application might be more or less complex. Some areas could be simple crud with no logic, while other areas involve heavy data processing and complex workflow and queries.</div>
<div>
<br /></div>
<div>
And even worser, this is a moving target. If I had a dollar for every time something I thought was pretty straight forward became much more complicated either because of changing requirements, scope creep, or just misunderstanding... Well, I'd have quite a few dollars!</div>
<div>
<br /></div>
<div>
As I see it, there are basically two strategies for dealing with this problem:</div>
<div>
<ol>
<li>Start as simple as you possibly can, and evolve to more complicated designs as things change</li>
<li>Start slightly more complex than may be strictly necessary so that it's easier to make changes later</li>
</ol>
<div>
I would expect people from the Agile and Lean communities to balk at the very mention of this question. They'd probably bring up stuff like YAGNI and evolutionary design. And I agree with this stuff, I agree with it completely!</div>
</div>
<div>
<br /></div>
<div>
But I also think <a href="http://en.wikipedia.org/wiki/Boiling_frog">boiling frog syndrome</a> is a real thing. Even a great team with the best intentions can easily find themselves stuck in the middle of a big ball of mud. That's just life. Little things change, one little thing at a time, and you do "the simplest thing that could possibly work" because hey, ya ain't gonna need to do a big overhaul now, this will probably be the last tweak. And next thing you know, everything is a tangled mess and all your flexibility is gone!<br />
<br />
To add insult to injury, when you find yourself wanting to do a significant refactoring to a more abstract design, it's frequently your unit tests that are the primary problem spot holding you back. Those same tests that were so useful when you were building the code in the first place are suddenly locking you into your ball of mud.<br />
<br />
I can hear you now. You're looking down your nose at me. Huffing and puffing that if I'd had more <i>experience </i>it never would have come to this! If I'd just <i>listened</i> to my tests, the ball of mud wouldn't have happened. If I'd just understood the <i>right way</i> to build software! blah blah blah. Sorry, I don't care. I build real software for real people with a real team, I'm not interested in idealism and fairy tales. I'm interested in practical results! I'm interesting in making the correct compromises to yield the best results while constantly striving to do better!<br />
<br />
And that's ultimately my point! No matter what design I start out with, I want it to allow me to strive to do better. If the simplest thing that could possibly work is going to be hard to evolve into something more flexible, that's a problem. Accounting for change doesn't necessarily mean doing the simplest thing, in some cases it means doing something a little more complicated, a little more abstract, a little more decoupled, or a little more communicative.<br />
<br />
If this ticks you off, please <a href="https://twitter.com/kberridge">come argue with me on twitter</a>!</div>
Kevin Berridgehttp://www.blogger.com/profile/13759114853595462455noreply@blogger.com2tag:blogger.com,1999:blog-6579772240267288367.post-35879715674639068482012-12-13T08:36:00.000-05:002012-12-13T08:36:22.475-05:00The Dizziness of Freedom<blockquote class="tr_bq">
"A man stands on the edge of a cliff and looks down at all the possibilities of his life. He reflects on all the things he could become. He knows he has to jump (i.e. make a choice). But he also knows that if he jumps, he'll have to live within the boundaries of that one choice. So the man feels exhilaration but also an intense dread." - <a href="http://transom.org/?p=28787">Jad Abumrad quoting</a> Kierkegaard</blockquote>
Kevin Berridgehttp://www.blogger.com/profile/13759114853595462455noreply@blogger.com1tag:blogger.com,1999:blog-6579772240267288367.post-4793813881614548632012-12-12T07:00:00.000-05:002012-12-12T11:38:17.104-05:00Neat F#: Custom OperatorsF# has support for <a href="http://msdn.microsoft.com/en-us/library/dd233204.aspx">custom operators</a>. The best use of this I've seen so far is in the <a href="http://lefthandedgoat.github.com/canopy/">canopy web testing library</a>. Canopy allows you to write code like:<br />
<pre>"#firstName" << "Kevin"
"#firstName" == "Kevin"</pre>
That code is the same as this code written with the <a href="https://github.com/featurist/coypu">Coypu web testing</a> library:<br />
<pre>browser.FillIn("#firstName").With("Kevin")
browser.FindField("#firstName").Value.ShouldEqual("Kevin")</pre>
As you've likely deduced, the "<<" operator has been overridden to lookup the field and set it's value, while the "==" operator has been overridden to lookup up the field and assert on it's value.<br />
<br />
In this case, both of these operators <a href="http://msdn.microsoft.com/en-us/library/dd233228.aspx">do exist already</a> in F#, but they obviously aren't usually used to drive a web browser. So this is a powerful use of operator overloading. But F# allows you to define custom operators that have no definition in F# as well. They can be any combination of a certain set of characters.<br />
<br />
For example, there is no "=~" operator in F#, but you could define one to do a regex match as follows:<br />
<pre>open System.Text.RegularExpressions
let (=~) input pattern = Regex.IsMatch(input, pattern)</pre>
And you'd use it like:
<br />
<pre>"some input" =~ ".*input"</pre>
And you could also define one that is case insensitive:
<br />
<pre>let (=~*) input pattern = Regex.IsMatch(input, pattern, RegexOptions.IgnoreCase)</pre>
These operators are not overloaded, they're just custom defined. <br />
<br />
There is clearly a tradeoff here between explicit code and concise code. Look back at the first example from Canopy again. If you knew that was web testing code, and you recognized "#firstName" as a css selector, you would probably figure out what it was doing. And this conciseness is going to be really nice in a situation where you're executing the same type of operations over and over and over again (say, like, in a Selenium web test!). So while there's no mistaking what the Coypu code is doing, I'd rather write the Canopy code!<br />
<br />
However, in the regular expression example, since =~ and =~* are not part of the language, how would you know what they do. Certainly there's a similarity to ruby, but I've never seen a =~* operator. So introducing stuff like this to your code base runs the risk of making your code harder to understand. <br />
<br />
In the end, I think it's an awesome feature to have at your disposal. And I think a good rule of thumb is to be willing to try some custom operators when you have a high and dense repetition of operations. That is, it's not a one off operation, or it's not used always by itself in far flung sections of code.<br />
<br />
In any case, this another powerful, and very neat, feature of F#.Kevin Berridgehttp://www.blogger.com/profile/13759114853595462455noreply@blogger.com0tag:blogger.com,1999:blog-6579772240267288367.post-61844301659856930272012-12-11T08:57:00.003-05:002012-12-11T08:57:39.296-05:00Neat F#: Inferred Return TypesWhat is the return type of this F# function?<br />
<pre>let hello name = sprintf "Hello %s" name</pre>
If you guessed string, you're correct! I know this syntax can be confusing at first glance, so here it is one element at a time:
<br />
<ul>
<li>let hello name =<br /><a href="http://msdn.microsoft.com/en-us/library/dd233238.aspx">let</a>: the "let binding's" job is to associate a variable name with a value or function. It BINDS things to names<br />hello: hello is the name of the function<br />name: hello takes one parameter, and it called name, and it's type will be inferred</li>
<li>sprintf "Hello %s" name<br /><a href="http://msdn.microsoft.com/en-us/library/ee370455.aspx">sprintf</a>: basically F#'s version of .net's String.Format, it's a function that takes a format string with placeholders and values as arguments and returns a string. In fact, this function is so neat it deserves it's own post.<br />"Hello %s": the format string, %s <i>tells the compiler</i> a string parameter is required<br />name: argument to sprintf</li>
</ul>
<div>
sprintf returns a string, therefore the hello function returns a string. Notice there's no explicit return statement, whatever the last statement returns the function returns. However, this is made more interesting by the fact that just about everything in F# is a statement that returns a value, including if statements:</div>
<pre>let hello name =
if name = "kwb" then
"'sup KBizzle!"
else
sprintf "hello %s" name</pre>
This function still returns a string, because the if statement returns a string. Note this means in F# the if and the else <b>must return the same type</b>!<br />
<br />
Also note, there's nothing wrong with that last code sample, but it's my impression that if statements are generally frowned upon in F# in favor of <a href="http://msdn.microsoft.com/en-us/library/dd233242.aspx">pattern matching</a>. A true F# dev would probably have written that last using the pattern matching function syntax like this:
<br />
<pre>let hello =
function
| "kwb" -> "'sup KBizzle!"
| _ as name -> sprintf "hello %s" name</pre>
That's really outside the scope of this post, but it makes me happy!<br />
<br />
So this brings us to the _really_ neat part: functions with changing return types. All the functions we've seen so far have had a single static return type. But what about this function?<br />
<pre>let crazy f =
f 4</pre>
What is it's return type? Maybe this will help?
<br />
<pre>let somestring x = sprintf "the number %d" x
let someint x = x
crazy somestring
crazy someint</pre>
Crazy's return type is different depending on what function we pass to it!<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="http://24.media.tumblr.com/tumblr_lvvco21Oo81r8058ko1_250.gif" imageanchor="1"><img alt="mind blown" border="0" src="http://24.media.tumblr.com/tumblr_lvvco21Oo81r8058ko1_250.gif" title="" /></a></div>
<br />Kevin Berridgehttp://www.blogger.com/profile/13759114853595462455noreply@blogger.com0