Developing applications with .NET sometimes feels like I'm working with a split personality. Now that .NET has been around long enough, I and many of you undoubtedly have had a chance to put .NET through its paces with some real applications rather than just little samples. For me, the .NET learning curve has been a long one. I find working with .NET both exciting and frustrating at the same time. Talking to other developers I think I'm not alone.
The Good
.NET has a new and fresh feel to it. Prior to .NET we had reached a point of technology and tools mish-mash that has been almost prohibitive to get into and become proficient at. Win32 API coding, COM, system level programming, COM+, XML and various sub technologies, all use their own specialized syntax and architectures. If you have grown with this technology over the years you might have actually had a decent handle on it. If you were starting from scratch, it was difficult to try to put all of the "specialized" pieces together. .NET provides much-needed relief in this area with a Framework that wraps a very large part of the currently needed technology into a relatively consistent and easy(ier)-to-use Framework of components. There's consistency in commonly used patterns that are wrapped into components that share the same layout. For example, the various security and identity objects required for authentication are the same regardless of whether you are building a Windows Forms, Web Form, or Web Service application. Stream usage for everything from strings to files, XML data, to i/o ports and protocols is another feature that provides great consistency. You can reuse skills, which makes it easier to implement applications quicker even when the overall syntax for these objects may at first seem more complex and even awkward.
Regardless of whether your background is in C++, Visual Basic, or Pascal, .NET is bound to have some features that you either couldn't implement previously at all, required extensive code, or required use of third-party controls.
The ease with which you can implement advanced features like multi-threading, creating Windows Services, handling events, accessing native Windows event processing, and graphics programming is a big win for developers who come from fourth generation languages (4GL) that, in the past, were hampered by their runtime implementations. Lower level programmers who come from languages like C++, on the other hand, likely appreciate the ease with which they can implement formerly complex tasks, and the fact that these tasks require only a fraction of the amount of code. I come from a 4GL language. I love the fact that I can dig into lower level functionality and integrate it directly into my application without having to build another project in C++ to integrate into my application. .NET can do many tasks that previously required splitting things out into other tools.
Shedding the shackles of the complexities of COM is another bonus. While you could make COM applications work well, it is a hassle to install such applications and keep them running - especially if the solution contained many different COM components. I recently finished a small .NET utility application that was a joy to deploy. It contained various advanced Windows controls, multi-threading support, and I shipped it as a single 130k EXE. No support files, no installation - just a single EXE that I could copy into a directory and run. My client could even run the application directly off a URL on the Internet by simply placing the application on a Web Server and accessing the EXE through Internet Explorer. .NET's deployment models, even for fat client applications, offer a lot of potential to deliver the flexibility of Web applications without the shackles of HTML development.
Visual Studio .NET, as a development environment, is impressive to work with. I think there are some usability issues that Microsoft should work out to make tasks easier, but overall the environment provides everything that you need at your fingertips in an understandable (although complex) environment. It takes getting used to, but you'll really appreciate all the helper tools and support that Visual Studio .NET provides. Beefed up IntelliSense, code comment exports, and outlining are some of my favorite features in the Visual Studio .NET editor. You can run multiple project solutions as one single application, which is cool, and the VS.NET debugger ranks high on my list.
Certainly there's much more: ADO.NET's distributed data paradigm is a huge step up from ADO, and of course ASP.NET's new Web Form metaphor is changing the way we think about Web development. If you follow the trade papers you surely have heard all the accolades about .NET so I won't go on. Suffice it to say that even a cynic like me can find a lot of things to like about .NET.
The Bad
Although I am very excited about .NET as a platform, I find it infuriating to work with at times. A lot of things are difficult to do or are implemented in a nearly incomprehensible fashion when it seems that there could have been easier and cleaner interfaces. Like any 1.0 release from Microsoft there are a number of unexpected behaviors. It seems like .NET is making some difficult things easy and some easy things more difficult.
My number one beef with .NET centers on databinding, both in Windows Forms and Web Forms. .NET databinding mechanisms try to do too much by trying to address 100% of scenarios at the cost of significant complexity rather than address 95% of scenarios and making databinding easy. Yes, the databinding mechanism is very powerful with its ability to bind anything to anything. The ability to page through data is good. But you must write a lot of code by hand to accomplish this. So much, in fact, that it's almost easier to bind data to controls manually than use the default databinding functionality. In Windows Forms specifically, you must manually write databinding code and when you're done the code can't be controlled via properties on the controls the data is bound to. For example, try binding a textbox to a property of a business object rather than a field from a dataset and see how much code you must write to display the data and keep it updated as you move through a list box. It isn't pretty. You can do it - it's just very tedious and very error prone because much of the code you write deals with indirect referencing (that is it's not type-safe) and you don't get IntelliSense or the compiler to help you out. If you do use DataSets exclusively, life becomes a little easier because you can use the Builders, but this process still takes too much time and you end up with reams of unmanageable code.
Not only does it take a lot of code to perform these tasks, but the mechanism involves a number of different objects. Just understanding how databinding works is a major task. Forget trying to figure it out from the .NET docs. Several third-party articles and books explain databinding, but even with a good description the topic is confusing at best. No doubt the power is all there. For me, the solution was to build my own databinding subclasses to simplify the process of adding properties to my custom controls that I can set in the property sheet. After all, if you write database applications, almost all controls are databound and you surely don't want to write code to bind each and every control manually.
.NET can do many tasks that previously required splitting things out into other tools.
Databinding in Web Forms, thankfully, is simpler, but it also has a major problem: It is one-way only. You can only display databound data. You can't write databound data back to the data source. It's hard to even call this behavior databinding. Granted, ASP.NET makes the population part easy by using the form controls to retrieve the data, but this still leaves me scratching my head as to why there isn't some way to grab the data from the controls and bind them back to the data since the control binding is already there. Just about every single data-driven Web page needs to do this, so why isn't this built-in?
Along the same lines, data validation is far from trivial. Instead of providing easy tools and masks on the various controls, you must use external objects and extra event handlers to make validation work. You must create lots of code and there are many opportunities for errors. Whatever happened to simple format string-based validation that covers the 90% scenario? .NET opts for completeness and complexity instead of the ease of use. As developers we can address this with wrapper classes, but since most of us will rewrite this stuff over and over again, why couldn't this functionality have been included in the Framework?
The Obnoxious
The UI designers themselves are another major cause of frustration. Both the Windows Forms and Web Forms designers have quirks that make them less than ideal to use on a regular basis. The designers are two-way code generators. Code is good - you can look at it and understand it. But the designer's code can be a hassle because if something happens to go into the code that the designer can't deal with, your form goes kaput. I've had at least five forms blow up on me when the Form designer decided that all contained controls no longer exist. The code is all still there, and the form compiles and runs correctly, but the designer doesn't show any of it. Saving at that point wipes the missing designer controls from the source file. Ironically, it's the form designer's own generated code that caused this problem. In many cases the problem was fixed by moving around the Windows Forms generated code section immediately following the property section, but figuring that out took quite a bit of digging and help from somebody who'd had this problem before. Again - hours and hours of wasted time.
Rather than using real containership, forms use code generation to hook up events and property settings. The designers have problems if you copy controls around - try copying a button with some code attached and paste it onto another or the same form. You can't keep the code with the control! Or try to rename a control after you've added some code to it. The events you implemented retain the original name like Button1_Click rather than update to the control's new name. Code generation can bite you in a variety of ways like this.
Web forms don't fare much better. The Visual Studio .NET HTML designer is incredibly tedious to work with if you need to create or manipulate HTML manually. It offers IntelliSense but no additional help for templates. And the Visual Studio .NET HTML designer is even worse at manipulating anything but simple HTML in design view. For example, try to resize an HTML table with the designer - you might get lucky and pull on the right handle to stretch a cell or you might stretch the entire table. Or add a column. For a tool that puts such a heavy emphasis on the Web developer, the HTML designer is almost embarrassing. You can't even select a control in the visual designer and switch to HTML view and edit the HTML code quickly. Instead you must find your place using the Search dialog or manually look through the document. How hard could it have been to implement this simple feature? Luckily other companies have figured out how to build an HTML editor that lets developers work both in visual and code modes simultaneously, but you can bet the majority of developers torment themselves with the VS editor. Visual HTML editing in the development environment has been Microsoft's weakest spot for years. Fixing it could provide the biggest productivity boost in Web application development.
Both the Windows and Web form designers suffer from the twitchy User Interface of the Property Sheet. When you set properties flipping from control to control, the focus doesn't stay on the same property. Or when you click onto a property in the property sheet the field is not auto-selected to simply overtype the text. Instead, you have to use the cursor keys or mouse to position the cursor when practically all of the time you simply want to write in a new value. The property sheet can't be navigated by keyboard easily either - you can't use up and down keys to move to the next property while in the value of a property. You can only navigate from the text field. In the editor, the various alignment tools are next to useless due to the scale and positioning of the various controls. Getting controls to line up requires that you manually move the controls even though there are supposed to be alignment tools. These are little issues but they cause lots of wasted time during everyday development.
And let's not forget about the Windows Forms UI itself - the stock controls aren't XP Themes aware, and the way stock menus and toolbars look seems to come out of the last century. A "state of the art" tool should support the latest Windows look and feel, but .NET doesn't. Menus don't support images natively (you have to owner draw them), and you can't move toolbars. The menu designer is easy to use, but it requires a new event handler for every single menu button - there's no central handler event you can pipe selections through. The Tree and Listview controls seem slow and flickery and have odd behaviors when you use default images. They don't have events you would expect like NodeClick().
One of my biggest complaints is the lack of a built-in Web Browser control. The Web Browser control has become a mainstay of the modern user interface, but it mysteriously wasn't provided as a managed control. Instead, every time you want to use a Web control in your application you have to import the ActiveX control. This causes several problems: You have to use object variables for most parameters on events and properties, and you have to pass variables by reference. Since the ActiveX control was based on optional parameters, you have to pass complete parameter lists which .NET requires when calling COM components. What's worse is some important events like BeforeNavigate2_which is needed to capture clicks in the Web Browser control - don't fire. Although that's a bug in the ActiveX control, this still makes using the control in .NET very limited. Microsoft has acknowledged this bug in the control for over 2 years but they haven't fixed it. Several third parties have created more complete COM wrappers for the control that work more reliably, but it's non-obvious to find these solutions and you're likely to find these solutions only after a futile attempt at getting the ActiveX import to work correctly. Using ActiveX controls in this fashion also poses a security problem since ActiveX controls are unmanaged code. You'll run into security issues in applications that run over the network unless you adjust the security.
The .NET documentation in MSDN is a major issue as well, especially for more advanced topics. I've been working on an application that implements the ASP.NET runtime in a desktop application (an article on this topic appears in this issue of CoDe Magazine), and trying to find information on this topic has been very painful. Ultimately, with the help of several developer papers and a decompiler I was able to figure out what was happening behind the scenes when a new Application Domain is created for hosting the ASP.NET runtime, but this is not documented anywhere in MSDN. Most methods that are related to this topic are documented with a single line in MSDN that say little more than the name of the method name with spaces in it. No example, no explanation of when this or that event would fire and what gets passed. I can't tell you how much time I've wasted searching for information in MSDN that ultimately wasn't there or is utterly useless. It seems to me that a policy is needed at Microsoft o document functionality as the specs and the code are created, not afterwards when nobody is around to explain how the functionality is supposed to work. Without adequate documentation .NET can be a huge time sink for unproductive research time.
Visual HTML editing in the development environment has been Microsoft's weakest spot for years. Fixing it could provide the biggest productivity boost in Web application development.
Many things in .NET seem to be designed without having been thought all the way through, especially in the Windows Forms engine where many features are implemented in a dead end way that can't be extended without throwing everything away and starting over. For example, .NET can't handle menus with a single event handler, but you must add a method for every single menu option. This yields extremely unwieldy source code for even a moderately sized menu. The Help provider has no generic events that you can capture when Help fires, which means you can't hook any external Help tools for editing Help. To fix this you need to completely throw out the built in behavior and built your own handlers or resort to third-party tools that get it right.
The Unknown
.NET touts easy installation and when you build applications that you have full control over it certainly seems that .NET delivers on this count. You easily can deploy applications as Web applications, Web services, or rich client applications. Rich client applications can take the form of Windows Forms apps running locally or from the Web or as Web Browser controls. Cool, right? Well, not so fast. The Web deployment scenario is certainly clean. You can pretty much create a virtual directory on your Web Server and copy the contents of your Web application into this directory. But for rich client applications, things are considerably more difficult. It always looks so easy in the prospectus.
You can build attractive rich client applications with .NET, but I wonder whether .NET is really the right tool to build vertical or shrink wrap applications with. .NET applications are monsters. Even the smallest.NET applications requires close to 8 megs of memory at startup. And startup is slow as the code compiles on the fly. A simple Windows Forms application takes around 12 megs of memory. While memory is cheap these days, it just doesn't seem right to build small utility applications that take this much memory. Especially if you want to have it run all the time as might be the case with a Windows Service. Most administrators would have a fit to have a simple application take 10 megs to run when it loads at startup.
Security is also a big issue for shrink wrapped applications. The only environment an application will likely be able to run from once the client gets it is the local machine. If you load an application from the network but you haven't set a specific security policy, the application will run into a host of security violations from any code that tries to access the file system, call unmanaged code (which a lot of code from any third-party provider is likely to do) or access content on the network. While this is configurable via machine and network policies, do you as a software developer/publisher want to be in the business on telling people how to configure their machines just so they can run your application? Security might be an important feature for Microsoft in large IT departments but it's not going to go over well with small businesses or sales to consumers who might want to do something as silly as run the application from a network share via their Wireless connection. .NET might be a sketchy platform to develop consumer or even business end user applications with. Security and security configuration in .NET is a very complex topic - I have three different .NET Framework security books on my bookshelf, each more than 800 pages, and most of it dealing with trying to justify the security features of .NET along with explaining the complex hierarchy of Code Access Security. Security is good, but providing a model so complex that it gets in the way of applications that you need to run can be a problem too. At the very least, Microsoft needs to make the configuration tools easier or .NET should ship with more default policies that you can easily apply to real life application scenarios.
It seems to me that a policy is needed at Microsoft to document functionality as the specs and the code are created, not afterwards when nobody is around to explain how the functionality is supposed to work.
There's also the issue of versioning applications as new versions of the .NET runtime become available. I've already seen that this is not a painless process with the beta version of the .NET 1.1 Framework. If you've built an application using the original version of .NET, upgrading to 1.1 is not as simple as simply recompiling your application. You have to swap out your application references for the new versions of the runtime assemblies. In my applications which are rather simple to boot, not a single application ran under the new version of .NET. Some errors that occurred were changes to parameters and types of VS.NET-generated code that were difficult to track down and fix (and not mentioned in the 'update' documents). In fact, I simply gave up trying to upgrade two applications and I've decided to be content with leaving these apps at version 1.0. Incremental application updates as the platform matures should be relatively painless; instead, you end up with a 'legacy' application that's a pain to bring up to the latest version. This is not how I would envision a great 'deployment story'.
Summary
I certainly don't want to be a naysayer as I really believe that .NET has accomplished a lot of technical milestones in this first release. It's a very capable development platform and I enjoy working with it. I merely point out a few of the issues that I have run into as a developer myself - I'm sure many of you have many more to add to this small personal list. Some of these things are minor and more annoyances. Others such security and deployment still make me wonder just how viable .NET is for building desktop applications that are shipped to many users.
Yet the trade press is pleased to say how perfect .NET is for every type of application and how well integrated and powerful the environment is. Indeed there are strengths but it is important to also voice some of the shortcomings, if for no other reason than to spur workarounds and solutions and to let Microsoft know that certain things require fixing.
There's so much great information from third parties out there today about .NET - if there's a problem somebody's probably figured it out and found a workaround. Many people are free about sharing this knowledge which is awesome. However, its difficult to find all of this knowledge and ultimately I think its Microsoft's responsibility to provide an out-of-the-box where the information is more accessible via MSDN and the .NET Help.
If you've built an application using the original version of .NET, upgrading to 1.1 is not as simple as simply recompiling your application. You have to swap out your application references for the new versions of the runtime assemblies.
This is a call for better usability in the tools. For me, this alone is a huge loss in productivity every day as I roll my mouse around the screen for things that should be automatically positioned or handled more naturally. This is also a call to try and keep things simple when they can be made simple. This doesn't mean to give up power, but it means supporting the powerful features with easy to use, common use features that require less code and are more intuitive. This may mean providing simpler ways to subclass existing classes (potential bloat) or sometimes maybe even breaking encapsulation in the class hierarchy chain to provide improved usability for common use scenarios. For a tool that has so much RAD potential it would be a shame to miss this opportunity to provide better developer productivity and reduce the learning curve.
As always if you have any comments or questions about this or any Code magazine article or commentary you can discuss them at http://www.west-wind.com/wwthreads/default.asp?Forum=Code+Magazine.