Targetprocess Product Blog

Agile development on a real project (we do Kanban)

Uncategorized

TargetProcess Development Tricks: Clear NHiberante cache using ASP.NET handler (.ashx)

Sometimes we need to clear cache of NHibernate. For example when the database was changed without using NHibernate. We have created the corresponding handler in web application ClearCache.ashx with the following code:

<%@ WebHandler Language="C#" Class="ClearCache" %>
using System;
using System.Collections;
using System.Web;
using NHibernate;

public class ClearCache : IHttpHandler
{
  public void ProcessRequest(HttpContext context)
  {
      context.Response.ContentType = "text/plain";

      //Need to retrieve ISession using your NHibernate session provider. In my case it is done in the following way
      ISession session = Portal.Instance.GetCurrentSession();

      DoCacheClearing(session);

      context.Response.Write("Done");
  }

  public void DoCacheClearing(ISession session)
  {
      ISessionFactory factory = session.SessionFactory;

      factory.EvictQueries();

      ICollection types = factory.GetAllClassMetadata().Keys;

      foreach (Type type in types)
          factory.Evict(type);

      foreach (string role in factory.GetAllCollectionMetadata().Keys)
          factory.EvictCollection(role);
  }

  public bool IsReusable { get { return false; } }

}

TargetProcess Development Tricks: Force ExtJS GridPanel skip events processing raised from nested grid panels

We got a problem with implementing inner grids based on ExtJS. ExtJS GridPanel reacts on every event from inner GridPanel by default. For example sorting in nested grid causes the sorting in parent. That is not good. Find below the code which will allow to deny the event processing in GridPanel if it is fired in its child grid panel:

Ext.override(Ext.grid.GridPanel, {
    processEvent: function(name, e) {
        var t = e.getTarget();

        if (!t) {
            return;
        }

        if (!this.el) {
            return;
        }

        if (jQuery('#' + this.el.id).find('.x-grid3').length > 1 && jQuery(t).parents('.x-grid3').length > 1) {
            return;
        }

        this.fireEvent(name, e);

        var v = this.view;
        var header = v.findHeaderIndex(t);

        if (header !== false) {
            this.fireEvent("header" + name, this, header, e);
        } else {
            var row = v.findRowIndex(t);
            var cell = v.findCellIndex(t);
            if (row !== false) {
                this.fireEvent("row" + name, this, row, e);
                if (cell !== false) {
                    this.fireEvent("cell" + name, this, row, cell, e);
                }
            }
        }
    }
});

TargetProcess Development Tricks: Setting the custom context to MS SQL Connection

We are developing the new audit history mechanism. SQL triggers were added. They do the shadow copy of added/deleted/updated data in important tables such as user story, project. The problem is that we need the custom context in these triggers implementation such as logged user and client date. In other words we need to set some custom info into the connection session before any change.

The code below shows how to set and extract context on MS SQL side:

GO

CREATE PROCEDURE setTpCnt
       @userID INT,
       @clientDate DATETIME
AS

DECLARE @BinVar varbinary(128)

SET @BinVar = CAST(CAST(@userID as nvarchar(20)) +
       '_' + CONVERT(nvarchar(100), @clientDate, 13)
              + '_' AS varbinary(128))

SET CONTEXT_INFO @BinVar

GO

CREATE FUNCTION f_GetLoggedUserID()
       RETURNS INT
       AS
BEGIN
       DECLARE @CONTEXT AS NVARCHAR(120)

       SET @CONTEXT = NULL

       SELECT @CONTEXT = CAST(CONTEXT_INFO AS NVARCHAR(120))
                     FROM master.dbo.sysprocesses WHERE spid = @@spid

       IF (@CONTEXT IS NULL)
              RETURN NULL

       RETURN CAST(SUBSTRING(@CONTEXT, 0, CHARINDEX('_', @CONTEXT)) as INT)
END

GO

CREATE FUNCTION f_GetClientTime()
       RETURNS DATETIME
       AS
BEGIN
       DECLARE @PAD_INDEX AS INT
       DECLARE @CONTEXT AS NVARCHAR(120)

       SET @CONTEXT = NULL

       SELECT @CONTEXT = CAST(CONTEXT_INFO AS NVARCHAR(120))
                     FROM master.dbo.sysprocesses WHERE spid = @@spid

       IF (@CONTEXT IS NULL)
              RETURN NULL

       SET @PAD_INDEX = CHARINDEX('_', @CONTEXT)
       SET @CONTEXT = SUBSTRING(@CONTEXT, @PAD_INDEX + 1, LEN(@CONTEXT) - @PAD_INDEX)
       SET @CONTEXT = SUBSTRING(@CONTEXT, 0, CHARINDEX('_', @CONTEXT))

       RETURN CONVERT(DATETIME, @CONTEXT, 13)
