Monday, June 1, 2015

Estimate a release in Scrum

In Agile, time and again people ask this question "How would you estimate a release for a product?". When it comes from management they want to know the following:

  • Calculate the man hours which is at their disposal to get to the release date
  • Risk assessment
  • How many people we need, can we expedite the development if we pump in more man power?

There are many more questions. In some cases they want to use some complex prediction algorithm to come up with the release date. Oh!! My god, I think, at the end of the day who is going to implement the features? Can an algorithm do an exact implementation? Can you use the available man hours?
 
I would say no. There is danger in using man hours. We don't take into account the diversity of a team. It can have people with experience levels. A person with ten years of experience may be able to finish a task in four hours, while another person with five years may take a day and someone less experienced may take two or more days. How does an algorithm include these differences? Or the team may be comprised of a tester, developer, BA etc. Each one has different work to do and you can't consider everyone to complete the different kind of work in the same hours at their disposal. Many a time management either doesn't understand or doesn't want to come out of its traditional way of running business.
 
There is an easy solution to this. No fancy algorithm, no man hour calculation, nothing. If you are aware of Agile concepts then what I am going to say may sound familiar. You can use the velocity of the team to come up with more accurate predictions. But before we see how we can predict release, we need to understand what velocity is.
 
Velocity is the story points a team can deliver in each sprint. A sprint can be anywhere between two to four weeks. I like to have smaller sprints of two weeks. Thinking that a sprint is of two weeks in length, let's examine further how velocity is calculated. Below is a table showing the sprint and the story points achieved in each sprint.

Sprint # Story points per sprint Velocity
Sprint 1

1

1
Sprint 2

3

(1+3)/2 = 2
Sprint 3

3

(1+3+3)/3 = 2.3
Sprint 4

5

(1+3+3+5)/4 = 3
Sprint 5

3

(1+3+3+5+3)/5 = 3

So from the above table you can see how a team's velocity is calculated. In the first sprint (two weeks) it achieved one story point (SP). In the second it gained three SPs. So velocity is the total number of SPs achieved in all sprints divided by the number of sprints. In the third sprint the velocity was 2.3 and by the end of fifth sprint the velocity stabilized to three SPs. With that knowledge of what velocity is, let's tackle the problem of calculating a release date for a set of features.

There are two ways to do this. One is where the team has historical data to calculate velocity and second where the team is new and there is no historical data. Let's see the easy one first.

When the team has Velocity data?
This situation is applicable for teams that have been working on products for a long time and has historical SP data to calculate its velocity. The product owner gets a set of ten new features from the client and he wants to know how quickly the team can deliver these.

The solution is simple. Give the ten new requirements to the team and ask them to come up with estimate. Here is the process which needs to be followed.

  1. The team (dev, QA, BA) gets into a quick release planning (not really release planning) meeting with the product owner.
  2. The team and Product Owner (PO) go through the list of features and try to understand each one of them. There is no need to know the nitty gritty of the requirements as they may be pulled out in future. The team needs to get enough information so that it can estimate.
  3. Once the team has enough understanding about a feature it can estimate the user stories (features). The estimate is done in terms of SPs. The team plays planning poker. Below is the table showing the SPs estimated by the team for the features.
Features Story points
Feature 1 5
Feature 2 3
Feature 3 3
Feature 4 8
Feature 5 5
Feature 6 8
Feature 7 3
Feature 8 3
Feature 9 5
Feature 10 2
  1. After all the ten features have been estimated calculate the total SPs for the ten user stories. From the above table the total SPs is 45.
  2. From the first table we know the team's velocity is 3 and the total SPs estimated for 10 stories is 45. If the team can deliver three SPs a sprint then to deliver 45 SPs it will take 15 (45/3) sprints. 15 sprints = 30 (15 * 2) weeks. 30 weeks = 7.5 months. So the team will take 7.5 months to finish the ten new features. To this you need to add the regression, stabilization and any other phases required for delivering a quality product. In essence the time taken is 7.5 months + Time required for Regression + any other stage.
For fairly new team that doesn't have historical data
  1. Follow the above steps from 1 to 4. Let's go with the same 45 SPs as the estimate.
  2. Now we don't have historical data to calculate the release date. What can be done? The team can decide and assume a number as its velocity. Say the team has decided two SPs as its velocity. Based on the team's assumption of its velocity you can calculate the release date.
  3. As the sprints end the team can start re-calculating its velocity and adjust the release dates.

From my experience a team reaches a stable velocity within four to six iterations. So in two months you can exactly predict the release date.

What happens if we don't meet the target?
During the release planning the team needs to fix dates on feature freeze and code freeze based on the overall estimate. By the time you reach the feature freeze date the team will have a good idea on whether it is going to deliver all the promised features. If the team is not able to keep the commitment -- if it has promised ten features and only eight will be completed --then the team members need not panic. The approach would be to ask the product owner to start negotiating with the client. Either the client has to accept the product with eight features or extend the time to get the whole set of features. This is quite normal and from my experience if you have a good product owner who has good negotiating skills the client will accept any of the above options.
Another advantage to Agile is that the client need not wait for years to get features. At the end of every end of the sprint the client gets a feature delivered. And I have seen except for few scenarios, client are quite accommodative. The reason is that client can see the ROI every two weeks and this actually builds confidence.

What happens if the client cuts short the estimate from x to y?
The answer is simple. You tell the client that X will be the time taken to deliver ten features and if you cut the time short then in Y time frame you can deliver only six features.

What happens if the client adds new requirements?
If the client adds more requirement and wants it in the same timeframe, then the team needs to tell the product owner that if you add new features then out of the previously committed ten features we may have to drop few to accommodate the new ones. This can happen only when prioritization comes into play.
The product owner and client need to decide the priorities for the features. Based on the priorities the team will tackle higher priority items first. Once the higher priorities are targeted it will pick up the lesser priority items. The product owner either needs to buy more time to include the new features or need to get few items off the list so that new items can be accommodated in the timeframe.

Monday, April 20, 2015

Documentation in Agile

Documentation is a big contentious issue in Agile. There is a reason for this. When you start your presentation on Agile you start by going through the 4 statements of agile manifesto. As soon as you go to the second statement, traditional waterfall guys start frowning their eyes. The second statement in the manifesto says this.

Working software over comprehensive documentation

Seeing the statement people assume that documentation is not part of the agile process. It completely ignores documentation. Here comes questions. Without documenting the process flow how do you know what is the process we need to follow? Without document how do you know what is the requirement? Without document how do you know what has been implemented? Without document how is a new dev/qa going to understand what is coded/system all about? And if it is someone from CMMi background, then god can only help you to convince him/her.
The key thing people forget is that processes are there to help people get their work done faster. Deliver software faster to the end user. Faster delivery will help you capture market compared to your competitors. In software development you are not delivering document to the end user rather a working software. The above statement never said documentation is not needed, just that the emphasis is on delivering value to the end user.
Now let’s try to address some of the questions raised above.

Process flow documentation
Agile is well documented. If you search the internet you will get not hundreds but thousands of documentation. Just put a few links to the website and that forms your document. I would say there is no need to re-create something which is freely available on the net. If you really want to have off-line document then use the save feature of your browser and save the pages. Make sure you have the permission to do the same. Or copy paste the contents and put it in a document with a link to the original article.
One of the best way of explaining your process is to have a pictorial representation of the same. If you search agile process in Google you will find lot of high quality diagrams. Click here to see few. Take appropriate permission and paste the same all over the office. I am of the opinion that if you want to implement some process don’t file it in a word, excel or powerpoint document. Rather display it to the whole world by pasting them in prominent places across the office. Make use of information radiator concept from Agile. Information radiator according to Alistair Cockburn is:

An Information radiator is a display posted in a place where people can see it as they work or walk by. It shows readers information they care about without having to ask anyone a question. This means more communication with fewer interruptions.
Requirements document
Yes you need to have requirements but not the traditional way of gathering requirement. In traditional way you write pages after pages of requirement, spend too much time up front (before the project even starts) gathering requirement. Agile says don’t spend too much time up front on gathering requirement. The reason, tomorrow the client’s requirement would change, so gather as much as you can but don’t over do it. Requirements are written in the form of User Stories. Typically user stories are written on a piece of paper or sticky notes. The template is as given below
As a <user type>, I want <some ability or action>  so that <some result>.

If the team is using JIRA, TFS (Team Foundation Server), Rally etc to manage the agile process, then the requirements can be captured in them. Each application has features to capture the nitty gritties of a user story. For e.g. JIRA has description column where one can elaborate on what the story is all about. In agile importance is given to discussions and understanding of the requirement within the team. Also user stories are not elaborated until they are worked upon. Again the reason is product backlog (where user stories are captured) gets re-prioritised every now and then. So one user story having high priority today can have a low priority tomorrow. To save everyone’s effort from getting wasted the user stories are elaborated or discussed in detail during implementation in a sprint. Typically in a sprint planning meeting.
In short the way requirements are captured have changed. You use different tools and techniques to capture requirement. JIRA, TFS, Rally etc have taken the place of traditional document. Oh I forgot to mention sticky notes.

Without document how can one know what the team has implemented?
The modern agile teams have moved away from the traditional way of maintaining records in document format. Agile teams use sprint review meeting to show what has been implemented in the current sprint. Sprint review meeting is a casual demo of what features have been developed in a sprint. If you want to know what the implementation looks like attend the sprint review meeting. Advantages are that one need not spend time reading pages after pages of boring document. Rather you get to see a demo of a working feature. If you are an end user you can visualise how it will fit in your scheme of things.
Ok, you are not satisfied, still want a document evidence? No problem, record the demo and keep it as a documented evidence. Again another advantage, you are not spending extra time in writing document. Optimisation at it’s best. Recorded video is acting as a document.

Without documents how a new developer/QA will get up to speed with the product? 
I have been a developer and in my career of nearly 12 years I have never understood a system by reading documents. Developers understand only one language and that is the language in which they code. They understand C#, Java, JavaScript etc. The only thing they need is cleanly written code or in other words clean code. Developers understand a system by reading the code. They understand by pairing up with other developers. They understand by making bug fixes. Any new developer is thrown into the water and he learns to swim. Most of the projects, developers are asked to start with bug fixes and as and when they are comfortable they are given features to develop.
If you are following Test Driven Development (TDD), then tests are the place to start. Tests help a developer to understand a feature/application very well. By looking at tests he/she will understand what the piece of code is doing. Having tests will give confidence to a developer to fix code and get early feedback whether the fix has broken anything.
As highlighted for a developer documentation is clean code and tests.

Let go of your traditional understanding of documentation
From my experience what I feel is that people need to come out of their traditional view of having document for each and everything. Document need not be in the form of word, excel or powerpoint. The world has moved on. Document can be in the form of videos, can be in the form record entries in tools like JIRA, TFS, Rally etc. Can be in the form of display charts, cards,Kanban board, sticky notes, mobile pictures of a white board discussion, audio recording, webex recording, goto meeting recording, any link to an article to a website etc. Did I miss anything?
The key is not to burden development team in writing documents which are not adding value to the customer. For me if it doesn’t add value to the customer then there is no point in spending time on documentation. One needs to leave the technical documentation part to the team to decide. I understand when someone leaves a company he takes along with him good amount of knowledge. The way to tackle this is to have videos, good tests and clean code.
The agile manifesto doesn’t say no documentation. The way to look at document has changed. In the bad olden days of CMMi/waterfall, development team use to spend too much of time in creating documents for requirement, design (HLD/LLD) etc. Even from developer’s perspective, hardly 1% of them use to read these. People understood that and they wanted the development team to focus more on what they do best i.e. development and testing. So the onus is on delivering value to a customer by giving a working software every sprint/iteration than writing documents.
This is my personal opinion. In the not so distant history, documents were used as a proof so that nothing went wrong. I feel the trust quotient was not there. People wanted to have this and that and what not kind of document to hold people responsible for their action. With agile that has change. It is not about individual, but about team. It is about empowering team and trusting them. Documents have also taken new forms like sticky notes pasted on a kanban board, videos, casual demo etc. With trust being an integral part I feel document has taken lower precedence.
In essence the definition of document has taken new forms. They have moved from the traditional written document format to include more visual forms.

Wednesday, June 26, 2013

VS debugger not getting attach to IE

Recently I had this weird error where Microsoft Visual Studio 2010 (VS 2010) debugger was not getting attached to Microsoft Internet Explorer (IE). The only change was that IE was upgraded from IE 9 to IE 10. Till before the upgrade everything was working fine. The error is pasted below.

Attaching the Script debugger to process '[XXXX] iexplore.exe' on machine 'XX-XX-XXX' failed. A debugger is already attached.

The solution for the above problem is pretty simple as well. Open the command prompt (cmd) in “Run as Admin” mode. Run the following command.

regsvr32.exe "%ProgramFiles(x86)%\Common Files\Microsoft Shared\VS7Debug\msdbg2.dll”

“regsvr32” is a command line utility provided my Microsoft to register and unregister dlls in the Windows Registry.

Friday, December 9, 2011

Readonly v/s Constants

Many a times people have asked me the difference between a readonly variable and a constant. With this article I hope to clarify that. I would also delve on when to use readonly and when to use constant variables.

Readonly variables

readonly variables are also know as runtime constants. One can initialize the value of readonly variable to any type. One can have one’ own custom object as a readonly variable. Once initialized the readonly variables cannot be tinkered with other than in the constructor. If one really wants to change the value then that can only be done in the constructor. E.g. is shown below.

public class Demo
{
    readonly Person p = new Person();
    
    public Demo ()
    {
        this.p = new Person { Name = "P1", Age = 43};
    }
    
    public Demo(Person pp)
    {
        this.p = pp;
    }
}
 
public class Person
{
    public string Name
    {
        get; set;
    }
    
    public int  Age
    {
        get; set;
    }
}

Also when you compile your code the readonly variable will have a reference to the actual object. readonly variable are slightly slower than constants in performance. readonly variables can be static.


public static DateTime time = DateTime.Now;

The above e.g. shows the readonly variable as static and the value is decided at runtime. readonly variables cannot be initialized inside a method. As readonly variables can be assigned in the constructor each instance of a class can have its own instance of the readonly object.

Const variables

const variables are compile time constants. By compile time constants it means the actual value is replaced and saved in the IL (Intermediate Language). For this reason one can only use primitive types as const variables. Enum and strings can also be used as const variables. Primitive types, enum and string are the only datatypes which can be replaced with literal values. DateTime variable cannot be used as a const variable. Though it is of value type it cannot be used as a const variable. The reason is that compile time constants cannot be initialized using the new keyword. const variables are static by default. Few e.g. of const variables are pasted below.


public class ConstantsEG
{
    public const int maxValue = 2000;
    public const double minValue = -.34343;
    public const VIBGYOR yellow = VIBGYOR.Yellow;
 
    public void SomeMethod()
    {
        const string con = "const";
        Console.WriteLine(con);
        Console.WriteLine("MaxValue: {0}, MinValue: {1}, Yellow: {2} ", maxValue, minValue, yellow);
 
    }
}
 
public enum VIBGYOR
{
    Violet,
    Indigo,
    Blue,
    Green,
    Yellow,
    Orange,
    Red
}

In the above e.g. we have primitive types along with string and enum type as well. We have also declared a const variable inside a function as well. If you use readonly in a method scope you will get the following error.


The modifier 'readonly' is not valid for this item

One thing to note is that readonly keyword will not be available in the intellisense of a VS inside a method. Just to highlight the difference I have pasted two classes below and their respective IL code.


public class ReadOnlyEG
{
    readonly int minValue = 100;
    readonly double maxValue = -.3432323;
    readonly string someString = "Some string.";
    readonly Person person = new Person() { FirstName = "Sandeep", LastName = "P.R"};
    public ReadOnlyEG()
    {
        someString = "Changed string";
    }
 
    public void Print()
    {
        Console.WriteLine("MinValue: {0}, MaxValue: {1}, someString: {2}, FirstName: {3} & LastName: {4}", 
            minValue, maxValue, someString, person.FirstName, person.LastName);
    }
}
 
public class Person
{
    public string FirstName
    { get; set; }
 
    public string LastName
    { get; set; }
}

The above classes highlights the different uses of a readonly variable. We are using int, double, string and user defined type. Also highlighted is the manipulation of a readonly string variable inside a constructor. Below IL code.


.class public auto ansi beforefieldinit ReadOnlyEG
    extends [mscorlib]System.Object
{
    .method public hidebysig specialname rtspecialname instance void .ctor() cil managed
    {
        .maxstack 3
        .locals init (
            [0] class ReadOnlyConst.Person <>g__initLocal0)
        L_0000: ldarg.0 
        L_0001: ldc.i4.s 100
        L_0003: stfld int32 ReadOnlyConst.ReadOnlyEG::minValue
        L_0008: ldarg.0 
        L_0009: ldc.r8 -0.3432323
        L_0012: stfld float64 ReadOnlyConst.ReadOnlyEG::maxValue
        L_0017: ldarg.0 
        L_0018: ldstr "Some string."
        L_001d: stfld string ReadOnlyConst.ReadOnlyEG::someString
        L_0022: ldarg.0 
        L_0023: newobj instance void ReadOnlyConst.Person::.ctor()
        L_0028: stloc.0 
        L_0029: ldloc.0 
        L_002a: ldstr "Sandeep"
        L_002f: callvirt instance void ReadOnlyConst.Person::set_FirstName(string)
        L_0034: nop 
        L_0035: ldloc.0 
        L_0036: ldstr "P.R"
        L_003b: callvirt instance void ReadOnlyConst.Person::set_LastName(string)
        L_0040: nop 
        L_0041: ldloc.0 
        L_0042: stfld class ReadOnlyConst.Person ReadOnlyConst.ReadOnlyEG::person
        L_0047: ldarg.0 
        L_0048: call instance void [mscorlib]System.Object::.ctor()
        L_004d: nop 
        L_004e: nop 
        L_004f: ldarg.0 
        L_0050: ldstr "Changed string"
        L_0055: stfld string ReadOnlyConst.ReadOnlyEG::someString
        L_005a: nop 
        L_005b: ret 
    }
 
    .method public hidebysig instance void Print() cil managed
    {
        .maxstack 4
        .locals init (
            [0] object[] CS$0$0000)
        L_0000: nop 
        L_0001: ldstr "MinValue: {0}, MaxValue: {1}, someString: {2}, FirstName: {3} & LastName: {4}"
        L_0006: ldc.i4.5 
        L_0007: newarr object
        L_000c: stloc.0 
        L_000d: ldloc.0 
        L_000e: ldc.i4.0 
        L_000f: ldarg.0 
        L_0010: ldfld int32 ReadOnlyConst.ReadOnlyEG::minValue
        L_0015: box int32
        L_001a: stelem.ref 
        L_001b: ldloc.0 
        L_001c: ldc.i4.1 
        L_001d: ldarg.0 
        L_001e: ldfld float64 ReadOnlyConst.ReadOnlyEG::maxValue
        L_0023: box float64
        L_0028: stelem.ref 
        L_0029: ldloc.0 
        L_002a: ldc.i4.2 
        L_002b: ldarg.0 
        L_002c: ldfld string ReadOnlyConst.ReadOnlyEG::someString
        L_0031: stelem.ref 
        L_0032: ldloc.0 
        L_0033: ldc.i4.3 
        L_0034: ldarg.0 
        L_0035: ldfld class ReadOnlyConst.Person ReadOnlyConst.ReadOnlyEG::person
        L_003a: callvirt instance string ReadOnlyConst.Person::get_FirstName()
        L_003f: stelem.ref 
        L_0040: ldloc.0 
        L_0041: ldc.i4.4 
        L_0042: ldarg.0 
        L_0043: ldfld class ReadOnlyConst.Person ReadOnlyConst.ReadOnlyEG::person
        L_0048: callvirt instance string ReadOnlyConst.Person::get_LastName()
        L_004d: stelem.ref 
        L_004e: ldloc.0 
        L_004f: call void [mscorlib]System.Console::WriteLine(string, object[])
        L_0054: nop 
        L_0055: ret 
    }
 
    .field private initonly float64 maxValue
    .field private initonly int32 minValue
    .field private initonly class ReadOnlyConst.Person person
    .field private initonly string someString
}

If you see the above IL you will notice against all the value we have defined there are some instruction like “ldc.i4.s”, “ldc.r8” and “ldstr”. Each instruction has its own meaning. ldc.i4.s means push a number value onto the stack as an integer, ldc.r8 implies that push a float onto the stack and ldstr is an instruction to push a string object. If you further go down and take a peek into the print function you can see few IL instructions which are basically instruction to push and pop data to stack and finally replace the reference value from the stack.

Now let’ see the code where a class has const variables.


public class ConstantsEG
{
    public const int maxValue = 2000;
    public const double minValue = -.34343;
    public const VIBGYOR yellow = VIBGYOR.Yellow;
    public const string test = "Test text";
 
    public void SomeMethod()
    {
        const string con = "const";
        Console.WriteLine(con);
        Console.WriteLine("MaxValue: {0}, MinValue: {1}, Yellow: {2}, Test: {3} ", maxValue, minValue, yellow, test);
    }
}
 
public enum VIBGYOR
{
    Violet,
    Indigo,
    Blue,
    Green,
    Yellow,
    Orange,
    Red
}

The above class is similar to the one we have already seen above except for a public const string variable added. The IL generated for the above code is pasted below.


.class public auto ansi beforefieldinit ConstantsEG
    extends [mscorlib]System.Object
{
    .method public hidebysig specialname rtspecialname instance void .ctor() cil managed
    {
        .maxstack 8
        L_0000: ldarg.0 
        L_0001: call instance void [mscorlib]System.Object::.ctor()
        L_0006: ret 
    }
 
    .method public hidebysig instance void SomeMethod() cil managed
    {
        .maxstack 4
        .locals init (
            [0] object[] CS$0$0000)
        L_0000: nop 
        L_0001: ldstr "const"
        L_0006: call void [mscorlib]System.Console::WriteLine(string)
        L_000b: nop 
        L_000c: ldstr "MaxValue: {0}, MinValue: {1}, Yellow: {2}, Test: {3} "
        L_0011: ldc.i4.4 
        L_0012: newarr object
        L_0017: stloc.0 
        L_0018: ldloc.0 
        L_0019: ldc.i4.0 
        L_001a: ldc.i4 0x7d0
        L_001f: box int32
        L_0024: stelem.ref 
        L_0025: ldloc.0 
        L_0026: ldc.i4.1 
        L_0027: ldc.r8 -0.34343
        L_0030: box float64
        L_0035: stelem.ref 
        L_0036: ldloc.0 
        L_0037: ldc.i4.2 
        L_0038: ldc.i4.4 
        L_0039: box ReadOnlyConst.VIBGYOR
        L_003e: stelem.ref 
        L_003f: ldloc.0 
        L_0040: ldc.i4.3 
        L_0041: ldstr "Test text"
        L_0046: stelem.ref 
        L_0047: ldloc.0 
        L_0048: call void [mscorlib]System.Console::WriteLine(string, object[])
        L_004d: nop 
        L_004e: ret 
    }
 
    .field public static literal int32 maxValue = int32(0x7d0)
    .field public static literal float64 minValue = float64(-0.34343)
    .field public static literal string test = string('Test text')
    .field public static literal valuetype ReadOnlyConst.VIBGYOR yellow = int32(4)
}

If you notice the IL code above all the const variables have been replaced by the actual values. At the bottom you can see the variables hold the actual value rather than only declaration as in the case with readonly variables. If you analyze the method (SomeMethod) in the IL you will notice that instead of some instruction to use the value by reference the actual values are used. In the case of readonly variable there were instruction to use the values by reference. But with const variables the actual values are being used.

