tag:blogger.com,1999:blog-91856732860314368252024-03-05T09:10:50.108-08:00AgilologyAgilology- [aj-ahyl-al-uh-jee] -noun
<ol>
<li>The raising of awareness of the benefits of the Agile Methodology</li>
<li>Promoting the use of the Agile Methodology for software development</li>
<li>Providing information on how to be Agile</li>
<li>A perfectly cromulent word</li>
</ol>Jeff Tuckerhttp://www.blogger.com/profile/06381849301612591461noreply@blogger.comBlogger37125tag:blogger.com,1999:blog-9185673286031436825.post-73326752271569825102016-11-29T14:52:00.001-08:002016-11-29T14:52:30.185-08:00Yet again, it's been a whileI've taken a long time off from blogging, mostly due to lack of time and too much general shit going on in my life. I think it's about time I start blogging again. I have a lot of stuff that I've been wanting to write about for a long time so here's to hoping that I can finally catch up and tell the dozens of people who used to read this about some things that will hopefully be useful.<br />
<br />
<h2>
What I've been up to</h2>
<div>
Since my last post in 2011 (wow it's really been that long) I have done quite a lot. I was teaching at DigiPen while also working on getting my MS in Computer Science (thesis is still "in progress" after several years of work). I then stopped teaching and joined the game industry, working at ArenaNet (Guild Wars 2) for a while. That was fun, but I've since decided the game industry in general seems not to be the best fit for me (more about that later). While that may change in the future, for now I'm back to Enterprise LOB application development and currently working for IMS Health (we're now QuintilesIMS as of a couple weeks ago), which you've probably never heard of but I have a shitload of data about your medical history (yes you, the person reading this).</div>
<div>
<br />
In addition, my supra still doesn't run, I've done a substantial remodel on my house including moving my electrical panel, and had virtually no time for anything else. My most significant change though was the birth of my son, Rowan, who just turned three as of the time that I'm writing this. </div>
<div>
<br /></div>
<h2>
The future of this blog</h2>
<div>
While I have a lot of unfinished topics that I want to address, I've also learned so much over the last few years so you can definitely look forward to some new content. I have a few topics that are likely to become a series as well. Here are some highlights:</div>
<div>
<br /></div>
<h3>
Putting the "Science" back in Computer Science</h3>
<div>
I have a few posts that I wrote a long time ago for this <a href="http://agilology.blogspot.com/2011/07/putting-science-back-in-computer.html">series </a>so I still hope to complete those as well as write a lot more about some of the fundamentals that many of us have forgotten. There are of course the basic data structures and algorithms that are pretty much CS101 material and yet many people still seem to forget about these. There are also a lot of other data structures and algorithms that I have found most people have never heard of (or forgotten about completely) that I just think are useful to know about or just plain interesting in some way. Ever heard of a Brodal queue? That's going to be on the list at some point.</div>
<div>
<br /></div>
<h3>
How to DevOps</h3>
<div>
DevOps has been something that I keep hearing in the software industry lately, especially when coupled with the question "how do I even DevOps?" or the more basic "what even is DevOps?" so I'm working on a series of posts that will take you through how to DevOps from the basics to the really cool and complicated shit. I've been doing a LOT with DevOps over the last few years so I have a lot to share in this area. I also have some great examples of what NOT to do, which I think is just as valuable. I find information on what doesn't work to be extremely useful; it doesn't (necessarily) help me solve the problem but at least it can save me a ton of time by eliminating solutions that may look promising but are provably incorrect.</div>
<div>
<br /></div>
<h3>
Nifty tricks for productivity</h3>
<div>
My last main topic area is a bunch of random crap that I've figured out that other people might find useful and that I've used to somehow boost my productivity. This includes some various bash tricks, how to turn Vim into the greatest Python IDE ever, and something I call "The Curious Case of the 12GB Docker Container" (yes that's actually a thing, it's really useful, never do it in production, and more about that in a future blog post).</div>
<div>
<br /></div>
<h3>
All Things Agile</h3>
<div>
I'm still very much into Agile and have seen it go both very well and very badly, with the latter case being more frequent in my experience. I'll start by being a bit controversial: I have come to hate what Scrum has turned into. There are far better ways to attempt to "manage" your software projects so I'll give some specifics on what I don't like about Scrum as well as some alternatives to consider.</div>
<div>
<br /></div>
<h3>
The Technical Interview: you're doing it wrong</h3>
<div>
My last major topic that has come up most recently is my general hatred of how we tend to handle modern technical interviews. Most people want to see "how you think" so they ask a bunch of esoteric questions or programming problems that in reality teach almost nothing about a candidate. I find that I usually only need to ask an interviewee a single question (one of several) and I've had far better results. Asking someone "how would you derp derp derp problem description?" where the answer is "use Dijkstra's algorithm" and then somehow expecting them to remember that algorithm well enough to whiteboard it in 45 minutes after several years of not having implemented it is a really poor way to assess whether or not you want to work with that person and tells you little about their general level of skill. There are better and more open-ended technical questions, but ever those just don't tell you as much about a potential hire. I've learned things from being on both sides of the interview table that I'll share that just maybe might help finally un-fuck this thing we call "hiring" in the tech industry. I've got a post or two worth of ranting about how we recruit in the tech industry as well; I'd love to facilitate some change in that area if at all possible.</div>
<div>
<br /></div>
<h2>
In Conclusion</h2>
<div>
I hope to have time to write at least once per week but we'll see what life actually ends up doing to me this time around. I'm sure I've got some other topics rolling around in my brain as well, probably involving TDD, BDD, and various other ways to write better code. Hopefully at least some of this will prove helpful to someone out there.</div>
<div>
<br /></div>
Jeff Tuckerhttp://www.blogger.com/profile/06381849301612591461noreply@blogger.com0tag:blogger.com,1999:blog-9185673286031436825.post-23881285018595138982011-07-17T18:30:00.001-07:002011-07-17T18:56:24.492-07:00Putting the "science" back in computer scienceHaving transitioned my career into academia and game programming, I'm starting to find that my original intents with blogging really no longer fit my interests much anymore. I still love Agile and also finding better ways to solve problems and write code, but I'm finding that I'm far more interested in algorithms and data structures in general, as well as problems dealing with issues in game programming. I'm taking on topics in networking, graphics, AI, and even *gasp* math. <br /><br />As a result, I'm going to start blogging more about these things starting now (and also make an effort to blog more regularly). As always, I hate blogging about specific technologies and how to use them, instead preferring a more generalist approach so that my posts are useful to anyone writing code to solve problems and not just how to do things with particular technologies or platforms. In fact, I honestly don't care anymore at all about things like platforms, libraries, and frameworks, other than looking at better ways to write such things. <br /><br /><div><span class="Apple-style-span" ><b>We've forgotten the "science" part. . .</b></span><br /><br /></div><div>I feel a lot like developers these days have strayed from fundamentals of things like algorithms and data structures. When was the last time you implemented a hash table? A linked list? Quicksort? Never, because we have all kinds of nifty stuff that handles this for us. That said, it's still important to really know how these things work and I think it's good practice to implement these things as well, if for no other reason than self-improvement. <br /><br />Justin Bozonier had an <a href="http://codelikebozo.com/katas-for-practicing-refactoring">interesting blog post</a> recently talking about code katas and that a kata is supposed to be narrow and focused, and that some of the TDD katas are overly complex, but also involve problem solving, which makes it more difficult to tell if you've done things "right." I feel like algorithms at their core are kata; there is one algorithm that is quicksort, but it has many applications and many flavors. The core of all flavors of quicksort is still quicksort, so it's good practice to be able to code quicksort, as it is easy to tell if you got it right and a deeper understanding of it will help you to understand different ways to apply it to your particular problem. This isn't to say that you should always be rigid and say "we're using quicksort to solve this problem so you implement it this way because that's what you do with quicksort" as this is the same problem that I have with people "doing" Agile or "implementing" design patterns. Design patterns, Agile, and algorithms are just guidelines for ways to solve particular problems, not rules, and as such it's important to know these things. They are the fundamentals of what we do as software engineers and computer scientists. <br /><br /><span class="Apple-style-span" ><b>Stand back, I'm going to try science!</b></span><br /><br />For the future, I'm going to focus each of my blog posts on a particular algorithm, data structure, or even mathematical concept. I'll explain the problem that it solves, how the algorithm works, and attempt to show an implementation of it in some programming language (I'll try to vary this but expect a lot of C/C++/C# for a while, with maybe some python thrown in here and there). <br /><br />My hope is that by reading these, you'll remember your computer science classes and be able to arm yourself with all sorts of nifty ways to solve problems that you can stash in your toolbox just in case they ever come up. After all, knowledge is power.</div>Jeff Tuckerhttp://www.blogger.com/profile/06381849301612591461noreply@blogger.com1tag:blogger.com,1999:blog-9185673286031436825.post-26528937954319234962010-09-27T12:04:00.001-07:002010-09-27T12:35:13.605-07:00Enabling SQL Sever on 800 computers at onceNow that I'm teaching a class in databases, it's useful to actually have a database that my students can use when they need to do their projects. Unfortunately, Sql Express (and other versions of SQL server) do not have TCP/IP turned on by default and even if they did, the default is to use dynamic ports, which of course is no good. The reasons for this security through obscurity was the sql slammer worm that hit several years ago, so for "security" (read: so Mort can be stupid without dire consquences) it disables all connectivity with the outside world. It's fairly simple to change the settings, however I can't do it manually on 800 computers. In addition to this, students (no admin access) need to be able to access the instance of Sql Server to create new databases, so that has to be done as well. In this post, I'll show exactly how I did this, just in case anyone else ever needs to do something similar on their own network.<br /><br /><span style="font-weight: bold;font-size:130%;" >The humble .bat file</span><br /><br />For this exercise, I chose a .bat file as my delivery vehicle. They're pretty easy to write and they work on every computer regardless of what you have installed, which is convenient when other more powerful tools are available. Also, I don't need anything more powerful to run a few commands.<br /><br />The requirements are pretty simple: IT is pretty slammed right now so it needs to be a script that can be run completely unattended, it can't affect anyone working on the remote computer, it shouldn't break anything if it's run multiple times, and if it fails, the fix should be to run it again.<br /><span style="font-weight: bold;font-size:130%;" ><br />First, enable Sql server</span><br /><br />First step is to enable Sql Server to listen on a specific port. There's no command line option to just enable TCP/IP, and obviously using the Sql Server Configuration Tool is out of the question. However, the Surface Area Configuration Tool is an option, and it turns out that tool can clone settings from another instance of Sql Server. All I have to do is enable TCP/IP on my instance, and then run SAC.exe to create a file that has my settings in it. The SAC.exe tool is in the c:\Program Files (x86)\Microsoft Sql Server\90\Shared directory. The command to generate the settings file is "sac.exe out <filename.txt>" and there are other options, but the default (export everything) is fine in this case. <br /><br />To run this on any arbitrary computer, however, the "C:\Program Files (x86)" is no good, since that directory could be anywhere, however Windows conveniently gives us an environment variable called %programfiles% which will be set to whatever directory programs are installed in by default. Finally, the config file could be anywhere (since IT is running this) so let's ensure that we pass that in as a parameter to the .bat file. Therefore, our first line in the file is this:<br /><br /><blockquote>%programfiles%\Microsoft Sql Server\90\Shared</blockquote><br /><br /><span style="font-weight: bold;font-size:130%;" >Setting the default port</span><br /><br />The default port Sql is supposed to listen on is 1433, and if it's not on this port then you'll have to pass the port as a param to sqlcmd (or whatever) and I don't want to do that. Also, by default, the port is dynamic (set to 0) so it could change every time the service is restarted, which is no good. It turns out that the only way to change the port outside of the configuration tool is by editing the registry. It turns out that in a .bat file, this is easy. The command is "REG ADD" and then a bunch of parameters. The registry key for where the port lives for Sql Server is here: <blockquote>HKLM\Software\Microsoft\Microsoft SQL Server\MSSQL.1\MSSQLServer\SuperSocketNetLib\Tcp\IPAll</blockquote><br /><br />We need to create a value here called "TcpPort" and set it to 1433. The command to do this is:<br /><blockquote><br />REG ADD "HKLM\Software\Microsoft\Microsoft SQL Server\MSSQL.1\MSSQLServer\SuperSocketNetLib\Tcp\IPAll" /v TcpPort /t REG_SZ /d 1433 /f</blockquote><br /><br />The /f is necessary to ensure that it doesn't prompt if the key already exists (it might; remember, this has to be able to run multiple times without error). However, the Sql service needs to be stopped and restarted in order for this to take effect. I can use "net start" and "net stop" to accomplish this. Therefore, the next three lines in our .bat file are:<br /><blockquote><br />net stop "SQL Server (SQLEXPRESS)"<br />REG ADD "HKLM\Software\Microsoft\Microsoft SQL Server\MSSQL.1\MSSQLServer\SuperSocketNetLib\Tcp\IPAll" /v TcpPort /t REG_SZ /d 1433 /f<br />net start "SQL Server (SQLEXPRESS)"</blockquote><br /><br /><br /><span style="font-weight: bold;font-size:130%;" >Giving students permissions</span><br /><br />Now that SQL is configured in a useful way, I need to grant some roles to the students. These will be in a .sql script, so all I have to do is run it (we'll examine the script in a minute). The way to run scripts is with sqlcmd, which should be part of the system %PATH% so I don't need to type the full path name, I can just use "sqlcmd" and now that the server is on the default port, it should work. I'll be passing in the location of a .sql file anyway, so let's make that a command line param as well. The final line of our .bat file is therefore this:<br /><blockquote><br />sqlcmd -E -S localhost -i %2</blockquote><br /><br />This tells sqlcmd to use a trusted connection and connect to the instance on localhost and read and execute the contents of the supplied file. Therefore, the full .bat file looks like this:<br /><blockquote><br />%programfiles%\Microsoft Sql Server\90\Shared<br /><br />net stop "SQL Server (SQLEXPRESS)"<br />REG ADD "HKLM\Software\Microsoft\Microsoft SQL Server\MSSQL.1\MSSQLServer\SuperSocketNetLib\Tcp\IPAll" /v TcpPort /t REG_SZ /d 1433 /f<br />net start "SQL Server (SQLEXPRESS)"<br /><br />sqlcmd -E -S localhost -i %2</blockquote><br /><br /><span style="font-weight: bold;font-size:130%;" >So what's in the sql script?</span><br /><br />In the .sql file, I need to enable some roles. Since all students are domain users, I felt it would be simplest to just add that group to the appropriate roles. You probably don't want to do this on your network; would be best to create a "DBUSERS" group or maybe a "DEVELOPERS" group. Not horribly important here though. Let's look at the script.<br /><br />First, we need to grant DB access to a group. That's pretty easy, just use sp_grantdbaccess (that's a stored procedure) that takes two arguements, the group and then a sql group to create. We'll need that group to assign to the correct role. The command therefore is this:<br /><br /><blockquote>sp_grantdbaccess "digipen.edu\domain users", "domainusers"</blockquote><br /><br />Next, we want the students to have db_owner permissions so that they can do things without being an admin, although I honestly don't care what level of access the students have since it's an academic setting. The way I grant db_owner is to use the group I just created and sp_addrolemember, so the next line is this:<br /><blockquote><br />sp_addrolemember "db_owner", "domainusers"</blockquote><br /><br />Finally, they need to be able to create databases. The role for this is "dbcreator" but it's a different kind of role (I don't totally understand this) and therefore I have to add it via sp_addsrvrolemember and the command is this:<br /><blockquote><br />sp_addsrvrolemember "digipen.edu\domain users", "dbcreator"</blockquote><br /><br />Don't forget to add the "go" so that it executes. The full .sql file is this:<br /><blockquote><br />sp_grantdbaccess "digipen.edu\domain users", "domainusers"<br />go<br />sp_addrolemember "db_owner", "domainusers"<br />go<br />sp_addsrvrolemember "digipen.edu\domain users", "dbcreator"<br />go<br /></blockquote><br />Now, everything is good and I can run this automatically on every computer with this command:<br /><br /><blockquote>dbsetup.bat settings.txt addroles.sql</blockquote><br /><br />I've run this on hundreds of computers and it works great. Obviously you can put whatever settings you want in this thing and grant whatever roles you need for your environment. Hopefully this will help someone with automating tasks; I sure could have used a post like this a week ago.Jeff Tuckerhttp://www.blogger.com/profile/06381849301612591461noreply@blogger.com0tag:blogger.com,1999:blog-9185673286031436825.post-79661283543060933172010-06-08T14:56:00.000-07:002010-06-08T15:31:15.264-07:00How to fix Office plugin dependenciesI've been doing some development lately on an Outlook plugin and I've run in to a ridiculous number of issues messing with references, particularly when I have been using 3 different versions of Outlook and uninstalling/reinstalling them continuously. As a result, I've had to figure out a lot about how these interop assemblies and COM objects work. In this post, I will share what I've learned over the last week or so in hopes that it will help others who are using popular search engines to try to figure this out.<div><br /></div><div><span class="Apple-style-span" style="font-size: large;">How to make a plugin</span></div><div><br /></div><div>To develop a plugin isn't horribly difficult. The dependencies you need are as follows:</div><div><br /></div><div><b>Office Interop</b>- you need the interop assemblies for the plugin to function. These are also referred to as the Primary Interop Assemblies (PIA's) Often these are installed with Office but you can download them manually if you need to. These are referenced as a COM object. More on that in a minute.</div><div><br /></div><div><b>Visual Studio tools for Office</b>- you need these also. You can get one version of them here: <a href="http://www.microsoft.com/downloads/details.aspx?familyid=5e86cab3-6fd6-4955-b979-e1676db6b3cb&displaylang=en">http://www.microsoft.com/downloads/details.aspx?familyid=5e86cab3-6fd6-4955-b979-e1676db6b3cb&displaylang=en</a> The dll's here will live in the GAC.</div><div><br /></div><div>For both of these, you'll need to reference the appropriate component for the Office program that you're targeting. For example, I am working with Outlook, so I need the Outlook PIA's to be referenced. The installer you download should have PIA's for all the office products so you shouldn't have to worry so much about that.</div><div><br /></div><div><b>Office.Tools.Common</b>- these are the common tools for office that you need for any addin you build (at least as far as I can tell). Also installed with VSTO so you should have them.</div><div><br /></div><div>The version you need of these depends on what version of Office you're building for, although in theory these are backwards compatible, so if you build a plugin for Office 2003, then it should (in theory) be able to install and run on later versions of Office. I've had some success with this so far; the only issues I've had is with building.</div><div><br /></div><div><br /></div><div><b>I can't find the reference- the dreaded yellow exclamation point!</b></div><div><br /></div><div>I've noticed that I tend to get a lot of build errors relating to these dependencies and not being able to find them. In 90% of the cases, this involves having installed multiple versions of Office or the PIA's, so in general all you have to do is fix the references. </div><div><br /></div><div>Another error you may see is something like "<span class="Apple-style-span" style="font-family: Verdana, Arial, sans-serif; font-size: 12px; color: rgb(51, 51, 51); line-height: 15px; ">HRESULT: 0x80029C4A (TYPE_E_CANTLOADLIBRARY)" </span>which means that Visual Studio can't figure out where the .dll is that you're trying to reference, most likely because that dll doesn't exist. </div><div><br /></div><div>Unfortunately, fixing this involves messing with registries, which is never fun. I'm going to walk you through it as it's not that hard if you know what you're looking for. </div><div><br /></div><div><b>FIRST: BACK UP YOUR REGISTRIES!!!!</b> Don't "pull an Atwood," be sure you have a good backup.</div><div><br /></div><div><b>Fixing the COM stuff:</b></div><div><br /></div><div>If you bring up the properties for the "Outlook" (or other product) interop assemblies, you'll see that the identity is set to some sort of GUID that looks a lot like this: {00062FFF-0000-0000-C000-000000000046}\9.4\0\primary</div><div><br /></div><div>The GUID identified the registry key under HKCR (HKEY_CLASSES_ROOT)\typelib. If this is messed up, it's usually because there are multiple versions of this thing installed, so open regedit and navigate to HKCR\TypeLib\{00062FFF-0000-0000-C000-000000000046} and look at the sub keys. You'll see 1.0 and 2.0 (most likely). Expand 2.0 and you should see 0, flags, and helpdir. Expand 0. You may see both win32 and win64. If you see both, delete the one that you don't need (probably win64) because it means that Visual Studio is confused about which tlb to load. Next, the default key under win32 (or win64) will point to a .tlb file somewhere. Make sure that the file it points to exists. If it doesn't, point it to the right file OR nuke the key and re-install the PIA's. You may see that multiple COM objects are being used. Their GUID's will be under the same TypeLib key in the registries so check those for multiple versions and nuke the keys that point to stuff that isn't installed. </div><div><br /></div><div>Next, check the stdole COM object the same way. Its key is is HKEY_CLASSES_ROOT\TypeLib\{00020430-0000-0000-C000-000000000046} and make sure that the file it points to exists and that there's only one entry.</div><div><br /></div><div><b>Fixing the VSTO stuff</b></div><div><br /></div><div>Next on the list is the VSTO dll's, which actually live in the GAC. There are a few things that can happen, but first nagivate to HKEY_CLASSES_ROOT\TypeLib\{00062FFF-0000-0000-C000-000000000046} and check for versions. You'll see various versions under there such as 9.4 (Office 2010) or 9.2 (Office 2007) and so on. I've found that previous office versions tend to stick around, and depending on what versions you have listed and what you actually reference and what's actually installed, you may find that there is a key that Visual Studio is using that points to something that doesn't actually exist. To fix this, delete all keys that are associated with versions of Office that you don't have installed. I had both 9.2 and 9.4 installed and when I nuked 9.2 (leaving 9.4, which was actually installed) then it started working again. Also, the same win32 and win64 problems can occur here as well, so be sure to delete what you don't need. Finally, check the default key under win32 and ensure that the file it points to exists and is the correct version for what you're building against.</div><div><br /></div><div>This last one is a bit more annoying, because even if you delete the reference in Visual Studio and re-add it, it still might point to the wrong location because the registries are pointing to an invalid file.</div><div><br /></div><div>Once you've gone through all of these, you should be able to build and run your addin and everything will be happy and good.</div><div><br /></div><div>One more thing of note: if your addin can't be loaded, Office will change another registry key to prevent the addin from being loaded the next time Office starts. That key is located here: HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Office\<version>\<office>\Addins\<your> and will contain a DWORD called "LoadBehavior" that controls how Office will load that plugin. If the value is 3, it will automatically load the plugin when that Office product starts. If it's 2, it will not be loaded. In order to force your plugin to be loaded, change this value appropriately. Office will re-set it as soon as it tries and fails to load the plugin so be aware of this and ensure that it's correct, or you'll spend extra time trying to figure out why your plugin isn't working when the cause is just an incorrect setting.</div><div><br /></div><div><br /></div><div>I hope that this has been useful to someone; it took me a few days to figure all of this out.</div><div><br /></div><div><br /></div>Jeff Tuckerhttp://www.blogger.com/profile/06381849301612591461noreply@blogger.com0tag:blogger.com,1999:blog-9185673286031436825.post-27779710368059482042010-05-28T10:00:00.000-07:002010-05-28T10:17:59.276-07:00Why I won't be adopting Visual Studio 2010 just yetI'm probably the only person in the twitterverse that isn't excited about VS2010. I've given a few reasons, but in general I don't think I can adequately express my concerns in 140 characters, so in this post I will explain the reasons behind my choice, hopefully in a way that makes sense.<div><br /></div><div><b><span class="Apple-style-span" style="font-size:large;">.NET 4.0</span></b></div><div><br /></div><div>I want to be perfectly clear; I'm limiting this post to Visual Studio 2010, NOT the .NET 4.0 framework. I actually really like .NET 4.0 and I think that it has some great new stuff and some good fixes for old stuff. I know that WCF has done some cool things also and I'm still excited about where the whole System.Web.MVC thing is going. The problem I have is really limited to the Visual Studio IDE. I'm also not going to mention my raging hatred for TFS here.</div><div><br /></div><div><span class="Apple-style-span" style="font-size:large;"><b>Past versions</b></span></div><div><br /></div><div>I've been really impressed with Visual Studio since VS97. In general, it's been fairly stable, it has some good features, and the debugger has saved me many times. I know that intellisense isn't always as intelligent as I would like, but overall it's been pretty great and has gotten better with time. I've always adopted fairly early on, also; I got VS 2008 from some sort of Visual Studio release event at MS (I forget what it was exactly). I have had a few complaints over the years (add reference took FOREVER in previous versions, vastly improved in VS2008, and then don't forget the dozens of unsorted new items you could add, all of which were fancy names for text file), but often these were with regards to how people were using Visual Studio (see my post about Visual Studio is not a build tool) and not really towards the product itself. I could leave it running for days and it would usually remain stable.</div><div><br /></div><div><span class="Apple-style-span" style="font-size:large;"><b>VS 2010- my history</b></span></div><div><span class="Apple-style-span" style="font-size:large;"><br /></span></div><div>So first of all, I'm not judging this just by the quality of the betas and of the RC build. Remember, I worked at Microsoft so I've actually been using VS2010 internally for a long time; I believe I started sometime back towards the end of 2008 actually and used it all through 2009, since I was working on .NET 4.0. My first impressions of NetFx for 4.0 were that the installer was pretty lousy (it didn't fully support win7 yet though) but otherwise it was pretty nice. However, my first impressions of Visual Studio were that it was slow and it crashed alot. No big deal, I thought, it's still very early in the product's lifecycle, I'll struggle with it for a while and see how things go.</div><div><br /></div><div>So months go by and the product is not any faster. If anything, it crashes more frequently, and this is while I'm trying to do simple things like open a file or type, not anything difficult, although I had problems with the debugger as well. Beta 1 came out, and there was a lot of feedback that it was slow and crashed a lot. That's because it was and it did. That's ok, still early in the product's lifecycle, right? Surely they must be addressing performance issues. </div><div><br /></div><div>Nope, still adding features. Next beta, product still slow and still crashes a lot. In fact, I think it was actually getting less stable towards the end of the year. In November and December, it would crash constantly when I would do simple, normal things like "find in files" or "right-click" or "type something" and I filed bugs. My personal favorite was when it crashed if a file was called "GlobalSuppressions.cs" (didn't matter if VS created the file or if I did, I think it was just the name). Ended up being something to do with corrupting the line endings. Oops. The beta didn't have that bug in it. </div><div><br /></div><div>Of course, towards the end, there seemed to be a massive push to make the thing go faster and crash less, which of course resulted in the release date slipping and a public RC. Surely this is a good thing, right?</div><div><br /></div><div><b><span class="Apple-style-span" style="font-size:large;">So why the hate?</span></b></div><div><br /></div><div>Over the course of this product's life, I've seen it get less and less stable, up through the end of last year. Features were added, and some of them were good, but overall the damn thing just didn't run and cost me weeks of productivity fighting with it. This tells me several things:</div><div><br /></div><div><ol><li>This is a re-write of Visual Studio's IDE. In fact, it's written in WPF, which is not something that I would have described as "fast" or "performance oriented" in general, so I (and some others that I knew) had some doubts from the beginning. That on its own would be a pretty dumb reason to hate on a product but that brings us to my second point:</li><li>This thing has, from the very beginning, been unstable and slow. This does not inspire confidence in the underlying design of the software, particularly since it was a total rewrite and has gotten worse over time. Then, at the end, it magically speeds way up somehow. How did that happen?</li></ol></div><div><br /></div><div>Well, if I were working on a product for over a year and it was slow the whole time, and then in the last couple of months I had to make it faster, I would definitely not have time to go back and look at the whole design and refactor or re-work fundamental parts of the system. I would profile it, find a bottleneck, and then hack it into submission, rinse, and repeat. I don't think I would be able to change the design to something fundamentally more stable at that point, and knowing what I know about how software is developed at Microsoft, there's no way I would be allowed to alter parts of the system like that. Just looking back at my own experience, I feel like what best fits the evidence and my observations is that people started hacking away at it trying to fix the bugs, leaving it in a state where it works, but the underlying design and code is unstable and brittle. If I still had more hacking to do, I would try to buy time by pushing the release date back a bit. </div><div><br /></div><div>I have also heard complaints and speculation that the use of WPF has caused problems. It is definitely true that WPF is somewhat untested technology, particularly within Microsoft, where VS 2010 (I believe) is the first major product to be built using that technology. Think of it as public dogfooding. However, I think trying to dogfood WPF by including it in a major product was a huge mistake, and other people (who will remain nameless but work at MS in divisions that aren't devdiv) have expressed similar concerns, and some of these people were in a better position than I to make those statements. My personal opinion is that WPF is a contributing factor but not the underlying cause of the performance problems.</div><div><br /></div><div>Now, I have not looked at the code base and I can't say for certain that a bunch of people just started hacking away at something with a fundamentally unstable design, however, in my mind at least (and in the minds of others that I know), this is the scenario that best fits both the evidence available as well as what I know about how Microsoft works internally (at least in some orgs). I know that some of you will probably flame me and say that I'm being completely unreasonable and acting on something for which I have no evidence. </div><div><br /></div><div>To that I would say: that's my point. I don't know exactly what happened with this product or why it was so slow and then suddenly got so much faster. I can't say for sure that it was a bunch of people just hacking away at the app at the last minute and I can't say with certainty that this made it brittle, unstable, or just poorly designed. What I can say is that, given what I have observed, I just don't trust it yet. I don't trust that it will increase my productivity. I don't trust that it will be stable and not corrupt my data. I don't trust that I will be able to use it without pain. I don't trust that I will be able to cleanly uninstall it if it ends up hurting more than it helps (heard plenty of uninstall complaints on Twitter and I know for a fact that the uninstall scenario is less of a priority at MS or at least it was when I was there). </div><div><br /></div><div>I haven't lost hope for it; I certainly think there are some great features included in VS2010, but I think I'll wait for the service pack. </div>Jeff Tuckerhttp://www.blogger.com/profile/06381849301612591461noreply@blogger.com1tag:blogger.com,1999:blog-9185673286031436825.post-50068290473640802202009-10-09T11:39:00.000-07:002009-10-09T12:12:18.957-07:00Don't comment it out - Delete that code!You have a big, ugly, huge block of code that you want to improve. The first thing you do? Comment it all out. Then, try to re-implement in a better way. Finally, you just leave the commented out code in the file in case you need to reference it in the future. I've been guilty of this a lot in the past but I've recently come to the conclusion that instead of commenting it out, you should delete it immediately. Here's why:<br /><br /><span style="font-size:130%;">It's bad code</span><br /><br />You've already identified this code as bad. You don't want it to exist. If you keep it "commented out" so that you can reference it, you're referencing bad code. Why would you want to do that? If the code were good, you wouldn't have commented it out, right? Since it's bad, why would you possibly want to use it. If you aren't going to use it, why keep it around?<br /><br /><span style="font-size:130%;">Copy and pasting of commented out code</span><br /><br />I also notice that I sometimes will copy and paste parts of that commented out code in my new implementation. My realization is that if I'm actually using the code that I commented out, I should either:<br /><ol><li>Stop using it. I commented it out for a reason.</li><li>Don't comment it out. If it actually is good code, even if it's a small part, why did I comment it out? I should have left it in.</li></ol><p><span style="font-size:130%;">Leaving it in for posterity</span></p><p>A lot of code that gets left in "so you can see how it used to work." If you want to see how it used to work, you have version control, right? Just look at the history of the file and diff the current file. Problem solved.</p><p><span style="font-size:130%;">Big block comments detailing how something works or what it does</span></p><p>These are also bad. If you find yourself writing one, it means that this part of your code is probably doing too much; split it up into understandable chunks. If you need an explanation of what the code is accomplishing, your unit tests are not descriptive enough. The only exception is if the code implements something intrinsicly complicated such as an an RFC, where even someone with domain knowledge may have difficulty understanding it (example: in RFC 2822, WTF is an addr-spec and what characters are allowed in a domain literal? I don't remember and I implemented it). In this case, two things are useful:</p><ol><li>Reference the RFC (or other standards documentation) by section and subsection. If I'm implementing an addr-spec reader, I can write "This implements the addr-spec in RFC 2822, section 3.4.1 (page 16)" and now someone reading the code can go read the RFC if they need to know more about what the code is doing. </li><li>Write a functional spec. I know, in Agile we favor working software over comprehensive documentation. That's fine. Just because we favor working software doesn't mean we never document. A functional spec of complex logic is hardly "comprehensive documentation;" it's a useful vehicle for clarifying how something works or how different components interact. If that the most effective solution, there's nothing non-Agile about doing it.</li></ol><p><span style="font-size:130%;">In conclusion</span></p><p>If you find yourself commenting out code, ask yourself if you really need to keep any of it and if so, then don't comment that part out. Delete everything else immediately. I promise you that you won't miss them.</p>Jeff Tuckerhttp://www.blogger.com/profile/06381849301612591461noreply@blogger.com1tag:blogger.com,1999:blog-9185673286031436825.post-17414966924719204152009-05-05T21:41:00.001-07:002009-05-05T21:50:02.807-07:00I know it's been a whileIt's been a long time since my last post but I have a few things that I'm working on so I will have something again soon. I just finished my first semester of teaching networking at Digipen and it was a lot of fun! I will be returning there in the fall to teach the same class again (CS260) as well as an advanced networking class (CS 261). I'll have more about this experience in another post.<br /><br />I've also got a few open source projects that I'm working on. I haven't had any spare time to work on any of them until class ended, but now I can devote at least one of them a bit of time so hopefully I'll have something to post about here within the next month or so.<br /><br />Finally, for those of you who have been asking, I am indeed still at the 'soft and did not get hit by the most recent round of layoffs, although unfortunately the recruiter that I worked with to get the job did get let go and I wish him the best of luck as he was awesome. Lots of stuff going on at the 'soft now with Win7 at RC (I'm using the RC build, it's great and I predict that Win7 is going to rule) as well as the .Net 4.0 Beta coming up in the not too distant future (don't know the exact date yet) as well as some Silverlight stuff that I'm only minimally involved with as of this point. I've been away from the Alt.net lists lately also so I hope to be a bit more active in the community in the not too distant future as well.<br /><br />Stay tuned!Jeff Tuckerhttp://www.blogger.com/profile/06381849301612591461noreply@blogger.com10tag:blogger.com,1999:blog-9185673286031436825.post-64008198150132539112009-03-23T13:51:00.000-07:002009-03-23T14:09:33.944-07:00Don't speed up your code, make it do less insteadI just read an extremely insightful blog post <a href="http://asserttrue.blogspot.com/2009/03/how-to-write-fast-code.html">here</a>. It's about speeding up your code, and the author makes an interesting point that he learned long ago from a mentor of his:<br /><br /><blockquote>So there is no way, really, to make code go faster, because there is no way to<br />make instructions execute faster. There is only such a thing as making the<br />machine do less.</blockquote><br />This is fscking brilliant advice. I never thought about code this way, but upon reflection I think he's absolutely correct. I can think of 1000 ways to accomplish this in both managed and unmanaged code, but ultimately it comes from knowing how your code is being built and what instructions are being created from it. As I think about some of the general principles of OO design (i.e. SOLID and such) I really am starting to see how efficient, extensible code improves this. Maybe the right thing to do in managed or unmanaged code when you start analyzing your code for performance is to actually look at the assembly or MSIL that is being generated instead of staring at it and trying to think of ways to optimize. Read the article and learn.Jeff Tuckerhttp://www.blogger.com/profile/06381849301612591461noreply@blogger.com1tag:blogger.com,1999:blog-9185673286031436825.post-40884591328978072942009-03-02T23:27:00.001-08:002009-03-03T00:22:56.642-08:00Alt.Net Seattle reflectionsI always have a hard time with my alt.net reflection blog post. Many great things happened, many great conversations were had, and a lot of great ideas were shared.<br /><br /><span style="font-size:130%;"><span style="font-weight: bold;">Organization</span></span><br /><br />First off, this was my first time as an organizer for anything, so that was a completely new experience for me. One of my first thoughts when we started planning this thing was that for a conference that is self organizing, we sure were doing a lot of work! Ultimately, it really is quite a challenge to pulling this thing off but I think that everyone did a great job. I would especially like to recognize Glenn Block for his outstanding leadership in getting this whole thing going. Finally, I would like to thank <a href="http://www.digipen.edu">Digipen </a>for graciously hosting the event again and for giving us access to their wireless network, as well as Joel and Wesley who were outstandingly helpful as well in making sure that rooms were set up and that everything with the facilities was running smoothly (sorry about the fire alarm).<br /><span style="font-size:130%;"><br /><span style="font-weight: bold;">Everyone still has something to contribute</span></span><br /><br />I said this last year and it definitely proved to be true this year again. There was a lot of diversity in the background, experience, and knowledge of the attendees and when all of them get together to discuss something, I always find that everyone has something valuable to contribute. It is important to remember that we are all leaders<br /><br /><span style="font-weight: bold;font-size:130%;" >Lots of n00bs</span>!<br /><br />It was also great to see a lot of new people to Alt .Net this year. There were lots of new faces and I think it's important that we continually encourage people to join the community. If we don't, I fear that we would just become an echo chamber which would not be good. I am glad that we were able to have so many new people attend this year and that we opened registration up a bit more to give as many people as possible a chance to attend. We also had a great conversation at the Alt .Net pedagogy discussion and I hope that we're able to get going on some of the ideas that we talked about, although I think that's going to have to wait for a future blog post for me to really do it justice. <br /><br /><span style="font-size:130%;"><span style="font-weight: bold;">And good to see you all again</span></span><br /><br />It was great to meet all of you whom I met for the first time and great to see everyone that I met last year again. We had a lot of good hallway conversations everywhere and it was always hard for me to go back home for the night as I felt like there was always something else to be said, someone else to talk to, or something new to learn (I had a great conversation at 13 coins at 3:00am on Sunday). I'm looking forward to the next conference or to wherever I see you. Feel free to tweet me (http://twitter.com/jeff_tucker), email me, or otherwise contact me any time about anything interesting (most of you have my phone number now and don't realize it as it was posted on the door of Digipen for two days). <br /><span style="font-size:130%;"><span style="font-weight: bold;"><br />Videos and stuff</span></span><br /><br />There's a lot of video out there from the conference. Several people were recording and streaming. I think Scott Hanselman has the most complete list of the videos that I've yet seen <a href="http://www.hanselman.com/blog/ExperiencingALTNETSeattle2009OpenSpaces.aspx">here</a>. You can also check out the wiki for the event <a href="http://altnetseattle.pbwiki.com/">here</a>.<br /><br />Finally, I'd like to join the staff of the Redmond Town Center Red Robin in wishing Justin Angel a very happy birthday!Jeff Tuckerhttp://www.blogger.com/profile/06381849301612591461noreply@blogger.com0tag:blogger.com,1999:blog-9185673286031436825.post-26858749967097404602009-01-19T16:25:00.000-08:002009-01-21T21:56:10.856-08:00Why dispose is necessary and other insights on managed codeJeff Atwood has once again <a href="http://www.codinghorror.com/blog/archives/001211.html">jumped the shark, this time about managed code</a>. Then there's this little gem from twitter:<br /><br /><blockquote>I believe .Dispose() is a form of optimization, which is necessary *sometimes*<br />but not *always*. Anyone got links with evidence otherwise?</blockquote><br />So for my next trick, I am going to show Jeff (and everyone else) how managed code works and when it fails.<br /><br />First, I always have a saying when introducing managed code:<br /><blockquote>Managed code isn't.</blockquote><br />The reason that I say this is that most people think that because your code is managed, you don't have to think about memory management at all; you can just allocate whatever you feel like and the garbage collector will just take care of it for you. According to Jeff, this is a good thing. It is indeed a good thing, although unfortunately it doesn't work that way, and if you don't know precisely what the CLR is doing to your code and how garbage collection works, you're going to have problems and when they occur you will have no idea where to look for solutions. The goal of this post is to try to educate you as to what is going on. I will not be able to go into a lot of depth in one post, however this should get you started and give you some resources to do further exploration when you run into these problems in your code. Let's start with looking at dispose().<br /><br /><br /><br />For those of you who are unsure, dispose() is an implementation of the disposal pattern. The idea behind this is that you have a way to mark a class as having an explicit cleanup that needs to occur prior to that object being deallocated. .Net accomplishes this by an object implementing the IDisposable interface with the Dispose() method, which you should call when you are finished using an object so that it can free its resources. This method should invoke the same code as when Finalize() is called (more on finalization below), so if someone forgets to call Dispose(), it is still guaranteed to be cleaned up prior to garbage collection occurring. Therefore, it is a good place for cleaning up unmanaged resources, like database connections or open streams (e.g. files and network connections). That way you are 100% guaranteed that this cleanup will occur, even if the programmer simply stops using a particular object and lets it fall out of scope.<br /><br /><span style="font-size:130%;">Using(disposal pattern)</span><br /><br />This brings us to our second useful piece of code, which is the using() {} block. This block allows you to put something that implements IDisposable (henceforth "disposable") inside the using() keyword, and then upon leaving the basic block defined by the using statement (i.e. going outside of the {} by any means), the dispose() method WILL be run prior to the jump that occurs. This means that inside my using block I can return, break, exit, throw, or otherwise jump to another block of code and before that code exists, dispose is called on the object in the using() statement. These can be nested, in which case objects are disposed in FILO order (first in last out). These also work with finally blocks so that if I have a try..finally with a nested using block, the dispose is called prior to the finally, even in cases where code inside the using block throws an exception dispose is still called first. You can test this quite easily by writing a simple app with nested using blocks and then throwing from inside one of them and catching outside of it.<br /><br /><br /><br /><span style="font-size:130%;">So why does using() exist?</span><br /><span style="font-size:130%;"></span><br /><br />When I interviewed for Microsoft, one of the questions I got asked was "Is the using() statement syntactical sugar?" My answer was that yes, it is, but it is important. Here's why: I define syntactical sugar as any language keywords that perform a function that you could still perform without using that specific keyword(s) but the implementation would be uglier, more difficult, or less likely for a programmer to use properly. For example, I could still close database connections with a try . . .finally block and explicitly call dispose(). In fact, if you look at the MSIL code generated for a using() block you'll see that it generates a try . . .finally block. I could even not have IDisposable and just have a cleanup method somewhere else or even explicitly define it. The nifty thing about using() is that I can just wrap an object around it and be guaranteed that the object will be disposed of properly in a deterministic fashion (with finally, it's impossible to know when dispose will be called because you don't know if an exception will be thrown until runtime and exception handling runs before finally does).<br /><br /><br />In addition, what if I forget to call dispose in the finally block? What if it is far away from where I use the disposable object so I don't see it right away? What if I need to ensure the order that dispose is called in for multiple objects and I mess that up? What if exception handling is significant to how I handle disposal? There are a lot of what-if's here and the using() statement basically give me a convenient shortcut while making my code a bit more clean.<br /><br /><br /><span style="font-size:130%;">So how does this tie into garbage collection now and why call dispose() at all?</span><br />The garbage collector mostly runs whenever it feels like it and what it does is entirely up to the garbage collector. Let's look at Jeff's SqlConnection cleanup example and see what's going on here:<br /><br /><blockquote>sqlConnection.Close();<br />sqlConnection.Dispose();<br />sqlConnection = null;<br /></blockquote><br />So first, we call Close(). This has nothing to do with garbage collection, presumably it just closes the connection itself. Then we call Dispose(). Presumably, Dispose() would clean up an open connection, probably by calling Close(), but it's entirely possible that it does other things as well. According to MSDN, Close() and Dispose() are redundant, so it looks like Jeff is violating DRY here, although I think that having Close() and Dispose() do the same thing is ugly and misleading code. Finally, he's setting the object = null. Remember kids, this isn't actually setting the value of the object, he's just setting his current reference to it to null, which tells the garbage collector that he's not using it here anymore. If there are no other references still in scope in the rest of the application, it means that the garbage collector is free to clean it up (in unmanaged code, it would mean you have a memory leak).<br /><br />Let's look at a non-real, contrived example; if I grab a connection to a db and I'm using winsock to connect, I'll get a handle to the socket that I'm using from winsock, which will be wrapped in some sort of SafeHandle object to ensure that it gets cleaned up. If Close() only closes the socket, it may not clean up the handles. If Dispose() calls Close() and then cleans up the handles, then it's entirely possible that the Close() and Dispose() calls are redundant, but that they do different things. Maybe if you call Close() you can re-use the connection object. That might be useful, particularly if that object takes a long time to create or is resource-heavy even when not connected (like if it allocates buffers for example). Ultimately, what you do depends on how you implement your object, so be sure that you have a good design and don't encourage bad code with redundant calls.<br /><br />One other problem can exist: when an object is Disposing, what if somewhere you have another reference to that object and that reference is in use that you don't know about? If you let the garbage collector just run Dispose for you then obviously this won't be a problem, but if an eager developer calls it, you definitely have a problem. I think that if you have this problem, probably your code is not well designed, but there's a cheap way to manage it if you think it's necessary: create a private "bool isdisposed" property and when you call dispose, set this property immediately at the start of the Dispose() method (and make this thread-safe through correct use of some sort of locking strategy). Then, on every other method call, you can check the value of this property and then react accordingly, although again I would label this as code smell.<br /><br /><span style="font-size:130%;">And then there's the object = null</span><br />Jeff mentions the confusing choice of calling dispose and setting null but in reality, if you know what these actually do, there's no confusion at all. If you call Dispose(), as I have mentioned at least six times now, it will run the cleanup of the object when you call it. If you set the object to null, then all you're doing is removing a reference to it and the garbage collector will then see that there are no more references to this object so it's ok to clean it up. If it wants to. When it does do cleanup, it will call Dispose for you, however it is completely non-deterministic as to when this occurs, so leaving it to the garbage collector for things like database connections or files or network connections is a bad idea since it would be easy for you to have a bunch of open connections this way, which can cause all kinds of bad problems.<br /><br /><span style="font-size:130%;">So now, how is disposal "more of an optimization than anything else?"</span><br /><br />It's not. Jeff is wrong because Jeff is right (different Jeff though. . .) and Jeff (me) says that calling Dispose is absolutely necessary so that you can have deterministic behavior in your application in terms of resource deallocation. There are lots of resources that you're using in the .Net framework, even if you are not aware of the fact (things like threads, files, even graphics tend to open handles into unmanaged code). If you are not careful about when you dispose things, it's easy to start leaking these, particularly in high-performance applications. It really isn't an "optimization" to call Dispose when you want to explicitly free up resources, particularly unmanaged ones.<br /><br />Also, if you have some significant amount of work that has to be done to free up those resources, then you really should do that work at a time of your choosing. If you don't, then potentially any time you create a new reference type, the garbage collector may run and may collect something that you aren't using anymore, at which point all of that work that needs to be done to free your resources will just happen, which may affect the performance of your app in various ways, none of which will make it go faster. This isn't optimization though, it's simply good coding style.<br /><br /><span style="font-size:130%;">So what should I do in my code?</span><br /><br />First, if you allocate any resources in an object, particularly unmanaged ones, you should clean them up in your Dispose() method (while ensuring that your object implements IDisposable). I find it unusual that your objects will need to allocate external resources, but it's likely that you will consume some without realizing it, which means that you should either dispose of them explicitly inside the object when you're through with them, or that you should call their Dispose() methods from inside your object's own Dispose() method.<br /><br />Next, if you have another method like "Close()" or "Shutdown()" or "DieYouGravySuckingPigDog()" then you should ensure that these methods don't do any disposal for you. These types of methods aren't meant to clean up an object so that it can't be used anymore (that's what Dispose() is for). If you have an object, then at any point in the object's lifecycle it should be usable in some way prior to calling Dispose(), and not-usable after calling Dispose(). Make sure that a disposed object won't try to do anything bad if you accidently call it after you've disposed it also, generally by writing good code where you don't attempt do this, but some checking in your object won't hurt. If you want to reuse objects a lot, consider using an object pool (a buffer pool for handling Socket reads would be a good idea as an example).<br /><br />Finally, remember that just because you set an object to null doesn't mean that it's going to be disposed at any point in the near future, it is just being marked as no longer in use (unless you have another reference to it somewhere else). This is not a strategy for garbage collection<br /><br /><span style="font-size:130%;">So what about Finalize()?</span><br />It turns out there is another method called Finalize() that is used by the garbage collector for cleaning up unmanaged resources. It's purpose in life, according to <a href="http://msdn.microsoft.com/en-us/library/ddae83kx(VS.80).aspx">MSDN</a>, is to clean up unmanaged resources in the event that Dispose was never called, but if you implement Dispose you should NOT have a Finalize and you should use GC.SurpressFinalize(this) to stop the finalize method from being called. This is to ensure that you do not do duplicate work that is not needed (generally the code called in Dispose and Finalize should be the same). There is also an object destructor, but for managed objects you should not use it. Again, this is all according to MSDN, and I would trust MSDN on garbage collection more than a person who used to code and stopped doing that to write about it.<br /><br /><span style="font-size:130%;">Wait, wait, I didn't get that. What should I do? Can you sum this all up?</span><br /><ol><li>If you are using something that is IDisposable, you should call Dispose() when you are finished with it and when it is a good time in your app to do so performance-wise. Just letting the garbage collector do it for you is not a strategy for anything except crappy coding (if crappy code is your goal, then never call dispose and you'll be about 80% there)</li><li>If you are implementing an object that uses unmanaged resources, you should make that object IDisposable and free those unmanaged resources and then call GC.SurpressFinalize(this) in your Dispose() method. Ensure that calling Dispose() multiple times does not throw an exception or duplicate work (setting a private property is a useful idea here)</li><li>Setting an object to null is not a strategy for garbage collection. It is a strategy for crap.</li><li>If you have an object that is re-usable after calling some sort of closing method (like a connection, file, etc.) then consider pooling that object, particularly if that object is expensive to create or destroy. Remember, every time you allocate a reference type you may trigger garbage collection and you'll never know it.</li><li>"Managed code" isn't managed all that well; you need to be absolutely aware of what the CLR is doing to your code and how garbage collection works. It's like walking on a tightrope- managed code gives you a safety net but that doesn't mean you should just jump into it whenever and then climb back up and keep going. That is not a strategy.</li><li>Every time codinghorror posts something that jumps the shark, check out <a href="http://agilology.blogspot.com/">http://agilology.blogspot.com/</a> for clarification and amusement.</li></ol>Jeff Tuckerhttp://www.blogger.com/profile/06381849301612591461noreply@blogger.com7tag:blogger.com,1999:blog-9185673286031436825.post-74067827747902535382008-12-23T21:08:00.000-08:002009-01-01T23:01:30.641-08:00Alt .Net Seattle Open Spaces is on!I just heard back from Digipen about using their facility for the Alt .Net open spaces this year and they are once again graciously willing to host the event. Therefore, it's looking like it's going to happen the weekend before the MVP summit, which is Feb 27 - Mar 1, 2009. I don't have a lot of details yet, but last year's open spaces event was phenomenal and this year is going to be at least as awesome also. Keep watching the blogosphere for details. I'll post updates here as well as link to other information once it becomes available. Registration hasn't opened yet but here's the site: <a href="http://altnetseattle.pbwiki.com/">http://altnetseattle.pbwiki.com/</a>Jeff Tuckerhttp://www.blogger.com/profile/06381849301612591461noreply@blogger.com0tag:blogger.com,1999:blog-9185673286031436825.post-79147016556744536852008-12-20T23:49:00.000-08:002008-12-21T00:29:01.844-08:00Can't blog now, I have a class to teach!So it's official, I will be teaching the networking class (CS 260) at <a href="https://www.digipen.edu/">Digipen</a> starting in January. This was a bit of a surprise to me (a friend of mine recommended me for the job), but I'm really excited about it. This will be my first official foray into the classroom, so I'm looking forward to the experience and more importantly the chance to teach and influence about 100 aspiring developers (and now would be the time where <a href="http://silverlight.net/blogs/JustinAngel/">some of you</a> probably have a heart attack). I've done plenty of public speaking and teaching on a much smaller scale, so I view this as a challenge to my current abilities but not something that is beyond me.<br /><br />Why am I doing this? Well, it goes back to something that <a href="http://www.hanselman.com/blog/">Scott Hanselman</a> said back at Alt.net Seattle last year. I don't remember his exact words, but he said to go out to your local schools and talk about programming and that engaging the next generation of programmers is important. Well, you can't say I wasn't paying attention.<br /><br />So the obvious question is, why me? Well, to start with, I work with networking every day. I am on the Network Class Library Team at Microsoft, and we are the owners of System.Net, which is where pretty much all low-level networking functionality lives in the .Net framework (technically it lives in winsock and we call into it via P/Invokes). I'm not a game programmer (although I originally started coding to write games) but I've written a few games in my day (tetris clone, text-based RPG, all the common ones that you start tinkering with) so I at least have a good idea about how these things work, and games are very non-trivial to write, even the simple ones.<br /><br />Also, networking for games isn't horribly different from networking for anything else in terms of passing data, however there are a LOT of interesting considerations in making a networked game. For example, <a href="http://en.wikipedia.org/wiki/Nagle">naggling</a> is absolute death for a game. Sending a dataset that is too large is also death because of a few reasons, two of which would be that longer packets are more prone to errors and collisions, and that larger sets of data are more likely to get sent as part of multiple packets, which can delay your messages even further and cause more lag, especially at lower layers than TCP/IP that you're probably not even aware of. On top of that, things like NAT and proxies are a huge problem. Finally, games are real-time sytems, and networks by definition do not have real-time, there is ALWAYS a delay of some type so handling that can be very painful as well. <br /><br />So, what's the hardest thing about teaching a networking class? So far, it's creating the fucking syllabus! I'm not talking about writing it out and all the class expectations, grading policies, and all that stuff; that's easy. The question is, how do I go from week one to week fifteen and teach people who may or may not know anything about networking how to program networked games? There are obviously a lot of topics that I should cover, and I could probably spend 15 weeks on any one of them. The problem is that I have to figure out what isn't as important and what can be cut out as well as what acedemic information I need to include.<br /><br />I've made a few choices so far. First, I'm only spending about an hour on the OSI model. It's not horribly useful and TCP/IP, which is the dominant protocol out there right now, doesn't really map very well onto it, despite what lots of people say.<br /><br />Next, I'm going to jump straight to the top of the TCP/IP model and introduce winsock so that the students can start writing code, then we'll work our way down from there. I will have at least three projects, but I'd like to have four if my current plan for a third project goes the way I intend it to. I won't say what they are (in case some of my students are reading my blog. Yes, I know you are AND I know how you figured out that this is my blog AND I know who told you about it) but they're going to be a lot of fun and a huge challenge. Everything in networking is multi-threaded, it pretty much has to be or you'll get stuck listening and unable to talk or talking and unable to listen. Or maybe you'll just take some of your data and then start doing something with it and meanwhile, your 8k buffer that winsock has is starting to fill up and all of a sudden you're rejecting packets. <br /><br />Beyond that, I won't say too much, although I will be posting about my experiences here periodically. Anyone who has any ideas or input for the class, please feel free to post up in the comments. I'm really looking forward to this and I hope that my students learn something valuable from it (and I hope they enjoy the class, too, but I'll take learning over enjoyment in this case).Jeff Tuckerhttp://www.blogger.com/profile/06381849301612591461noreply@blogger.com1tag:blogger.com,1999:blog-9185673286031436825.post-81745539745401671782008-09-15T16:05:00.000-07:002008-09-15T16:25:49.741-07:00Visual Studio quirk- it works on my boxI encountered an interesting Visual Studio thing today. Someone sent me a bug with a repro. I ran it on my machine and started stepping through the internals of the framework to see what the issue is. It worked fine. Hmm, that was interesting, I wonder why? So I run it again and this time I don't step through it and it fails. Ok, that's strange. When I just execute the code, it fails, but if I step into it and don't do ANYTHING except step through the code, it succeeds. WTF?<br /><br />Well, I had forgotten about something: Autos and locals. In Visual Studio, when debugging, the debugger creates watches on local variables as well as a few things it just watches automatically. In order to get the values of these, it has to evaluate them, and therein lies the problem: If evaluating any of those variables causes any side effects that don't occur during the normal running of the application, it can cause unexpected behavior. Here's an example: <br /><br />Let's say that I have some state property on my object that is initialized to null. I have a method that depends on this state property being set. That state property is set when you access another property somewhere. Assuming that property is not accessed in the code path that I'm executing, the state property will not be set. HOWEVER, if I trace through the code and evaluate the property that sets the state property, it will end up setting my state, thus changing the way my code executes. Let's look at a concrete example:<br /><br /><blockquote>class testthing<br /> {<br /> private string s = null;<br /><br /> public string PropString<br /> {<br /> get { if (s == null)s = "new"; return "new";}<br /> set { s = value; }<br /> }<br /><br /> public bool forceit = false;<br /><br /> public bool DoSomething()<br /> {<br /><br /> if (forceit)<br /> Console.WriteLine(PropString);<br /><br /> return s == null;<br /> }<br /><br /> }<br /><br /> class Program<br /> {<br /> static void Main(string[] args)<br /> {<br /> Console.WriteLine("Starting run");<br /> testthing t = new testthing();<br /> bool x = t.DoSomething();<br /><br /> Console.WriteLine("result was: " + (string)(x ? "true" : "false"));<br /> Console.ReadKey();<br /><br /> }<br />}</blockquote>So the class testthing has a property PropString that doesn't set the internal value of the private field s until the Get is called. Therefore, if you never call PropString.Get, it never sets the value of s, and DoSomething() will return true because s defaults to null. Run the example code and observe this, it's pretty straightforward.<br /><br />Now, run it a second time, except this time put a breakpoint on the first line in DoSomething(). When it breaks, hover over the Console.WriteLine(PropString) so that it forces the debugger to evaluate PropString. Now, execute the rest of the code (f5) and observe the output is false, because the debugger has executed the getter of PropString which had a side-effect.<br /><br />So, the next time you debug an application in Visual Studio and it works in the debugger but not in the code, look at your variables within the method throwing the exception and see if any of them could possibly be changed through evaluation. If so, then you may have found the problem. <br /><br />One final word: If you have a unit test for something like this, your unit test will fail since it won't evaluate the property when it's run. It would be far easier to write a failing unit test around the method that has the bug and then figure out why it's failing than to step through the method and hope that you can see where it's going wrong.Jeff Tuckerhttp://www.blogger.com/profile/06381849301612591461noreply@blogger.com1tag:blogger.com,1999:blog-9185673286031436825.post-26787621463512662502008-09-11T02:27:00.000-07:002008-09-15T16:04:28.973-07:00Let's just blame Microsoft!This is a good one. Some guy named <a href="http://blogs.computerworld.com/user/137">Steven J. Vaughn-Nichols</a> is <a href="http://blogs.computerworld.com/london_stock_exchange_suffers_net_crash">blaming the Sept. 10th London Stock Exchange crash</a> on .Net. Wow, informative! It crashed. it runs on .Net, so that must be the reason. .Net isn't suited for real time systems! Right? Not so fast, dude.<br /><br /><span style="font-weight: bold;font-size:130%;" >Full disclosure</span><br /><br />Before I start, let me just say that I do work for Microsoft and I work on the .Net framework. Does this make me biased? Probably, but I'm going to attempt to focus on other things besides "Microsoft good, .Net good" here and draw a logical conclusion.<br /><br /><span style="font-size:130%;"> <span style="font-weight: bold;">What happens</span></span><br /><br />So, what's the scenario? Well, apparently (according to Steven) the LSE runs some software called TradElec, which is a c# application. It also runs on Windows 2003 with Sql Server 2000. Clearly, the weak point is .Net here, nothing else it could possible be. Right?<br /><span style="font-size:130%;"><br /><span style="font-weight: bold;">You are full of fail</span></span><br /><br />So Steven probably wrote all those "conclusions" down on a mat, which he then placed on the floor, so that he can "jump" to them. He clearly has. Something broke, so it's Microsoft's fault, because .Net just sucks for real-time applications. So does Sql Server 2000 and Windows Server 2003. There's nothing else that could have gone wrong, right?<br /><br /><br /><span style="font-weight: bold;font-size:130%;" >There's no way it could be human error. No way at all</span><br /><br />What he doesn't say is that this could possibly be programmer error. There are thousands of ways that a programmer could mess this up and just write crappy code. For network connections, the Asynchronous programming model is not trivial and requires some reasonably deep understanding before you can really make it work well for you. I see a lot of people mess this up, and unfortunately it's their fault and their problem most of the time because the performance you get through asynchronous programming comes at the price of being complex and involving multiple threads, which is something that a lot of people just don't understand.<br /><br />Additionally, we don't know how they're doing their DB access here. Maybe they have some sort of transaction hell that's locking the shit out of their DB. Maybe they don't use stored procs (BIG performance issue in Sql2k, fixed in Sql2k5 so not a big deal there). Maybe they don't know how to create an index. My point is that we don't know, so we can't say for sure. Probably, however, this is an issue.<br /><br />Finally, the .Net framework itself has some interesting quirks if you don't really understand the CLR well. I don't usually recommend books on specific software technologies, but go out and get a copy of <a href="http://www.microsoft.com/MSPress/books/6522.aspx">CLR via C#</a> by Jeffery Richter; I learned more about the CLR in that book in a month than I did in two years of using .Net every day. Granted, garbage collection takes away a lot of the complexities of memory management, which can be a big performance issue, however as a developer you STILL need to understand what the CLR is doing. Things like boxing and unboxing can take time, mis-using value types and reference types eat performance, even how you allocate objects can affect performance. For example, if you're using buffers for network traffic, if you allocate a new buffer each time, you may trigger garbage collection which will randomly hurt performance and be difficult to track down. if instead you allocate a massive pool of buffers and then just use those, they will live on the large object heap and they will NEVER trigger garbage collection so your app will be more consistent.<br /><br /><span style="font-weight: bold;font-size:130%;" >Blame Canada . . .um. . . er. . . .Net? </span><br /><br />So do we blame .Net? With this much information, we really can't. It's far more likely that Sql 2000 is to blame (if anything), although I've seen shit databases created in open source just as often as MS Sql so it's entirely possible that it was just designed stupidly. It's also equally likely that the people who wrote this just screwed up, either in writing the code or improperly testing it. Again, these things would happen if the same programmers used open source software.<br /><br /><span style="font-size:130%;"><span style="font-weight: bold;">Wow, what a useful solution!!!</span></span><br /><br />What does Steven suggest? Use linux. Wow, that will fix everything! I'll just go install it right now, with KDE and everything!!! Wait, no.<br /><br />Next, he suggests Oracle. I've used Oracle and in some ways I love it way more than MS Sql Server but in other ways I hate it a lot. Oracle is better than Sql2k but I have yet to see proof that it's better than Sql2k5, however I won't pass judgement on that yet. Maybe Oracle would be a better db choice. Not that Oracle's open source or anything. It also works with .Net. I've used it.<br /><br />Next, he recommends Java. Java, with the worst threading model in the history of the world (more on that later), is his recommendation for a fix! I have yet to see a case where a Java application works significantly better than a .Net application doing the same thing. A lot of the tools are similar. The languages are similar.<br /><br />In conclusion, Steven is jumping to conclusions that Open Source software (+Oracle) is better for performance. He has no evidence other than "it was running .net and it crashed" to base this on. He is therefore wrong. I have an idea. So you take this mat, and you write various "conclusions" on it, and put it on the floor, so you can "jump" to them. I'll send him one!<br /><br /><span style="font-weight: bold;font-size:130%;" >And I KNOW it wasn't a .Net networking issue because</span><br /><br />I am on the NCL team at Microsoft. We own the System.Net namespace, which is what handles networking in the .Net framework. It was my turn to handle issues that came that week. If it had been a .Net issue with networking, I would have heard about it. I heard nothing.Jeff Tuckerhttp://www.blogger.com/profile/06381849301612591461noreply@blogger.com0tag:blogger.com,1999:blog-9185673286031436825.post-54843936763769227682008-07-29T13:44:00.000-07:002008-07-30T13:15:45.754-07:00Teaching Java in school is just as controversial as an interview with Justice GrayI read a great article today <a href="http://itmanagement.earthweb.com/entdev/article.php/11070_3761921_1">here </a>that was a follow up to an interview <a href="http://itmanagement.earthweb.com/career/article.php/3722876">here </a>with a Computer Science professor Robert Dewar of New York University. I'll stop for a moment while you go read the articles. Both of them. Like I did. All done? Good, now we can have an intelligent conversation about them, and I have to say that I absolutely agree with Prof. Dewar's main points about today's graduates. (disclosure: I have a degree in Computing and Software Systems from the University of Washington. While Java was used for some things, the majority of my degree was in c++).<br /><br />One of the main arguments that he makes is that Java has a lot of libraries. A lot. To quote Prof. Dewar as quoted from the article (not sure how to cite a quote from a quote correctly so just pretend that I did):<br /><br /><blockquote>“If you go into a store and buy a Java book, it’s 1,200 pages; 300 pages are the language and 900 pages are miscellaneous libraries. And it is true that you can sort of cobble things together in Java very easily…so you can sort of throw things together with minimal knowledge,” he says. “But to me, that’s not software engineering, that’s some kind of consuming-level programming.”</blockquote><br /><br />Now this is absolutely true, and that's one of the strengths of Java is that there are a lot of libraries for everything. The same can be said of <span class="blsp-spelling-error" id="SPELLING_ERROR_0">php</span>, .Net, and <span class="blsp-spelling-error" id="SPELLING_ERROR_1">perl</span>. In fact, .Net has <span class="blsp-spelling-error" id="SPELLING_ERROR_2">CLR</span> implementations of functional programming as well (F#). There are also thousands of applications out there written in Java, .Net, <span class="blsp-spelling-error" id="SPELLING_ERROR_3">php</span>, and <span class="blsp-spelling-error" id="SPELLING_ERROR_4">perl</span>. True, none of them keep airplanes in flight or help launch the space shuttle. However, they do help trade stocks, manage companies, guard private health data, run military equipment, and create useless social -networking sites. So, what's the problem then? Is it that Java isn't as popular anymore in the business world? (Hint: no). Is it that Java is the wrong language to teach students how to program? (hint: no). Is it that we're not teaching computer science properly? (hint: warmer). Well, if you want my opinion, and since you're reading this blog I'm going to assume that you do, then my Answer-with-a-capital-A is:<br /><br /><span style="font-weight: bold;">WE'RE NOT TEACHING THE WRITE THINGS WITH THE RIGHT TOOLS!!!11!1!!11!one!1</span><br /><br />Allow me to explain a bit.<br /><br /><span style="font-weight: bold;font-size:130%;" >Computer Science is too hard so only nerds can take that class</span><br /><br />CS is intimidating for a lot of people. Computers are scary. Computers are complicated. Computers are for nerds who stare at the command prompt all day and never see the sun. These are all things that I've heard from non-CS majors.<br /><br /><span style="font-size:130%;"><span style="font-weight: bold;">Except that people in Math, Chemistry, and Physics need to take that class too</span></span><br /><br />When I was in school, there were also a number of degrees that required the introductory computer programming classes (that's <span class="blsp-spelling-error" id="SPELLING_ERROR_5">CSE</span> 142 and the follow up <span class="blsp-spelling-error" id="SPELLING_ERROR_6">cse</span> 143 at the <span class="blsp-spelling-error" id="SPELLING_ERROR_7">UW</span>). I took the <span class="blsp-spelling-error" id="SPELLING_ERROR_8">cse</span> 142 equivalent class at community college when I was in high school through the running start program. The class was conducted in c (not c++) and I got credit for <span class="blsp-spelling-error" id="SPELLING_ERROR_9">cse</span> 142 by taking it as well as a year of science credits for my high school so that I could free up an extra period for a year to do nothing. The class was challenging but not overly so (in my opinion) and something that helped was that the class had about 20-25 people in it so there was a lot of opportunity for students to get individual help from the professor.<br /><br />I took <span class="blsp-spelling-error" id="SPELLING_ERROR_10">cse</span> 143 at the <span class="blsp-spelling-error" id="SPELLING_ERROR_11">UW</span> my freshman year (way back in 1999 so now you all know how old I am) and it was in c++ at that time. I already knew c++ but that class was still challenging, even for me. I recall the first quiz we had, I got something like 44 out of 100 and I was still two full standard deviations above the mean. A lot of people dropped the class. I remember a project that was our first big exposure to objects and it was a <span class="blsp-spelling-error" id="SPELLING_ERROR_12">dll</span>-hell type situation and almost no one (including me) could get the code to actually build and link. The <span class="blsp-spelling-error" id="SPELLING_ERROR_13">TA's</span> couldn't get it to work. My friend Kevin who was a graduating senior in CS couldn't get it to work. The professor finally said that we should all just turn in what we had and if it didn't build or link, he'd grade more easily on this assignment. This almost made me hate computers. It did make a large number of students in that class say "fuck it, this sucks" and drop.<br /><br /><span style="font-size:130%;"><span style="font-weight: bold;">These are the problems that Java is trying to solve</span></span><br /><br />Java doesn't have <span class="blsp-spelling-error" id="SPELLING_ERROR_14">dll</span> hell. It had an <span class="blsp-spelling-error" id="SPELLING_ERROR_15">IDE</span> that is well supported. It's free. It can be run all platforms easily enough and doesn't require special changes to the code to get it to build on different platforms. The syntax is reasonable friendly. It does have a lot of libraries and stuff, but it's still able to implement most data structures and algorithms that you'd commonly find in such classes, such as linked-lists, b-trees, heaps, <span class="blsp-spelling-error" id="SPELLING_ERROR_16">hashtables</span>, etc. as well as common searching/sorting algorithms. Now, students only have to worry about their code and making it work. There is no (or minimal) frustration with things like getting the damn compiler to work or worrying about environment. If a student likes solving problems in code, they may now choose to <span class="blsp-spelling-corrected" id="SPELLING_ERROR_17">pursue</span> that as a degree instead of getting overly frustrated with dealing with their build tool or <span class="blsp-spelling-error" id="SPELLING_ERROR_18">IDE</span> or whatever. The thoughts of the universities are clearly in making CS not look as intimidating at first and I think that Java solves this problem about as well as it can be solved.<br /><br /><span style="font-size:130%;"><span style="font-weight: bold;">How Java creates at least 10 new problems (that's 10 in like base 50)</span></span><br /><br />The first problem is how students are taught using Java. Just because Java has 100000 different libraries doesn't mean that you have to use them. Ultimately, most of those libraries are written in Java, right? So that's the first problem: when you start teaching data structures and algorithms, you must actually teach them; you can't just let people use the libraries to build applications. Maybe a good example for teaching <span class="blsp-spelling-error" id="SPELLING_ERROR_19">hashtables</span> would be to show the Java <span class="blsp-spelling-error" id="SPELLING_ERROR_20">HashTable</span> class and write a working application that stores and retrieves values from one, but write that application against the Map interface (which <span class="blsp-spelling-error" id="SPELLING_ERROR_21">hashtable</span> <span class="blsp-spelling-corrected" id="SPELLING_ERROR_22">implements</span>). Now, write your own <span class="blsp-spelling-error" id="SPELLING_ERROR_23">Hashtable</span> class that <span class="blsp-spelling-corrected" id="SPELLING_ERROR_24">implements</span> Map and the output from your implementation and the Java <span class="blsp-spelling-error" id="SPELLING_ERROR_25">HashTable</span> class should be the same. Repeat for other data structures and algorithms. Wow, problem solved.<br /><br /><span style="font-size:130%;"><span style="font-weight: bold;">So now that the students learned Java, we can just do everything in Java, right?</span></span><br /><br />Wrong. You just can't teach everything in Java. You can teach some things in Java. I had an operating systems class that was taught about 50% in Java (the other 50% was c++ on a <span class="blsp-spelling-error" id="SPELLING_ERROR_26">linux</span> kernel). It was taught in Java because illustrating concepts with multi-threading is much more complex in c++. Doesn't mean that I don't know how to <span class="blsp-spelling-error" id="SPELLING_ERROR_27">multithread</span> in c++, but it was much easier to debug this crap in Java, which let me focus on the concepts of an OS. The same is true of file IO- we had to implement a virtual file system, which Java made easy by handling the actual file IO for me, however we only got one really big file, and inside that file we had to have our <span class="blsp-spelling-error" id="SPELLING_ERROR_28">inodes</span> and our data and we had to create a "file" implementation that would simulate reading and writing to our big "file." Again, this helped me understand the concept without having to worry about formatting an actual hard drive and interfacing with it. Here's the point:<br /><br /><blockquote>Java allows you to focus more on the concept that you're trying to study without having to spend a lot of time working on the tools and environment. If focusing on the concept is not dependent on the tools or environment, then Java is an acceptable choice.</blockquote><span style="font-size:130%;"><span style="font-weight: bold;">Learning about memory management in a language that manages memory for you is hard</span></span><br /><br />This is probably the biggest point in which Java breaks down as a teaching tool. In order to be a developer, you have to have a solid understanding of how the machine handles things like memory and what implications it has on your program. You don't have to worry about memory at all in Java, so this makes it an inadequate tool for the job. A language like C is really the best teaching tool here since you have to do everything manually. In fact, I think the best way to really understand how memory works is in assembly, where you can actually look at the addressing modes and see the difference between them. This helped me understand pointers more than anything else, which brings us to:<br /><br /><span style="font-weight: bold;font-size:130%;" >You can't learn about machine language without an actual machine</span><br /><br />Java is a virtual machine, but we want to know about actual machines. Having a strong working knowledge of the principles behind how computers work is critical, especially when something goes terribly wrong. You probably won't ever use assembly again in your career after college. You will probably never write a driver or a compiler. However, if you are using these tools (yes, I consider a compiler to be a tool), it's important that you know generally how they work because if they ever don't work, you'll never be able to figure out why. You need to learn this by actually looking at hardware and how it's built. You should be able to design a relatively simple logic-based circuit. You should know how these circuits are used to make up a computer. These things aren't that hard if taught well (and I was taught well so thanks Arnie if you're reading this). Assembly language is how the hardware and software interface, so it's pretty important that you learn it as well. I learned <span class="blsp-spelling-error" id="SPELLING_ERROR_29">motorola</span> 68000 assembly which I think is much simpler than x86 assembly but still illustrates the points well. I now know the difference between<br />int a = 5<br />int* b = a<br />int* b = 5<br />is really in what assembly instructions are <span class="blsp-spelling-corrected" id="SPELLING_ERROR_30">emitted</span> (hint: it's the same instruction but the addressing mode changes). This helps me understand how memory works in programming, and that helps me to ensure that I write programs that don't leak memory (or references in the case of managed code because it's a similar concept).<br /><br /><span style="font-size:130%;"><span style="font-weight: bold;">And now, the things that are missing from the education system.</span></span><br /><br />What I (and many other people) think is missing is a good foundation in object-oriented programming. Most people get a week or two and a homework assignment on polymorphism. That's cool, you understand inheritance not really. What they don't teach is WHY to use inheritance and how to use it correctly. There is nothing on patterns, or <span class="blsp-spelling-error" id="SPELLING_ERROR_31">refactoring</span>, or just generally how to program with objects. There needs to be, as I think this skill is critical to have and that most college grads don't have it because they were never taught it (I know I wasn't). I think that Java would be a good tool for teaching this (although obviously not the only one).<br /><br /><span style="font-size:130%;"><span style="font-weight: bold;">And then there was testing</span></span><br /><br />No one teaches how to test code or even how to make code testable. I'm not talking about running your app and checking inputs and outputs. I'm talking about unit testing, integration testing, and the automation of those things. It's not enough to just know that you have to test or that unit tests are important. You need to understand things like test doubles, test automation, and how to write code that can be tested in isolation. Java would probably be a good language for this.<br /><br /><span style="font-size:130%;"><span style="font-weight: bold;">And then there was all the "other stuff"</span></span><br /><br />So how do you handle building big projects? How do automate a build? How do you manage source code? What is a branch? These are all things that most developers who have experience with them take for granted, but we all had to learn somewhere. Probably we either figured it out by experiencing the problems that these things solve, or someone at our jobs showed us. This needs to start in schools. Don't focus on a specific technology for any of these but again teach the concepts and why they're important. The code isn't all that important in this type of class so I could argue that you could use any language you want. HOWEVER, remember the purpose of this class is managing code not writing it, so don't force students to do anything complex in the code. Use some existing code and make trivial changes to it that force the students to use version control and to change the build process to take into account the more complex stuff.<br /><br />The final thought<br /><br />A lot of universities stick with Java because the students already know it and it's the lowest common denominator. That's fine if you want your students to come out being the lowest common denominators in the world of developers. One critical skill that developers have is the ability to learn new languages, particularly since new languages are developed all the time. This helps stay competitive in the workforce as technology changes. If you just teach the whole thing in Java, then that's a problem because students never get the opportunity to figure out a new language rapidly. <br /><br />So my solution?<br /><br /><ol><li>Teach every class in the most appropriate language for the subject. Intro classes should be taught in something that has a minimum of extra crap to make the programs compile and run. Java is really ideal for this but I would be <span class="blsp-spelling-corrected" id="SPELLING_ERROR_32">OK</span> with c# also. The point of this class is an intro to <span style="font-style: italic;">programming</span>, not an intro into fucking with the compiler.<br /></li><li> At a minimum, each student should be required to work in at least four programming languages while in school, one of which should be assembly and one of which should be object-oriented. HTML is not a programming language.<br /></li><li>Teach how to write good code. Comments != good code. This should be enforced in every class but there needs to be a specific class in how to do this and it needs to happen early in a student's career. Class should cover things like patterns, principles of <span class="blsp-spelling-error" id="SPELLING_ERROR_33">OO</span> design, unit testing, etc.<br /></li><li>Require version control to be used by every student for every class past the intro classes. Universities should provide access to a university-run <span class="blsp-spelling-error" id="SPELLING_ERROR_34">vcs</span> for each student. This isn't as hard to do as it sounds.<br /></li><li>Compiler, Hardware, and Operating <span class="blsp-spelling-corrected" id="SPELLING_ERROR_35">Systems</span> classes should be mandatory (sometimes some of these are not). I wrote a disassembler in assembly language as a final project in hardware. It was hard but not impossible and everyone in the class got at least something that sorta worked. Mine could <span class="blsp-spelling-corrected" id="SPELLING_ERROR_36">disassemble</span> itself accurately.</li><li>Students should be forced to collaborate with each other in every class. Collaboration might include working together, but could also include code reviews or paired programming. <br /></li><li>Don't ever force a student to have their code reviewed in front of the class unless the student is <span class="blsp-spelling-error" id="SPELLING_ERROR_37">ok</span> with it, but anonymous code review or review by the professor in a private setting is fine. I realize that the business world will not conform to this but this is school and we don't want to alienate students. I think this is a compromise that will still teach a code <span class="blsp-spelling-error" id="SPELLING_ERROR_38">review's</span> value and how to conduct one without making people want to drop out of the program (or worse).</li><li>Every class should involve writing at least some code. <br /></li><li>Professors should provide at least one well-written piece of code that demonstrates something that the class is teaching. It's helpful for students to read good code. It's equally helpful for students to read bad code and know why it's bad.</li></ol>Finally, if you're a professor, college administrator, or anything similar and you want to talk to me or anyone else in more detail about this, I'd be happy to chat with you any time. I only rant about this because I <span class="blsp-spelling-corrected" id="SPELLING_ERROR_39">passionately</span> believe that it's important and I will do everything in my power to try to make Computer Science education better. If you're reading this, I challenge you to make this a priority as well. Go talk to your local college. Email your professors. Go offer to talk to classes at your local schools, particularly at the high school and community college levels. Encourage people to be CS students. You never know what kind of influence you'll have on someone unless you do nothing.Jeff Tuckerhttp://www.blogger.com/profile/06381849301612591461noreply@blogger.com2tag:blogger.com,1999:blog-9185673286031436825.post-9962680045682358902008-07-21T14:20:00.000-07:002008-07-21T15:03:22.775-07:00Tag Soup sucks: Hey Jeff, here's a better wayJeff Atwood of coding horror<a href="http://www.codinghorror.com/blog/archives/001155.html"> posted about "tag soup" in web development</a>. I absolutely agree with him on this one: every web development framework currently in existence renders crap HTML code. Remember my <a href="http://agilology.blogspot.com/2008/03/its-called-html-and-its-not-hard.html">HTML wall of shame</a>? Yes, that's a good example of crap HTML being rendered by frameworks. Jeff (Atwood) asks if there's a better solution. Luckily, Jeff (me) has one: it's called writing good HTMLand separation of concerns in rendering. Wow, that's a long phrase. Let's try again: Don't use frameworks because you don't know HTML; the people who wrote the framework don't know HTML either. No, still not good. Let's stick with the old favorite:<br /><br /><span style="font-weight: bold;font-size:130%;" >It's called HTML and it's not hard</span><br /><br />That's right, HTML is not a complex thing and writing clean HTML isn't particularly difficult. In fact, you can leverage a framework and still write good HTML and I'm going to show you how. It's really as simple as using separation of concerns. Let's analyze the various parts of a web page.<br /><br /><span style="font-size:130%;"><span style="font-weight: bold;">HTML</span></span><br /><br />What is the HTML for? It's really a place to store content. Your text, your menu bars, your stupid scrolling marquees, your <blink> tags, etc. All of this goes here. The way I think about it is that you're using HTML tags to create containers for content. A <p> tag is a container for some text. A <table> contains some related data in rows and columns. A <span> tag is going to hold some special line of content. A <div> is going to contain some special stuff inside of it. Notice that I haven't said a thing about formatting, style, or actual content yet. The reason would be that it DOESN'T BELONG IN YOUR STUPID HTML!!!!! One more thing I'd like to bring up here is the hell of nested tables. This occurs when someone wants to do some sort of complex formatting and doesn't know how to use the div tag with CSS. Nested tables are an anti-pattern called "Nested fucking tables" and should be avoided. It won't make your formatting better (Firefox and IE sometimes render different table elements differently so often this actually makes things worse). This brings us to:<br /><span style="font-size:130%;"><br /><br /><span style="font-weight: bold;">Formatting and Style</span></span><br /><br />So wouldn't it be nice if there were some sort of "style" thing you could use to store all your styles so you can keep them in one place (DRY, right?). Maybe some sort of "sheet" where your "styles" could go, and then they would "cascade" throughout the whole site for every page that referenced them. Maybe some sort of "cascading style sheet?" Oh wait, that already exists. Let's use it! Now, you can focus on the HTML only be containers for content and let your CSS define how that content is presented and styled. Separation of concerns, right? Now you have only containers and maybe some information in the containers to identify them to your style sheets (ID and Class are the attributes you're looking for). This is good separation of concerns.<br /><span style="font-size:130%;"><br /><br /><span style="font-weight: bold;">So what about behavior?</span></span><br /><br />This is where the client side stuff comes in. Things get a little trickier here but not that tricky. Ok, I lied, it's not tricky at all if you actually know javascript and treat it as actual application code and not some bastardized client side tag-hiding-style-manipulating crap. Javascript is a language. It is subject to the same rules of all programming: Separation of concerns, DRY, IoC, etc. It should also have its own unit tests. Finally, like CSS, it should be extracted into its own file so that every page can consume it. <br /><br />So now you have containers that can be identified, styles that can be applied to them, and scripts that can determine their behavior all in separate places. The ID's and classes of your containers help your styles and scripts know what to apply themselves to. There is a minimum of code that exists in your HTML that helps bind these things together, and in those pages that really, really are one-offs, you have inline styles and inline javascript (this should REALLY be the exception though). <br /><br /><br /><span style="font-size:130%;"><span style="font-weight: bold;">But the server blah blah blah . . . .</span></span><br /><br />This is where the example that Jeff shows really breaks down. I'm not going to post it up here, but go look at his post and check out the example code. You'll see something really stupidly obvious: YOU'RE DOING LOGIC IN THE DAMN MARKUP!!!! You're concatenating links, you're looping through stuff, you're doing all kinds of crap. Hell, as long as you're at it, why don't you query the database there too just so all your crap is at least in one file? <br /><br />There is a simple solution to this problem: You already have containers defined by your html. Use them. Expose them to the server side code and let that code render stuff inside them. For example, in ASP .Net one of my favorite tricks is to have a table on my page and actually use the <asp:table> object so that my codebehind can expose it to my controller (You're using MVC, right?) and my controller can populate it with data. Wait, controllers shouldn't populate data, so wtf am I doing? Am I breaking my own rules? No, I don't directly populate tables from the controller; typically I use an intermediary object to do that for me (more about this in a future post, I promise). This way, the controller is able to provide the model to the view via some other object that is responsible for doing complex formatting. I can reuse my formatting objects where appropriate. I can also change the formatting without changing the model or the view itself. I can change the view even if I want to without caring how the formatting is created (as long as the contract between the view and my formatting object is fulfilled, i.e. if the view is expecting a table then the formatter had best be rendering one). <br /><br /><br /><span style="font-weight: bold;font-size:130%;" >Here you go, Jeff-</span><br /><br />A nice, happy, clean solution looks something like this:<br /><br />1. The HTML provides containers for content and possibly some content as well.<br />2. The CSS provides style information and formatting for the containers.<br />3. Javascript manipulates the containers client-side to create a client-side view when neccessary<br />4. The server side code populates the HTML containers with content.<br />5. The server side uses helper objects to populate content that requires more complex rendering (tables with grouping levels I think are a good example here).<br /><br />The only thing you need in order to pull this off is to know all of these different technologies. This isn't that hard, and as a web developer you really should know all of this stuff anyway. I think Microsoft started a horrible trend with Asp .Net that allowed application developers to write web apps without knowing anything about web technologies. This attitude has brought us the viewstate, page events, chatty controls, and a bunch of other crap that makes your html look like tag soup. Rails and MVC haven't helped this problem at all.Jeff Tuckerhttp://www.blogger.com/profile/06381849301612591461noreply@blogger.com8tag:blogger.com,1999:blog-9185673286031436825.post-5381457031395322172008-06-26T13:51:00.000-07:002008-06-26T14:46:16.592-07:00Handling time zones in .Net is really easyI have a project right now where we are going to implement a feature that allows an admin to specify the time zone that each user is in. When they view reports on things like system activity or similar that have a time component to them, they will see the times in their own time zone. When they request a report and specify a time, it will parse that time in whatever their own time zone is. <br /><br />Time is a fairly difficult problem to handle since many different areas have different time zones with different rules. Does it have Daylight Savings time? When does that start/stop? What if the dates it starts or stops on change? What about the 25 hour day you get when you change and the 23 hour day you get when you change back? There are a lot of edge cases and a lot of time zones (for example, Arizona is on Pacific Time but it does not have Daylight Savings Time) that you have to account for. Fortunately, .Net has this nifty thing called the TimeZoneInfo class that makes this a trivial problem. <br /><br /><span style="font-weight: bold;font-size:130%;" >Some useful methods</span><br /><br />There are a number of static methods on this class that are useful to the feature that I'm trying to implement. The first story that I want to implement is "As an Admin, I want to see all available time zones so that I can select the appropriate one for a user." Not a problem. I want to load them all and store them in a listbox. Here's the code:<br /><br /><br /> <blockquote style="font-family: courier new;">ListBox list = new ListBox();<br />IList<timezoneinfo> systemtimes = TimeZoneInfo.GetSystemTimeZones();<br /> foreach(TimeZoneInfo t in systemtimes)<br /> {<br /> list.Items.Add(t);<br /> list.DisplayMember = "DisplayName"; <br /> }</blockquote>This will give me a list box that tells me all the time zones that are currently installed in the registries. I have a property on my TimeZoneInfo class called "Id" that gives me the id of the particular time zone, so if I want to save the time zone that a user is on, I can persist the id of that class somewhere and then use this to retrieve it:<br /><blockquote><br /><span style="font-family: courier new;">int tzID = MyTimeZoneRepository.GetTimeZoneIDForUser(someUser);</span><br /><span style="font-family: courier new;">TimeZoneInfo tz = TimeZoneInfo.FindSystemTimeZoneById(tzID);</span></blockquote>Alternately, I can serialize and deserialize my TimeZoneInfo class in order to be able to persist it and reconstitute it in situations where I may not want or have available the system time objects. The code for that would be this:<br /><br /><blockquote style="font-family: courier new;">TimeZoneInfo tz = TimeZOneInfo.FindSystemTimeZoneById(1);<br />//tz now has some time zone value<br /><br />string serialized = tz.ToSerializedString();<br />//serialized is some really long string that has all the time zone info in it<br /><br />TimeZoneInfo tzNew = TimeZoneInfo.FromSerializedString(serialized);<br /><br />Assert.AreEqual(tz, tzNew); //should return true</blockquote><br /><br />This also means that I can create my own custom timezone if I want to by defining a set of rules and then instantiating a TimeZoneInfo class from my rules (I'm not going to give an example here but there's plenty of them out there). <br /><br />Now, to actually use these things, I use the TimeZoneInfo.ConvertTime() method. So, if I want to fulfil my second user story, which is "As a user, I want to have all my reports reflect my local time zone so that I can see when things happened in relation to where I am" then I have a means to do so. <br /><br />In order to do this, I need a UserTimeZoneRepository that gets the correct time zone for a user by their ID. First, some helpful interfaces. Let's assume that these all have implementations that do what they look like they should do:<br /><br /><blockquote style="font-family: courier new;">public interface IUser{<br /> public int ID {get;set}<br />}<br /><br />public interface ITimeZoneRepository {<br /> TimeZoneInfo GetTimeZoneForUser(IUser u);<br />}</blockquote><br /><br /><br />Now, here's some code to handle the time zone problem. Let's assume that ALL times in my database are converted to UTC when they are stored there:<br /><br /><blockquote style="font-family: courier new;">public class TimeZoneConverter{<br /><br /> private IUser u;<br /> private ITimeZoneRepository r;<br /><br /> public TimeZoneConverter(ITimeZoneRepository r, IUser u){<br /> _repository = r;<br /> _user = u;<br /> }<br /><br /> DateTime ConvertTimeToUTC(DateTime t){<br /> return TimeZoneInfo.ConvertTimeToUTC(t, r.GetTimeZoneForUser(u));<br /> }<br /><br /> DateTime ConvertTimeFromUTC(DateTime t){<br /> return TimeZoneInfo.ConvertTimeFromUTC(t, r.GetTimeZoneForUser(u));<br /> }<br />}</blockquote><br /><br />So why all of this? Well, first, this gives me a centralized place to handle all time zone conversion issues (Don't Repeat Yourself). Next, it decouples the user and the user's time zone from the actual functionality of converting the times (Single Responsibility Principle) so that I can test it in isolation but I also don't have to concern myself with where that time zone is coming from. Finally, this gives me a convenient place to hook date formatting into my application when I need to. Remember, I can't just user DateTime.Parse because I don't know if 04/05/2008 means April 5th or May 4th without having some sort of cultural info associated with this. If I store the user's culture somewhere and have a similar repository, I can then combine this object with the DateTime parsing and formatting commands and create one unified DateTimeService for my application where a Date string goes in and a DateTime comes out (works the other way also). It just so happens that I have another story that reads "As a user, I want to read dates and enter dates in a way that I am familiar with so that I can interperate the meaning correctly" so this is definitely going to come in handy in the future. Some other useful things that the TimeZoneInfo class has:<br /><br />TimeZoneInfo.SupportsDaylightSavingTime - this property returns a bool that is true if there is a daylight savings time on that instance of TimeZoneInfo. For Pacific Time, this would return true, for Arizona time it would return false.<br /><br />TimeZoneInfo.DaylightName - this property returns the name of the Daylight Savings Time Zone, so for Pacific time it would return "Pacific Daylight Time"<br /><br />TimeZoneInfo.Local - this static property returns a TimeZoneInfo class that reflects whatever the computer you're running it on is set to.<br /><br />TimeZoneInfo.Utc - static property that returns a TimeZoneInfo class that is set to UTC time<br /><br />TimeZoneInfo.IsDaylightSavingsTime(DateTime) - instance method that tells you if a particular datetime occurs within daylight savings time for that time zone<br /><br />Anyway, this is my first exposure to having to deal with this stuff and it's convenient that .Net provides some good functionality for dealing with it easily. If you want more info, there's a number of MSDN articles on the<a href="http://msdn.microsoft.com/en-us/library/system.timezoneinfo.aspx"> TimeZoneInfo class</a> and how to deal with <a href="http://msdn.microsoft.com/en-us/library/ms973825.aspx#datetime_topic9">Dates and Times</a> in general that you can read but this post has enough info to get you started.Jeff Tuckerhttp://www.blogger.com/profile/06381849301612591461noreply@blogger.com1tag:blogger.com,1999:blog-9185673286031436825.post-64254791466344653092008-06-26T12:35:00.001-07:002008-06-26T12:49:53.016-07:00Alt .Net meeting- why do only developers attend?At every Alt .Net event I've been to (all three of them but I'm still kinda new to this) as well as every conference, it seems like the vast majority of the attendees are developers. While we're there, we have sessions on things like "how to convince project managers to use Agile" and "how to talk to business people" and stuff like that. Then we return to our jobs and try to convince these people that we're right or that code quality is important or that unit tests help improve your product or other things that are obvious to us (especially after two hours of discussion). So here's my question:<br /><br /><span style="font-weight: bold;font-size:180%;" >WHY DON'T THE BUSINESS PEOPLE ATTEND OUR CONFERENCES?????</span><br /><br />whoa, I just had an epiphany:<br /><br /><span style="font-weight: bold;font-size:180%;" >WHY DON'T WE SOFTWARE PEOPLE ATTEND THE BUSINESS CONFERENCES????</span><br /><br />It seems like we're trying to figure out how to communicate with the "other side" that is the business. We are saying that we value communication, engagement, and people over process, however all we're doing is creating a process for trying to communicate with them. Isn't this a violation of our own principles? Certainly seems like it to me.<br /><br /><span style="font-size:130%;"><span style="font-weight: bold;">It works both ways, people</span></span><br /><br />Instead of just talking to each other about how we communicate with the business people (and I assume the MBA conference probably has similar ideas about talking to software people), why don't we practice what we preach and bring some of these business people to our conferences and directly engage them in this whole communication thing? We can tell them how we communicate and what our needs are and what is important to us and most importantly, why these things are important. In turn, they can tell us the same thing from their perspective. I think that this would be infinitely superior to what we do now.<br /><br /><span style="font-size:130%;"><span style="font-weight: bold;">If you build it, they will come (and they've built it and we're sitting around)</span></span><br /><br />On the flip side of this, how many of us developers actually attend any business-oriented conferences? Have any of us? What about presenting a session at them? Anyone do that? I certainly haven't and I have only myself to blame for this. I think it's time for us as a community to take action and not only bring the business folks and managers into our movement, but actively reach out to them and approach them in their community as well and let them bring us into their world for a change. Anyone out there agree with me? Anyone have any ideas on how we can do this?Jeff Tuckerhttp://www.blogger.com/profile/06381849301612591461noreply@blogger.com2tag:blogger.com,1999:blog-9185673286031436825.post-15269357972408618102008-06-25T11:30:00.001-07:002008-06-25T11:56:51.512-07:00New Job!I'm excited to announce that I have a new job working at Microsoft! I will be on the networking team of the Core Operating Systems Division and I will be working on System.Net in the .Net framework. I'm really excited about this position as it will give me a chance to learn a lot of new things and to grow as a developer. I'd just like to thank everyone at Microsoft that I've worked with so far, especially my recruiter who has been very helpful and infinitely patient with my constant stream of questions. I'd also like to thank JP Boodhoo for his <a href="http://www.jpboodhoo.com/blog/DontPlayLimboWithYourGoals.aspx">blog post</a> which helped me to make this decision. He is absolutely right about setting goals and making sure that you're constantly raising the bar so that you are continuously improving yourself. If you don't have any goals for your life, career, family, and anything else that is important to you, then drop what you're doing and set some. There are some things that you can't change, however you can always change yourself and your situation if you make enough effort.Jeff Tuckerhttp://www.blogger.com/profile/06381849301612591461noreply@blogger.com0tag:blogger.com,1999:blog-9185673286031436825.post-41975531786166984612008-06-16T02:15:00.000-07:002008-06-16T02:37:45.928-07:00How I made it faster- the yearly windows reinstallEvery year my computer starts behaving very strangely. Programs get really slow, the start menu takes forever to load, the OS crashes randomly, and other strange things happen. This year's strangest thing was that for reasons unknown, Visual Studio decided that Notepad++ was my default web browser every time I launched a web application. I have no idea how this happened and it has defied my efforts to fix it. As a result, I find it easier to just reinstall windows and everything else from scratch. This usually takes me two days to get everything the way I like it, which is much less time than it usually takes me to go through and fix everything (if I even can fix everything, and yes, I have timed this). This time around, I decided to change things a bit and I've noticed that some things are much faster.<br /><br /><span style="font-size:130%;"><span style="font-weight: bold;">Visual Studio</span></span><br />I develop web applications in C#. That's really all I do at work (besides read blogs and drink coffee). Therefore, when Visual Studio prompted me to do the "common" install, I hit "custom" for the first time ever. I then got rid of everything that wasn't C# and web application related. No C++, no C++ diagnostic tools, no VB, no installation packager or whatever it is, just C# and web stuff. I also got rid of things that I never use like the icons and other crap packages. I also gave up any plugins that I don't directly use. I just started using my fresh Visual Studio install, and this thing flies now. It loads really, really fast. It still takes forever to load my solution (it has 14 projects in it, but I promised that I wouldn't complain about my project setup in this post, and no, I wasn't the one who added those projects) but everything else is fast. I also have several plugins turned on, including ReSharper, CodeIt.Right (like FxCop but useful), and the TeamCity personal build thing. Also, unlike my previous computer, I only have one version of Visual Studio installed (2008) as opposed to four versions (I used to need all four of them too).<br /><br /><span style="font-size:130%;"><span style="font-weight: bold;">Sql Server<br /></span></span>Again, the only thing I care about in Sql Server is the database and the client tools. I don't use Reporting Services, Business Intelligence, the legacy DTS stuff, or any of that extra crap. I don't need it at this time. So I hit "custom installation" again and chose only those components that I actually use. I also found that I no longer need Oracle to be installed locally so I don't have that installed either, although I doubt this is speeding things up any because I had it turned off unless I was actively using it.<br /><span style="font-size:130%;"><br /><span style="font-weight: bold;">Other Software<br /></span></span>So before I started randomly installing all the stuff from <a href="http://www.hanselman.com/blog/ScottHanselmans2007UltimateDeveloperAndPowerUsersToolListForWindows.aspx">Hanselman's tool list</a>, I made a list of all the software installed on my old computer. I then started crossing out things that I can't remember using in the last six months. I installed what was left, including Launchy, Nant, NUnit (sorry MbUnit, but some people at my work don't like you so I can't use you anymore. . . at work), DisplayFusion, ReSharper, Firefox, Subversion, and Notepad++. So far, I have yet to find something that I miss. Please also note that I didn't install Tortoise SVN this time around, which brings us to the next most useful thing that I installed:<br /><br /><span style="font-weight: bold;">Cygwin!!!!!!11!11!1!1!!one!11!!</span><br />I love this thing. It basically gives me a Bash shell on windows. It has all the unix commands that I'm used to using. It has <span style="font-style: italic;">alias</span> and <span style="font-style: italic;">ln</span>. It has hundreds of packages, including subversion. It's find totally pwns windows find. It has <span style="font-style: italic;">grep</span> so I can do something like <span style="font-style: italic;">alias devenv=`find / -name devenve.exe | grep devenv.exe`</span> and I get to type "devenv" and it launches Visual Studio without me having to fuck around with my Path or other environment variables. I also have vi and nano, which rule (I use nano when I need to change one stupid line of a config file because I find it simpler to use for that purpose than vi, but vi is for anything more complex). I have only begun to figure out the coolness that is Cygwin. I also get Python and Perl and probably Ruby, although I haven't actually looked for a Ruby package yet. Be warned, however: If you are not familiar with Unix, including commands, the file system, and concepts like fork(), it probably is not for you. Also, when you want to launch a program and not have the shell sit there and wait for the program to terminate, the correct thing is to add a '&' to the end of the line, i.e. <span style="font-style: italic;">/devenv.exe &</span><br />will launch Visual Studio and kick it into the background so I can do other stuff with the shell.<br /><span style="font-size:130%;"><br /><span style="font-weight: bold;">The results</span></span><br />My computer loads faster. A lot faster. This is probably due to a combination of factors, but I would say the biggest difference between this computer and the last is Sql Server only has two services running now instead of like 1000 or something (I'm exaggerating but you get the idea). I also don't have Tortoise slowing explorer down, although I may reinstall it if I find that I'm not more productive using svn from the command line. Visual studio starts faster. I also don't have to worry about which version of Visual Studio launchy decides to launch for me either. It also stops faster when I close it.<br /><br /><span style="font-size:130%;"><span style="font-weight: bold;">The moral of the story: </span></span><br /><br />The moral here is really stupidly obvious: Don't install crap that you don't use or need. This really shouldn't need to be said, but I find that a lot of people just hit "default install" when they shouldn't be. They also install crap that they don't use and don't need. That being said, may I present:<br /><br /><span style="font-weight: bold; font-style: italic;">Jeff's guide to the obvious: Volume 1</span><br /><ol><li>Always use custom install when installing software. Pick only what you need. This applies to everything.</li><li>You can always run setup again if you need to add something.</li><li>Don't just install something because it "looks like you might use it"</li><li>Any software that you don't use in more than six months, get rid of it.</li><li>Any software that you don't immediately start to love and use frequently, get rid of it<br /></li><li>Don't just install everything off of Hanselman's tools list (uh, not that I ever did or anything. . . . )<br /></li></ol>Follow these simple instructions and I guarantee your computer will run faster and have less random behavior, although having Notepad++ be your default browser is useful sometimes.Jeff Tuckerhttp://www.blogger.com/profile/06381849301612591461noreply@blogger.com1tag:blogger.com,1999:blog-9185673286031436825.post-21428605367687294412008-06-16T02:14:00.000-07:002008-06-16T02:37:14.816-07:00Seattle Alt.Net open spacesThere was an open spaces event for the Seattle Alt .Net community on May 24th (I know, this post has been sitting around for a while just be glad I have insomnia tonight). I think I learn more in these open spaces events than anything else I've been to so my first advice is to find (or start) a local group and have these things.<br /><br /><span style="font-size:130%;"><span style="font-weight: bold;">Everyone has something to contribute</span></span><br /><br />I think it was Dave Laribee (please correct me if I'm wrong) who said that "everyone here is a leader" at the last open spaces I went to. This is absolutely true. I find that everyone, no matter who they are, what their experience is, or what they work on, has something meaningful to say on something. That's one of the things I really like about these events.<br /><br /><span style="font-size:130%;"><span style="font-weight: bold;">The event</span></span><br /><br />So this open spaces was at the offices of <a href="http://www.lexisnexis.com/">Lexis Nexis</a> so I would like to publicly thank them for generously donating their space and providing lunch. Employer support of Alt .Net and these types of events is critical in ensuring that they happen and that the are accessible to all. I hope that everyone's company will follow Lexis Nexis' lead in supporting these types of events as they directly contribute to the education of their developers, and a company with good developers is more likely to be successful and deliver a better product.<br /><br />We discussed a number of things at the event, most of which we were able to video, so I'm not going to spend a bunch of time recapping, however I will come back and edit this post with the links to the videos once they're are available.<br /><br />The biggest thing that we got out of this event was a good foundation for a Seattle Alt .Net community. It turns out that there are a lot of us devs out there, definitely more than I had suspected, that are interested in this whole Alt .Net thing. In fact, it's looking like our open spaces is going to be a monthly thing (last I heard we're going for the fourth Saturday of the month) so I'm excited about seeing where this is going to go. If you are interested (you should be) you should subscribe to our <a href="http://groups.google.com/group/altnetseattle">google group</a> and start coming to these things. Remember, everyone is welcome and everyone has something to contribute. Seriously, you should come to our next event. Even if you disagree with everything Alt .Net is, come out anyway and see what we're all about (and if you do disagree with everything, by all means share your opinions because maybe you've thought of something that none of us have).<br /><br />The next event will be on June 28th at:<br /><p><span style="font-weight: bold;">Mantis Technology Group, Inc. </span><br /><span style="font-weight: bold;"> 12413 Willows Road NE </span><br /><span style="font-weight: bold;"> Suite 300 </span><br /><span style="font-weight: bold;"> Kirkland, WA 98034 </span><br /> </p>I'll see you there!Jeff Tuckerhttp://www.blogger.com/profile/06381849301612591461noreply@blogger.com0tag:blogger.com,1999:blog-9185673286031436825.post-82081486243790032132008-05-28T12:00:00.000-07:002008-05-29T10:59:25.138-07:00Why Elegant Code doesn't get AgileThis <a href="http://elegantcode.com/2008/05/27/why-agile-doesnt-really-work/">blog post</a> seems to insinuate that Agile does not work. I believe that <del>their</del> David Starr (<span style="font-style: italic;">correction: I directed this at all of Elegant Code when I should have been specific to the poster. Apologies for this oversight on my part</span>) conclusions are flawed and that they truly don't understand that Agile is an idea and not a process. I think a better title of this post would be "why being dogmatic about Agile doesn't really work" or "why people who do things because that's what you do in Scrum doesn't really work" or some such. By making this blanket statement about Agile not working, they are both ignoring the many success stories that Agile has and betraying their own ignorance of the Agile process.<br /><span style="font-weight: bold; font-style: italic;font-size:130%;" >"Agile supports the idea of frequent delivery of value to customers." </span><br /><br />Let's look at shipping software for a minute. Where in the <a href="http://agilemanifesto.org/">Agile Manifesto</a> does it say "You have to ship software every two weeks" or anything like that? Go ahead, look for it. I'll wait. Didn't find it? That's because it isn't there, and it isn't there for a reason. That reason (I generally believe) is that shipping software to customers every two weeks is a retarded-stupid idea for all of the reasons that the article goes into. I'll summarize them here:<br /><ul><li>Sales can't keep up with that release cycle</li><li>Training can't keep up with that release cycle</li><li>Documentation is often not available at that frequency</li></ul>I'll even add a few more:<br /><ul><li>Any type of release-preparation can't be done (burning CD's, peer-review, post-mortems, etc)</li><li>Software with a high amount of overhead to upgrade won't allow for this (think SAP or Sharepoint or some such product)</li><li>Most customers don't want a new version every two weeks because they'll have to upgrade and re-train their employees</li><li>This pace is not sustainable, which is something that is, in fact, on the Agile Manifesto ("Agile process promote sustainable development")</li></ul>So what's the point? In Agile, we recognize that working software is the best measure of productivity. We also recognize that we want to deliver working software as frequently as possible. This brings us to:<br /><br /><span style="font-weight: bold;font-size:180%;" >DELIVERING WORKING SOFTWARE IS NOT THE SAME AS SHIPPING A PRODUCT!!!!!!!!!!!!!!!!!</span><br /><br />That's right, you can deliver working code constantly. You can deliver it to sales so that they can preview what they're going to sell. You can deliver it to your customer proxy to verify that you have correctly implemented the features that you need. You can deliver it to your sprint demo so that the rest of the world can see it work and know that you're going well. You can deliver it to your project manager so that he doesn't have a heart attack every sprint because the software doesn't work. BUT YOU DON'T HAVE TO SHIP IT. Just because you CAN ship something doesn't mean that you should.<br /><br /><span style="font-weight: bold;font-size:130%;" >So why do we deliver working code in the first place if we're not going to ship it?</span><br /><br />Because in Agile, we want rapid feedback. It is much, much easier to fix something right after you build it than it is to fix it three months after you build it. The sooner you know that you need to change something, the easier it is. For example, let's say that your QA department is one sprint behind your development in their testing. On my team, we average about ten builds per day (utilizing our CI tools at the time of checkin, but if you count personal builds it's probably a lot more). Our sprint is three weeks, which gives us about 14 days of development on average (adjusted for the time spent on code review, sprint planning, sprint demos, holidays, etc.). With ten builds per day, that means at a minimum, QA is finding a bug that has existed for 140 builds. Other functionality may be built on top of it. It may have dependencies on other parts of your code. Finally, where the hell is that bug occurring, given that maybe you've worked on a dozen different objects since the bug was introduced? You'll have to hunt for it, and that takes time.<br /><br />So Elegant Code has missed the boat on this one: They're assuming that delivering working software means "shipping it to the customer" when this is absolutely not the case. They're jumping to that conclusion. Maybe I should write "delivering software means shipping it to the customer" on a mat on the floor, and they could "jump" to it. I'll make a million dollars!<br /><br /><span style="font-size:130%;"> <span style="font-weight: bold; font-style: italic;">"[The] organization [you're shipping to] must actually be able to receive the update without tipping over</span></span><span style="font-weight: bold; font-style: italic;font-size:130%;" >"</span><br /><br />This is their second argument against Agile, and (coincidentally enough) their second mistake. I've added some words to clarify their point so that it isn't taken out of context, but I would encourage you to read the article so that you don't think I'm making this up. That is not my intent. Anyway, we aren't shipping the software every two weeks, so the customer only gets their release when they actually want it. The strength of Agile is twofold on this:<br /><ol><li>We can show them what they're going to get more easily because the software is always working. We can give them a beta whenever they're ready for it so they can start coding against our API if they want to. If they don't like our API, we can change it easily and ship a new version. They can see if the features they want are actually going to work the way they want. They can give us rapid feedback, which is very important to our ability to deliver them the features that they want.<br /></li><li>We don't have to ship it to them "on time" either, because when you can ship every two weeks, "on time" starts to mean whatever you want it to mean. If they aren't ready for a month or two, we can delay and continue to add value (or just branch the code) and ship when they're ready to receive. If they suddenly get an upgrade to their database and our code is going to break it if we add Oracle support, we can release a working version prior to adding Oracle support. BizTalk no longer supports a feature? Prioritize that as a sprint item and ship two weeks later. Try doing that in waterfall.</li></ol>In short, we gain a lot of flexibility over when we can ship. Again they're leaping to a conclusion (maybe two spaces on the mat and they can "jump" to both "conclusions") that they have to ship and it'll cause all kinds of problems for the customer if they do. In fact, the opposite is true: because you can ship at any time, you have the flexibility to deliver value whenever it is best for the customer. If you force them to upgrade, that's really an anti-pattern that I call "shoving functionality down their throats until they choke on it." This is never good.<br /><br />In fact, the problems that they describe are actually readily solved by Agility: Documentation team needs another week or two? No problem. At least we have a working piece of software for them to document against. We either add something small that they can easily document, refactor the code against our //TODO list, or branch and keep going with the intent to release a branch. IT says you need a week-long burn in test? Or what about a month long peer-review process like my company? Not a problem either, we just branch and continue working on the trunk, fixing anything that comes up in the branch (which is what we're releasing) and merge those fixes with the trunk one at a time as soon as they're finished so that integration is easier.<br /><br />Ultimately, <del>Elegant Code</del> David Starr has not missed the boat, but unfortunately the boat that they caught<a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEii6wfey9sZDJDmMieNQwRfggbY7bHhDsU2TpmiHI-XnK7cEP_0cShppMCZGzHwvVAvGMj8Le7Y7kowsOgtzbDVdr997Bir-3C1qGhern3S14yyPVEiAPkyaqBsjzK7LO7yNmqYG_i840KG/s1600-h/failboat.jpg"><img style="margin: 0pt 0pt 10px 10px; float: right; cursor: pointer;" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEii6wfey9sZDJDmMieNQwRfggbY7bHhDsU2TpmiHI-XnK7cEP_0cShppMCZGzHwvVAvGMj8Le7Y7kowsOgtzbDVdr997Bir-3C1qGhern3S14yyPVEiAPkyaqBsjzK7LO7yNmqYG_i840KG/s200/failboat.jpg" alt="" id="BLOGGER_PHOTO_ID_5205545059232803954" border="0" /></a> was the failboat. Their argument sounds good on the surface, but they have failed to realize that Agile's ability to handle change combined with a rapid feedback cycle actually deals quite nicely with all the problems that they are describing. I'd like to close with a question: If Agile doesn't work, what does? Huh? Can't find that in the article? It's in the same place in the article as "shipping software" is in the Agile Manifesto (i.e. it's not there). I think Elegant Code needs to do some more studying on what Agile is and what it truly means, as well as looking at some success and failure stories before they suggest that Agile has failed because you can ship too frequently if you're dogmatic about it.Jeff Tuckerhttp://www.blogger.com/profile/06381849301612591461noreply@blogger.com2tag:blogger.com,1999:blog-9185673286031436825.post-32283859614106031242008-05-27T11:10:00.000-07:002008-05-27T11:12:26.953-07:00New concept: Code TasteThis came up at the Alt .Net Seattle conference last weekend. Code Smell doesn't necessarily mean that a particular piece of code is wrong; it just looks like it's probably wrong (more on this in another post). Code Taste is when you actually execute the Code Smell code and find out if it really is wrong.Jeff Tuckerhttp://www.blogger.com/profile/06381849301612591461noreply@blogger.com0tag:blogger.com,1999:blog-9185673286031436825.post-44193893031140673102008-04-29T11:40:00.000-07:002008-04-29T16:39:28.320-07:00I can haz spec# kthx<a href="http://codebetter.com/blogs/gregyoung/default.aspx">Greg Young</a> has been talking about <a href="http://research.microsoft.com/SpecSharp/">Spec</a># for a long time. I was skeptical. I was argumentative. I was interested in attending the Spec# talk at the Seattle Alt .Net open spaces. I was blind, but now I see.<br /><br /><span style="font-size:130%;">DBC</span><br /><br />DBC is Design By Contract. <span style="font-style: italic;">The Pragmatic Programmer</span> dedicates a decent chunk of time to this concept (chapter 4, pp 109-119 in my copy) but I'm going to give a brief overview that will probably not be adequate to really explain it, but I hope it makes you want to go read about it.<br /><br />The idea behind it is that it's hard to work with many different modules and their interactions with each other because invariably you'll make mistakes. In order to make this easier, you specify contracts that a module will abide by. These are defined by preconditions, postconditions, and invariants. A precondition is something that must be true in order for a module to do its job. It isn't user input validation, since the user might make mistakes. It's things that, if met, the object with them will guarantee a particular result. This result is defined by the postconditions. Invariants are things that may interact with that particular method but at the end of that method their conditions will be true, regardless of what may have happened during that method call. So here's an example:<br /><br />Let's say that I have a method that searches a sorted array for a particular value. Preconditions would include:<br /><ol><li>The list must be sorted</li><li>The list object can never be null</li></ol>Postconditions would be:<br /><br /><ol><li>The output object will be the object that was searched for if found.</li><li>The ouptut object will be null if the input was not found.</li></ol>Invariants might be:<br /><ol><li>The order of items in the list will not change</li><li>The list will never be null</li></ol>So what does this mean in code? It means that in order for this method to be successful, I have to guarantee that the caller will sort the list first and that they'll NEVER pass a null object in the list. It also means that the search method will always return the object searched for or null if not found, and it will NEVER return anything else. Finally, it means that although the method may do things to the list while it executes, the list that exists after the method terminates will be identical to the list that was passed in (assuming you're passing the list by reference).<br /><br /><span style="font-size:130%;">So how do you enforce this? </span><br /><br />Short answer: you can't. The only thing you can do is to put Asserts on your contracts and let them fail if somehow your contract is not met. This means that somewhere, your code is not correct. These constraints define things that should NEVER happen. A breach of contract is NOT a bug, it's a part of your code that is incorrect and needs to be fixed. At runtime, it's possible that something totally messed up might occur, like something in your list getting overwritten due to a buffer overflow or getting an out-of-memory exception because Sql Server is consuming all of your available RAM (I've seen that happen). When that happens, your contracts will catch it and throw an exception with detailed error messages. That is, if you've left Asserts turned on in Release, which I know most of you don't. My lead would probably castrate me if I suggested this.<br /><span style="font-size:130%;"><br />Enter The Dragon (where Dragon = Spec#)</span><br /><br />Spec# allows you to explicitly define contracts in your code that are then checked at compile time (this is optional). You can also add invariant constraints to your properties and such. You can add preconditions and postconditions. This does a few things for you:<br /><ol><li>Spec# sets up checks for violations of your contracts at runtime. It will automatically throw exceptions for you if they are violated, so no more checking if an object is null, just put a precondition on it.<br /></li><li>There is static code verification that analyzes your code to see if you are ever potentially violating your contracts. It will actually throw a compile error if you might be writing incorrect code (this is an option that you can disable though).</li></ol><span style="font-size:130%;">The halting problem</span><br /><br />So, like me, you might have said "Well, what about the <a href="http://en.wikipedia.org/wiki/Halting_problem">halting problem?</a> It's provably true that you can never write a program to analyze another program to determine if it will ever halt. What about that, huh? How do you get around that? Look at me, I know Computer Science buzzwords even if I can never actually show you the proof of that problem or illustrate it on a Turing machine or anything. I don't know what a Turing machine is but I read about it in <span style="font-style: italic;">Cryptonomicon </span>and it makes me sound smart."<br /><br />Well, that isn't a problem because the static verification will only prove your program under certain conditions. There are methods that are too complex to prove, or conditions under which a proof is impossible. To help this, you get the "Assume" keyword which allows you to set assumptions about the circumstances of your methods so that static verification can try to prove it, but this may still break something (although your contracts should still catch this at runtime).<br /><br /><span style="font-size:130%;">In conclusion</span><br /><br />Go <a href="http://research.microsoft.com/SpecSharp/">download spec#</a> and see how awesome it is. Then email microsoft and tell them to release it as a product. I told <a href="http://www.hanselman.com/blog/">Scott Hanselman </a>that if he blogged about it, and I blogged about it, then the 30,000 people who read his blog will all email Microsoft about it and the eight or so people who read my blog will also email Microsoft about it and then they'll have 30,008 emails demanding Spec# and we'll get it released. <span style="text-decoration: underline;"></span><a href="http://www.hanselman.com/blog/"><br /></a>Jeff Tuckerhttp://www.blogger.com/profile/06381849301612591461noreply@blogger.com3tag:blogger.com,1999:blog-9185673286031436825.post-5041166686359470872008-04-21T21:31:00.000-07:002008-04-21T22:26:11.283-07:00My brain is full and my liver is angrySo the Alt .Net open spaces event has concluded. This is the best conference I've ever been to (with DevTeach Vancouver being a close second) for a variety of reasons that I will get into later, but let me first start out with a brief description of what exactly this type of event is. <br /><br /><span style="font-size:130%;">Format</span><br /><br />First, there is no agenda, no speakers submit their sessions for approval, there is no keynote, and there isn't even a fixed list of topics. Everyone has equal input and there is collective decision making in what occurs. You start out by proposing topics and discussing them and then people decide what topics they most want to talk about. These become the sessions that you can go to.<br /><br />Each session can be whatever the people want them to be. If the sessions are small, everyone can just discuss the topics. If they are larger, a fishbowl format is used, where some number of people <span style="font-style: italic;">n</span> are sitting in <span style="font-style: italic;">n+1</span> chairs such that one chair is always empty. Anyone may go up and sit in the empty chair at any time and the person who has been there the longest has to get up. I like this format because everyone gets a change to speak and contribute. Sessions aren't death by powerpoint and they aren't some company just trying to sell you something. <br /><br /><span style="font-size:130%;"><br />People</span><br /><br />A lot of people were there. Some of them were new to Alt.Net and were interested in learning more about the movement. There were quite a few people from Microsoft, including ScottGu, Scott Hanselman, and many others. Also, a lot of the usual Alt.Net people were there (most of whom are bloggers that I link to on my home page). I missed Justice Gray and I hope that he will be there for the next one (<a href="http://www.igloocoder.com/archive/2008/04/16/building-community-one-developer-at-a-time.aspx">study your VB 6 hard, Justice, so you can be an MVP</a>). I also got to meet a few local developers that I hope to stay in touch with (including one from my own company but a different division than I work for). To everyone whom I gave a business card: please keep in touch. To everyone who gave me a business card: I'll try to get back to all of you as soon as I can.<br /><br /><span style="font-size:130%;">Topics</span><br /><br />So many things were talked about that my head is spinning. There was discussion and the exchange of ideas pretty much nonstop throughout this conference, so I'll try to go over a few of the highlights that I remember.<br /><span style="font-size:130%;"><br />Spec#</span><br /><br />This was an interesting demonstration. Greg Young has long hyped the coming of Spec# because it enables true design-by-contract where contracts can be explicitly specified at design time and verified at compile time. This forces you to ensure that your code is 'correct' when it is built. I had my doubts (the halting problem comes to mind), but now that I've actually seen it work I think it's going to be a great tool. I hope that all eight of you who read my blog will join the 30,000 or so that read Hanselman's blog in sending emails to Microsoft demanding the release of Spec#.<br /><br /><span style="font-size:130%;">Are we innovating or just porting?</span><br /><br />This talk was about all the new tools in the Alt .Net community and asking if we're actually creating any truly "new" tools or if we're just porting them from the Java community. It was a great discussion with a lot of people saying a lot of things that I wish I could write more specifically about. Someone videotaped this, I hope that it gets posted somewhere.<br /><br /><span style="font-size:130%;">How to talk to suits</span><br /><br />Very interesting talk about how to sell Agile to management but also some good information about how to talk to business people in general. Something that was brought up was the idea of having respect and trust for each other which is something that I think is lacking in a lot of places. Some ideas for helping to "sell" Agile was to present different practices as a solution for existing pains that a company is feeling. Lots of good information here. I was also surprised by the number of consultants at this talk, it was well over 75% of the group.<br /><br /><span style="font-size:130%;">Has software development failed?</span><br /><br />A good talk about the current state of software development projects. There have been some very notable failures in the industry over the years. I brought up my question of "are we all wrong" and got some good discussion going on there. <br /><br /><span style="font-size:130%;">Javascript- it's not just the bastard step-child of your web app</span><br /><br />This was a cool talk. A lot of people tend to treat javascript like some sort of second class citizen. It's there, but it isn't too important. As a result, there aren't a lot of test frameworks and established patterns out there for javascript and its code quality often is sub-par. While there are some great frameworks out there (some of which I need to take a fresh look at), there is a real need for improving the tools, particularly now that javascript is becoming more of a tool for the presentation layer and contains business logic. It is a real programming language so all the rules of good design apply to it and I think people largely haven't realized that until recently. Justin Angel had a great tool also for running javascript unit tests at build time. It wasn't quite what I would want but it is still very slick and would definitely be useful. <br /><br /><span style="font-size:130%;">Education in the industry</span><br /><br />This was a great point that Scott Hanselman mentioned at least a dozen times and I still think he could have said it more without it being overkill because it's that important. There is a significant lack of education in basic software engineering principles out there in schools. Computer Science programs teach algorithms, O(n), data structures, and polymorphism. Those things are super-important to developing software. However, what's missing is things like concepts in good object-oriented design, how to test your software, unit testing, refactoring, patterns, and version control. He mentioned speaking to local schools about your career and software development in general. I think he's right, and I intend to actually go out and do something about it. I'm not sure what yet, but I did talk to a few friends of mine who happened to be students at digipen. I ran into them on the last day and they asked me about the conference and we ended up talking for an hour or so. I'll post more in the future as I continue to follow up on this.<br /><br />Overall, this was an awesome conference. There was a lot of good dialog and exchange of knowledge as well as a lot of respect for everyone there. Someone there said that we're all leaders (might have been David Laribee who said that) and so we need to go out and lead. I'm going to go out and lead, and I'm going to challenge everyone who is reading this to do the same.<br /><br />Also, if you're not at the next open spaces, you'd better be dead or in jail, and if you're in jail then break out.<br /><br />Also, if you are interested in seeing some more of it, Jeff Palermo made some <a href="http://codebetter.com/blogs/jeffrey.palermo/archive/2008/04/18/video-of-alt-net-opening.aspx">videos</a> that are posted over on <a href="http://codebetter.com/blogs/jeffrey.palermo/">his blog</a>.Jeff Tuckerhttp://www.blogger.com/profile/06381849301612591461noreply@blogger.com1