END

GO

We can do the following things with the procedure and functions above

  • We can set the context using stored procedure setTpCnt
  • We can get the logged user anywhere using function f_GetLoggedUserID
  • We can get the client time using the function f_GetClientTime

Now we need to set the context from our client. Only our client knows the logged user id and the date. We need somehow to the call of stored procedure setTpCnt in our C# client. We are using NHibernate. So we need to figure out how to pass the custom context information into every connection which is created by NHibernate.
Please find the solution below. We created the custom driver for NHibernate to make a call to stored procedure with setting required value:

#region

using System;
using System.Data;
using System.Data.SqlClient;
using NHibernate.Driver;
using NHibernate.SqlCommand;
using NHibernate.SqlTypes;
using Tp.BusinessObjects.Components.Authentication;

#endregion

namespace Tp.BusinessObjects.Data
{
    public class Driver : SqlClientDriver
    {
        private bool _isSecurityInjected;

        public override IDbConnection CreateConnection()
        {
            var connection = base.CreateConnection();
            _isSecurityInjected = false;
            return connection;
        }

        public override IDbCommand GenerateCommand(CommandType type,
                SqlString sqlString, SqlType[] parameterTypes)
        {
            var command = base.GenerateCommand(type, sqlString, parameterTypes);

            if (_isSecurityInjected)
                return command;

            var commandText = command.CommandText;

            if (string.IsNullOrEmpty(commandText))
                return command;

            if ((commandText.IndexOf("INSERT ",
                    StringComparison.InvariantCultureIgnoreCase) < 0)
                && (commandText.IndexOf("UPDATE ",
                    StringComparison.InvariantCultureIgnoreCase) < 0)
                && (commandText.IndexOf("DELETE ",
                    StringComparison.InvariantCultureIgnoreCase) < 0))
            {
                return command;
            }

            var userID = UserAuthentication.UserID;

            if (userID != null)
            {
                _isSecurityInjected = true;
                var text = @"EXEC setTpCnt @cnt_userID, @cnt_ClientDate" + Environment.NewLine;
                command.CommandText = text + commandText;
                command.Parameters.Add(new SqlParameter("@cnt_userID", userID));
                command.Parameters.Add(new SqlParameter("@cnt_ClientDate", CurrentDate.Value));
            }

            return command;
        }
    }
}

Now we need to improve NHibernate configuration to include the driver created above. It should be done in the following way

Will keep you informed about other tricks (if have time for sure).

Agile Project Management Tools Evaluations

Short comparison of several agile project management tools. I can’t resist to provide the quote :)

Even though it is [TargetProcess] a massive application somehow it feels very intuitive. Reports are easily customizable, processes can be changed to fit your style such as XP or SCRUM. You can comprehensively organize your stories into iterations by dragging and dropping. In-place editing almost everywhere allows for super quick updates. Overall the app seemed extremely configurable yet uncluttered. Also available is a public API, support for Subversion integration and a rich story card board that seems easier to use than Mingle’s.

Retrospective Meeting Results 2

Today we held one more retrospective meeting. First we evaluated some action items from previous meeting:

Practice Result
Daily Code Demos: Each developer must spend ~15-30 minutes every day demonstrating his code to other developer. Development teem liked this practice and decided to keep it forever.
Coding Deadline: Two days before Iteration end all user stories that are not completed excluded from the iteration delivery and moved to the next iteration. Not sure whether it helped. Team decided to keep this practice for one more iteration to try.
Define Iteration scope and specs before iteration start. Good practice that allows to start iteration right away. Decided to keep it.

The major discussion topic on this meeting was the product quality. Sometimes testing is not started when required. For example, developer completes the feature on Monday, but testing starts on Thursday. The problem is in communication between development and testing teams. Two practices will be tried in the next iteration:

Developer/Tester team for user story. Each user story will have a pair of developer and tester. It will be known who is responsible for the user story testing and development and make it clear for all team members. It should help to discuss user story for interested parties.

Developer-to-QA demo. When developer completes the user story it should demonstrate the functionality to the tester right away. It will clearly identity the moment when implementation is done and help to identify initial most critical problems early. Also developer should demonstrate ready pieces of functionality during daily code demos (if he has something new to show).

Manage Multiple Teams with Tags and Bundles in TargetProcess v.2.10

You have a project and several teams. You want to have a single project backlog and manage work separately for each development team. How can you do that in TargetProcess? The quick answer is “tags and bundles”, however some guidance will help to get the idea.

Tags and bundles is a way to categorize information. With creativity you may find very nice applications for this idea. Let’s try to see how it help to manage several teams’ work in scope of a single project.

First of all, we will create a bundle Teams and add tags Team A and Team B to the bundle. Team A is just a tag, people should know to what team they belong. Usually it is not a problem at all.

The next step is to assign user stories to teams. It can be done in several places. For example, you can go to User Stories list, mark several user stories and add “Team A” tag to these stories.

Alternative way is to use Tags Board. Navigate to General -> Tags Board screen and select Teams bundle. On the left you will see backlog of user stories that are not assigned to teams. On the right you will see two teams tags. All you need is to drag some user stories and drop them to required team.

As a result you will have backlog for each team. What about iteration planning? Navigate to Iteration Plan page and filter user stories by “Team A” tag if you want to see all user stories for Team A. Thus you may plan iteration for one specific team.

Potential problem is a team velocity. If you track overall velocity, it will work out of the box. To have a separate velocity for each team it is required to create parallel releases and iterations inside the project. Each team should have separate releases thread. For example, we create Release 1.A for Team A and Release 1.B for Team B. All releases will have the same Start/End dates (it is not a requirement, if you want you may have different dates).

Now you have iteration plan for both teams. All you need is progress tracking. First of all, user stories list itself give overview of the stories progress.

You may filter the list by Team A or Team B to see the progress specific for each team. Overall progress accessible in Release and Iteration Burn Down charts. However if you have parallel releases it is impossible to see combined burn down for all teams.

As you see, multiple teams support in TargetProcess is possible and quite painless.

Some Issues in v.2.10.4 Build

TargetProcess v.2.10.4 has some problems reported. We are working on them and likely will release new build today. The list of known problems:

  • Date custom field is not visible in lists.
  • Exception in list if it is filtered by checkbox custom field.
  • Sometimes javascript errors appear in lists (not reproduced yet, but several customers reported this issue).

UPD: bug with javascript reproduced and fixed, new build will be available today.

UPD2: v.2.10.7 released and contains all the fixes above.

Retrospective Meeting Results

Last week we had retrospective meeting. We have identified two major problems. We often unable to ship fully tested and complete build in the end of iteration. The main reason is that some user stories still in development even in the last iteration day, it means integration and acceptance tests will not be run. The other problem is knowledge transfer. Some developers are not willing to use pair programming all the time, the team decided to pair only for complex refactoring and development tasks.

We decided to try three new practices in the next iteration:

  1. Daily Code Demos: Each developer must spend ~15-30 minutes every day demonstrating his code to other developer. It is a kind of code review on a daily basis, it does not take much time and should improve awareness inside the team.
  2. Coding Deadline: Two days before Iteration end all user stories that are not completed excluded from the iteration delivery and moved to the next iteration. They must be hidden in UI and do not affect application in any way.
  3. Define Iteration scope and specs before iteration start. When iteration starts, the following must be ready: iteration scope clearly defined, all use stories in the iteration scope have brief description, iteration planing meeting is done. It will help to start iteration development from the day one.

Let’s see the results in two weeks :)

TargetProcess v.2.10 Released!

TargetProcess v.2.10 released yesterday. This release includes quite many features and was too long on my opinion. We will focus on shorter releases (about 6 weeks) starting from v.2.11.

The killer feature in v.2.10 is painless tags categorization. We’ve provided a framework that resolve many categorization problems, from Modules to several Teams in one project. It is possible to add tags to entities, filter and search by tags, see tags in lists and views. There is also exceptional Tags Board area where you can categorize entities easily.

The most important features in v.2.10 include:

  • Tags and Bundles
  • JIRA Integration
  • Next/Prev navigation in views
  • Convert entities from one type to another (for example, bug to user story)
  • Import custom fields values
  • Plugin: Auto-reply email when new request created
  • Plugin: Bind emails/requests to a project based on a [key] in the subject
  • Create custom field for several entities at once
  • Feature is the assignable entity now (it has own workflow, assignments, appears in ToDo list, etc.)
  • Help Desk Tickets

Targetprocess Help

All you want to know about Targetprocess