Showing posts with label process. Show all posts
Showing posts with label process. Show all posts

Tuesday, September 3, 2013

Presenting at SDC on Empowering a Team as an Individual Contributor

I had the opportunity to present at the SDC on "Empowering a Team as an Individual Contributor" (9/1/2013).

http://www.meetup.com/SoftDev/events/134325872/

Most developers are individual contributors (IC) – in other words they do not have direct reports. But even as a non-manager, you can empower an entire team. This is due to the nature of software engineering, where developers create their own tools, a star developer can be 10x as productive as an average developer, and a single developer can use technology for team-wide impact. With the right mindset ("add business value"), and using a combination of hard skills (automation, tooling, code generation, open source, code reuse, etc…) and soft skills (interviewing, mentoring, communication and knowledge sharing, etc…), you can be that IC developer who helps lift your entire team, and have fun along the way.

Monday, August 20, 2012

Digging with spoons – the case against progress

Say you need to dig a big hole. Do you dig with a spoon or a shovel? Most progress-oriented developers would think “of course we use shovels”, but they continually get surprised when on their real projects the team still essentially digs with spoons. Why? How could someone possibly want to dig with a little spoon instead of a big shovel? Sure, I favor shovels, but I’ve seen over the years that people think very differently, and some people could offer lots of reasons to use spoons instead:
1.       We already have a spoon right now.
2.       It won't really take that long to dig with spoons.
3.       I used a spoon before; you should use a spoon to.
4.       Using a spoon teaches you how to dig, when I was in school they taught us to dig with spoons.
5.       Using a shovel is the lazy way out.
6.       A spoon gives you the granularity you need, you don't really know what you're digging if you have a shovel.
7.       The boss thinks spoons are better (that's how he did it back when he dug).
8.       If we switch to shovels now, that would be admitting we were wrong before.
9.       We need objective measurements (committees, score cards, analysis docs) to truly show if a shovel is better than a spoon.
10.   You’re just advocating using shovels because you read some blog about it.
11.   That big shovel is too heavy; spoons are lighter so we can dig faster.
12.   The shovel wasn’t built here.
13.   You’re not part of the process improvement team, so don’t worry about it.
14.   We’re already successful, so we don’t need to change how we do things.
15.   Well, I actually read that shovels are bad.
16.   Spoons were working fine before you got here.
17.   My last company used shovels, and they went out of business.
18.   Your attempt to change our process means that you’re not being a team player.
19.   Your job is to dig, focus on that.
20.   We can use spoons for now, and then use shovels later.
21.   Not everyone knows how to use shovels, and we can't afford the training costs right now.
22.   We’re under contract to use spoons.
23.   The boss’s boss is friends with a spoon manufacturer; we really ought to keep using spoons.
24.   Are you so special; is a spoon not good enough for you?
25.   If we use spoons, there won't be enough work to do and people will lose jobs.
26.   Our competitors use spoons (I heard), so we should be fine.
27.   Our competitors use shovels, so doing something different gives us a competitive advantage.
28.   This discussion of spoons vs. shovels is just a distraction from the real goal of digging.

Each of these brings to mind some analogy with some past software project where the “slow” way (i.e. spoons) was preferred. Part of empowering a team is to overcome this sort of thinking to show that it’s really in the team’s best interest to use shovels.

Friday, December 30, 2011

The benefits to “check in early and often”

I am a huge advocate of checking in early and often. I’ve seen many a project get burnt by the developer who saves 3 weeks of work for a single “glorious” check-in.
I favor frequent check-ins because it’s:
  1. Cheaper integration. Someone once said “Integration is pay me now or pay me later”, and I find it much easier to pay now. Especially with automated builds and continuous integration, it’s much easier to check in 10 little changes than 1 big change (Sometimes I think of it like being easier to hold my breath for 30 seconds, ten times, as opposed to holding it for 5 minutes straight). Why? Because with bigger changes, you inevitably get farther out of sync – especially on critical shared files – and there’s more to forget.
  2. More objective measure of what you really have: Code that isn’t checked in, that just works on a developer’s machine, doesn’t really exist. They might as well say “it works in my head”. Once you actually get the code past a build server’s policy, then we can see what’s really there.
  3. Earlier Detection: We all know it’s cheaper to fix a bug or redesign the sooner you catch it. I’d rather developers check in code early so we can quick detect things (“why is there 5000 lines but no tests?”)
  4. More Modular: Checking in 10 chunks of code, where each one works, implies more granular and modular code. I.e. code that can at least be split into multiple check-ins is more modular than code that can’t be split at all.
Of course there’s always exceptions (you do a massive refactoring, etc…), but those should be the exception, not the rule.
Most of the time, in my experience, large check-ins by developers means something bad – spaghetti code, tightly-coupled code, code that was trying to hide under the radar until right before the deadline and then the developer says “oops, I just don’t have time to change it”, or something like that. Think of it like this: there is zero benefit to you to have to wait one month before seeing what a developer is doing, but there is benefit to early detection of code, so risk-reward wise it’s better to check-in early.
Note that for these purposes, a shelve set is not the same as a check-in. Shelvesets are private, and hence deliberately avoid the benefits listed above (which some say is a feature). For example, you mostly likely don’t have builds on a private shelfset. For a developer to say “I put my 20,000 lines in a shelveset” is misguided– use a branch instead if you need to.
So how to encourage check-in early and often?
You could write a whole chapter on this, but here's a short answer: You can explain the benefits so some developers are internally motivated, or you can make it official policy so that other developers are externally “motivated”. You can leverage the TFS Code Churn tables to automatically monitor activity, or even just view check-ins in Team Explorer, to see how often a developer checks in and how much code has changed. If a developer or contractor insists that they need to wait 1 month to check-in their code when “it’s ready”, you’ve got problems, much like if a developer insisted they didn’t need to follow any other policy or good practice.

Friday, December 2, 2011

10 Reasons why the build works locally but fails on the build server

This is a braindump:
1.       Developer did not check all the files in, or developer doesn't have the latest files (sometimes TFS hiccups getting latest dlls files).
2.       Different modes (release vs. debug). Either #if DEBUG, or project is unmarked in configuration manager.
3.       Different bin structure - each project gets its own (Default for visual studio), vs. single shared bin for all (default for TFS). This is especially common when different versions of the same assembly is referenced in multiple projects in the same solution.
4.       Different platform/configuration
5.       The build is running other steps (perhaps a packaging or command-line unit tests)
6.       Different bitness, say developer workstation is 64-bit, but build server is 32-bit, and some extra step breaks because of this.
7.       Rebuild-vs-build. Developer not running a rebuild. Hence there's an error in creating a dll, but it already exists on dev machine due to some other process, but build server fails.
8.       Workspace mapping is incorrect – TFS not getting all the files it needs
9.       Unit test code coverage – visual studio (at least 2008) can be very brittle running command line unit tests and code coverage.
10.   Treat warnings as compile errors – depending on your process, the build server may fail on these, but Visual studio may only flag you with a warning (which dev ignores)

Wednesday, August 3, 2011

Whatever requirements we're given tomorrow, we got to get that done

I've seen a thousand hacks justified with "We got to get it done". You know the drill – copy and paste 200 lines of code, hard-code data that should be configurable, skip any automated testing, etc… Such hacks come at the expense of future flexibility (i.e. good design).
However, ironically, given the continual feature change, scope creep, and unknowns in software development, the real question becomes "Whatever requirements we're given tomorrow, we got to get that done."
This second question, the more realistic one for long-term departments, brings completely opposite connotations than the first. Instead of cranking out a feature now with no concern for maintenance costs or flexibility tomorrow, developers need to prepare – i.e. ensure they have automation, builds, reuse, etc…
Besides technical debt, the other problem I have with the "just get it done now" crowd is the false sense of nobility. Often these devs insist that they're doing a good thing (putting out a fire), but really it's just punting the problem down the road for someone else to pay while they boast how quickly they've solved it.

Wednesday, July 27, 2011

Why you’re in trouble if you rely on 30-page SOPs

Every organization wants to have its development processes documented into Standard Operating Procedures (SOPs) for the obvious reasons – faster onboarding, standardization, auditing, etc… The Holy Grail is the potential to hire a bunch of contractors (or outsource), tell them to read a novel worth of documentation, and then they’re fully up to speed a week later. SOPs also imply that the team knows what it is doing and has a plan, which is one indicator of a mature organization. SOPs are also a prerequisite for outsourcing, an appealing option for large organizations.
While documentation has its benefits, you can’t rely solely on large documents to communicate process and onboard new people. Here are at least four common problems, and it will result in a frustrated and confused team:
  1. The doc itself will be wrong (or outdated), such as skipping steps or assuming institutional knowledge. This is especially common if you hire outside consultants (with no institutional knowledge of your systems) to document your process.
  2. It’s easier to bluff a doc – a busy tech writer will hurry the doc, thinking it looks done ("I’ve written 50 pages!"), but the content won’t be correct or specific enough.
  3. Screens will vary (example: the software is upgraded or the OS doesn’t match).
  4. People simply won’t read the docs, they’re skim and miss details.
Several ways to communicate an SOP instead of just 30-page MSWord docs:
  • Favor automation over documentation where possible. The best document is an automated script. A script is usually kept up to date (compared to a doc) because developers need the script to work. It’s also much faster (and less error-prone) for a new guy to kick off the script than to tediously step through 20 pages of instructions.
  • Lower the cost of documenting by leveraging a wiki. Developers are far more likely to update or correct a wiki then a big MSWord doc on SharePoint.
  • Favor simplifying the process so the doc itself is simpler.

Monday, May 24, 2010

Developer balance of power

[This was originally posted at http://timstall.dotnetdevelopersjournal.com/developer_balance_of_power.htm]

You need people to get the project done, but people are eventually error prone. Just like in government there are "separation of powers", software projects can also benefit from such separation. As a general rule, for production code, the same person should not both:
  • Code and Review - The reviewer checks the code quality (It's too easy to give a free pass, or have bias, to your own code)
  • Develop and Test - The tester checks the developer. (The dev already thinks their code works fine)
  • Build and Deploy - Having someone else deploy what the developer built encourages easier and objective deployment, and helps invalidate the it works on my machine.

Wednesday, May 19, 2010

Using SMO to automate SQL tasks

[This was originally posted at http://timstall.dotnetdevelopersjournal.com/using_smo_to_automate_sql_tasks.htm]

I used to use shelling out to the console with osql, or splitting out all the "GO" keywords and using ADO.Net to execute non-queries.

And years ago, I guess that was fine.

But Server Management Objects (SMO) are phenomenal. They just work. With a few lines in C#, you can create or kill a database, install schema scripts, enumerate the database, and much more. You also get exceptions thrown if there is an error (much easier than parsing the osql output from the command line).

Good stuff.

Sunday, March 7, 2010

Process as Infrastructure Enhancements

[This was originally posted at http://timstall.dotnetdevelopersjournal.com/process_as_infrastructure_enhancements.htm]

Most devs I meet hate process, almost like it's a stupidity-tax from some ivory-tower folk (who themselves don't actually need to use the process that they're imposing on others). These devs just want to get the app done, and they think that the process gets in their way with tedious constraints that add no value. I recall projects with "process" like forcing devs to go and update all the internal variable names to be compliant with some new coding standard, or not allowing devs to have admin rights to their own machines until three levels of paperwork is approved (good luck being a dev using a Windows OS if you're not an admin), or requiring that developers test the app by taking success screen shots of every single step - and then printing out that 600 page doc and getting it signed by QA.

That sort of stuff bothers me too, but I'm still a big fan of good process. What I realize is that I essentially view "process" as "developer infrastructure enhancements". I think of process as helpful things like automation, unit tests, code generation, proper tools, CI builds, checkout and install scripts, etc...  Devs just want to get the job done, and good process assists them in doing that, it doesn't burden them with ivory-tower taxes. If your process code-generates the data access layer, then the dev need not do all that manual ADO.Net plumbing code, and hence the dev gets the job done faster.

Sure, it's semantics - "process" vs. "infrastructure enhancements", but semantics are important because it affects how a thought is communicated to other people, and people are important.

Wednesday, May 13, 2009

Troubleshooting Visual Studio Profiler with ASP.Net

[This was originally posted at http://timstall.dotnetdevelopersjournal.com/troubleshooting_visual_studio_profiler_with_aspnet.htm]

Visual Studio 2008 (and I think 2005) come with a built-in .Net profiler. Profilers are especially useful for troubleshooting performance bottlenecks (Related: CLR Profiler for old versions of Visual Studio; SQL Profiler). There are already good tutorials on it, so here I'm just offering misc tips and troubleshooting. Basically, you can go to Analyze > "Launch Performance Wizard", and just select all the defaults. You can use this with ASP.Net web projects too.

Error: When trying to start, I got "Value does not fall within the expected range".

Solution: You can set the config of a website to "Any CPU".

Error: VSP1351 : The monitor was unable to create one of its global objects

Other times I got this error:

Error VSP1351 : The monitor was unable to create one of its global objects (Local.vsperf.Admin). Verify that another monitor is not running, or that another application hasn't created an object of the same name.
Profiler exited
PRF0010: Launch Aborted - Unable to start vsperfmon.exe

Solution: You can use Process Explorer to see what is locking "vsperf.Admin", and then kill that process tree. For me, it was the aspnet_wp.exe process.

Error: PRF0010: Launch Aborted - Unable to start vsperfmon.exe

Sometimes I got this error:

PRF0010: Launch Aborted - Unable to start vsperfmon.exe
Error VSP1342 : Another instance of the Logger Engine is currently running.
Profiler exited

Solution: I restarted Visual Studio (yes, it's lame, but it appeared to work). I also ensured that all other instances of VS were closed.

Error: Sometimes clicking the stop button caused IE and VS to crash, without even collecting data

Solution: By just closing the IE browser directly, it worked.

Thursday, May 7, 2009

Technical Debt is like a steep hill, not a brick wall

[This was originally posted at http://timstall.dotnetdevelopersjournal.com/technical_debt_is_like_a_steep_hill_not_a_brick_wall.htm]

Overtime, bad software decisions (design, coding, process) get compounded, like interest on a loan, and effectively presents the team with a "technical debt" that yearns to be repaid. This debt weighs down the system, making it harder and harder to make changes or add new features. One way to measure technical debt is by lines of code that require maintenance. Therefore you can reduce debt by reducing lines of code (codeGen, refactor, automate, buy instead of build, etc...).

For example, a developer may copy and paste duplicate code a hundred times (like in HTML or SQL), or create thousands of lines of tedious plumbing code, or create an army of brittle JavaScript files, or write an entire app with no code coverage. Many of the best practices out there are designed to explicitly reduce technical debt.

One thing to note is that technical debt is like a steep hill that can go infinitely high. You can go fast bicycling on a flat road, but as that road turns into a steep hill that gets gradually steeper, you slow down. In software terms, because code may have been copied to 10 different places, making a single change requires 10 separate updates - so it takes longer.

I don't think technical debt is like a brick wall - where suddenly at a specific point you're blocked and you simply cannot go further. And that's part of the problem. As long as you're moving, albeit slower and slower, it's seductive to think that you can still keep making "enough" progress so you don't need to change yet. The stubborn leader can just keep pushing on: "longer hours, more developers..." There are two choices to make: keep going forward, or turn around. However, if you were to hit that brick wall, then it forces you to stop and reevaluate. It's easier in the sense that you now only have one choice - you must "turn around".

Tuesday, April 14, 2009

Tips to incrementally check in code without breaking the build

[This was originally posted at http://timstall.dotnetdevelopersjournal.com/tips_to_incrementally_check_in_code_without_breaking_the_bui.htm]

No one wants to break the build. However, every time you check in code, you risk breaking the build. This leads some developers to avoid checking in for days (or weeks!) until they have a dangerously-big component. That has its own problems. Integration is pay-me-now-or-pay-me-later. I'm a big fan of paying upfront with small, continuous check-ins. Here are some tips to do check-ins without breaking the build:

  • Try to do multiple smaller commits as opposed to one giant commit.
  • Where reasonable, try to keep a component split into multiple smaller files instead of one giant file, especially if these files are updated by many developers. This reduces contention, and hence likeliness of breaking the build.
  • Check in a file that won't hurt anything, like a class file that's not added to the project yet.
  • Make sure you understand how code-generation integrates into your build. It's easy to have the code "work on your machine", only to have a code-generated script on the build server overwrite your changes and break the build. Make sure all your local code is in sync with what will be actively code-generated.
  • Make sure you always check in all the needed files, especially files that get "registered" with a master file list. For example, C# files get registered with a csproj project file.
  • Use a source control that allows merging (SVN, not VSS)
  • Split your code into isolated components - i.e. reduce dependencies in your code.
  • If you're working on a unit test, and you "need" (?!) to check in a partially-completed test that currently breaks, then consider applying the "Ignore" attribute so the test doesn't run yet.
  • If you really need to check it in, perhaps comment out the breaking section.
  • If you're checking in to send code to another dev, consider not checking in, and sending them a patch instead
  • If you're checking in to the global trunk just to "back up" your work, consider checking into your own private branch.

Sunday, March 29, 2009

Tips to be a good code-reviewer

[This was originally posted at http://timstall.dotnetdevelopersjournal.com/tips_to_be_a_good_codereviewer.htm]

Code reviews are essential to high-quality code. Imagine back in high school when you're taking a difficult math test, and then in the last few minutes, the teacher lets you pair up with another student to compare your answers. You almost always will catch extra errors that way, and it's the exact same result with a code review. So, given that we all know that we should do some sort of code review, here are ideas on how to be a good code reviewer:

  • Always keep in mind that the other person worked hard on it, and they probably have an emotional attachment. Someone once said something like "Their code is like their baby - don't say 'he looks so ugly', rather make a nice comment like 'Oh, he looks just like his father.' "
  • Start with major things first. Don't start nit-picking ("your naming convention isn't good"), if they have major other issues. Focus on their biggest need. If they want your opinion on the data access strategy, that's what they'll be most receptive too.
  • Don't just be a rubber stamp - it wastes their time by giving them a false sense of security and tells them nothing new.
  • Look to affirm good ideas as well as discourage bad ones.
  • Unless they are really missing the basic concepts, don't just tell them to go read some 500 page book - they'll see it as you dismissing them. Give them a tangible example and perhaps provide a web link to a short article or reference guide. If they read that (or they ask for more material), then suggest the books.
  • Keep the session relatively short, short enough to fit within their attention span.
  • Keep in mind the goal is to make better code for the good of the team, not show off how smart you are.

Thursday, March 5, 2009

How to integrate Generated code into your application

[This was originally posted at http://timstall.dotnetdevelopersjournal.com/how_to_integrate_generated_code_into_your_application.htm]

Code generation is great, but sometimes it can be confusing how to integrate that generated code into your custom application. Keep in mind that an application isn't solely SQL or C#. It could include Html, ASP.Net, Xml, JavaScript, project files, and much more.

  • New file: Generate its own, new, separate file. This is the most basic way. You could then integrate it into your other files:
    • (C#) Base Class - For an OOP language like C#, you could code-generate the base class, and then have your derived classes inherit it.
    • (C#) Partial classes - Starting with .Net 2.0, C# offered partial classes which let you split the class definition across multiple physical files.
    • All: Include statements - Many languages offer a way to include one file within another. For example, ASP.Net offers server side includes, MSBuild offers the import command, HTML allows you to reference an external JavaScript, etc... (Yes, you could to this with SQL to using SqlCmds)
  • Existing file: Merge into existing file with custom regions. For example, CodeSmith offers two kinds of custom regions:
    • InsertRegion - Insert your generated code into a marked region of a custom file
    • PreserveRegion - Insert your custom code into a code-generated file.

You could also integrate CodeSmith into your builds and processes by calling the CodeSmith console app.

Tuesday, March 3, 2009

Getting source code from places other than source control

[This was originally posted at http://timstall.dotnetdevelopersjournal.com/getting_source_code_from_places_other_than_source_control.htm]

Of course all official code should ultimately be stored in source control (real source control, not VSS). However, when creating an automated build on a build server, getting the source code may not be as easy as just doing a single SVN checkout. There may be other steps to effectively get the latest source code:

  • Copy in other reusable blocks - Where feasible, you want avoid checking in binaries into source control when those binaries will be constantly updated. Unlike plain-text files, you can't do an effective diff on binaries - it will just look like a mess. So instead of storing just the change set, it will probably need to store the entire physical assembly - which will bloat your source control. So, say you've got a team that is actively working on a set of reusable class libraries, to be shared across multiple departments and product groups. It may make sense to have your product's build copy in those latest reusable blocks (from their build's published output) to some external folder where you store your third-party assemblies, as opposed to constantly storing the latest version in source control. (So, ultimately the reusable blocks are still stored in source control, it's just a different repository).
  • Code Generate from input files - You can use code-generation for lots of things, such as SQL base data or your data-access layer. If these files are completely code-generated (i.e. no merge regions), then you may not want to check them into source control, as you'll just face synchronization errors. For example, if you generate your data-access layer, and it's 100% determined from some set of xml files and database schema, then your build server could simply re-generate that code. If you check it into source control, then that version may be out-of-sync with what gets regenerated, and your build fails. In other words, as long as the server can already obtain the code by regenerating it, there's no reason to check it in - and risk checking in something that doesn't match what will be re-generated. (So, the generated files are effectively stored in source control via the inputs necessary to recreate them are being stored in source control).

Sunday, March 1, 2009

Things to CodeGenerate besides the Data Access Layer

[This was originally posted at http://timstall.dotnetdevelopersjournal.com/things_to_codegenerate_besides_the_data_access_layer.htm]

CodeSmith is a powerful code generator (worth its weight in gold). And while one of the most popular things to automatically generate is the data access layer, there's a lot more to CodeSmith than just wrapping databases:

  • System data - Given an xml file, you can generate all your interrelated system data. For example, say your application has a data-driven relationship of groups, roles, menu items, tabs, and such (i.e. security and navigation) - you could write tons of tedious and brittle SQL scripts, or you could abstract it to an xml file and generate the SQL scripts from that.
  • Data Structures - Especially before Generics in .Net 2.0, CodeSmith was popular for its strongly-typed collections (much faster performance than boxing and unboxing an ArrayList). You could make other data structures as well, depending on your application's need.
  • Documentation - While CodeSmith's default DataDictionary template is popular for documenting your database schema, you could use CodeSmith as a Super-XSLT to transform any arbitrary xml list (like a file containing business rules, config, or test cases), into human-friendly HTML reports.
  • Domain-Specific-Language - It's often more efficient to work at a higher level of abstraction. So, you could write an xml script, and use CodeSmith to translate that ("compile?") into useful actions.
    • Say you were trying to write automated UI tests, but the UI technologies keep changing, so you write a simple abstract xml script for the basic actions you care about (Load page, click button, etc...), and CodeSmith transforms that into the UI testing code for the relevant testing framework.
    • You could write abstract tests in xml (i.e. the data for pairs of input and output), and then use CodeSmith to dynamically generate all the unit tests from that.
    • You could read your file system to create an MSI installer using something like Wix.
  • Starting Templates - I favor active re-generation when possible, and there's a balance between what to code-generate vs. what to refactor, however, sometimes it's useful to passively generate a starting template - just to give you a head start. For example, say your UI is too complicated to actively re-generate, but you could take an xml file of input and generate a stating template, from which you could then modify.

Basically, CodeSmith lets you take any input (a database, xml file, your file system, etc...) and generate any text output (sql, xml files, C#, aspx, html, js, etc...), and then also call C# to do anything on those files (install them in the database, commit it to source control, execute the resulting C#, etc...). It's a beautiful thing.

Sunday, February 22, 2009

Killing the file handles, but not the process (from the command line)

[This was originally posted at http://timstall.dotnetdevelopersjournal.com/killing_the_file_handles_but_not_the_process_from_the_comm.htm]

Most developers have come across that annoying error where you try to delete or rename an innocent file, only to be  rebuffed with "Access denied, another process is accessing this file." For example, you'll get this type of error if you create a text file, open it in Microsoft Word, and then try to delete the file. This happens for all sorts of things - whether it's a process that didn't clean up after itself (perhaps from an unexpected crash), or something like IIS that locks certain website directories. While PSTool's ProcessExplorer GUI is great for finding what process is locking the file, what if you just want to find the handle, and kill it - from the command line?

Note that there's s a difference between the process, and the handle that that process has on the file. For example, if you want to delete a website that IIS is locking, you could shutdown or kill IIS (i.e. the process itself), but say you want to leave IIS running? Killing just the handle would leave the process intact, while allowing you control of the file again.

A useful tool for this is the (free) PsTools Handle.exe. From the command line, you can query all handles to a file, and then you can delete those handles. For example, this will find all handles on the given directory:

handle.exe C:\MyFolder

And returns something like so:

inetinfo.exe pid: 1696 3DC: C:\MyFolder\MySubfolder
inetinfo.exe pid: 1696 3E0: C:\MyFolder

You can then use this info to close the handles (one-by-one), without killing the process by passing in the "-c" switch, along with the handle id (in hex), and the process id, and the "-y" switch to confirm the delete.

handle.exe -c 3DC -p 1696 -y
handle.exe -c 3E0 -p 1696 -y

You could glue these two steps together into one by calling System.Diagnostics.Process to run the first command, parse its output, and then use that to create the parameters for the second command.

I'm sure there are more elegant ways (perhaps direct C++ calls, or even some special method in the .Net Framework), and I'm all ears to any, but this approach will get the job done.

Sunday, February 15, 2009

Part of the problem testing UI technologies is that they change so frequently

[This was originally posted at http://timstall.dotnetdevelopersjournal.com/part_of_the_problem_testing_ui_technologies_is_that_they_cha.htm]

Anyone who has actually tried to write automated tests knows that testing the UI is much harder than testing a backend class library. Besides having an obscure interface to the test (like parsing an HttpResponse), and juggling far more dependencies (like needing a live application, complete with database and HttpContext), another problem is that UI technologies change much more frequently than backend ones. For example, you could still call a C# .Net 1.0 library from 8 years ago. However, during that time, the web UI has gone from Html (request/response) to JS-enabled, to advanced JS with Ajax/JSON/JQuery (by now your test harness needs its own JS engine), to Silverlight (where the request/response model no longer even applies). By the time you've built a robust UI test framework, your UI could be using a different technology that your framework cannot handle.

This makes it much harder to write automated tests for the GUI - i.e. not the sort of thing you just add in hindsight. There seems to be a lot of projects out there that have designed themselves into a corner. A manager rushes the project to market with an un-testable design because they think they'll just whip up UI testing later, but then they find they've accrued an insurmountable technical debt, and they just can have it. It's like they spent years constructing the pyramid on the east side of the river, but oops - now they realize they wanted it on the left side instead.

I think this is one of the reasons why good unit testing (and MVC) is becoming so popular in many circles.

Tuesday, February 10, 2009

How slow build time hurts code quality

[This was originally posted at http://timstall.dotnetdevelopersjournal.com/how_slow_build_time_hurts_code_quality.htm]

Every developer on a large-scale project has probably had to deal with slow compile times. For example, you change one line in a backend assembly, and you wait three whole minutes for the assembly to recompile. While I understand that there are some cases out there where this is just life (I've had smart people on enormous projects drool over the thought of "just" three minutes to compile), in general, this is very bad for application developers.

It's not just the three minutes lost waiting for the compiler. There are at least a few other big problems:

  1. It constantly ruins your train of thought. Imagine a train that needs to stop at every station - it's not just the time stopped (i.e. compiling), it's also the time accelerating and decelerating (i.e. getting back in the groove). If Visual Studio is effectively frozen for over a minute because it's compiling, most devs will distract themselves with something else - and remain distracted even once Visual Studio finishes.
  2. It discourages developers from writing unit tests. For example, in an ASP web project, you can compile just the single page you're one. So, rather than a developer putting code in a backend assembly (where you can test it), they'll put it in the codebehind (where you cannot test it) so that it compiles fast enough and they can move to the next thing (this example assumes no MVC).
  3. It discourages developers from re-factoring. If even removing a dead comment will cost you several minutes, developers simply won't clean up "working" code.

 In other words, given human nature - slow compile times don't just slow you down, they degrade your code quality.

While sometimes the machine is just slow, there are a lot of tips and pointers out there to tweak Visual Studio to run faster:

Another big thing is to split up your assemblies. If you have a 5MB assembly, changing one line will requiring building all 5MB. However if you split that up into five one-MB assemblies, changing a line requires building just that single assembly, sparing you from rebuilding the other 4MB. There's a balance between number vs. size of assemblies, but it's a good thing to keep in mind when dealing with slow build times.
 

Wednesday, January 14, 2009

Why good-intentioned devs might not write good unit tests

[This was originally posted at http://timstall.dotnetdevelopersjournal.com/why_goodintentioned_devs_might_not_write_good_unit_tests.htm]

I'm a big fan of unit testing. A related question to "How many tests are sufficient?" is "Why don't we write good unit tests?" While I've seen some people attribute it to purely negative things like laziness or dumbness or lack or care for code quality, I think that misses the mark. While sure, there are some devs who don't write tests for those reasons, I think there are tons of other devs who are hard-working, smart, and do care about their work, but still don't write good or sufficient unit tests. Calling these hard-working coworkers "dumb" isn't going to make anything better. Here are some reasons why a good-intentioned developer might not write tests.

  1. I think I already write sufficient unit tests for my code.

  2. I don't have time - the tests take too long to initially write.

  3. I don't have time - the tests take too long to maintain and/or they keep breaking.

  4. The unit tests don't really add value. It's just yet another buzzword. They don't actually catch the real errors. So it's not the best use of my time.

  5. It's so much faster to just (real quick) run through my feature manually because all the context is already there (the data, the web session, the integration with other features, etc...).

  6. My code isn't easily testable - unit tests are great for business logic in C#, but I write code other than C# (SQL, JS), or things that aren't business logic (like UI rendering), or my code is too complex for unit tests.

  7. My code isn't easily testable - there are too many dependencies and limits. For example, I can't even reference an ASP.Net CodeBehind in a unit test.

  8. The tests take too long to run (the full test suite takes about 10 minutes, even without the database tests it still takes 3 minutes).

  9. I write code that already works, so it doesn't require unit tests.

  10. My code is so simple so that it doesn't need tests. For example, I'm not going to test every option in a switch-case.

  11. Sounds great, but I just don't know how to write tests for my code.

Note that I absolutely don't offer these as excuses, but rather as practical ideas to help understand a different perspective so you can improve things. For example, if someone is working on a 2-million line project that takes 5 minutes just to compile, let alone run any sort of test, they might skip running the tests with a "I don't have time" mindset. Yes, I still think it's overall faster to write and run the tests, but at least it helps you understand their perspective so you can try to meet them half way (perhaps improve their machine hardware, split up the solution, split up the tests, etc...). Of, if someone thinks that unit tests don't catch "real errors", then you can have a discussion with concrete examples. Either way, understanding someone's reasons for doing something will help bridge the gap.