Saturday, January 16, 2010

Great programmers do not make great software engineers

In our world you have two kinds of people, programmers and software engineers. I don't believe in such a thing as a good programmer or a bad programmer because everyone judges in different ways and it its very big headed of them to consider another programmer when I am sure they have failings of their own. Such behaviour effects moral, team work and a persons confidence and achieves nothing. Those programmers that consider them selfs 'great and good' and can code amazing algos in 3 seconds can fail at code design and testing, while others can take a little longer but achieve good design, consideration of patterns and testability. Everyone is different and its more about where you want both your self (and prehaps your team) to be with out making it a witchhunt.


Every single programmer should aim to be a software engineer, write great code but consider everyone else, they can design their code in a paper or tdd way, they can test there code and consider testability in their code, they undertstand concepts like patterms and they can consider patterns in their code to help improve their code. These are just a few things but doing we do is much more than bashing the keyboard, even great programmers can churn out plates of pasta with no thought or consideration of anyone else coming to the code. A key example, in my own experince a fraction of programmers (a very small fraction) know how to unit test, a even smaller fraction know what TDD is let alone use it and even smaller fraction still know about BDD. Even so called great programmers do not write unit tests yet programmers who some may consider not so great do, I know who gets the vote there.


I don't believe in stupid interview questions or tests, while they are suppose to give you an idea of persons ability they can very quickly turn into a wits contest and do not reflect on a person at all. Every person is different, some may succeed at these sorts of questions at interview level and some may not. Does that make them a bad programmer, no it just means they need to carefully consider what they are doing. Prehaps rather than asking them to code something (and again everyone approaches a problem in a different way) ask them how they would approach a problem, what steps they would take and where they have used that approach before. It's all about attitude, for any given persons CV you can see if they go the extra miles in their spare time and career.

Let's also not pick on grads, every single grad I have worked with have been open minded, hard working and who are willing to push them selfs to be better and most important of all aim to be software engineers.

Friday, October 30, 2009

Maintaining the states of selected checkboxes during paging in gridview

If you have a Gmail account then probably you have observed a great feature of maintaining selected CheckBoxes states in different pages on Inbox Grid, i.e. suppose that you are in the first page of your Inbox & select some mails through CheckBoxes & move to the second page. You also select some mails there and further move to the next page. Finally you return back to the first/second page where you find that all the previously selected mails are already selected. This means that Gmail maintains all the selected mails’ states in deferent pages of Inbox Grid. Now if you select mails in different pages of the Inbox Grid & click Delete link, then only current page’s selected mails are deleted. But my clients wanted some more advanced features. Actually my client’s requirement was to delete all pages’ selected mails by clicking on Delete link. So I started to work on it & finally came up with this solution.

CheckBoxes.aspx:
<%@ Page Language="C#" AutoEventWireup="true" CodeFile="CheckBoxes.aspx.cs" Inherits="CheckBoxes" %>



<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml">

<head runat="server">

<title>Untitled Page</title>



<script type="text/javascript">

//Reference of the GridView.

var TargetBaseControl = null;

//Total no of checkboxes in a particular column inside the GridView.

var CheckBoxes;

//Total no of checked checkboxes in a particular column inside the GridView.

var CheckedCheckBoxes;

//Array of selected item's Ids.

var SelectedItems;

//Hidden field that wil contain string of selected item's Ids separated by ''.

var SelectedValues;



window.onload = function()

{

//Get reference of the GridView.

try

{

TargetBaseControl = document.getElementById('<%= this.gvCheckboxes.ClientID %>');

}

catch(err)

{

TargetBaseControl = null;

}



//Get total no of checkboxes in a particular column inside the GridView.

try

{

CheckBoxes = parseInt('<%= this.gvCheckboxes.Rows.Count %>');

}

catch(err)

{

CheckBoxes = 0;

}



//Get total no of checked checkboxes in a particular column inside the GridView.

CheckedCheckBoxes = 0;



//Get hidden field that wil contain string of selected item's Ids separated by ''.

SelectedValues = document.getElementById('<%= this.hdnFldSelectedValues.ClientID %>');



//Get an array of selected item's Ids.

if(SelectedValues.value == '')

SelectedItems = new Array();

else

SelectedItems = SelectedValues.value.split('');



//Restore selected CheckBoxes' states.

if(TargetBaseControl != null)

RestoreState();

}



function HeaderClick(CheckBox)

{

//Get all the control of the type INPUT in the base control.

var Inputs = TargetBaseControl.getElementsByTagName('input');



//Checked/Unchecked all the checkBoxes in side the GridView & modify selected items array.

for(var n = 0; n < Inputs.length; ++n)

if(Inputs[n].type == 'checkbox' && Inputs[n].id.indexOf('chkBxSelect',0) >= 0)

{

Inputs[n].checked = CheckBox.checked;

if(CheckBox.checked)

SelectedItems.push(document.getElementById(Inputs[n].id.replace('chkBxSelect','hdnFldId')).value);

else

DeleteItem(document.getElementById(Inputs[n].id.replace('chkBxSelect','hdnFldId')).value);

}



//Update Selected Values.

SelectedValues.value = SelectedItems.join('');



//Reset Counter

CheckedCheckBoxes = CheckBox.checked ? CheckBoxes : 0;

}



function ChildClick(CheckBox, HCheckBox, Id)

{

//Modifiy Counter;

if(CheckBox.checked && CheckedCheckBoxes < CheckBoxes)

CheckedCheckBoxes++;

else if(CheckedCheckBoxes > 0)

CheckedCheckBoxes--;



//Change state of the header CheckBox.

if(CheckedCheckBoxes < CheckBoxes)

HCheckBox.checked = false;

else if(CheckedCheckBoxes == CheckBoxes)

HCheckBox.checked = true;



//Modify selected items array.

if(CheckBox.checked)

SelectedItems.push(Id);

else

DeleteItem(Id);



//Update Selected Values.

SelectedValues.value = SelectedItems.join('');

}



function RestoreState()

{

//Get all the control of the type INPUT in the base control.

var Inputs = TargetBaseControl.getElementsByTagName('input');



//Header CheckBox

var HCheckBox = null;



//Restore previous state of the all checkBoxes in side the GridView.

for(var n = 0; n < Inputs.length; ++n)

if(Inputs[n].type == 'checkbox' && Inputs[n].id.indexOf('chkBxSelect',0) >= 0)

if(IsItemExists(document.getElementById(Inputs[n].id.replace('chkBxSelect','hdnFldId')).value) > -1)

{

Inputs[n].checked = true;

CheckedCheckBoxes++;

}

else

Inputs[n].checked = false;

else if(Inputs[n].type == 'checkbox' && Inputs[n].id.indexOf('chkBxHeader',0) >= 0)

HCheckBox = Inputs[n];



//Change state of the header CheckBox.

if(CheckedCheckBoxes < CheckBoxes)

HCheckBox.checked = false;

else if(CheckedCheckBoxes == CheckBoxes)

HCheckBox.checked = true;

}



function DeleteItem(Text)

{

var n = IsItemExists(Text);

if( n > -1)

SelectedItems.splice(n,1);

}



function IsItemExists(Text)

{

for(var n = 0; n < SelectedItems.length; ++n)

if(SelectedItems[n] == Text)

return n;



return -1;

}

</script>



</head>

<body>

<form id="form1" runat="server">

<asp:GridView ID="gvCheckboxes" runat="server" AutoGenerateColumns="False" OnPageIndexChanging="gvCheckboxes_PageIndexChanging"

OnRowDataBound="gvCheckboxes_RowDataBound" AllowPaging="True">

<Columns>

<asp:TemplateField HeaderText="Select">

<ItemTemplate>

<asp:CheckBox ID="chkBxSelect" runat="server" />

<asp:HiddenField ID="hdnFldId" runat="server" Value='<%# Eval("Id") %>' />

</ItemTemplate>

<HeaderStyle HorizontalAlign="Center" VerticalAlign="Middle" Width="50px" />

<ItemStyle HorizontalAlign="Center" VerticalAlign="Middle" Width="50px" />

<HeaderTemplate>

<asp:CheckBox ID="chkBxHeader" onclick="javascript:HeaderClick(this);" runat="server" />

</HeaderTemplate>

</asp:TemplateField>

<asp:BoundField DataField="RandomNo" HeaderText="Random Number">

<HeaderStyle HorizontalAlign="Center" VerticalAlign="Middle" Width="150px" />

<ItemStyle HorizontalAlign="Center" VerticalAlign="Middle" Width="150px" />

</asp:BoundField>

<asp:BoundField DataField="Date" HeaderText="Date">

<HeaderStyle HorizontalAlign="Center" VerticalAlign="Middle" Width="75px" />

<ItemStyle HorizontalAlign="Center" VerticalAlign="Middle" Width="75px" />

</asp:BoundField>

<asp:BoundField DataField="Time" HeaderText="Time">

<HeaderStyle HorizontalAlign="Center" VerticalAlign="Middle" Width="100px" />

<ItemStyle HorizontalAlign="Center" VerticalAlign="Middle" Width="100px" />

</asp:BoundField>

</Columns>

<RowStyle BackColor="Moccasin" />

<AlternatingRowStyle BackColor="NavajoWhite" />

<HeaderStyle BackColor="DarkOrange" Font-Bold="True" ForeColor="White" />

</asp:GridView>

<asp:HiddenField ID="hdnFldSelectedValues" runat="server" />

<asp:Button ID="btnDelete" runat="server" OnClick="btnDelete_Click" Text="DELETE" />

</form>

</body>

</html>
CheckBoxes.aspx.cs:
using System;
using System.Data;
using System.Configuration;
using System.Collections;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;

public partial class CheckBoxes : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
if (!Page.IsPostBack)
BindGridView();
}

private void BindGridView()
{
gvCheckboxes.DataSource = GetDataSource();
gvCheckboxes.DataBind();
}
protected void gvCheckboxes_PageIndexChanging(object sender, GridViewPageEventArgs e)
{
gvCheckboxes.PageIndex = e.NewPageIndex;
BindGridView();
}
protected void gvCheckboxes_RowDataBound(object sender, GridViewRowEventArgs e)
{
if (e.Row.RowType == DataControlRowType.DataRow && (e.Row.RowState == DataControlRowState.Normal e.Row.RowState == DataControlRowState.Alternate))
{
CheckBox chkBxSelect = (CheckBox)e.Row.Cells[0].FindControl("chkBxSelect");
CheckBox chkBxHeader = (CheckBox)this.gvCheckboxes.HeaderRow.FindControl("chkBxHeader");
HiddenField hdnFldId = (HiddenField)e.Row.Cells[0].FindControl("hdnFldId");

chkBxSelect.Attributes["onclick"] = string.Format("javascript:ChildClick(this,document.getElementById('{0}'),'{1}');", chkBxHeader.ClientID, hdnFldId.Value.Trim());
}
}
private DataTable GetDataSource()
{
DataTable dTable = new DataTable();

DataRow dRow = null;
DateTime dTime;
Random rnd = new Random();

dTable.Columns.Add("Id", System.Type.GetType("System.Int32"));
dTable.Columns[0].AutoIncrement = true;
dTable.Columns.Add("RandomNo");
dTable.Columns.Add("Date");
dTable.Columns.Add("Time");

for (int n = 0; n < 25; ++n)
{
dRow = dTable.NewRow();
dTime = DateTime.Now;

dRow["RandomNo"] = rnd.NextDouble();
dRow["Date"] = dTime.ToString("MM/dd/yyyy");
dRow["Time"] = dTime.ToString("hh:mm:ss tt");

dTable.Rows.Add(dRow);
dTable.AcceptChanges();
}

return dTable;
}
protected void btnDelete_Click(object sender, EventArgs e)
{
//Get Ids
string[] IDs = hdnFldSelectedValues.Value.Trim().Split('');

//Code for deleting items
foreach (string Item in IDs)
{
//Call appropiate method for deletion operation.
}
}
}

Saturday, November 1, 2008