Thursday 31 January 2013

Software Requirements - Part 5

This is the fifth and the last part of the following book summary.



Previous posts:


Software Requirements Management

Requirements management includes all activities that maintain the integrity, accuracy, and currency of the requirements agreement as the project progresses.

No one approach is universally correct because projects differ in their flexibility or features, staff, budget, schedule and quality. Base your choice on the priorities that the key stakeholders establish during project planning.

The requirements baseline is the set of functional and nonfunctional requirements that the development team has committed to implement in a specific release. The base-lined SRS document should contain only those requirements that are planned for a specific release. Requirements baselines are dynamic. The set of requirements planned for a specific release will change as new requirements are added and existing ones are deleted or deferred to a later release.

Your organization should define the activities that project teams are expected to perform to manage their requirements. Documenting these activities and training practitioners in their effective application enables the members of the organization to perform them consistently and effectively. Your process descriptions should also identify the team role that's responsible for performing each task. The project's requirements analyst typically has the lead responsibility for requirements management.

Every team member must be able to access the current version of the requirements, and changes must be clearly documented and communicated to everyone affected. Consider appending a version number to each individual requirement label, which you can increment whenever the requirement is modified.

A more sophisticated technique stores the requirement documents in a version control tool, such as those used for controlling source code though check-in and check-out procedures.

The most robust approach to version control is to store the requirements in the database of a commercial requirements management tool.

You can find detailed feature comparisons of these and many other tools in International Council on System Engineering web site.

The main benefits of a requirements management tool are:
  • Manage versions and changes
  • Store requirements attributes
  • Facilitate impact analysis
  • Track requirements status
  • Control access
  • Communicate with stakeholders
  • Reuse requirements

These products show a trend toward increasing integration with other tools used in application development.

Think of each requirement as an object with properties that distinguish it from other requirement. A rich set of attributes is especially important on large, complex projects but selecting too many requirements attributes can overwhelm a team such that they never supply all attribute values for all requirements and don't use the attribute information effectively.

Software developers are sometimes overly optimistic when they report how much of a task is complete. They often give themselves credit for activities they've started but haven't entirely finished. Track status against the expectation of what "complete" means for this product iteration.

Measuring actual development and project management effort requires a culture change, and the individual discipline to record daily work activities. Effort tracking isn't as time-consuming as people fear. The team will gain valuable insights from knowing how it has actually devoted its effort to various project tasks. Note that work effort is not the same as elapsed calendar time.

What about Requirement Changes?

Most developers have encountered an apparently simple change that turned out to be far more complicated than expected. Such uncontrolled change is a common source of project chaos, schedule slips and quality problems.

An organization that is serious about managing its software projects must ensure that:
  • Proposed requirements changes are carefully evaluated before being committed to.
  • The appropriate individuals make informed business decisions about requested changes.
  • Approved changes are communicated to all affected participants.
  • The project incorporates requirements changes in a consistent fashion.

The closer you get to the release date, the more you should resist changing that release because the consequences of making changes become more severe.

Using short development cycles to release a system incrementally provides frequent opportunities for adjustments when requirements are highly uncertain or rapidly changing.

The Change Control Process

The change control board has been identified as a best practice for software development. The CCB is the body of people, be it one individual or a diverse group, who decides which proposed requirement changes and newly suggested features to accept for inclusion in the product. A higher-level CCB has authority to approve changes that have a greater impact on the project.

Policies are meaningful only if they are realistic, add value and are enforced.

Useful change-control policy:
  • All requirements changes shall follow the process
  • No design or implementation work other than feasibility exploration shall be performed on unapproved changes.
  • The contents of the change database shall be visible to all project stakeholders
  • Impact analysis shall be performed for every change.
  • The rationale behind every approval or rejection of a change request shall be recorded

Many teams use commercial problem or issue-tracking tools to collect, store, and manager requirements changes. Remember however that a tool is not a substitute for a process.

The CCB Chair will typically ask a knowledgeable developer to perform the impact analysis for a specific change proposal.

Impact analysis has three aspects:
  • Understand the possible implications of making the change.
  • Identify all the files, models, and documents that might have to be modified if the team incorporates the requested change.
  • Identify the tasks required to implement the change, and estimate the effort needed to complete those tasks

Skipping impact analysis doesn't change the size of the task. It just turns the size into a surprise. Software surprises are rarely good news.

It is useful to create a checklist to help you in the process. The book contains lot of examples.

Many estimation problems arise because the estimator doesn't think of all the work required to complete an activity. For substantial changes, use a small team - not just one developer - to do the analysis and effort estimation to avoid overlooking important tasks.

To improve your ability to estimate the impacts of future changes, compare the actual effort needed to implement each change with the estimated effort. Understand the reasons for any differences, and modify the impact estimation checklists and worksheet accordingly.

Requirements Tracing

It's hard to find all the system components that might be affected by a requirement modification.

