How to retrieve the selected Ids from an ASP .Net list with jQuery

by andrei 26. September 2008 21:38

Here is an example of a list in which I can select rows (through checkboxes), and when the lnkGetSelection button is clicked I want to retrieve the selected Ids:

<ul runat="server" id="ulTest">
    <asp:Repeater runat="server" ID="rptTest">
        <ItemTemplate>
            <li>
                <asp:CheckBox ID="ckTest" runat="server" />
                <asp:HiddenField ID="hdnId" runat="server" Value='<%# Eval("Id") %>' />
                <p>
                    <%# Eval("Name") %></p>
            </li>
        </ItemTemplate>
    </asp:Repeater>
</ul>
<a href="#" id="lnkGetSelection" onclick="getIds();">Get selection</a>

 

It's incredibly easy to do with jQuery:

function getIds()
{
    var checkedCombos = $('input:checkbox[id*=ckTest]:checked'); // we get an array with the checked checkboxes
    var selectedIdControls = checkedCombos.next(); // we get an array with the correspondent hidden fields
    var selectedIds = new Array(selectedIdControls.length); // we create a new array for the Ids
    selectedIdControls.each(function(i){selectedIds[i] = selectedIdControls[i].value;}); 
    // we iterate over the hidden fields, and put each id value in the list
    
    return selectedIds;
}

 

Technorati Tags: ,,

 

 

Enjoy programming!

 

With a Web Application Project you have to build the website almost each time

by andrei 26. September 2008 20:57

Before using a Web Application Project, I was used to:

  • making changes in any website file and hitting CTRL-F5 to get the changes built on the fly
  • making changes in any project from the solution, building only that project, and hitting CTRL-F5 to automatically get the new dll version in the website's /bin directory

With the Web Application Project these tricks don't work anymore, and it made me ask the classical developer question 'Why doesn't this work (I did everything that was needed)?' a few times already.

The thing that fortunately still works is making changes in the UI(.aspx, .ascx, .css or .js files), and hitting CTRL-F5 to get the changes updated in the browser.

 

I am slowly getting used to building the website more frequently, but the real solution will be a more efficient build mechanism (probably with nant).

 

 

 

Enjoy programming!

 

When two developers work on the same file under SVN source control, be careful with renaming

by andrei 26. September 2008 20:28

UPDATE 09.29.2008: Today I got back at the office and I checked if the file has really been deleted from the desktop computer where I modified it on Friday. It was not deleted, it was just excluded from the list of SVN maintained files. This explains why it did not go to the repository on commit, and why it did not arrive on my laptop when I did the update.

The conclusion is that SVN is really smart (and I am not): because the local version was different than the one which was deleted from the repository, it simply excluded it from his list instead of deleting it. This is probably the best solution, because it does not create problems in the repository and it also gives me a chance to recover my code. If only I would pay attention to the messages.

I did the test below with a local file that was similar with the one in the repository, and this is seemed to work (it was deleted at the update). Which is also a correct move from SVN.

 

 

Yesterday I was working on the same class with a fellow developer, and at the end of the day he told me that he split it in 2 separate classes. I was focused on my work and did not think about the implications immediately... but I really should have.

As usual, before leaving the office I did a full commit... after a full update, because SVN told me I have to do an update before committing. I did not pay much attention to what happened with the files during the process... and again, I really should have.

One day later I am looking at the code, and I realize that he also renamed the class. And the next thing I do... I am searching for the class where I did my changes, and it is no more!

 

Here is the explanation: when updating, SVN observed that the file I have been working on had been deleted. So it simply and silently removed it from my local directory. This kind of cool update goes something like this:

ScreenHunter_02 Sep. 27 09.19

(and ends with the ironic TortoiseSVN Finished!)

 

Because I did the update before committing, this means I also lost my version of the file. The good part is that the file had only a few changes made by myself, so this time it's not a disaster.

 

But it's a good lesson to remember when two developers work simultaneously on the same file.

 

Technorati Tags: ,

 

 

Enjoy programming!

 

Avoid unnecessary select queries with join or left join, part 2

by andrei 26. September 2008 09:50

In my previous post about optimizing NHibernate queries I presented a simple technique using joins or left joins. Here is another simple but useful trick.

 

Considering that we have these 2 entities:

ScreenHunter_01 Sep. 26 22.24

 

here is one way of mapping the relation:

<many-to-one name="ClientAddress" column="AddressId" class="Address" cascade="save-update" lazy="false" />

 

When we load the client, we get one select for the client and one select for the address:

image

 

Let's add one more attribute to the mapping:

<many-to-one name="ClientAddress" column="AddressId" class="Address" cascade="save-update" lazy="false" fetch="join" />

 

Now we are getting only one select, which makes a left join between the client and the address:

image

 

Conclusion: Map foreign key relationships with fetch="join" in order to load related entities in the same select instead of separate selects.

 

 

 

Enjoy programming!

 

Draggable window, cookies, AJAX callbacks, user controls and JSON - combination powered by jQuery, ASP .Net and JSON .Net

by andrei 26. September 2008 08:53

The code for this example can be found here.

 

Here is an interesting functionality I had to implement the other day:

  • a floating / draggable window
  • loads its content (a web control) from a web service through an AJAX callback, based on information that is sent from the client
  • keeps the last location in cookies, when you come back the window pops up where you left it the last time

Here is how it will look like:

ScreenHunter_03 Sep. 26 22.00

Let's start.

 

First of all, I am working with a Web Application project (which is included in Visual Studio 2008, but needs to be installed manually in Visual Studio 2005). With a simple Website project you might encounter problems with Web Services (for example, I was unable to access the classes for my user controls from inside the web service class).

ScreenHunter_02 Sep. 26 20.17

 

I am adding the Javascript files that I need:

ScreenHunter_04 Sep. 26 20.20

and putting them into the page:

<head runat="server">
    <title>Untitled Page</title>

    <script src="JS/jquery-1.2.6.pack.js" type="text/javascript"></script>

    <script src="JS/jquery.easydrag.js" type="text/javascript"></script>

    <script src="JS/JSON.js" type="text/javascript"></script>

    <script src="JS/jquery.cookie.pack.js" type="text/javascript"></script>

</head>

You can get these files from the following locations:

 

Also, a reference to JSON .Net:

ScreenHunter_07 Sep. 26 20.44

which you can get from here.

 

I am also adding a div for the draggable window (with a handle area containing a title and a close button, and a content area where we will load the data from the server):

<div>
    <div id="divExample">
        <div id="divExample_handle">
            <span id="divExample_title">This is a draggable window</span> <span id="divExample_close">
                <a href="javascript:clearExamplePosition();" id="lnkExampleClose">[ x ]</a></span>
        </div>
        <div id="divExample_content">
        </div>
    </div>
</div>

and a link to show / hide the draggable window:

<a href="#" id="lnkShowDraggableWindow">Show the draggable window</a>

 

To prepare the stage, let's add

  • a JSON serializer helper:
using Newtonsoft.Json;

namespace DraggableWindow.CodeFiles
{
  public delegate T Action<T>(T value);

  public class JsonConverter
  {
    public static string Serialize(object entity)
    {
      return JavaScriptConvert.SerializeObject(entity);
    }
  }
}
  • a base response class:
public class BaseResponse
{
  public string htmlValue { get; set; }
  public IList<string> errorMessages { get; set; }
}
  • a base service (which basically knows how to serialize a BaseResponse) - I am using an idea and some code from Rick Strahl's West Wind Ajax Toolkit for ASP.NET
  • a user control to fill the content of the draggable window with (DraggableWindowContent.ascx)
  • and finally the web service which will handle the client calls:
namespace DraggableWindow.Services
{
  [ToolboxItem(false)]
  [ScriptService]
  public class DraggableWindowService : BaseService
  {
    [WebMethod(EnableSession = true)]
    public string GetDraggableWindowContent(string text)
    {
      return Response(delegate(Page p)
      {
        DraggableWindowContent ctrl =
          p.LoadControl("~/DraggableWindowContent.ascx") as
          DraggableWindowContent;

        if (ctrl != null) ctrl.Initialise(text);
        return ctrl;
      });
    }
  }
}

Back to the client-side, we need to initialize the draggable window:

if($ != 'undefined'){
    $('document').ready(function(){                    
        $("#divExample").easydrag();
        $("#divExample").setHandler('divExample_handle');
        $("#divExample").ondrop
            (
                function(e, element)
                    { 
                        $.cookie('examplePosLeft', element.offsetLeft); 
                        $.cookie('examplePosTop', element.offsetTop); 
                    }
            );
    
        $('#lnkExampleClose').click(function() 
            { 
                    $("#divExample").hide(); 
                    $.cookie('showExample', 0)
            }); 
            
        $('#lnkShowExample').click(function() 
            { 
                    $.cookie('showExample', 1);
                    $.cookie('examplePosLeft', 100); 
                    $.cookie('examplePosTop', 100); 
                    loadData();
            });
            
        loadData();
    });
}

We store the user preference of showing the window or not in the showExample cookie. The position cookies (examplePosLeft and examplePosTop) will be set each time the draggable window is dropped.

 

I also need to write the loadData method:

function loadData()
{
    var show = $.cookie('showExample');
    if (parseInt(show) == 0)
    {
        $("#divExample").hide(); 
        return;
    }
    
    $("#divExample").show(); 
    var left = $.cookie('examplePosLeft');
    var top = $.cookie('examplePosTop');
    if (left != undefined && left.length != 0 && top != undefined && top.length != 0)
    {
            $("#divExample").css('top', parseInt(top));
            $("#divExample").css('left', parseInt(left));
    }
    
    var text = 'Client Side Text';
    
    var dataForPost = {
        someText : text
        };

    $.ajax({
            type: "POST",
            url : "/Services/DraggableWindowService.asmx/GetDraggableWindowContent",
            contentType: "application/json; charset=utf-8",
            dataType : "json",
            data : JSON.stringify(dataForPost),
            
            success : function(res){
                var objReturned = eval("("+res.d+")");
                $("#divExample_content")[0].innerHTML = objReturned.value;
            },
        
            error: function(res){
                alert(res.responseText);
            }
                
    });
                    
    return false;
}

which checks if the user wants to see the draggable window or not. If yes, it puts it in the last known location and loads the content from the server.

 

That's it. You can get the code from here.

 

 

 

Enjoy programming!

 

Write a little less code with IEnumerable and yield

by andrei 26. September 2008 06:48

I was used to creating many IList<T> classes, but recently I started using IEnumerable<T> more. The more I use it, the more I realize it is enough for most situations.

 

Here is the relation between IList<T> and IEnumerable<T>:

ScreenHunter_01 Sep. 26 19.42

 

A nice thing with IEnumerable is that it works with yield, so instead of writing this:

private IList<int> GetIds()
{
  IList<int> list = new List<int>();

  foreach (RepeaterItem item in rptData.Items)
  {
    HiddenField hdnId = item.FindControl("hdnId") as HiddenField;
    if (hdnId != null)
      list.Add(Convert.ToInt32(hdnId.Value));
  }

  return list;
}

you can write this:

private IEnumerable<int> GetIds()
{
  foreach (RepeaterItem item in rptData.Items)
  {
    HiddenField hdnId = item.FindControl("hdnId") as HiddenField;
    if (hdnId != null)
      yield return Convert.ToInt32(hdnId.Value);
  }
}

which is a little less code. And you can still do a foreach over the result.

 

 

Enjoy programming!

 

Application layer Mappers play well with domain Services

by andrei 23. September 2008 18:14

I needed a mapper which would transform a domain entity (Product) into a display DTO (ProductProfileDisplayDTO).

 

The DTO looks like this:

public class ProductProfileDisplayDTO
{
    public int Id { get; set; }
    public string Name { get; set; }
    public string Gain { get; set; }
}

 

I can get the Id and Name from the entity easily, but the profile Gain is calculated in comparison with another list of products. This information is not part of the Product entity alone, instead it is a domain service method:

public class ProductProfileService : IProductProfileService
{
  public decimal CalculateGainFor(Product profile, IList<Product> productsToCompareWith)
  {
    IList<Product> occurences = FindOccurrencesOfProductsInProfileUsing(profile, productsToCompareWith);
    decimal individualProductPrice = occurences.Sum(p => p.ProductDiscountPrice) / occurences.Count;
    decimal profileProductPrice = profile.ProductDiscountPrice / profile.SubProducts.Count;
    return individualProductPrice - profileProductPrice;
  }
}

I think it's ok to let the mapper use the domain service to obtain this information when preparing data for the UI, so here it is:

public class ProductProfileDisplayDTOMapper : IMapper<Product, ProductProfileDisplayDTO>
{
    private readonly IProductProfileService _productProfileService = new ProductProfileService ( );
    private readonly IList<Product> _products;

    public ProductProfileDisplayDTOMapper(IList<Product> products)
    {
        _products = products;
    }

    public void CopyFrom(Product source, ProductProfileDisplayDTO destination)
    {
        throw new System.NotImplementedException();
    }

    public ProductProfileDisplayDTO MapFrom(Product input)
    {
        return new ProductProfileDisplayDTO()
                   {
                       Gain = StringFormatter.FormatPrice(_productProfileService.CalculateGainFor(input, _products)),
                       Id = input.Id,
                       Name = input.ProductName
                   };
    }
}

 

And here is how the the application layer task gets a list of ProductProfileDisplayDTOs:

IEnumerable<Product> possibleProfiles = _productProfileService.LoadAllPossibleProfilesFor ( products );

IEnumerable<ProductProfileDisplayDTO> possibleProfileDTOs = possibleProfiles
    .MapAllUsing ( new ProductProfileDisplayDTOMapper(products) );

The list of possibleProfiles does not contain information about the Gain, but the possibleProfileDTO list has it as soon as it is created.

 

 

Enjoy programming!

 

DTOs are for JSON serialization (and any serialization) also, not only for display

by andrei 23. September 2008 18:00

Data transfer objects are very useful for preparing domain information for a presentation layer, and this usually means the UI. But they are at least as useful when it comes to transferring information between different environments, especially when serialization is involved.

 

Here is an example: I needed to serialize a hierarchy of value objects in JSON, so I can put them in a hidden field and use them in an algorithm on the client-side.

These are the value objects:

 

  • CombinationOfProfiles:
public interface ICombinationOfProfiles
{
  IList<ProfileInCombinationWithOtherProfiles> ProfilesInCombinationWithOtherProfiles { get; }
  void AddProfileInCombinationWithOtherProfiles(ProfileInCombinationWithOtherProfiles combination);
  bool IsEmpty { get; }
}

public class CombinationOfProfiles : ICombinationOfProfiles
{
  private IList<ProfileInCombinationWithOtherProfiles> _profilesInCombinationWithOtherProfiles = new List<ProfileInCombinationWithOtherProfiles>();

  public IList<ProfileInCombinationWithOtherProfiles> ProfilesInCombinationWithOtherProfiles
  {
    get { return new ReadOnlyCollection<ProfileInCombinationWithOtherProfiles>(_profilesInCombinationWithOtherProfiles); }
    set { _profilesInCombinationWithOtherProfiles = value; }
  }

  public void AddProfileInCombinationWithOtherProfiles(ProfileInCombinationWithOtherProfiles combination)
  {
    _profilesInCombinationWithOtherProfiles.Add(combination);
  }

  public bool IsEmpty
  {
    get { return _profilesInCombinationWithOtherProfiles.Count == 0; }
  }
}
  • ProfileInCombinationWithOtherProfiles:
public class ProfileInCombinationWithOtherProfiles
{
  private readonly Product _profile;
  private readonly ProductCombinationForProfile _combinationOfProductsForProfileWhichIsValidInCombination;

  public ProfileInCombinationWithOtherProfiles(Product profile, ProductCombinationForProfile combinationOfProductsValidInCombinationForProfile)
  {
    _profile = profile;
    _combinationOfProductsForProfileWhichIsValidInCombination = combinationOfProductsValidInCombinationForProfile;
  }

  public ProductCombinationForProfile ValidCombinationOfProducts
  {
    get { return _combinationOfProductsForProfileWhichIsValidInCombination; }
  }

  public Product Profile
  {
    get { return _profile; }
  }
}

  • ProductCombinationForProfile:
public class ProductCombinationForProfile
{
  private readonly IList<Product> _products = new List<Product>();

  public IList<Product> Products
  {
    get { return new ReadOnlyCollection<Product>(_products); }
  }

  public void AddProductInCombination(Product p)
  {
    _products.Add(p);
  }
}

 

As you can see, they encapsulate a list of products (profiles) and for each product a list (valid combination) of products.

 

I initially tried to serialize the list of CombinationOfProfiles:

hdnProfileAssistanceData.Value =
    JsonConverter<CombinationOfProfiles>.Serialize(dto.PossibleCombinations);

(dto.PossibleCombinations is an IList<CombinationOfProfiles>)

This got me an error, because the hierarchy contains Product entities (which contain subentities and a whole business structure), and these are not serializable.

 

So I have 2 options: either make the Product entity serializable, or find another way to transmit the information I need to the client.

Making the Product entity serializable is a bad idea, because it would mean I am doing changes in my domain classes because of an infrastructure issue. This will impose initial restrictions, and in time it will become a problem. The domain must remain independent and uninterested of the other layers.

I realized I only needed the Ids of the products and nothing else, because on the client-side I just wanted to check al valid combinations based on this hierarchy. And this made things very simple.

 

I created a set of DTOs for JSON serialization:

[Serializable]
public class CombinationOfProfilesJSONDTO
{
    public CombinationOfProfilesJSONDTO()
    {
        
    }

    public CombinationOfProfilesJSONDTO(IEnumerable<ProfileInCombinationWithOtherProfiles> profiles)
    {
        Profiles = new List<ProfileInCombinationWithOtherProfilesJSONDTO>();
        foreach(ProfileInCombinationWithOtherProfiles profile in profiles)
        {
            Profiles.Add(new ProfileInCombinationWithOtherProfilesJSONDTO(profile));
        }
    }

    public IList<ProfileInCombinationWithOtherProfilesJSONDTO> Profiles { get; set; }
}

[Serializable]
public class ProfileInCombinationWithOtherProfilesJSONDTO
{
    public ProfileInCombinationWithOtherProfilesJSONDTO(ProfileInCombinationWithOtherProfiles profile)
    {
        Product = profile.Profile.Id;
        ProductCombinationForProfile = new ProductCombinationForProfileJSONDTO(profile.ValidCombinationOfProducts);
    }

    public int Product { get; set; }
    public ProductCombinationForProfileJSONDTO ProductCombinationForProfile { get; set; }
}

[Serializable]
public class ProductCombinationForProfileJSONDTO
{
    public ProductCombinationForProfileJSONDTO(ProductCombinationForProfile products)
    {
        Products = new List<int>();
        foreach(Product p in products.Products)
            Products.Add(p.Id);
    }

    public IList<int> Products { get; set; }
}

 

and a mapper between a CombinationOfProfiles domain value object and an CombinationOfProfilesJSONDTO:

public class CombinationOfProfilesJSONMapper : IMapper<CombinationOfProfiles, CombinationOfProfilesJSONDTO>
{
    public void CopyFrom(CombinationOfProfiles source, CombinationOfProfilesJSONDTO destination)
    {
        throw new System.NotImplementedException();
    }

    public CombinationOfProfilesJSONDTO MapFrom(CombinationOfProfiles input)
    {
        return new CombinationOfProfilesJSONDTO(input.ProfilesInCombinationWithOtherProfiles);
    }
}

Here is how my call looks now, which generates the entire hierarchy of DTOs automatically:

hdnProfileAssistanceData.Value =
    JsonConverter<CombinationOfProfilesJSONDTO>.Serialize(
        dto.PossibleCombinations.MapAllUsing(new CombinationOfProfilesJSONMapper()));

 

 

Enjoy programming!

 

NHibernate optimization - avoid unnecessary select queries

by andrei 23. September 2008 10:09

Let's consider the following structure of entities:

ScreenHunter_01 Sep. 23 22.23

On Product we have this mapping:

<bag name="ProductDetailCells" inverse="true" cascade="none" lazy="false">
    <key column="ProductId" />
    <one-to-many class="ProductDetailCell" />
</bag>

which means that I am always loading at least some of the cells.

Here is a quick test:

[Test]
public void normal_load_does_2_selects()
{
  Product p = Repository<Product>.LoadById(726);
}

and the result in SQL Server Profiler:

ScreenHunter_02 Sep. 23 22.42

It runs one select to get the Product and one select to get the ProductDetailCells for the Product. For 300 products we will obtain 301 database queries. If the ProductDetailCell table contains many rows, this will be a performance disaster as soon as we try to load a list of Products.

In my case I always needed to load a cell based on the type of column (ProductDetailColumnId), and I also knew that there is only one ProductDetailCell per ProductColumnType for each Product. So I tried to find a solution to avoid the performance hit.

Here is another test:

[Test]
public void optimized_load_does_1_select()
{
  Product p = new ProductRepository().InitialiseCriteriaFor(726)
    .WithProductDetailCellsOfType(enumProductDetailColumn.SubProductColumn)
    .LoadProduct();
}

I am using a fluent repository, like the one presented here.

Here is the WithProductDetailCellsOfType method:

public ProductRepository WithProductDetailCellsOfType(enumProductDetailColumn type)
{
  _criteria
    .CreateCriteria("ProductDetailCells", JoinType.LeftOuterJoin)
    .Add(Expression.Eq("Column.Id", (int)type));

  return this;
}

and here is the result in SQL Server Profiler:

ScreenHunter_03 Sep. 23 22.49

There is only one select, because this time it uses a left join with ProductDetailCell:

FROM dbo.Product this_ left outer join dbo.ProductDetailCell productdet1_ on this_.ProductId=productdet1_.ProductId

 

What I did is I used the knowledge that I always need ProductDetailCells based on the ProductDetailColumnType, and that there will be only one result each time. So I forced a left join instead of a separate select. This would not have worked if I had two ProductDetailCells per ProductDetailColumnType for each Product, because it would have doubled the returned rows. But in this case, it worked and it made a big difference.

This is only a punctual case, but the general idea is more important: always watch what your ORM is doing, at least until you learn it very well. Most of the times you can do the same thing in at least 2 different ways, and the ORM can't always make the best decisions on its own. It will get you what you want one way or the other, but sometimes you must say how.

 

 

Enjoy programming!

 

Process concepts

by andrei 19. September 2008 21:44

You can read about the purpose of this list and how to use it here.
Also, the list of resources is here.

 

  1. general implementation
  2. concepts
    1. harvested framework
      watch out so you don't fall into the trap of building frameworks up front. It's generally better to let them show themselves in your code and then you go from there.
    2. YAGNI
      So it's important to be careful and not think "You Aren't Going to Need It" (YAGNI) too often when it comes to operational mechanisms. Using YAGNI often will cost too much when it comes to adding the mechanism if (or rather when) you will need it. Remember, the idea with YAGNI is that the cost of adding something is pretty much the same now and later, in which case you can always wait until you really need it. When the cost is low now and high later, and there's a good chance you will need it, you should make a different decision.
      going for a Query Object, especially a domain-specific one, or the Specification pattern is to start by going too far, too quickly, don't you think? Let's go for the simplest possible and only consider two of all possible criteria for now
      The third solution could be to create an interface called ICustomer (or something similar, or let Customer be an interface) and then create a stub implementation of the interface. Again, that feels like overkill right now, and what would the purpose be when moving forward? To be able to swap ICustomer implementations? Is that really something I expect? No, I don't, so until proven wrong, I decide that this isn't the solution I am going to start with.
      Well, what value does the factory really add? Not anything yet. It just adds a bit of complexity. I really should have at least started without the factory, because it shouldn't be around if it doesn't add value. It feels strange to refactor away from a factory. But it's just a sign that I got carried away and started out with a too detailed design from the beginning.
      B4
    3. whiteboard or sketchpad for software design meetings
      Diagrams are a means of communication and explanation, and they facilitate brainstorming. They serve these ends best if they are minimal.
      resources
      B1
    4. Strategic Design Decision Making
      Strategic design requires minimalism and humility
      resources
      B1
    5. source control
      1. SVN
    6. Software Factories
      The idea of Software Factories is to have two lines in the software company. One line creates architectures, frameworks, and such to be used for families of applications. The other line creates the applications by using what the first line has produced, and thereby amortizing the cost of the frameworks on several projects
      A problem is that it's troublesome to just invent a framework. It's probably a better idea to harvest instead. Another thing that is somewhat problematic with Software Factories, though, is that they probably require pretty large organizations before being efficient to use
      At the heart of Software Factories is that of Domain Specific Languages
      resources
      B4
    7. risk management
      except when the team has proven skills and the domain is very familiar, the first-cut system should be based on some part of the CORE DOMAIN, however simple.
      the CORE DOMAIN is high risk because it is often unexpectedly difficult and because without it, the project cannot succeed.
      resources
      B1
    8. project documentation
      Documents Should Complement Code and Speech
      resources
      B1
    9. continuous integration
      The key to significantly reducing integration problems is to generate your builds automatically and to use an incremental integration strategy where all the code is rebuilt and tested at least daily, if not continuously. The idea is that if your recently added code breaks a build, you either fix it immediately or roll back the changes to restore the system to the last known good state.
      resources
      B4
    10. bug fixing
      It's a good idea to use TDD and refactoring for bugfixing also. First expose the bug with a red test, then solve the bug so you get green, and then refactor.
      resources
      B4
    11. Big Design Up-Front (BDUF)
      I think it's pretty well known that a Big Design Up-Front (BDUF) has some big problems. At the same time, most often we know some things from day one. It's a matter of balance.
      resources
      B4
    12. automated build & deploy
      code & implementation
      E2

 

You can find the entire list of techniques in progress in the Development base concepts category. Please feel free to leave any comments or suggestions which could make these lists more useful for everyone.

Also, if you are interested in learning these skills you can try the Developer training modules.

 

 

 

Enjoy programming!

 

Powered by BlogEngine.NET 1.4.5.0