Static Analysis

Subscribe to Static Analysis: eMailAlertsEmail Alerts newslettersWeekly Newsletters
Get Static Analysis: homepageHomepage mobileMobile rssRSS facebookFacebook twitterTwitter linkedinLinkedIn


Static Analysis Authors: AppDynamics Blog, Jason Bloomberg, RealWire News Distribution, Skytap Blog, Jayaram Krishnaswamy

Related Topics: SOA & WOA Magazine, Static Analysis

SOA & WOA: Article

Bulletproof .NET Code

A practical strategy for developing functional, reliable, and secure .NET code

.NET languages are becoming increasingly popular for driving the application logic for business-critical SOA and Web applications. In these contexts, functional errors are simply not acceptable, and reliability, security, and performance problems can have serious repercussions. Yet, few development teams have the resources to ensure that their code is free of implementation errors, let alone also worry about reliability, security, and performance. Whether or not your team has a satisfactory strategy for functional testing, you're taking several significant risks if you haven't yet implemented a comprehensive team-wide quality-management strategy:

  • New code might cause the application to become unstable, produce unexpected results, or even crash when the application is used in a way that you didn't anticipate (and didn't test for).
  • New code might open the only door that an attacker needs to manipulate the system and/or access privileged information.
  • The functionality that you worked so hard to design, implement, and verify might be broken when other team members add and modify code.
This paper explains a simple four-step strategy that has been proven to make .NET code more reliable, more secure, and easier to maintain - as well as less likely to experience functionality problems:
  1. As you write code, comply with development rules for improving code functionality, security, performance, and maintainability.
  2. Immediately after each piece of code is completed or modified, use unit-level reliability testing (exercising each function/method as thoroughly as possible and checking for unexpected exceptions) to verify that it's reliable and secure.
  3. Immediately after each piece of code is completed or modified, use unit-level functional testing to verify that it's implemented correctly and functions properly.
  4. Use regression testing to ensure that each piece of code continues to operate correctly as the code base evolves.
All four steps can be automated to promote a consistent implementation and let your team reap the potential benefits without disrupting your development efforts or adding overhead to your already hectic schedule. Moreover, automating these practices lets you concentrate on deeper design/logical issues during code review.

It's important to note that the strategy and practices discussed here were designed for team-wide application. Unless they're applied consistently across an entire development team, they won't significantly improve the software that the team is building. Having a development team inconsistently apply software development standards and best practices as it implements code is like having a team of electricians wire a new building's electrical system with multiple voltages and incompatible outlets. In both cases, the team members' work will interact to form a single system. Consequently, any hazards, problems, or even quirks introduced by one "free spirit" team member who ignores the applicable guidelines and best practices can make the entire system unsafe, unreliable, or difficult to maintain and upgrade.

1. Comply with development rules for improving code functionality, security, performance, and maintainability
The first step in improving the quality, reliability, and security of your code is to comply with applicable development rules as you write it. Many developers think that complying with development rules involves just beautifying code. However, there is actually a wealth of available .NET development rules that have been proven to improve code robustness, security, performance, and maintainability. In addition, each team's experienced developers have typically developed their own (often informal) rules that codify the application-specific lessons they've learned over the course of the project.