Traceability links can help you build a more complete picture of how the pieces of your system fit together. On many projects you can gain 80% of the desired traceability benefits for perhaps 20% of the potential effort.

Defining traceability links is not much work if you collect the information as development proceeds but it's tedious and expensive to do on a completed system.

Determine the roles and individuals who should supply each type of traceability information for your project. Educate the team about the concepts and importance of requirements tracing.

It's impossible to perform requirements tracing manually for any but very small applications. Requirements tracing however can't be fully automated because the knowledge of the links originates in the development team members' minds. However, once you've identified the links, tools can help you manage the vast quantity of traceability information.

If you're maintaining a legacy system, the odds are good that you don't have traceability data available, but there's no time like the present to begin accumulating this useful information.

Even if your products won't cause loss to life or limb if they fail, you should take requirements tracing seriously.

Don't define traceability links until the requirements stabilize. 

The Impact of Software Requirements

The path to improved performance is paved with false starts, resistance from those who are affected, and the frustration of having too little time to handle current tasks, let alone improvement programs.

Requirements lie at the heart of every well-run software project, supporting the other technical and management activities.

It is interesting to consider the relationship of requirements to other project process.


It's not surprising that the long-suffering people at the end of the requirements chain, such as technical writers and testers, are often enthusiastic supporters of improved requirements engineering practices.

If customer-support costs aren't linked to the development process, the development team might not be motivated to change how they work because they don't suffer the consequences of poor product quality.

Process changes don't always result in fabulous, immediate benefits for every individual involved. A better question - and one that any process improvement leader must be able to answer convincingly - is , "What's in it for us?" Every process change should offer the prospect of clear benefits to the project team, the development organization, the company, the customer, or the universe.

Conclusion

The single biggest threat to a software process improvement program is lack of management commitment. Professional software practitioners don't need permission from their managers to better themselves and their teams. However, a broad process improvement effort can succeed only if management is motivated to commit resources, set expectations, and hold team members accountable for their contributions to the change initiative.

Keep the following four principles of software process improvement in mind:
  • Process improvement should be evolutionary, continuous and cyclical.
  • People and organizations change only when they have an incentive to do so.
  • Process changes should be goal-oriented.
  • Treat your improvement activities as mini projects.

Even motivated and receptive teams have a limited capacity to absorb change
, so don't place too many new expectations on a project team at once. Write a roll-out plan that defines how you'll distribute the new methods and materials to the project team and provide sufficient training and assistance.

Accept the reality of the learning curve - that is, the productivity drop that takes place as practitioners take time to assimilate new ways of working. This is part of the investment your organization is making in process improvement. 

Software project managers must identify and control their project risks, beginning with requirements-related risks. Formal risk management planning is a key element of a successful large-scale project. Project managers can control requirements risks only through collaboration with customers or their representatives. Jointly documenting requirements risks and planning mitigation actions reinforces the customer-development partnership.

Nothing is more important to a software project's success than understanding what problems need to be solved. If you actively apply known good practices and rely on common sense, you can significantly improve how you handle your project's requirements, with all the advantages and benefits that brings. 

Sunday 27 January 2013

The Template Method Pattern in .NET

The Template Method Pattern defines the skeleton of an algorithm in a method, deferring some steps to subclasses. Template Method lets subclasses redefine certain steps of an algorithm without changing the algorithm's structure.

This pattern is typically used to implement frameworks as an important technique for code reuse. It allows to encapsulate pieces of algorithms so that subclasses can hook themselves right into a computation.

You can use this pattern when you recognize that two or more algorithms are similar except that some of the steps require different implementations.

General procedure to follow:
  • Create a class (abstract if you want mandatory steps)
  • Create a generalized version of the algorithm in a method or more (possibly sealed)
  • Use protected abstract methods when a step of the algorithm is required
  • Use protected virtual methods when a step is optional
  • If needed, add a default implementation for optional steps
  • Create a subclass for each specific algorithm implementing all the various steps
It is quite easy to create a simple example of the pattern but I think that is much more useful to identify implementation of the pattern in your favourite frameworks. This pattern is used in almost every framework.

Example: The XNA Framework

The XNA Framework extensively use the Template Method Pattern to provide a base class Game that encapsulates the common algorithms of a game. Each subclass of the Game class implement a specific game reusing lots of the code defined in the baseclass.

If you look at the documentation of the Game class on MSDN you can see that there a lot of protected virtual methods. Each of this method can be seen as a step of the "generic game" algorithm.

Let's consider the two more important hooks:
  • Update()
  • Draw() 

Using a .NET Disassembler you can easily look inside the Game class and identify the template methods.


You can see that the Game class provides a default implementation of Update() and Draw() methods.



As a consumer of the framework the only thing you need to do is to override Update() and Draw() and the base class will take care of all the aspects of the game.

It is important to notice that clients can call or not the base class method with the default implementation. This can cause subtle bugs that can be hard to find and can be seen as a drawbacks of the pattern. As a framework implementer you should avoid this situation if you can, otherwise is important to document well what a client should do.

Example: Event Handling in .NET libraries

The entire .NET framework uses the Template Method Pattern extensively to provide internal clients with a simplified way to handle events.

Microsoft recommends using a protected virtual method for raising each event. This provides a way for subclasses to handle the event using an override.

You can see an example of this pattern in the ASP.NET Control class.


An internal client can override the method and add custom logic to it. Note that the Page class inherit indirectly from the Control class.


Having a default implementation makes the client asking the following questions:
  • Should I call the base method?
  • Should I write my custom code before calling the base method?
  • Should I write my custom code after calling the base method?

There is not a generic answer to this questions because it always depends by the framework and how the base method is implemented. This should clearly be documented because it can be the source of many problems.

A way to avoid all of this problems is to use abstract methods. However, adding too many abstract methods can make the framework difficult to use because the client is forced to override all the methods even if it is not necessary.

Finding the right trade-off is surely not something easy to do.

Microsoft says on this:
The derived class can choose not to call the base class during the processing of OnEventName. Be prepared for this by not including any processing in the OnEventName method that is required for the base class to work correctly.
This problem is strictly related to the Liskov substitution principle. Not calling the base class can violate the principle.

Design Principles and Limitations

It is possible to continue forever with examples from the .NET Framework but I think that you got the idea behind the pattern.

The object oriented design principles used by the pattern are:
  • "The Hollywood Principle": Don't call us, we'll call you.
  • The Open/Close principle

The main benefits of the pattern is:
  • Code reuse (subclasses implement only the behaviour that can vary)

There are however some limitations in using this pattern.

The first limitation is that the pattern rely on inheritance. A way to avoid inheritance and achieve a similar goal is to use the Strategy Pattern.

The second limitation is that inheritance makes difficult to merge two child algorithms into one. In that situation, the Decorator Pattern can be a solution.


Saturday 19 January 2013

The Pragmatic Programmer

In this post I would like to collect the best advices from the book The Pragmatic Programmer.



The book start with some interesting sentences about the role of programmers that is often wrongly perceived.
If you don’t think carefully you might think that programming is just typing statements in a programming language.
Are you a pragmatic programmer?

If you are a pragmatic programmer, you'll share many of the following characteristics:
  • Early adopter / fast adapter
    • You have an instinct for technologies and techniques, and you love trying things out. When given something new, you can grasp it quickly and integrate it with the rest of your knowledge. Your confidence is born of experience.
  • Inquisitive
    • You tend to ask questions.
  • Critical thinker
    • You rarely take things as given without first getting the facts.
  • Realistic
    • You try to understand the underlying nature of each problem you face. This realism gives you a good feel for how difficult things are, and how long things will take.
  • Jack of all trades
    • You try hard to be familiar with a broad range of technologies and environments, and you work to keep abreast of new developments. Although your current job may require you to be a specialist, you will always be able to move on to new areas and new challenges
Self-Development and Career
  • Take responsibility for everything you do.
  • Every day, work to refine the skills you have and to add new tools to you repertoire.
  • A pragmatic programmer takes charge of his or her own career, and isn't afraid to admit ignorance or error.
  • Don’t blame someone or something else, or make up an excuse. Don’t blame all the problems on a vendor, a programming language, management, or your co-workers. Any and all of these may play a role, but it is up to you to provide solutions, not excuses. Instead of excuses, provide options. Don’t say it can’t be done; explain what can be done to salvage the situation.
  • Don’t be afraid to ask, or to admit that you need help.
  • You must invest in your knowledge portfolio regularly
  • You need to know the ins and outs of the particular technology you are working with currently. But don’t stop there. The face of computing change rapidly. The more technologies you are comfortable with, the better you will be able to adjust to change. Stay current!
  • Learning an emerging technology before it becomes popular can be just as hard as finding an undervalued stock, but the payoff can be just as rewarding.
  • Learn at least one new language every year.
  • Read a technical book each quarter (and then each month).
  • Read non-technical books, too.
  • Think critically about what you read and hear.
  • Make a point of reading other people’s source code and documentation, either informally or during code reviews. You’re not snooping- you’re learning from them. Even if your project doesn't use that technology, perhaps you can borrow some ideas.
  • There are two world-class professional societies for programmers: the Association for Computing Machinery (ACM) and the IEEE Computer Society. We recommend that all programmers belong to one (or both) of these societies. In addition, developers outside the USA may want to join their national societies, such as the BCS in the United Kingdom.
Perfectionism
  • Don’t spoil a perfectly good program by over embellishment and over-refinement. Move on, and let your code stand in its own right for a while. It may not be perfect. Don’t worry: it could never be perfect.
  • In addition to doing your own personal best, you must analyze the situation for risks that are beyond your control.
  • There is no such thing as a best solution, be it a tool, a language, or an operating system. There can only be systems that are more appropriate in a particular set of circumstances.You shouldn't be wedded to any particular technology, but have a broad enough background and experience base to allow you to choose good solutions in particular situations.
  • Because we can’t write perfect software, it follows that we can’t write perfect test software either. We need to test the tests. After you have written a test to detect a particular bug, cause the bug deliberately and make sure the test complains.
People
  • Participate in local user groups.
  • Care and cultivation of gurus is important.
  • Turn the meeting into a dialog, and you’ll make your point more effectively. Who knows, you might even learn something.
  • There’s one technique that you must use if you want people to listen to you: listen to them.
  • A good idea is an orphan without effective communication.
  • Dealing with computer systems is hard. Dealing with people is even harder.
  • Work out what you can reasonably ask for. Develop it well. Once you've got it, show people, and let them marvel. Then say “of course, it would be better if we added…”. Pretend it’s not important. Sit back and wait for them to start asking you to add the functionality you originally wanted. People find it easier to join an ongoing success.
  • Organize your resources (people) using the same techniques you use to organize code.
General Advices
  • Always respond to e-mails and voice mails, even if the response is simply “I’ll get back to you later”.
  • DRY – Don’t Repeat Yourself
  • It’s a great idea to record your estimates so you can see how close you were. When an estimate turns out wrong, don’t just shrug and walk away. Find out why it differed from you guess.
  • What to say when asked for an estimate: “I’ll get back to you”.
  • It’s important to discover the underlying reason why users do a particular thing, rather than just the way they currently do it.
  • We want to see pride of ownership. People should see your name on a piece of code and expect it to be solid, well written, tested, and documented.
Technical Advices
  • Never run on auto-pilot. Constantly be thinking, critiquing your work in real time.
  • We want to design components that are self-contained: independent, and with a single, well-defined purpose. An orthogonal approach reduces the risks inherent in any development.
  • Be careful to preserve the orthogonality of your system as you introduce third-party toolkits and libraries. Choose your technologies wisely.
  • Normally, you can simply hide a third-party product behind a well-defined, abstract interface. In fact, we've always been able to do so on any project we've worked on.
  • Write code using the vocabulary of the application domain.
  • Tools amplify your talent. The better you tools, and the better you know how to use them, the more productive you can be.
  • The best format for storing knowledge persistently is plain text.
  • GUI environments are normally limited to the capabilities that their designers intended. The command line is better suited when you want to quickly combine a couple of commands to perform a query or some other task. Invest some energy in becoming familiar with your shell and things will soon start falling into place. Investigate alternatives to you current shell.
  • Make sure that the editor you choose is available on all platforms you use.
  • Embrace the fact that debugging is just problem solving and attack it as such. It doesn't really matter whether the bug is your fault or someone else’s. It is still your problem.
  • Set compiler warning levels as high as possible. Concentrate on the harder problems at hand. You must brutally test both boundary conditions and realistic end-user usage patterns. You need to do this systematically.
  • The best way to start fixing a bug is to make it reproducible.
  • A very simple but particularly useful technique for finding the cause of a problem is simply to explain it to someone else. They do not need to say a word; the simple act of explaining, step by step, what the code is supposed to do often causes the problem to leap off the screen and announce itself.
  • Once a human tester finds a bug, it should be the last time a human tester finds that bug.
  • When faced with a “surprising” failure, you must realize that one or more of your assumptions is wrong. Don’t gloss over a routing or piece of code involved in the bug because you “know” it works. Prove it. Prove it in this context, with this data, with these boundary conditions.
  • If it can’t happen, use assertions to ensure that it won’t. Never put code that must be executed into an assert. Don’t use assertions in place of real error handling. Assertions check for things that should never happen.
  • Exceptions should rarely be used as part of a program’s normal flow.
  • We need to allow for concurrency and to think about decoupling any time or order dependencies.
  • Coding is not mechanical. There are decisions to be made every minute- decisions that require careful thought and judgment if the resulting program is to enjoy a long, accurate, and productive life. Pragmatic programmers thing critically about all code, including our own. We constantly see room for improvement in our programs and our designs. You should be careful of tools that write reams of code on your behalf unless you understand what they’re doing.
  • For routines you call, rely only on documented behavior. If you can’t, for whatever reason, then document your assumption well.
  • Don’t be a slave to history. Don’t let existing code dictate future code.
  • Software development is still not a science. Let your instincts contribute to your performance.
  • The only timing that counts is the speed of your code, running in the production environment, with real data. Be wary of premature optimization. It’s always a good idea to make sure an algorithm really is a bottleneck before investing your precious time trying to improve it.
  • Time pressure is often used as an excuse for not refactoring. But this excuse just doesn't hold up: fail to refactor now, and there’ll be a far greater time investment to fix the problem down the road- when there are more dependencies to reckon with.
  • Keep track of the things that need to be refactored.
  • Refactoring is an activity that needs to be undertaken slowly, deliberately and carefully. Don’t try to refactor and add functionality at the same time. Make sure you have good tests before you begin refactoring.
  • We need to build testability into the software from the very beginning, and test each piece thoroughly before trying to wire them together.
  • It’s convenient, but not always practical, for each class or module to contain its own unit test.
  • Don’t be a slave to any notation; use whatever method best communicates the requirements with your audience. A big danger in producing a requirements document is being too specific. Good requirements documents remain abstract.
  • Many projects failures are blamed on an increase in scope. It’s easy to get sucked into the “just one more feature” maelstrom.
  • Create and maintain a project glossary.
  • Publishing of project documents to internal web sites for easy access by all participants is particularly useful for requirements documents.
  • When faced with an intractable problem, enumerate all the possible avenues you have before you. Don’t dismiss anything, no matter how unusable or stupid it sounds. Now go through the list and explain why a certain path cannot be taken. Are you sure? Can you prove it?
  • Great performers share a trait: they know when to start and when to wait.
  • Software development is still not a science. Let your instincts contribute to your performance.
  • Blindly adopting any technique without putting it into the context of your development practices and capabilities is a recipe for disappointment.
  • We prefer to understand the whole of the system we’re working on. It may not be possible to have an in-depth grasp of every aspect of a system, but you should know how the components interact, where the data lives, and what the requirements are.
  • Never underestimate the cost of adopting new tools and methods.
  • Pragmatic programmers look at methodologies critically, then extract the best from each and meld them into a set of working practices that gets better each month.
  • There are advantages to being a pragmatic individual, but these advantages are multiplied many fold if the individual is working on a pragmatic team. The team speaks with one voice-externally. Internally, we strongly encourage lively, robust debate. Good developers tend to be passionate about their work.
  • Compile projects with make files, even when using an IDE environment.
  • Many development teams use an internal web site for project communication, and we think this is a great idea.
  • As with validation and verification, you need to perform usability testing as early as you can, while there is still time to make corrections.
  • Use metrics: cyclomatic complexity, inheritance fan-in and fan-out, response set, class coupling ratio, …
  • Pragmatic programmers embrace documentation as an integral part of the overall development process.
  • In reality, the success of a project is measured by how well it meets the expectations of its users. Never lose sight of the business problems your application is intended to solve.
Programmers are constantly in maintenance mode. Our understanding changes day by day.

Pragmatic programmers should always be learning.

Wednesday 16 January 2013

Software Requirements - Part 4

This is the forth part of the following book summary.



Previous posts:

Requirements Validation
Validation ensures that the requirements exhibit the desirable characteristics of excellent requirement statements (complete, correct, feasible, necessary, prioritized, unambiguous and verifiable) and of excellent requirements specifications (complete, consistent, modifiable and traceable).
Informal reviews are useful for educating other people about the product and collecting unstructured feedback.

If you are serious about maximizing the quality of your software, your team will inspect every requirements document it creates.

Inspection has been recognized as a software industry best practice.

The participants in an inspection should represent four perspectives:
  • The author of the work product and perhaps peers of the author
  • The author of any predecessor work product or specification for the item being inspected
  • People who will do work based on the item being inspected
  • People who are responsible for work products that interface with the item being inspected
It is useful to create a defect checklist to help inspectors look for typical kinds of errors in the products they inspect. Some studies have shown that giving inspectors specific defect-detection responsibilities is more effective than simply handling all inspectors the same checklist.

As with all quality activities, make a risk-based decision as to how much energy to devote to improving requirements quality.

Considerations:
  • For large requirements documents perform incremental reviews or identify high-risk areas that need a careful look and use informal reviews for less risky material
  • Keep the number of reviewers small because large inspection teams make it hard reaching agreement on issues
Testing the Requirements

It's hard to visualize how a system will function under specific circumstances just by reading the SRS. Writing black box (functional) test cases crystallizes your vision of how the system should behave under certain conditions. Dialog maps can be useful to describe test cases and by tracing the execution path, you can find incorrect or missing requirements.

Acceptance testing should focus on anticipated usage scenarios. Acceptance tests focus on the normal courses of the use cases, not on the less common alternative courses or whether the system handles every exception condition properly.

User acceptance testing does not replace comprehensive requirements-based system testing, which covers both normal and exception paths and a wide variety of data combinations.

Acceptance test planning, informal reviews, SRS inspections and requirements testing techniques will help you to build higher-quality systems faster and more inexpensively than you ever have before.

Maintenance

Maintenance often consumes the majority of a software organization's resources. 

Maintenance programmers typically correct defects, add new features or reports to existing systems, and modify functionality to comply with revised business rules.

The requirements specification for the next release of a mature system often says essentially:
"The new system should do everything the old system does, except add these new functions and fix those bugs"
And often there is not a description of the original system!

In absence of accurate requirements documentation, maintainers must reverse-engineer and understanding of what the system does from the code. Begin by recording the new requirements in a structured, if incomplete, SRS or in a requirements management tool.

When you add a new functionality, you'll have to figure out how new screens and features will interface to the existing system.


Building a requirements representation that includes portions of the current system achieves three useful goals:
  • Future maintainers better understand the changes that were just made
  • It collects some information about the current system that previously was undocumented.
  • It provides an indication of functional coverage by the current set of system tests.
Some other techniques that you can try on a small scale during maintenance include:
  • Creating a data dictionary
  • Drawing analysis models
  • Specifying quality attributes and performance goals
  • Building user interface and technical prototypes
  • Inspecting requirements specifications
  • Writing test cases from requirements
  • Defining customer acceptance criteria
Any existing requirements representations must be kept current during maintenance. 

There is a widespread fear in the software industry that writing documentation will consume too much time.

The decision is yours and you should do it based on the question:
What is the cost if you don't update the requirements and a future maintainer has to regenerate that information?
What if you are purchasing a commercial off-the-shelf product (COTS) as part of a new project?

You still need requirements because typically this products need to be configured, customized, integrated and extended to work in the target environment. You should focus on requirements at the user requirements level and use cases work well for this purpose. Obviously COTS give the acquiring organization less flexibility over requirements than does custom development.

What about outsourced projects?

Contracting product development to a separate company demands high-quality written requirements because your direct interactions with the engineering team are likely to be minimal.

What about emergent and fast-moving projects?

This kind of projects has led the creation of various agile development methodologies that emphasize rapidly putting useful functionality into the hands of users. The agile methodologies take a lean approach to requirements development and an informal approach to requirements management. Requirements are described in terms of product features or in the form of user stories.
Detailed requirements documentation is rejected in favour of continuous interaction with an on-site customer representative.
The agile development philosophy views software change as both inevitable and desiderable. This agile approach works well for dealing with a high degree of requirements uncertainty in information systems of internet projects. It's less well suited to applications whose requirements are well understood and to embedded systems development.
The requirements for rapidly changing projects are too unstable to justify investing a lot of requirements development effort up front.
Regardless your development methodology frequent conversations between project team members and appropriate customers are the most effective way to resolve many requirements issues. Written documentation, however detailed, is an incomplete substitute for these ongoing communications.
Don't expect a single individual to resolve all the requirements issues that arise. The product champion approach, with a small number of user representatives, is a more effective solution.
Beyond requirements development

The most important thing is that all project stakeholders reach a shared understanding of their business objectives and the users' needs.

Experienced project managers and developers understand the value of translating software requirements into robust designs and rational project plans.

Considerable evidence shows that taking time to understand the requirements actually accelerates development. Not all the requirements development effort should be allocated to the beginning of the project. Projects that follow an iterative life cycle model will spend time on requirements during every iteration.

You can use a commercial estimating tool that suggests feasible combinations of development effort and schedule. These tools let you adjust estimates based on factors such as the skill of the developers, project complexity, and the team's experience in the application domain.
If you don't compare your estimates to the actual project results and improve your estimating ability, your estimates will forever remain guesses.
A project manager who can justify an estimate based on a well-thought process and historical data is in a better bargaining position than someone who simply makes his best guess. Include contingency buffers in your schedule and budget to accommodate some requirements growth. Don't let your estimates be swayed by what you think someone else wants to hear. Your prediction of the future doesn't change just because someone doesn't like it.

Major planning mistakes include overlooking common tasks, underestimating effort or time, failing to account for project risks, not anticipating rework, and deceiving yourself with unfounded optimism.

Keep your specifications free from implementation bias except when you have a compelling reason to intentionally constrain the design. The time you spend translating requirements into designs is an excellent investment in building high-quality, robust products.

The simple act of thinking through how you'll verify each requirement is itself a useful quality practice. Testing against requirements must be performed at every level of software construction, not just the end-user level.

Strive for a sensible balance between rigorous specification and off-the-top-of-the-head coding that will reduce to an acceptable level the risk of building the wrong product.

Next post:



Monday 14 January 2013

Lambda Expressions Resolution in C#

Consider the code:


How this type of lambda expression is translated by the C# compiler?
The compiler internally resolves this type of lambda expressions by writing a private method and moving the expressions's code into that method.
It is possible to verify this using a free .NET decompiler like dotPeek.


Why this is relevant?

I am a strong believer that is important to understand what happens under the covers because it gives you a broader perspective and a better awareness of how the code works.

There are plenty of features of the C# languages that actually maps themselves to a subset of the C# language. This is one of the best thing of C# because this features usually improve significantly the developers productivity. The price is that something magic happens under the cover and this is why is important to learn about them.

Contravariance in C#


Contravariance is a new feature introduced with the version 4 of the C# language.

The definition of Contravariance
Assuming A is implicitly convertible to B,  X is contravariant when 
X<B> is implicitly convertible to X<A> 
or similarly
X is contravariant if X<B> can be cast to X<A> if B subclasses A
Contravariance in C# 4

From C# 4, generic interfaces support contravariance for type parameters marked with the in modifier. This is supported when the generic type parameter only appears in input positions, designed with the in modifier.

While covariance is intuitive, contravariance seems useless and wrong.

However, it makes sense and there are situations when is useful.

One example is the IEquatityComparer<T> interface that has been changed using the in modifier.

Example

Suppose that we have the following classes.
Thanks to contravariance the following code compiles and works as expected.


If you use a previous version of C# the code does not compile and generates a build error.


Covariance in C# 4

Covariance for generics interfaces is a new feature introduced with the version 4 of the C# language.

The definition of Covariance for Generics Interfaces
Assuming A is convertible to B,  X is covariant if X<A> is implicitly convertible to X<B>
or similarly
X is covariant if X<A> can be cast to X<B> if B subclasses A
Covariance for Generics Interfaces in C# 4

From C# 4, generic interfaces support covariance for type parameters marked with the out modifier. This modifier ensures that covariance with interfaces is fully type-safe.

Covariance in interfaces is something that is typically consumed. It's less common that you need  to write variant interfaces.


The implementation of IEnumerable in the framework has been changed using the out modifier and this makes all the collections in the base class library covariant.

Example

Suppose that we have two classes in a inheritance relationship.


Thanks to covariance the following code compiles and works as expected.



If you use a previous version of C# the code does not compile and generates a build error.


It is worth noting that previous versions of C# already supported arrays covariance and delegates covariance.



Sunday 13 January 2013

Windows 8 Tip - Shut Down

One of the most annoying thing of Windows 8 on a PC is that shutting down your computer is a very long procedure.

However, there is a very quick way to do it.

ALT + F4

Press this keyboard short-cut when you are in the desktop mode and a dialog pops up.


There are other techniques to solve the problem but this is good enough for me and does not require any special configuration.

Hope this helps you.


Tuesday 1 January 2013

Software Requirements - Part 3

This is the third part of the following book summary.


Previous posts:

Who is the Requirements Analyst?
The Requirements Analyst is the individual who has the primary responsibility to gather, analyze, document, and validate the needs of the project stakeholders. The analyst serves as the principal conduit through which requirements flow between the customer community and the software development team.
The Requirements Analyst is a project role, not necessarily a job title.

What are the analyst tasks?
  • Define business requirements
  • Identify project stakeholders and user classes
  • Elicit requirements
  • Analyze requirements
  • Write requirements specifications
  • Model the requirements
  • Lead requirements validation
  • Facilitate requirements prioritization
  • Manage requirements
What are important skills for an analyst?
  • Listening
  • Interviewing and questioning
  • Analytical
  • Facilitation
  • Observation
  • Writing
  • Organizational
  • Modeling
  • Interpersonal
  • Creativity
Developers who enjoy collaborating with customers to understand the needs that drive software development are good candidates to specialize in requirements analysis.


Software Requirements Development

What is the product vision?

The vision describes what the product is about and what it eventually could become. The product vision aligns all the stakeholders in a common direction. 

What is the project scope?

The project scope identifies what portion of the ultimate long-term product vision the current project will address. The details of a project's scope are represented by the requirements baseline.
For each vision there are usually multiple project scopes.


What is a Context Diagram?

It is a kind of diagram that is often included in the vision and scope documents.

From Wikipedia:
A System Context Diagram (SCD) in software engineering and systems engineering is a diagram that represents the Actors outside a system that could interact with that system. This diagram is the highest level view of a system. 

What is a data flow diagram?

It is the basic tool of structured analysis.  

The DFD provides a way to represent the steps involved in a business process or the operations of a proposed software system.



What is a Dialog Map?

It is a way to model user interfaces.




The heart of requirement engineering is elicitation, the process of identifying the needs and constraints of the various stakeholders for a software system. Requirements elicitation is perhaps the most difficult, most critical, most error-prone, and most communication intensive aspect of software development.

Few tips for Requirements Elicitation: 

  • Simply ask "why" several times
  • Imagine yourself learning the user's job, or actually do the job under the user's direction. What tasks would you need to perform?
  • Probe around the exceptions
  • Rather than simply transcribing what customers say, a creative analyst suggests ideas and alternatives to users during elicitation
  • Consider the use of focused elicitation workshops 
  • Don't justify doing whatever any customer demands because "The customer is always right". The customer is not always right. The customer always has a point, though, and the software team must understand and respect that point.

What is a CRUDL matrix?

It is an interesting way to search for missing requirements. 

CRUD stands for Create, Read, Update and Delete. A CRUD matrix correlates system actions with data entities to make sure that you know where and how each data item is created, read, updated and deleted. Some people add an L to the matrix to indicate that the data item appears as a List selection.



How do you know when you are done in Requirements Elicitation?

You'll never be completely done, but the following suggest that you are reaching the point to stop:
  • If the users can't think of any more use cases
  • If users repeat issues that they already covered in previous discussions
  • If suggested new requirements are out of scopes
  • If proposed new requirements are all low priority
Your goal is to make the requirements good enough to let construction proceed at an acceptable level of risk.

What is a use case?

A use case describes a sequence of interactions between a system and an external actor. An actor is a person, another software system or a hardware device that interacts with the system to achieve a useful goal.

Use cases are at the center of the widely used Unified Software Development Process.

The objective of the use-case approach is to describe all tasks that users will need to perform with the system.

The user stories that serve as requirements in Extreme Programming are essentially casual use cases typically written on index cards.

Use cases help analysts and developers understand both the user's business and the application domain. The use case approach helps with requirements prioritization.

A use case is a collection of related usage scenarios.
A scenario is a specific instance of a use case.


Software developers don't implement business requirements or use cases. They implement functional requirements, specific bits of system behaviour that allow users to execute use cases and achieve their goals. Use cases describe system behaviour from an actor's point of view, which omits a lot of details. A developer need many other views to properly design and implement a system.

The translation from the user's view of the requirements of the developer's view is one of the many ways the requirements analyst adds value to the project.

The result of requirements development is a documented agreement between customers and developers about the product to be built.

Structured natural language, augmented with graphical models, remains the most practical way for most software projects.

What is the Software Requirements Specification?

The SRS precisely states the functions and capabilities that a software system must provide and the constraints that it must respect. The SRS is the basis for all subsequent project planning, design, and coding, as well as the foundation for system testing and user documentation. It should describe as completely as necessary the system's behaviours under various conditions. It should not contain design, construction, testing or project management details other than known design and implementation constraints.

Who rely on the Software Requirements Specification?
  • Customers, the marketing department and sales staff need to know what product they can expect to be delivered
  • Project managers base their estimates of schedule, effort and resources on the product description
  • The SRS tells the software development team what to build
  • The testing group uses the SRS to develop test plans, cases and procedures
  • The SRS tells maintenance and support staff what each part of the product is supposed to do
  • Documentation writers base user manuals and help screens on the SRS and the user interface design
  • Training personnel use the SRS and user documentation to develop educational materials
  • Legal staff ensure that the requirements comply with applicable laws and regulations
  • Subcontractors base their work on, and can be legally held to, the SRS
There is no formulaic way to write excellent requirements. The best teacher is experience!

Software Quality Attributes

If you don't explore the customers' quality expectations during requirements elicitation, you are just lucky if the product satisfy them. Customers generally don't present their quality expectations explicitly.

Quality goals must be verifiable otherwise you can't tell whether you've achieved them.
  • Availability
  • Efficiency
  • Flexibility
  • Integrity
  • Interoperability
  • Reliability
  • Robustness
  • Usability
There are other software quality attributes that are usually important for developers:
  • Maintainability
  • Portability
  • Reusability
  • Testability
To address the problem of ambiguous and incomplete non-functional requirements, consultant Tom Gilb has developed Planguage, a planning language with a rich set of keywords that permits statements of quality attributes and other project goals.

Certain attributes combinations have inescapable trade-offs. The designer and programmers will have to determine the best way to satisfy each quality attribute and performance requirement.

The following table is extremely useful to understand the positive and negative relationships among quality attributes.


What does it mean prototyping?

Prototyping puts a mock-up or an initial slice of a new system in front of the users to stimulate their thinking and catalyze the requirements dialog.

Prototyping serves three major purposes:
  • Clarify and complete the requirements
  • Explore design alternatives
  • Grow into the ultimate product
What is an horizontal prototype?

Horizontal prototypes primarily depicts a portion of a user interface. It is also called behavioural prototype or a muck-up.

What is a vertical prototype?

A vertical prototype, also known as a structural prototype or proof of concept, implemented a slice of application functionality from the user interface through the technical services layers. It is useful when you are uncertain whether a proposed architectural approach is feasible.

It is important before constructing a prototype, to make an explicit and well-communicated decision as to whether the prototype will be discarded after evaluation or become part of the delivered product. The throwaway prototype is most appropriate when the team faces uncertainty, ambiguity, incompleteness, or vagueness in the requirements.

What is a paper prototype?

It is a cheap,fast and low-tech way to explore what a portion of an implemented system might look like. A similar technique is called storyboard.

The biggest risk of prototyping is that a stakeholder will see a running prototype and conclude that the product is nearly completed.

The next steps in Requirements Development is setting priorities.

Why prioritize requirements?

To make sure the product delivers the most valuable functionality as early as possible.

How to establish priorities?

One way to assess priority is to consider the two dimensions of importance and urgency.


Few software organizations seem to be willing to undertake more formal methodologies like Quality Function Deployment (QFD) or Total Quality Management (TQM).