The natural progression in the career of most developers goes from uncomplicated procedural programming and desktop applications that use only the resources of the local computer (“monolithic applications”)—to object-oriented programming and wide-ranging enterprise software systems spread across possibly thousands of computers encompassing multiple physical locations. Accordingly, enterprise development introduces developers and architects to obstacles they won’t find with desktop development. Much like human beings, software is said to have “matured” as it can do more and becomes more reliable and more robust.
So, take a look at what separates the enterprise from the desktop. Having recently spent several months prototyping, developing, testing, and deploying an enterprise software system aimed at Fortune 500 businesses, here are some concerns I had to address up front:
- Scalability Requirements (handling hundreds of concurrent users)
- DBMS Neutrality (must work with any OLEDB data source)
- Distributed Architecture Requirements
- Security Requirements (including accessibility/visibility of data by users)
- Unicode Support Requirements
- API Requirements (for third-party application integration)
- Software Configuration/Settings
- Deployment Requirements (Setup, Web UI vs. Thick “Fat” client)
- Architect Experience/Knowledge (Distributed Software Architectures)
- Developer Experience/Knowledge (OOP, COM, .NET, SQL, and so forth)
- Development Methodologies/Practices/Tools
This is not a comprehensive checklist for enterprise development by any means, but it serves the purpose of showing that enterprise development is difficult and requires some forethought. This list does not include schedule, budget, or resource constraints—which usually add more complexity to the project.
As you may have noticed, I listed architect experience separate from developer experience. I did this because I have seen projects with brilliant developers fail because the person that architected the system did a poor job. It is much easier to overcome a lack in development experience than a lack in architecture experience. Good architects are rare and possess more soft skills that, in many cases, can only be learned, not taught. Development experience is not so fickle and most times can be remedied by books, training, or mentoring. Although a discussion of hiring and interviewing practices is outside the scope of this article, it suffices to mention that getting the right people for the job can make or break a project.
Now, let me enumerate the list in more detail, starting from the top. My goal is to cover a wide range of topics, thus I will abstain from going into any real depth on the particulars. I would recommend consulting Google or Amazon.com for resources specific to any topic discussed hereafter.
If you’re building a software system that could, for any conceivable reason, end up needing to support many concurrent users, you’re going to want your system to be as scalable as possible. Don’t make the mistake of not anticipating the number of users to grow. Even if your system starts off supporting a small user base, you probably will not want to re-design the system a year later when that same group has 500 people, all depending on your system to do their jobs. Here are some development tactics that will help you achieve scalability for applications, no matter what size:
- High Availability State Servers: If you are building a Web application, make sure you are using a state server that scales. In other words, you must be able to manage state across a Web farm (sometimes referred to as a “web cluster”). Instead of using the default in-process state handlers provided by ASP.NET, PHP, ColdFusion and other Web development application platforms, look into a state server that uses a database, an out-of-process state server, or a third-party state server. This will give you the ability to restart your Web server without losing session state data. In some environments, this is not just important, but required by the nature of the data being handled and the potential length of user sessions. When session state is being managed on a separate machine, keep in mind issues such as network latency and security. An ideal setup is for the state server machine to be on a private network accessible by the Web server. You’ll also want to make use of connection pooling if you use a database as your state server.
- Database Connections: The rule with database connections is, “Acquire Late, Release Early.” That is, don’t open your database connections until absolutely required, and close them as soon as possible. You might also hear this rule said as “Get in, then get out!” in regards to retrieving data. Avoid server-side cursors and operations that require keeping an open database connection. There’s also a chance you’ll make friends with a DBA or two when developing with this mindset.
- Distributed Architecture: Typically, the more you can spread out the computing load across machines, the more you can scale. Ultimately, each application and network topology contributes to a unique environment that determines requirements. Having said that, you will generally be best equipped to scale if the components from each logical tier of your application can be configured to run either on the same machine or on a different machine for each tier. I will expand on this further in a section devoted to this topic.
Every enterprise-class system I’ve built or used stored its data in a relational database. Depending on the market or industry you’re targeting with the software you’re building, you might be fortunate enough to support only a single DBMS. If you’re not so lucky—and few of us are—you’re going to need a strategy for supporting multiple database systems with a single code base. What helps you do this?
- Avoid ODBC: ODBC Drivers have limitations dealing with large binary data types. Use OLEDB drivers instead. If you’re going to use ODBC anyway, consider providing a tool that will allow you to switch drivers. You never know what data types you could need in the future.
- Decouple your SQL: Most developers have heard the rule of not hard-coding SQL into your code. So what should you do then? One strategy is to store all of the DDL and DML in a separate file accessible by your application. Ideally, this will be an XML (.config) or INI file. This file can contain all your SQL statements for any DBMS you support. You can also use a set of characters as a replacement token in your SQL file so that you can have parameterized queries. For example, (“SELECT Field1, Field2 FROM MyTable WHERE Field3 = ‘~XYZ~’ “) where ~XYZ~ would be the token replaced by a value you supply at run-time. I’ve done this before and results were an XML file about 200K in size that contained over 500 queries. I spent about two hours to develop a utility that helped me easily manage the XML query file during development. This approach also allows you to fix SQL bugs without recompiling any of your code. Don’t forget to wrap your important database actions within transactions.
- Avoid Stored Procedures: This is controversial advice, no doubt, but I’m definitely not the only one advising this. When the majority of your SQL is ad-hoc, using stored procedures will not provide a significant performance or security benefit. Additionally, if you have to support more than one DBMS, (for example, SQL Server and Oracle) you’ll have to translate all of your stored procedure T-SQL to PL/SQL. Sometimes it makes sense to include specific T-SQL or PL/SQL functions in your SQL statements—like CONVERT() or TO_DATE() to handle dates—but use them sparingly. Also note I have used the word ‘avoid’ with regard to stored procedures. Some situations might require their use and you just have to bite the bullet.
- Research DBMS Differences: Familiarize yourself (or your team) with the differences that exist among the popular database systems. For example, SQL Server’s auto-incrementing (Identity) fields don’t exist in Oracle. Instead, you’ll have to use Oracle sequences along with insert triggers to automatically get a primary key value inserted. Knowing these idiosyncrasies will allow you to make design accommodations for them early.
Distributed Architecture Requirements
Until the last five years or so, developing, testing, and deploying distributed applications was one of the most complicated things you could attempt to do (some might argue that it still is). You have to worry about the reliability of the network and the performance of communicating with remote servers compared to local machine processes. During the initial stages of system design, you have some choices to make with regard to your architecture.
- Require client-side database drivers? With a Web UI, the answer is an obvious no (with the possible exception of embedded ActiveX controls). For a thick client, the answer is not so clear cut. If you don’t want to require client-side database drivers, you’ll need a way to instantiate objects remotely from a machine that has the database drivers—then pass them to the client. This can be done with technologies such as .NET Remoting, DCOM(COM+), Java RMI, or CORBA. The distributed technology you choose will most likely depend on your development platform.
- Which Protocol/Port? Most distributed technologies allow you to use different ports (or channels) to pass serialized objects back and forth. Should the application be able to work over the Internet or only within an intranet? Does your application need to bypass firewalls?
- Deployment Risks: Most distributed objects must be registered somehow on client machines. This has the potential to make deployment more complex. You’ll need a strategy to keep the deployment risks minimal.
- Interoperability Requirements: Discussing interoperability could take up an entire article (or book) by itself, so I’ll summarize by mentioning that you want to use the simplest data types possible at your endpoints. Avoid returning types such as DataSet from your endpoints if interoperability is a goal of your system.
Commonly, software security means authentication and authorization. Make the user prove who they are (authenticate) and then check their privileges (authorize). These two ideas, along with user roles and groups, have been around for a long time and are pretty much assumed to be in place for any enterprise software package. What is emerging more recently, however, is smart, flexible data security. Organizations want to be able to define (authorize) who gets to see the many pieces of data they collect. To help them achieve this with your software, here are some ideas:
- Support Active Directory: Not only do users have enough user name/password combinations to remember already but, if your system requires managing its own user names and passwords, you’re potentially requiring someone to spend several hours inputting names and, essentially, duplicating existing data. Try to avoid this.
- Don’t Require Active Directory: Don’t forget that some networks aren’t running Active Directory. Have a configurable backup plan for managing user information.
- Simple and Extendable: Keep the security model simple and extendable. One of the most easily maintainable security models I’ve implemented consisted of defining all actions that could be taken against entities in the system (View, Edit, Create, Delete, and so on) and then allowing the admin user to define whether those actions could be taken (or not) for each entity. A “Role” then consisted of the combined settings for allowable actions upon entities. Users then could be added to roles. If for some reason we wanted to add another entity to the system, it was simply a matter of adding a row for the entity to the correct database table. All actions for the entity were already defined.
The other point to be made here is the word data in flexible data security. Allowing admin users to define wildcard strings to be used in data retrieval (SQL statements) provides the utmost power. For example, allowing an admin to express the requirement that users in the operations role should only see rows where a particular field starts with the letters ‘OPS’.
- Maintain Consistent Standards: If administrators of your system are network administrators also, they’re going to be used to things like denied permissions overriding approved permissions. Make sure your security works the same way to avoid confusion.
- Use Application Roles: Using application roles for your database connections helps further security by allowing you to define permissions for everyone with a single account. It’s also possible to define database-object level permission with an application role to avoid costly accidents involving deletion of data. Create a standard user application role and deny delete permissions on any tables that standard users should never need to delete information from.
If one of your requirements is to support multiple languages, you must familiarize yourself with supporting Unicode data. An in-depth discussion of Unicode support is outside the scope of this article. Besides, Joel Spolsky has already said it best. What you should know is how Unicode affects your database design (data types used), how it affects the encoding used for your Web application pages, and how you’ll need to handle localization data differently for client software versus a Web application. It’s definitely something to research if localization and internationalization (i18n) aren’t familiar topics to you.
Another feature of enterprise software that can make it appealing to an organization—especially one that employs developers—is a publicly exposed, documented API. What this means to your customers is that they can build their own customized applications and have them integrate with your system. Here are some general rules to follow:
- Document your API: This will benefit both you and your customers. By documenting your API, it will help reinforce your understanding of the system as well as make you evaluate the design of your system.
- Provide an SDK: An SDK with sample application code can go a long way towards making a large client feel like they’re buying an open, extensible system that they can write custom modules for. Providing an SDK with sample applications also allows you to “dog-food” your API and evaluate its quality.
Most systems require network and local machine-specific settings to run properly. E-mail addresses, IP addresses, directories, themes, intervals, timeouts, licensing…the list goes on. Where and how you store these settings is not as important as how you make them accessible to an admin user. I like to allow these settings to be configured during setup and then also later on with an administrative “control panel” feature. With client software, I like to try and avoid standard users being able to access the control panel application.
|Provide a control panel where these settings can be adjusted.||Require setup to define success or failure based on whether settings are provided or not. They might not be known at setup time.|
|Provide security over who can access this control panel.||Make users update settings directly in the database with a tool like TOAD, SQL Plus, Query Analyzer, or Enterprise Manager.|
|Encrypt settings in the database that contain sensitive information.||Allow settings to become corrupted or lost. Wrap setting update actions within transactions.|
|Provide a chance to configure settings during setup.||Force refusal of settings values because of validation failure. Remember, your validation might not always work in every environment.|
|Attempt to validate settings (ping IP addresses, check for directories specified, query domain for e-mail aliases, and the like)|
|Provide helpful tool-tips and descriptive names for system settings. Not everyone will have the same interpretation of certain words. Avoid using acronyms.|
You want prospective clients to be able to try out your system without too much help from you. The perception that your software is easy to use starts with the setup process (some might say it starts when they visit your Web site to download it). Any computer-savvy customer should be able to get themselves up and running with your setup without getting you involved. Take a look at what that involves:
- Avoid Database Scripts: You should keep DDL and DML scripts around for your own development and testing purposes, but never give them to your clients for them to create a database for your software. Doing so is fraught with possible headaches. Some clients might have zealous DBAs who think certain data types should never be used and change them in your scripts before executing them. It sounds funny, but I’ve actually seen it happen. So, if you don’t give them scripts then, what?
- Create a Database Setup: Allow the DBA or whoever has administrative database privileges to run a setup program to create the database. You can point the setup program to a separate file that contains the database scripts if you want; but if you do, make sure the scripts are encrypted and decrypt them inside the setup program. This will help you avoid problems like the one mentioned above and the user will be none the wiser. Your database setup program should create the database and all the database objects. If you want to get fancy, and you don’t have a separate database requirement, you can allow the user to specify which existing database they would like your application’s database objects created in. This is why it’s good practice to give database objects a small system-specific prefix for enterprise software so that the names are less likely to clash with existing objects.
- Always Make Rebooting an Option: If you have a desktop client setup that requires a reboot of the machine after completion, make sure it allows the user to end the setup and reboot their machine manually. If your setup causes someone to lose their work (even if accidentally because they weren’t paying attention), your program is already an enemy before they’ve used it. Personally, I prefer setup programs that inform me I need to reboot but don’t do so on my behalf.
- Web Application Setup: If you have a Web application setup, make sure it creates any required settings. For example, if your ASP.NET application’s virtual directory needs to be configured to run as an IIS application, make sure your setup creates it as such. If your Web application requires a database connection string or other sensitive information stored in a configuration file, make sure the setup prompts the user for the required information and encrypts it in the configuration file for them. You don’t want users at any level exposed to the inner workings of your system configuration.
- Licensing: If you want people to be able to try your software before buying it, make sure that updating the license information is a simple process. Don’t make your setup program be the only place that licensing information can be input.
- Web UI vs. Thick Client: This is an important decision and will have deep ramifications for deployment options. Be sure that you’re making your choices for the right reasons. Technologies such as DHTML are making Web applications more appealing because of the robust interface capabilities coupled with extremely simplistic deployment. However, Click-Once Deployment for .NET applications is attempting to bring that same deployment simplicity to Windows desktop software. Click-Once is great, but unfortunately it has a long way to go to convince both developers and managers who have suffered through DLL-hell for almost a decade now. Having said that, if your application requires a rich graphical interactive UI, Click-Once might help resolve those DLL-hell induced headaches for you.
Among those working in software, some take the title of ‘Architect’ more seriously than others. This can make it difficult to judge whether someone claiming to be an architect is the real deal. To be sure the person in charge of system architecture has the skills needed to hit the ground running, here are some things to focus on.
- Has architected software systems before.
- Has first hand knowledge of platform weaknesses/idiosyncrasies and how to overcome them.
- Can effectively communicate the architecture of the system to the developers who will be implementing it.
- Can handle the business side of software as well as the technical side (for example, working with project managers and other stakeholders).
- Knows first-hand the strengths and weaknesses of many different commercial application platforms and their components.
- Can properly identify cases when transactions, queuing, caching, messaging, and other system behaviors are necessary.
- Has dealt with standards compliance before (ISO, ASNI, IEEE, and so forth)
If I were held responsible for hiring developers for an enterprise development team, here are the top 10 skills I would look for:
- Can code in more than one language. Can fairly easily translate code in one language to the other(s).
- Understands both the Web programming model as well as the desktop model. Can articulate the strengths and weaknesses of each.
- Has, at some point in their career, achieved certification. This does not by any means prove they know their stuff, but tells me a little about how seriously they take their career as a developer.
- Doesn’t crack under pressure or under criticism.
- Can explain, in their own words, a design pattern of their choice.
- Has a Google hit count of 100 or more on their name/identity/alias. This shows me they’re on the Internet finding and giving answers, writing articles, have a blog, or are involved in the community at some level. I’m not an Internet celebrity by any means, but my name turns up almost 3,000 results.
- Has a very strong grasp on OO programming and the benefits of interface-based design.
- Understands the “how” and “why” of distributed software systems.
- Has strong communication skills. This means that they can read, write, and clearly speak the primary language spoken by your team.
While no single development methodology is a panacea for complex software development, it helps to know what’s out there and how it can benefit your development processes. With so many different methodologies out there all preaching similar things in different ways, I’m going to avoid discussing any of them in detail. I think it’s sufficient to state what parts of your development processes you should place importance on. Here is a cursory look at what’s important: (Please note that this list is slanted towards .NET because that is my primary development platform).
For Brainstorming & Requirements Gathering
Modeling/Use Case tools
Automated Code Documentation
One thing you might like to do as a sort of “checklist” exercise is to evaluate your development practices against The Joel Test and see how you score.
You also can find another interesting quiz here.
The next time you’re in charge of developing an enterprise software system, remember how many things you’ll need to juggle in your mind over the course of the project. There are probably a few items that enterprise architects and developers will notice didn’t receive mention (testing, usability, and source code control, just to name a few) because this article serves the purpose of getting you started rather than leading you from start to finish. If you’re building a commercial product, shipping the software will only be the beginning of the work. Be sure to have a system in place to handle support requests, feature requests, and don’t forget about the need to market and sell your product. Ideally, someone else will take care of that for you, but it never hurts to have knowledge that spans outside the realm of software development. Chances are good you’ll be working in tandem with other teams to push the most important features of your product. And as always, there is version 2.0 to start planning.
About the Author
Jason Mauss is Chief Technology Officer for Knowledge Relay, Inc – a business intelligence visualization company, providing tools and resources at all levels of the enterprise. In addition to writing technical articles, he keeps a weblog at http://weblogs.asp.net/jamauss. You can contact him at Jason.Mauss@KnowledgeRelay.com or through his weblog.