With above IL code it is clear how readonly and const variables behave.

When to use readonly/const variables?

From the above most of you may be clear when to use const and when to use readonly variables. const variables can be used when the value of the variable is rarely going to change like the value of PI. Readonly can be used when you want to use the variables by reference or you want to inject runtime values. Also const variables are faster than readonly. By faster I don’t mean they are lighting fast. They give small performance benefit over readonly variables. Here one should use due diligence as const variables don’t provide any flexibility. Once assigned const variables cannot be changed.

Note:

A real time problem we faced in one of our projects. In one of our projects we had defined const and readonly variables in a separate project and added a reference of it in another project. After the release of the project we got requests from client to change few things. As a result we had to make changes in the const variables. Since the changes were only in few places, our team decided to just distribute the changed project and not to reinstall the whole application. So as a patch release we included few dlls in the installer and installed the same at the client place. But behold, the changes were not showing. The reason, the const variables used in other parts of the applications were not updated as only few projects were compiled and not the whole of the application. Because of this const values which were replaced were not updated. Confused? Let’ see this with an example. Below is a sample code which has a const and readonly variable in a separate project.


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
 
namespace SeparateProject
{
    public class Values
    {
        public const double PI = 3.14;
        public static readonly double Value1 = 40000;
    }
}

The above code is pretty straight forward. In a namespace called SeparateProject, we have a class called Values. Values class has one const variable called PI. Another readonly variable called “Value1” having 40000 as the value. The above project is referenced and used in the below project. The code is pasted below.


namespace ReadOnlyConst
{
    class Program
    {        
        static void Main(string[] args)
        {
            Console.WriteLine("Constant: {0}", SeparateProject.Values.PI);
            Console.WriteLine("Readonly: {0}", SeparateProject.Values.Value1);
            Console.ReadLine();            
        }
    }
}

The above code is pretty straight forward. It is a console app which prints “3.14” and “40000” respectively. Now let’ change the values inside Values class and compile only that project.


namespace SeparateProject
{
    public class Values
    {
        public const double PI = 3.14159;
        public static readonly double Value1 = 80000;
    }
}

What we have done here is changed both the variable’ values and compiled only the “SeparateProject” project. Also we have replaced the dlls in the debug folder of the bin directory of “ReadOnlyConst” project with the latest compiled dll of “SeparateProject” project. If you run the console app, you will see the value of PI printed as “3.14” whereas the value of “Value1” printed as “80000”. You can see the value of PI has not been updated but the value of “Value1” has been updated. The reason is where ever const variables are used the values have been replaced where as in the case of readonly there is reference to the actual variable. In other words, in the main function the value of PI has been replaced by the actual value and that of “Value1” has reference. As we have not compiled this part of the application the substitution has not happened. Just to shed more light lets see the IL for the console app.


   1: .method private hidebysig static void Main(string[] args) cil managed
   2: {
   3:     .entrypoint
   4:     .maxstack 8
   5:     L_0000: nop 
   6:     L_0001: ldstr "Constant: {0}"
   7:     L_0006: ldc.r8 3.14
   8:     L_000f: box float64
   9:     L_0014: call void [mscorlib]System.Console::WriteLine(string, object)
  10:     L_0019: nop 
  11:     L_001a: ldstr "Readonly: {0}"
  12:     L_001f: ldsfld float64 [ConstReadonly]SeparateProject.Values::Value1
  13:     L_0024: box float64
  14:     L_0029: call void [mscorlib]System.Console::WriteLine(string, object)
  15:     L_002e: nop 
  16:     L_002f: call string [mscorlib]System.Console::ReadLine()
  17:     L_0034: pop 
  18:     L_0035: ret 
  19: }

The above pasted IL is that of the main method of the console app. At line no 7, you can see the value of PI. Whereas at line no 12 instead of any value we have some IL instructions. Since we have not compiled the console application the altered values have not been updated.