Monday, January 05, 2009
#
I'm writing a series of concise montly web development tips over at DotNetSlackers.com. My first tip, published in December, looked at caching data for the lifespan of a request, which is a quick and easy way to improve the performance of data-driven web applications that have pages where the same data is requested multiple times per request. My most recent tip takes a deeper look at HTTP redirection.
Every ASP.NET developer is familiar with Response.Redirect, but do you know what happens behind the scenes when you do a Response.Redirect? In a nutshell, it sends an HTTP 302 status back to the client with the redirection URL. The 302 status code is used to indicate that information has temporarily moved; there is another HTTP status code (301) that indicates that a resource has permanently moved. You should use a 301 redirect when using URL rewriting, “retiring” old URLs, or doing a website structure re-org.
For more information check out the tip, An In-Depth Look at HTTP Redirection.
Monday, December 29, 2008
#
My Toolbox column in the January 2009 issue of MSDN Magazine is available online. The January issue examines:
- Script# - Script# is a utility created by Nikhil Kothari that translates C# code into JavaScript code, allowing you to create ASP.NET AJAX components and behaviors and Windows Vista Sidebar gadgets writing using a strongly-typed language (C#) with compile-time error checking, familiar OOP syntax and semantics, and better design-time tool support.
- Blogs of Note - Eric Lippert. Eric is a Senior Software Design Engineer at Microsoft. His blog offers some of the best in-depth looks at features in C#. He's also a very witty and talented writer, and has a knack for describing and illuminating complex topics in an interesting and lighthearted manner. For example, check out this blog entry, which looks at why getting a 'simple' change in one of Microsoft's products is not as easy as one might naively expect: How many Microsoft employees does it take to change a lightbulb?
- IntelliSpell - IntelliSpell is a Visual Studio Add-In that checks the spelling of your comments, strings, and markup. It's a stand-alone spell checker (you don't need Microsoft Word installed on your computer, for instance), and offers a host of features like as you type spell checking, custom dictionaries, and foreign language dictionaries for spell checking multi-lingual projects.
This issue's Bookshelf section reviewed Pro T-SQL 2008 Programmer's Guide, by Michael Coles. An excerpt follows:
I recently finished the book Pro T-SQL 2008 Programmer's Guide (Apress) by Michael Coles, which provides a thorough review of the T-SQL syntax and language features. The book begins with a look at the new features in T-SQL 2008, such as the MERGE statement and new data types. The author then moves on to the core T-SQL constructs—user-defined functions; stored procedures; triggers; XML, XQuery, and XPath support. He then continues with coverage on encryption, common table expressions and windowing functions, SQL CLR programming, and error handling, among others. Each of these topics is given its own chapter with in-depth discussion and examples. And each chapter concludes with a series of exercises whose answers are provided in the appendix.
Enjoy! - http://msdn.microsoft.com/en-us/magazine/dd315418.aspx
As always, if you have any suggestions for products, blogs, or books to review for the Toolbox column, please send them to toolsmm@microsoft.com.
Thursday, December 18, 2008
#
One of the first things I do when creating a new ASP.NET web application is create a custom base page class and add a handful of useful methods I've used in other projects. My latest article on DotNetSlackers.com shares four helpful features that you can add to your base page class:
- Display a JavaScript Alert
- Recursively Search the Control Hierarchy
- Record Page Execution Times
- Set the Page's Title
Read more at: Four Helpful Features to Add to Your Base Page Class.
Thursday, December 04, 2008
#
Over Thanksgiving weekend Fredrik Normen asked an interesting hypothetical question: What would you be doing today if computers didn't exist?
I've been programming since age 10 when my family procured its first personal computer and my dad showed me how to use GW-BASIC and your imagination to make computer games. So it's hard to imagine a life without computers. (Heck, it hard to imagine life without the Internet, yet close to half of my computing lifetime was spend disconnected. I guess I have a poor imagination.)
If computers didn't exist I would probably be employed in one of three fields:
- The sciences - in high school I had an interest in biology and physics and, for a brief time, actually considered majoring in Biology at University before deciding that computer science would be a more interesting and enjoyable path. If computers had never existed I could see myself going down this path, perhaps being an 'in the field' biologist or, if the math didn't kill me, a physicist.
- Education - I've always enjoyed teaching and tutored younger kids in science and math during high school to earn some spending money. I doubt I'd have the patience or fortitude to be a full-time public teacher, but teaching in a higher education facility or personal tutoring could be something I'd do for a living.
- Writing - I started writing stories (longhand) when I was in elementary school, and didn't stop writing fiction until college. If computers didn't exist perhaps I'd be a technical writer, writing the instruction manual for abacuses and slide rules.
What would you be doing today if computers didn't exist?
Tuesday, December 02, 2008
#
My Toolbox column in the December 2008 issue of MSDN Magazine is avaiable online. The December issue examines:
- Improving Software Quality with Static Code Analysis Tools, in which three tools are examined:
- FxCop - a free tool from Microsoft that examines compiled assemblies for conformance to Microsoft's official Design Guidelines for Developing Class Libraries. This includes checks for naming, type design, exceptions, and so forth.
- StyleCop - another free tool from Microsoft. StyleCop examines the C# source code (rather than a compiled assembly) and reports any violations against a defined coding style. For example, StyleCop will warn you if you indent loops using spaces instead of tabs (if you have it configured as such), or if you omit white space from both sides of operators like == and !=.
- CodeIt.Right - a third-party tool that integrates within Visual Studio and provides similar conformace tests as FxCop and StyleCop. Some of the advantages of CodeIt.Right over FxCop and StyleCop include a much easier mechanism for creating and defining custom rules and the ability to refactor violating code into conforming code with the click of the mouse.
- Blogs of Note - Matt Berseth. Matt's blog is an excellent resource for ASP.NET and AJAX development, and includes a level of detail and professionalism not found in most blogs. Most of Matt's entries show how to do some cool task with ASP.NET and AJAX. There are a plethora of screen shots in virtually every blog entry, along with downloadable source code and online demos.
There was no book review in this issue.
Enjoy! - http://msdn.microsoft.com/en-us/magazine/dd263071.aspx
As always, if you have any suggestions for products, blogs, or books to review for the Toolbox column, please send them to toolsmm@microsoft.com.
Monday, November 24, 2008
#
I learned this Visual Studio keyboard shortcut from a client a couple of months ago. I use it several times a day now.
Typing the Ctrl key and - (the minus key) returns you to the previous cursor location, be it in the same file or in a different, open file.
Visual Studio maintains your position in a file as a stack. So as you do a Find and jump to a particular location in a file, or right-click on a method or property name and choose “Go To Definition” Visual Studio keeps track of your position prior to these jumps. You can then 'pop' the position off the stack and return to it by hitting Ctrl+-.
This keyboard shortcut is quite useful when you're bug hunting or trying to understand how some bit of code is working and are drilling down into methods and search results. When you are ready to return to the previous location, which could be in another file or elsewhere in the currently opened file, just hit Ctrl+- to get back! And if you need to get back to the spot before that, hit Ctrl+- again.
Thursday, November 20, 2008
#
ELMAH is a free, open-source library created by Atif Aziz for logging errors that occur in an ASP.NET application. I've written about ELMAH many times before; its one of the first things I setup when creating a new ASP.NET application. A new version - ELMAH 1.0 BETA 3 - was recently released.
With just a few minutes of setup and configuration you can have ELMAH automatically log unhandled exceptions to a number of different data stores - SQL Server, Oracle, a Microsoft Access database, an XML file, to an e-mail address, and so on. You can also write code to proactively record an error via the ELMAH library. Granted, ASP.NET provides some built-in support for logging errors via its health monitoring system, but ELMAH is a simpler version of the health monitoring system that focuses specifically on error logging and is easier to configure. It also works in ASP.NET 1.x applications, whereas health monitoring is only available in ASP.NET 2.0 and up. What's more, ELMAH provides a built-in web page and RSS support for viewing error information.
So, what's new in ELMAH 1.0 BETA 3? The project page and issue tracker has the full set of details, but in a nutshell here are the enhancements that most interest me:
- Three new error logging sources: Oracle, Microsoft Access, and VistaDB.
- Log errors in AJAX applications.
- Addition of an ErrorLogDataSourceAdapter, which you can use with the ObjectDataSource to declaratively work with the error log details from an ASP.NET page.
It is imperative that every web application in production log errors and report those errors to the development team. ELMAH offers this important functionality and can be setup, configured, and customized within a few minutes.
Monday, November 17, 2008
#
One of my clients has a data-driven Software as a Service (SaaS) web application that is used by a dozen different customers. In particular, this client of mine has a web application that's used by various clinics and hospitals to track, schedule, and bill health care-related activities. As discussed in the Multi-Tenant Data Architecture guide from Microsoft, there are three approaches for modeling data that comes from many distinct customers:
- Separate Databases - each customer has a separate database on the database server.
- Shared Database, Separate Schema - a single databsae is used, but each customer has a unique set of database tables.
- Shared Database, Shared Schema - a single set of database tables are used, with a CustomerId column or some other technique used to identify what rows belong to what customers.
Each approach has its pros and cons, and is good reading if you plan on building a SaaS web app.
For security and privacy reasons (important concerns for health care providers), we used the Separate Databases approach - each customer's data is hosted as a separate database on the server. I would not recommend this approach for the vast majority of multi-tenant applications. The most pronounced drawback of this model centers around the pain points associated with managing and administration of these databases. For example, when rolling out a new version or a bug fix, the database changes must be applied to all customer databases. If there is a business logic-type bug discovered, where there may be logically incorrect data in the database that needs to be addressed, you now have to look through all databases to see where the problem occurs and apply the fix across all databases.
One tool that assists with such debugging challenges is the undocumented Microsoft SQL Server stored procedure sp_MsForEachDb. In short, this stored procedure allows you to run a command on every database on the server. You can use it like so:
EXEC sp_MsForEachDb @command1='command to execute on all databases'
Within the @command1 input you can use a question mark (?) to denote that the name of the database the command is currently executing on be injected.
sp_MsForEachDb is most commonly used for administrative tasks such as updating statistics on all databases, but can also be used for debugging or bug hunting in a multi-tenant SaaS architecture that uses separate databases. Here's how: consider that you unearth a bug in the application code that allows for some illogical value in the database. Perhaps there's some business rule that dictates that a patient cannot have their insurance information entered if the patient's primary address is not provided, yet the application did not correctly enforce this rule and as a result there may be some patients with insurance information on file but without a primary address. Your task is to find out what patients in each database fit this description. You could run the following query on every single database:
SELECT p.PatientId, p.PatientName
FROM Patients p
INNER JOIN PatientInsuranceInformation pi ON p.PatientId = pi.PatientId
WHERE p.Address1 IS NULL AND pi.Active = 1
The issue is that this quickly becomes a pain if you have many different databases. Here's where sp_MsForEachDb comes in - you can use it to run the above on each database with the following statement:
EXEC sp_MsForEachDb @command1 = 'SELECT ''?'' as DatabaseName, p.PatientId, p.PatientName
FROM ?.dbo.Patients p
INNER JOIN ?.dbo.PatientInsuranceInformation pi ON p.PatientId = pi.PatientId
WHERE p.Address1 IS NULL AND pi.Active = 1'
This will output a three column resultset that displays those patients that have insurance information but no primary address along with what database the patient information resides in. The ''?'' part in the SELECT list displays the database name. The question mark character is also used in the FROM and INNER JOIN clauses to indicate the database from which to query against (i.e., you can refer to a table as database.owner.tableName).
The only downside of sp_MsForEachDb is that it runs on all databases, meaning it will run on databases like master, which don't have the application tables. As a result, you'll get SQL errors for those databases which clutter the output a bit. But for the databases specific to the application you will quickly see the results of your query and know, in an instant, what patients in what databases have this particular problem.
Thursday, November 13, 2008
#
Feel free to print out a copy of these commandments and tape them to your coworker's monitor.
- You shall check in early and check in often. You anger your coworkers when you check out a file and insist on keeping it checked out until some future point in time that is measured using variables that exist solely in your brain.
- You shall never check in code that breaks the build. If you code does not compile, it does not belong in the source control repository.
- You shall not go home for the day with files checked out, nor shall you depart for the weekend or for a vacation, with files checked out.
- You shall leave a descriptive comment when checking in your code. You need not include your name or the date in the comment as that information is already tracked.
- You shall use the 'Undo Checkout' option if you check out a file and do not make any changes. It displeases your coworkers when you check in code that has not changed at all from the original.
- You shall not use comments to 'save' defunct code. Fear not, for the code you delete still exists in the source control code history and can be retrieved if needed.
- You shall use source control for more than archiving just code. The source code control repository makes an excellent storage for technical docs, SQL scripts, and other documents and files related to the project.
- You shall religiously backup your source code control database on a regular basis and store a copy in an off-site location.
Tuesday, November 11, 2008
#
Many websites that support user accounts, such as the ASP.NET Forums, include information as to how what users are currently online and what they are doing. For example, the Who Is Online page on the ASP.NET Forums shows the users currently online, what forum they're viewing, and how many minutes it's been since they were last active. Unfotunately the Membership system does not offer much in the way of tracking user activity. All it has out-of-the-box is the ability to log the date and time the user was last 'active' and to report the total number of users online - that is, the count of users whose last active date and time falls within a certain time window (15 minutes, by default).
With a little bit of elbow grease it's possible to track user activity. I use the word activity here loosely. An activity might mean visiting a particular URL, much like how the ASP.NET Forums Who Is Online page shows what forum the user is visiting. It could also be more broad. For example, if a user just updated their account information the activity could be logged as, “Updating account information.” The activity information of interest can be logged in a database table and, once there, can be used in reports, be it a Who Is Online page or a report detailing the activity of a particular user.
To learn how to log user activity and display the results in the aforementioned reports, check out my latest article on DotNetSlackers.com: Tracking User Activity.
Wednesday, October 29, 2008
#
My Toolbox column in the November 2008 issue of MSDN Magazine is avaiable online. The November issue examines:
- DayPilot - DayPilot is an AJAX-enabled calendar and scheduling ASP.NET Web control that offers functionality not unlike what you find in Outlook and other desktop-based calendar applications. Plus there's a free, open-source Lite version.
- Blogs of Note - Jeff Smith - Jeff's blog contains great posts on T-SQL syntax, queries, and tips and tricks for getting the most out of Microsoft SQL Server.
- RegexBuddy - with its terse syntax and mix of special characters, regular expressions are usually hard to read, understand, and enhance when using the naked eye. However, with a tool like RegexBuddy, regular expressions are much easier to grok. RegexBuddy is a desktop application with features that assist in building, testing, and editing regular expressions. RegexBuddy includes a regular expression debugger and wizards for turning your regular expressions into C# or VB code.
For The Bookshelf section I reviewed The Productive Programmer
, by Neal Ford. An excerpt from the review follows:
In the Productive Programmer (O'Reilly, 2008), Neal Ford shares proven techniques that will help any developer improve his or her productivity. The first part of the book explores behaviors and tools for boosting developer productivity; the second part looks at software development practices that help contribute to a more streamlined development process. He espouses the Don't Repeat Yourself tenet for improving productivity and provides examples of how to avoid needless repetition in areas from version control to technical documentation. Poor software development practices can quickly swallow up those productivity gains, Neal notes. Adding unnecessary features, insufficiently testing your code, and failing to correctly encapsulate your objects are all practices that lead to bugs and unmaintainable code. The willingness to question the status quo is another important aspect in developer productivity. Too often developers get into a rut and use a particular design pattern or coding technique because that's the way it's always been done, overlooking or turning down alternatives that may be more efficient.
Enjoy! - http://msdn.microsoft.com/en-us/magazine/dd148647.aspx
As always, if you have any suggestions for products, blogs, or books to review for the Toolbox column, please send them to toolsmm@microsoft.com.
Tuesday, October 28, 2008
#
Rick Strahl recently posted about some his frustrations with the Visual Studio 2008 Designer - HTML Mangling with Literal Controls in the <head>. While I've not had Visual Studio mangle my pages' markup when switching between the Design and Source views like Rich has, I have had one especially nagging issue since Visual Studio 2005: when I'm in the Designer and I select a control on the page very often the properties for the selected control are not loaded in the Properties window. This problem has been particularly accute in Visual Studio 2008. Does this happen to anyone else?
Here are things I resort to when this behavior starts:
- Say au revoir to the Designer and do your development from the Source view. This is fine if you are comfortable with HTML and Web control and data binding markup, but this option is less palatable if you are training or teaching a class or helping a coworker who is most familiar with the Designer.
- Try loading the properties by selecting another control on the page and then re-selecting the initial control whose properties I wanted to view. Sometimes this works.
- Right-click on the control and select Properties from the context menu. This technique worked 100% of the time in Visual Studio 2005 but rarely works for me in 2008.
- Selecting a control in the declarative markup seems to 'wake up' the Properties window. To load a control's properties, then, go to Split view, click up in the declarative markup to 'wake up' the Properties window and then select the control from the Designer.
This Designer behavior is especially frustrating when teaching a class. Each quarter I teach a class that introduces ASP.NET to students and it's a triffle embarassing to be standing at the front of the class showing them how to perform a certain task and fighting with Visual Studio's Designer to get a control's properties loaded in the Properties window.
It could be worse, I guess. I have one client who uses Visual Studio 2005 and he cannot set controls' ID properties from the Designer. If he adds a TextBox Web control to the page from the Designer its properties load in the Properties window and the ID displays as TextBox1. Now, if he goes to the Properties window and types in, FirstName, for instance, the Properties window shows FirstName but once he clicks off that control and returns to it the ID value has reverted to TextBox1. The only way he can change a control's ID property is to go to the Source view and change it from the declarative markup.
Monday, October 13, 2008
#
My Toolbox column in the October 2008 issue of MSDN Magazine is avaiable online. The October issue examines:
- SQL Data Generator - Quickly generate unbounded amounts of real-world test data for your database with a few points and clicks of the mouse.
- Blogs of Note - Dare Obasanjo - Dare is a Program Manager at Microsoft and writes about social networks and the transport and data exchange standards common used in such sites. Dare is also the creator of RssBandit, a popular (and free) desktop-based RSS reader.
- Displaying Color-Coded Syntax in a Web Page - There are a bevy of tools that you can use to format source code into lively markup on a web page. I look at three:
- Quick Highlighter, a web-based tool where you enter code into a textbox and the page generates corresponding HTML and CSS.
- CopySourceAsHtml, a Visual Studio Add-In that lets you select code (or markup) from Visual Studio and right-click and copy the source code to HTML and CSS markup for display.
- squishySyntaxHighlighter (which appears to be offline right now), which is a .NET component for programmatically converting a string of Visual Basic or C# code into display markup.
For The Bookshelf section I reviewed ADO.NET 3.5 Cookbook, by Bill Hamilton. An excerpt from the review follows:
When I write or maintain ADO.NET code, I like to keep a copy of Bill Hamilton's book ADO.NET 3.5 Cookbook (O'Reilly, 2008) within arm's reach. ADO.NET 3.5 Cookbook offers more than 200 recipes for common ADO.NET problems—everything from where to store database connection strings to how to execute a SQL statement asynchronously. When I get stuck trying to recall how to perform a certain action, I reach for this book, flip to the Table of Contents, find the recipe, and am off and running. Each recipe starts with a problem statement, such as: "You want to access an output parameter returned by a stored procedure." Next is the solution, and then the discussion. This problem/solution/discussion format results in self-contained recipes that are easy to understand.
Enjoy! - http://msdn.microsoft.com/en-us/magazine/cc947918.aspx
As always, if you have any suggestions for products, blogs, or books to review for the Toolbox column, please send them to toolsmm@microsoft.com.
Saturday, October 11, 2008
#
Between work and diaper changes I've been reading Michael Coles's book Pro T-SQL 2008 Programmer's Guide, and found this little gem (pg. 527-528):
The OUTPUT Clause
You can use the OUTPUT clause with the the INSERT, UPDATE, DELETE and MERGE DML statements. ... The OUTPUT clause returns information about the rows affected by the DML statements that can be useful in comparing preupdate and postupdate data, or for troubleshooting and logging purposes. ... You can use the OUTPUT clause to output a SQL result set like that returned by a SELECT statement, or you can combine OUTPUT with the INTO clause to output rows to a table or a table variable.
This feature is supported in T-SQL 2008, but was initially added to Microsoft SQL Server 2005. And here it is three years later and I'm just learning about it!
One use of the OUTPUT clause is to grab the just-inserted IDENTITY column value:
INSERT INTO TableName(ColumnList)
OUTPUT inserted.IdentityColumnName
VALUES(Values)
The above will return the just-inserted IDENTITY value as a result set, just as if you had followed an OUTPUT-less INSERT statement with the statement:
SELECT SCOPE_IDENTITY()
You could use the OUTPUT statement to return information about the rows affected by an UPDATE. For example, in these tough economic times you might need to increase prices by 20% for all products that cost less than $10.00. The following statement performs the described update and returns those products whose prices were increased, showing both their old price and their new price:
UPDATE Products SET
Price = Price * 1.20
OUTPUT inserted.ProductID, deleted.Price AS OldPrice, inserted.Price AS NewPrice
WHERE Price < 10.00
This UPDATE statement will modify the data and return a three-column result set with a row for each modified product along with its preupdate price (deleted.Price) and its post-update price (inserted.Price).
Pretty neat, eh?
In fact, You can string these DML statements together, so you do an UPDATE with an OUTPUT whose results are then automatically INSERTed into another table (such as an audit table). The OUTPUT statement feels like in-place triggers (kind of like how Common Table Expressions are akin to in-place views).
I'll have to write an article on the OUTPUT statement on 4Guys one of these days...
Further Reading....
Thursday, October 09, 2008
#
A decision all independent software developers must make early on in their career is when to bill a client and under what terms. This decision, of course, is not the developer's alone to make - it must be discussed and agreed upon by the client, as well. Similarly, a developer must decide how to charge: by hour or by project. Over the years I have received numerous e-mails from fellow developers who are contemplating striking it out on their own, and wonder what suggestions or advice I have for billing.
My general policy is as follows:
Software Development:
For software development I charge per hour. I have never taken on a client and billed per project, and likely never will. My primary concern with billing per project is that my estimation or the client's estimation may be off base, which hurts one of us. Also, when billing by the hour there is no concern about scope creep or other things tacked on by the client late in the game in an attempt to get more bang for his buck. Billing per hour is ideal for the software developer, but customers often prefer a fixed price for the project because it puts a cap on the amount it will cost. A new customer does not know what kind of work they can expect from a developer per unit time. To ameliorate this concern, I usually propose a very simple, short feature or milestone for new clients, so that they can get a good gauge of how long it takes me to complete a task, and what level of quality they can expect. I have also given price caps for customers on tight budgets, but this is more the exception than the rule.
Another reason that I propose a very short and simple first project for new clients is because I require payment in full and up-front for new customers. This sours some customers and I've certainly lost some business because of this policy. The way I see it, this requirement serves as a vetting process. It shakes out customers who may have shaky cash flow or who are going to later nickel and dime me for the work performed or, worst yet, not pay at all. Once I've had some time to work with a client and have established a good working relationship, I will relax these conditions and bill on a monthly basis (or more often, if requested). If I have not yet established a relationship and do not fully trust the client, I continue requiring payment up front and in full. When I finally end up billing on a monthly basis, my terms are Net 15 (that is, I require payment within 15 days of invoice), but I have some customers who much prefer Net 30 and once that relationship and trust is established I'm willing to agree to those terms.
I find this process of establishing trust by requiring payment up front at first, and then billing monthly with Net 15 terms to be a surefire approach to ending up with solid clients. To ensure prompt payment, some independent software developers use tactics like hosting the application on their server and not sending the code to the client until payment is received in full. Another, more questionable approach, is to put a backdoor into the application so that if the client does not pay the software developer can "break into" the application and "turn it off" until payment is received. I dislike both of these techniques as it frames the working relationship in adversarial terms.
I have waived or relaxed these requirements - payment up front for new clients, Net 15 terms, etc. - for very large or very established customers, such as regional businesses with thousands of employees, or Fortune 500 companies. These types of clients are more the exception than the rule, though, as the vast majority of my clientele are small businesses. And some companies or industries have Net 60 terms and won't make any exceptions.
Training
Like with software development, I require payment up front or on delivery of services for new clients. I will make exceptions for very large and established clients, but only sparingly. My hesitancy here in due in part to a negative experience with a local training company that was very late with payment. I ended up taking the client to small claims court, but was paid in between the time they were served and when the court date was set. (My decision to go to small claims court and the resulting process is summarized in My Small Claims Court Experience.)
While I always charge by the hour for software development, I charged for training services using a variety of models. For personal training I usually charge hourly, as it makes the most sense. In this way the customer has direct control over the costs and knows the precise charge for another hour or day's worth of training. For classroom events I usually charge a per-day rate, which depends on a number of factors, including:
- Class size
- Number of days of instruction
- The location relative to my home - is the classroom setting five miles away, or across the country?
- The material used and the topics covered - am I given the course-wear to teach or do I need to create it?
When a potential customer asks for a training quote, I use the above criteria to judge how long it will take me to create the course-wear (if needed) and to prepare for the class, how much travel time there will be (if any) and the total hours of instruction. I then multiple that number by my usual hourly rate for software development, then multiply that by a number between 1.0 and 2.0. This coefficient depends on the size of the class (the more students, the higher the number) and based on how excited I am to teach the class. If I'm teaching a two-day class to 5 smart devs who work in a fun company that's headquartered on the beach, and we're having a luau at the end of the second day, then that number will be a lot closer to 1.0 than if it's a class of 25 devs at a stuffy corporate office and I have to wear a suit each day. The figure derived from that equation, plus any travel and entertainment costs, are what I quote the client.
Writing
Unlike training and software development, it's hard to get a client to pay you by the hour for an article, tutorial, or book. Also, in my experience, it's rare to be paid by the word. Usually publishers have a pre-determined rate they pay for a written piece with a minimum word count. For print media - books and magazines - there is also a maximum word count. The pre-determined rate for magazines and websites is usually a dollar amount; for books it's a royalty rate and advance. (For a breakdown of compensation on writing a book, see The Economics of Writing a Computer Trade Book.)
Also unlike training and software development, it's virtually impossible to get a client to pay you anything up front. Book publishers offer advances, sure, but they don't start rolling in until you have completed a significant portion of the work. (This is true for computer trade authors; I'm sure Stephen King gets his advance whenever he wants.) As a result, as a write you have to be willing to get paid after the article or tutorial or book is written and published. As a result, I take a bit of a gamble if I write for a small publisher, small magazine, or small website. Having been bitten in the past, these days I rarely write for small operations unless I know the people running them and trust that I'll be compensated. But if a small publisher contacts me out of the blue and wants me to write five chapters for a book, I'll pass.
In Summary...
What's infinitely more important than the decision you make as when to you bill your clients and what terms to use, is to have very frank and clear communication before any work begins. It is imperative that you discuss with your client when you will bill and when you expect payment. They may agree, or they may want to change the terms. But what's vital is that there is a clear understanding. I've talked with many independent software developers who were too uncomfortable bringing the subject up or just assumed that the client understood and agreed with implicit payment terms, and as a result there was no communication prior to the work. This can lead to an unhappy client if his expectations of the payment terms were different than yours.
Also, if you have sent an invoice to a client and he has not paid by the time the invoice is due, do not hesitate to contact the client and politely inquire about payment. And, lastly, if a client becomes severely overdue, do not hesitate to stop working for him. You are not obligated to work for free.