WHY IS IT IMPORTANT?
The key benefits of complying with applicable development rules are:

  • It cuts development time and cost by reducing the number of problems that need to be identified, diagnosed, and corrected later in the process.
    Complying with meaningful development rules prevents serious functionality, security, and performance problems. Each defect that is prevented by complying with development rules means one less defect that the team has to identify, diagnose, correct, and recheck later in the development process (when it's exponentially more time-consuming, difficult, and costly to do so).

    Or, if testing doesn't expose every defect, each prevented defect could mean one less defect that will impact the released/deployed application. On average, one defect is introduced for each 10 lines of code according to A. Ricadela writing "The State of Software" a few years ago, and over half of a project's defects can be prevented by complying with development rules according to what R.G. Dromey said in "Software Quality - Prevention Versus Cure." Do the math for a typical program with millions of lines of code and it's clear that preventing errors with development rules can save a significant amount of resources. And considering that it takes only three to four defects per 1,000 lines of code to affect the application's reliability, according to Ricadela, it's clear that ignoring defects is not an option.

  • It makes code easier to understand, maintain, and reuse
    Different developers naturally write code in different styles. Code with stylistic quirks and undocumented assumptions probably makes perfect sense to the developer as he's writing it, but may confuse other developers who later modify or reuse that code - or even the same developer, when his original intentions are no longer fresh in his mind. When all team members write code in a standard manner, it's easier for each developer to read and understand the code. This not only prevents the introduction of errors during modification and reuse but improves developer productivity and reduces the learning curve for new team members.

    WHAT'S REQUIRED TO DO IT? a. Decide which development rules to comply with.
    First, review industry standard .NET development rules and decide which ones would prevent your project's most serious or common defects. The rules defined by Microsoft's .NET Framework Design Guidelines and the rules implemented by automated .NET static analysis tools offer a convenient place to start. If needed, you can supplement these rules with the ones listed in books and articles by .NET experts. As you're deciding which rules to comply with, aim for quality over quantity to ensure that the team members get the greatest benefit for the least work. The point of having the team comply with development rules is to help the team write better code faster. Checking compliance with too many insignificant rules could defeat that purpose.

    Next, consider practices and conventions that are unique to your organization, team, and project (for instance, an informal list of lessons learned from past experience). Do your most experienced team developers have an informal list of lessons learned from past experience? Have you encountered a specific bug that can be abstracted into a rule so that the bug never occurs in your code stream again? Are there explicit rules for formatting or naming conventions that your team is expected to comply with?

    b. Configure all team tools to check the designated rules consistently.
    To reap fully the potential benefits of complying with development rules, the entire development team must check the designated set of rules consistently. Consistency is required because even a slight variation in tool settings among team members could allow non-compliant code to enter the team's shared code base. If the team has carefully selected a set of meaningful development rules to comply with, just one overlooked rule violation could cause serious problems.

    For instance, assume a developer checks in code that doesn't comply with rules for closing external resources. If your application keeps temporary files open until it exits, normal testing - which can last a few minutes or run overnight - won't detect any problems. However, when the deployed application runs for a month, you can end up with enough temporary files to overflow your file system, and then your application will crash.

    c. Check new/modified code before adding it to source control.
    Study after study has shown that the earlier a problem is found, the faster, easier, and cheaper it is to fix. That's why the best time to check whether code complies with development rules is as soon as it's written or updated. If you check whether each piece of code complies with the designated development rules immediately, while the code is still fresh in your mind, you can then quickly resolve any problems found and add it to the source control with increased confidence.

    d. Check all new/modified code in the team's shared code base on a nightly basis.
    Even if all team members intend to check and correct code before adding it to the source control, code with problems might occasionally slip into the team's shared code base. To maintain the integrity of the team's shared code base, you schedule your testing tool to automatically check the team's code base at a scheduled time each night.

    e. Hold weekly reviews for bug root cause analysis and prevention.
    Hold weekly meetings to analyze the root cause of the various bugs (defects that were reported by testers, customers, etc. - not violations of development rules) that were fixed during that week. The best time to do root cause analysis on a bug is when it's still fresh in your mind. After the root cause analysis, try to identify a set of rules that will prevent the same bugs from reoccurring then add these rules to the set of development rules you check.

    2. USE RELIABILITY TESTING TO VERIFY THAT EACH PIECE OF CODE IS RELIABLE AND SECURE
    The next step toward reliable and secure code is to do unit-level reliability testing (also known as white-box testing or construction testing). In .NET, this involves exercising each function/method as thoroughly as possible and checking for unexpected exceptions.

    WHY IS IT IMPORTANT?
    If your unit testing only checks whether the unit functions as expected, you can't predict what could happen when untested paths are taken by well-meaning users exercising the application in unanticipated ways - or taken by attackers trying to gain control of your application or access to privileged data. It's hardly practical to try to identify and verify every possible user path and input. However, it's critical to identify the possible paths and inputs that could cause unexpected exceptions because:

    • Unexpected exceptions can cause application crashes and other serious runtime problems.
      If unexpected exceptions surface in the field, they could cause instability, unexpected results, or crashes. Many development teams have had trouble with applications crashing for unknown reasons. Once these teams started identifying and correcting the unexpected exceptions that they previously overlooked, their applications stopped crashing.
    • Unexpected exceptions can open the door to security attacks.
      Many developers don't realize that unexpected exceptions can also create significant security vulnerabilities. For instance, an exception in login code could allow an attacker to bypass the login procedure completely.

  • More Stories By Hari Hampapuram

    Hari Hampapuram is currently Parasoft's Director of Development. Hampapuram has extensive experience in building software development tools at Microsoft Research, Intrinsa, Philips Semiconductors, and AT&T Bell Laboratories. Hari has a PhD in computer science from Rutgers University.

    Comments (2) View Comments

    Share your thoughts on this story.

    Add your comment
    You must be signed in to add a comment. Sign-in | Register

    In accordance with our Comment Policy, we encourage comments that are on topic, relevant and to-the-point. We will remove comments that include profanity, personal attacks, racial slurs, threats of violence, or other inappropriate material that violates our Terms and Conditions, and will block users who make repeated violations. We ask all readers to expect diversity of opinion and to treat one another with dignity and respect.


    Most Recent Comments
    j j 09/30/06 12:05:06 PM EDT

    .NET languages are becoming increasingly popular for driving the application logic for business-critical SOA and Web applications. In these contexts, functional errors are simply not acceptable, and reliability, security, and performance problems can have serious repercussions. Yet, few development teams have the resources to ensure that their code is free of implementation errors, let alone also worry about reliability, security, and performance. Whether or not your team has a satisfactory strategy for functional testing, you're taking several significant risks if you haven't yet implemented a comprehensive team-wide quality-management strategy:

    j j 09/30/06 11:17:56 AM EDT

    .NET languages are becoming increasingly popular for driving the application logic for business-critical SOA and Web applications. In these contexts, functional errors are simply not acceptable, and reliability, security, and performance problems can have serious repercussions. Yet, few development teams have the resources to ensure that their code is free of implementation errors, let alone also worry about reliability, security, and performance. Whether or not your team has a satisfactory strategy for functional testing, you're taking several significant risks if you haven't yet implemented a comprehensive team-wide quality-management strategy: