A Man and His Machine

Ramblings on .NET, programming, and technology

Friday, August 8, 2008

Working Smarter vs. Working Harder

Jon Davis over at System.Reflection.Emit has a great post about using debuggers, tools, designers, and other things to get the job done. I am consistenly stunned with the culture of "macho programming" where tools, code-generators, and debuggers are shunned in favor of nothing but a text-editor. IMHO, folks coding routine web apps in vi or notepad are control freaks.

BTW, I once sent an email to a old-school programmer who didn't know what IMHO stood for. He came over and asked me what "I am a Ho" meant ;-)

Thursday, July 24, 2008

Record Locking and ASP.NET DataSources

I never use ASP.NET DataSources.

Never.

Why?

As Peter says "...ASP.NET DataSources create a problem by updating every field in the record."

That is just wrong on so many levels. He does offer of a couple of work arounds, but only one is practical -- Changing Only What's Changed . But his approach involves Table Adapters instead of dealing with the fundamental weakness of the DataSource, DataSet, TableAdapter architecture -- it is essentially 2-tier. And messy.

And rarely seen in Enterprise application development.

Yes, small consultants and evangalists love it, because it lets them get up and running with quick prototypes, but it is not something you want to use to build scalable, maintainable applications.

Stick with a nice n-tier approach, where your front-end knows nothing about the back-end, and vice-versa.

Wednesday, July 16, 2008

How the Big Sites are Built

I found an interesting site that details the architecture of sites like YouTube, Google, and Amazon. Sorry to say, few of the sites mentioned on http://highscalability.com/ use .NET (except MySpace -- which often gets slammed for poor performance), but the reading is fascinating.

Here are some take-aways that caught my eye:

Amazon:

  • Create a staging site where you can run thorough tests before releasing into the wild.
  • Have a way to rollback if an update doesn't work. Write the tools if necessary.
  • Developers themselves know best which tools make them most productive and which tools are right for the job.

EBay

  • No stored procedures are used. There are some very simple triggers. (Wow!!???)

FaceStat

Now, I knew that Ruby developers have some kind of diety-like reverence for that language, but some have even gone so far as to name a server monitoring and management tool "God." This tool calls for some ironic syntax (ie, "God.watch do").

MySpace

  • You can build big websites using Microsoft tech.
  • The cache is a better place to store transitory data that doesn't need to be recorded in a database, such as temporary files created to track a particular user's session on the Web site.

PlentyOfFish

  • In the process of getting rid of ASP.NET repeaters and instead uses the append string thing or response.write. If you are doing over a million page views a day just write out the code to spit it out to the screen. (This really blew my mind. I hate seeing response.write all over the place -- it is so classic ASP. And it is a nightware to debug and maintain. I'd like to see the benchmarks on the two approaches.)

New Eclipse Version -- As Good As Visual Studio?



According to InfoWorld:

New Eclipse member looks to rival Visual Studio Russian company also added to the fold at open-source tools organization

Two new members of the Eclipse Foundation will make their formal debuts with the open-source tools organization Tuesday, including Sonatype, which plans to offer a Java environment to rival Visual Studio, and Excelsior, a Russian-based software company.

Founded by the team that built the Apache Maven Java build and release framework and repository, Sonatype joins Eclipse as a strategic developer. Sonatype will lead development of the m2eclipse project, which is an Eclipse plug-in combining Maven and Eclipse. Release 1.0 of m2eclipse is anticipated by mid-September, said Jason van Zyl, CTO and co-founder of Sontatype and developer of Maven.

"Maven combined with the Eclipse IDE is, we think, a solution that is starting to approach the usability of Visual Studio," van Zyl said.

Sonatype offers support and tools around Maven to increase compatibility, ease dependency-tracking and reduce barriers between development environments, the company said. One planned product, Nexus, will be a repository manager for Maven.

The company has a seat on the Eclipse Board of Directors and the Eclipse Planning and Architecture council.

Excelsior is believed to be the first-Russian-based Eclipse vendor and becomes an Add-in Provider member.

"Our next product is designed specifically for the developers of Eclipse RCP (Rich Client) applications, so we are primarily interested in marketing opportunities and in networking and collaboration with other members of the Eclipse Foundation and the Eclipse community," said Dmitry Leskov, Excelsior director of marketing.

The company has built Excelsior Jet, which is an implementation of Java Platform, SE 6 featuring an "ahead of time" compiler and deployment toolkit.

The ahead of time compiler is meant as a countermeasure to the Just In Time (JIT) compiler; ahead of time compilation happens on the developer's system and takes as input portable Java class files to produce a conventional Windows or Linux executable featuring optimized native x86 code. The application can then run on the hardware without overheads inherent in JIT compilation, according to Excelsior. JIT compilers are included in the Jet runtime to handle classes that cannot be pre-compiled to native code.

"[Jet] enables you to compile your Java classes into an optimized native executable and create a JRE-independent (Java Runtime Environment) installer for the compiled application," Leskov said. Certified with Windows and Linux/x86 platforms, Jet 6.4 currently supports the 32-bit x86 architecture; plans call for adding 64-bit support as well.

Jet offers faster application startup, better initial responses and raw performance, the company said.



As good as VisualStudio? Uh, probably not. I loaded Eclipse once because I was working at a place that has some Java code I needed to port to .NET. Not much fun. It was very spartan, and slow. Way slow.


Wednesday, June 18, 2008

Installing and Debuging .NET Windows Services

Everytime I write a new Windows Service in .NET, I always forget the details and syntax for installing it and debugging it. For the last several years, I have been refering to the same article from Ken Getz because it has all the information I need to know.

You can find it here.

Here's scoop on testing and debugging a service:

Testing Your Service


Unlike many applications you'll create using Visual Studio .NET, you cannot simply run a Windows service from within the development environment. You must build the executable, install it, and test it as a running service. (Debugging a service is another story altogether, which I'll cover in the next section.) Follow these steps to test your Windows service:

Use the File Save All menu item, or press Ctrl+Shift+S, to save your entire project.

Choose the Build Build menu item (or press Ctrl+Shift+B) to build your service's executable file.

Find the executable. Use the Visual Studio .NET Command Prompt item from the Start menu. It's installed as a subitem of the Visual Studio .NET Tools item to open a Windows command prompt. (If you don't follow these steps, you won't have your MS-DOS path set correctly.) Change to the folder where your project is stored. Navigate to the bin\debug folder for C# projects, or the bin folder for Visual Basic projects, and locate the FileWatcher.exe file you've just created.

Install your service. Run the InstallUtil tool that comes with Visual Studio, using the following command line:

InstallUtil filewatcher.exe


Figure 12 shows the output of running the InstallUtil utility. InstallUtil runs a transactioned install. If anything fails as part of the install, all changes are rolled back. Unless you set the Account or Password and UserName properties of the ServiceProcessInstaller object, this installation will fail. If you want to view all the options available for this installation utility, run
InstallUtil /?


Start the service. Unless you modified the ServiceInstaller1 StartType property, you'll need to start your service. Bring up the Windows service manager. (The exact steps depend on your operating system. In Windows 2000, you can use the Administrative Tools applet in Control Panel and select the Services item.) In the Services tool, find the FileWatcher service and double-click it to load the properties dialog box for the service. If you want to specify a path other than C:\ for the FileWatcher class, you can do that in the Start Parameters textbox. When you're ready, press Start to start the service.

Investigate the Startup events. Open the Event Viewer (again, the steps vary depending on your operating system). Select the Application log, and note that you should find two entries in the event log already. The first, sent from your service's OnStart event procedure, contains the text "FileWatchService starting. There are 0 args. Watch path is 'C:\'." (The text will be different if you specified an argument when you started the service.) The second, sent automatically (because you set the service's AutoLog property to True), indicates that the service started successfully.

Test the service. Open Windows Explorer, navigate to the folder your service is "watching," and make some changes. Rename, delete, or modify files. Switch back to the event viewer, and you should see information about your changes logged there.

Remove the service. When you're done, use the Services dialog box to stop your service. Run InstallUtil with its /u parameter to uninstall your service. You'll also need to shut down the Windows Services applet to completely remove your service from memory.

Debugging Your Service
At some point, you're likely to want to single-step through the code you've written in your service application. Although you can debug services much as you debug other applications, you cannot simply press F5 to start running the service from within the Visual Studio development environment, as you can with other projects.
Because you must compile and install a service before running it, debugging becomes a little more complex than for normal applications. Visual Studio .NET makes this process as easy as possible. Once your service is running, you can grab onto the running process and debug your code. To test this out, follow these steps:

Reinstall and start your service, as described in the previous section. (You must start the service running, or you won't be able to debug it.)

In Visual Studio, with your project loaded, select the Debug Processes menu item, displaying the Processes dialog box.

Select the Show system processes checkbox so that the Available Processes list includes running services.

In the Available Processes list, select the Filewatcher.exe entry, and then click Attach. On the Attach to Process dialog box, make sure that the Common Language Runtime option is selected, then select OK to accept. Then you can close the Processes dialog box.

Set a breakpoint in your code at the location you'd like to test. In this case, set a breakpoint on one of the event procedures you've created within the FileWatcher class.

Trigger the breakpoint by taking the necessary action within the file system. For example, if you set a breakpoint in the Created event procedure, creating a new folder in the "watched" folder should bring you back to your breakpoint. At this point, you can single-step through the code, as you would with any other application. Press F5 to continue running when you're finished with your testing.

When you're finished debugging, detach the debugger from the running process using the Debug Processes menu. Select the FileWatcher project in the list of debugged processes, then click the Detach button that's to the right of the list. Dismiss the dialog box.

Use the Debug Stop Debugging menu item to end the debugging session.

If you've gotten this far, you're most likely very happy to see that you can debug services so easily, but the nagging question about how you debug your service's OnStart event handler remains. Because you can't start debugging unless the process is running, and the OnStart event procedure runs when you start the service, how can you debug this code? One easy solution is to embed calls to EventLog.WriteEntry in the code, as pioneer coders might have done before the advent of adequate debugging tools.
Single-stepping though your startup code, however, will take a bit more effort. The .NET SDK explains that the OnStart method must return within 30 seconds, or the SCM will time out. If you must start the service and attach to it in order to debug, how do you grab onto the process before the Start event has completed?
One solution is to cheat—that is, insert a pause into the OnStart procedure, using code like this (I'll leave it to anyone using Visual Basic to remove the semicolon when inserting the following code into their class):

System.Threading.Thread.Sleep(25000);
This code causes the thread to sleep for 25 seconds. This is long enough for you to dig through the Debug Processes menu item, find the process you want to debug, and attach to it, but not so long that the SCM times out. Once you've added this code, you can step through your OnStart procedure.

Monday, June 9, 2008

Insert Multiple Rows With One Stored Procedure

One of the few programming challenges I've come across is what I call the "Insert n-Number of Records" scenario.

This comes up when a user can select one or more items, and that set of items (or usually their IDs) has to be inserted into the database. This can be done one of two ways:

1. Loop through the list of items, and call a SQL insert command for each item from the client application. This requires a round trip to the database each time -- not so good.

2. Package the list of items and pass them to a stored procedure that will then call the individual insert statements. This way one trip to database will insert n-number of records.

Here's an example where a stored procedure inserts rows into a table called UserReportSections which has two columns: ReportSectionID and UserID. It involes dynamic SQL to load a temp table, a delete query to purge any existing records for the given userID, and single insert statement to load n-number of UserReportSection rows.

The trick is to pass in the IDs of the records to be inserted in a comma delimited string, which is then used to build the dynamic SQL. This way, a large number of IDs can be passed to the procedure in one call. If the string of IDs is more than 1000 characters, there is probably something wrong, because you are talking about doing a mass insert of hundreds of records, which is an unlikely scenario for a web app.

Here's the proc:



CREATE PROCEDURE
[dbo].[usp_UserReportSection_InsertReportSections]
@UserId int,
@ReportSectionIDs varchar(1000)

AS
DECLARE @SQL VarChar(1000)


CREATE TABLE #ReportSections (ReportSectionID int)
Select @SQL = 'SELECT
ReportSectionID FROM ReportSections'
Select @SQL = @SQL + ' WHERE
ReportSectionID in (' + @ReportSectionIDs +')'

INSERT INTO #ReportSections
Exec ( @SQL)

-- this deletes any existing records for this
user, because we are creating a new set of rows

DELETE FROM
dbo.UserReportSection WHERE UserID = @UserID


-- this will insert a
record for every row that is in our temp table

INSERT INTO UserReportSection
SELECT @UserID,
ReportSectionID FROM #ReportSections



Calling this procedure like this:

EXEC usp_UserReportSection_InsertReportSections 1, "1,2,3,4"

will give us a table with 4 records for UserID 1.

Friday, May 23, 2008

PHP Appears to Suck

I've stayed away from PHP ever since I cracked open a PHP 3.0 manual and read the what's new section. At the top of the list was "Support for Arrays."

That was as much as I ever wanted to know about PHP. I think my instinct to avoid learning that langauge has been correct. While rampant in the Web 2.0, flip-meat world (where you are building an app to raise money or to sell an idea), PHP is almost non-existent in corporate application development. And that is where I dwell.

Jeff Atwood at Coding Horror sums it nicely here: PHP Sucks, But It Doesn't Matter


While Jeff says that it may not matter if end up building Facebook or YouTube with PHP, I think it does matter if you decide to build the average web application with PHP. Folks like me won't touch it. I just don't want to go back the days of SQL wrapped in code wrapped in markup, like ASP was.