tag:blogger.com,1999:blog-73627274757929782592024-03-05T01:06:22.065-08:00Effective Software DevelopmentEverything is possibleAnonymoushttp://www.blogger.com/profile/03428406119776865921noreply@blogger.comBlogger72125tag:blogger.com,1999:blog-7362727475792978259.post-59800520426238457222015-04-28T20:36:00.001-07:002015-04-28T20:36:30.814-07:00Merging Access MDB files<div dir="ltr" style="text-align: left;" trbidi="on">
Recently I came across a task that seemed trivial, but turned out into an adventure on a second look. I needed to merge 33 MDB files having one or two tables with same structure each. I was disappointed that Access has no standard means to do so I also could not use Excel as the data could have been spoiled by its auto-type function (will they ever fix that?!).<br />
<br />
So I started creating a program that would do the task. The fact that tables can be named differently (thanks for a silly decision of a person who created them in the first place) I faced unexpected complexity. The following query can be used to get the list of tables in Access MDB:<br />
<br />
<span style="font-family: Courier New, Courier, monospace;">SELECT Name FROM MSysObjects WHERE Type=1 AND Flags=0</span><br />
<br />
However it does not work due to permission schema if executed by a program. Running it under administrator does not work either (famous Microsoft integration of solutions is to be blamed). SO I needed to grant the required access with another query before above query starts working:<br />
<br />
<span style="font-family: Courier New, Courier, monospace;">GRANT SELECT ON TABLE MSysObjects TO PUBLIC</span><br />
<br />
<i>Note: Just hold on for a second and think how stupid it seems. I can't do a query but I can run another one to grant the required access and voila it does the magic. So what is the point of restriction in the first place? Ah?...</i><br />
<br />
This is the code that does the job:<br />
<br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;">var conn = new OleDbConnection(@"Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" + file + ";" +</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span>@"Jet OLEDB:System Database=C:\Documents and Settings\<user>\Application Data\\Microsoft\Access\System.MDW");</user></span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><br /></span>
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;">var cmdToExecute = new OleDbCommand();</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;">cmdToExecute.Connection = conn;</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;">cmdToExecute.CommandType = System.Data.CommandType.Text;</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;">cmdToExecute.CommandText = "GRANT SELECT ON TABLE MSysObjects TO PUBLIC";</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><br /></span>
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;">conn.Open();</span><br />
<span style="font-family: Courier New, Courier, monospace;"><br /></span>
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;">// set permissions to read system object to get the list of tables</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;">try</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;">{</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span>cmdToExecute.ExecuteNonQuery();</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;">}</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;">catch(Exception e)</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;">{</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span>Console.WriteLine(e.Message);</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span>return;</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;">}<span class="Apple-tab-span" style="white-space: pre;"> </span></span><br />
<br />
<i>Note: You must reference a schema file otherwise you will an exception during query execution.</i><br />
<br />
And the second step - getting the list of tables:<br />
<br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;">cmdToExecute.CommandText = "SELECT Name FROM MSysObjects WHERE Type=1 AND Flags=0";</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;">try</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;">{</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span>var reader = cmdToExecute.ExecuteReader();</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span>while(reader.Read())</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span>{ </span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span>tables.Add(reader[0].ToString());</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span>}</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span>reader.Close();</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;">}</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;">catch()...</span><br />
<br />
Then for each table selected I ran the query to read the content and added it to a StringBuilder object:<br />
<br />
<br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;">cmdToExecute.CommandText = "SELECT * FROM " + table;</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;">reader = cmdToExecute.ExecuteReader();</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;">while(reader.Read())</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;">{</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span>var sb = new StringBuilder();</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><br /></span>
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span>for(int i=0; i<reader .fieldcount-1="" font="" i=""></reader></span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span>{</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span>sb.Append(reader.GetValue(i).ToString());</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span>sb.Append(delim);</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span>}</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span>sb.Append(file);</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span>sb.Append(delim);</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span>sb.Append(table);</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span>sb.Append("\n");</span><br />
<span style="font-family: 'Courier New', Courier, monospace;"><span style="font-size: x-small;">}</span></span><br />
<span style="font-family: Courier New, Courier, monospace;"><br /></span>
<br />
This is pretty much it. The only other thing is that I faced some corruption within the files scanned and needed to use Access to fix the database before it starts working for those.<br />
<br />
Feel free to copy and modify the code as you like. Hope it helps.<br />
<br />
Full solution code is provided below:<br />
<br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;">static void Main(string[] args)</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;">{</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span>// read folder</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span>var files = Directory.GetFiles(inDir, "*.mdb", SearchOption.TopDirectoryOnly);</span><br />
<span class="Apple-tab-span" style="white-space: pre;"><span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> </span></span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span>// prepare to writing results into a file</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><br /></span>
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span>using (var stream = new StreamWriter(outDir + @"\alldata.txt"))</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span>{</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span>// write the header</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span>foreach(var header in headers)</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span>{</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span>stream.Write(header + delim);</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span>}</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span>stream.Write("\n");</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><br /></span>
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span>// for each MDB file, read it and save content into CSV</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span>foreach(var file in files)</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span>{</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span>Console.WriteLine(file);</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><br /></span>
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span>var conn = new OleDbConnection(@"Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" + file + ";" +</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span>@"Jet OLEDB:System Database=C:\Documents and Settings\<user>\Application Data\\Microsoft\Access\System.MDW");</user></span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><br /></span>
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span>var cmdToExecute = new OleDbCommand();</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span>cmdToExecute.Connection = conn;</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span>cmdToExecute.CommandType = System.Data.CommandType.Text;</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span>cmdToExecute.CommandText = "GRANT SELECT ON TABLE MSysObjects TO PUBLIC";</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><br /></span>
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span>conn.Open();</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><br /></span>
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span>// set permissions to read system object to get the list of tables</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span>try</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span>{</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span>cmdToExecute.ExecuteNonQuery();</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span>}</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span>catch(Exception e)</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span>{</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span>Console.WriteLine(e.Message);</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span>return;</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span>}</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><br /></span>
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span>var tables = new List<string>();</string></span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><br /></span>
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span>// get data</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span>cmdToExecute.CommandText = "SELECT Name FROM MSysObjects WHERE Type=1 AND Flags=0";</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span>try</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span>{</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span>var reader = cmdToExecute.ExecuteReader();</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span>while(reader.Read())</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span>{ </span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span>tables.Add(reader[0].ToString());</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span>}</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span>reader.Close();</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span>// reading data for each table</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span>foreach(var table in tables)</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span>{</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span>cmdToExecute.CommandText = "SELECT * FROM " + table;</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span>reader = cmdToExecute.ExecuteReader();</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span>while(reader.Read())</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span>{</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span>var sb = new StringBuilder();</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><br /></span>
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span>for(int i=0; i<reader .fieldcount-1="" font="" i=""></reader></span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span>{</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span>sb.Append(reader.GetValue(i).ToString());</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span>sb.Append(delim);</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span>}</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span>sb.Append(file);</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span>sb.Append(delim);</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span>sb.Append(table);</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span>sb.Append("\n");</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><br /></span>
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span>stream.Write(sb.ToString());</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span>}</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span>}</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span>}</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span>catch(Exception e)</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span>{</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span>Console.WriteLine(e.Message);</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span>return;</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span>}</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><br /></span>
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span>conn.Close();</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span>}</span><br />
<span class="Apple-tab-span" style="white-space: pre;"><span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> </span></span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span>}</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><br /></span>
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span>Console.ReadKey();</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;">}</span><br />
<div>
<br /></div>
</div>
Anonymoushttp://www.blogger.com/profile/03428406119776865921noreply@blogger.com0tag:blogger.com,1999:blog-7362727475792978259.post-11632029305020269872014-08-24T17:48:00.000-07:002014-08-24T17:48:16.399-07:00Agile or Traditional is not just your preference<div dir="ltr" style="text-align: left;" trbidi="on">
Many of us have been through mainstream both types of development: traditional and Agile. I am not going to speculate on which one is best because no one but you can answer this question with due probability. The choice depends on many parameters that no one can advise you on. In short, Agile works best in the situation of volatile requirements whereas traditional shows better results backed by steady specifications.<br />
<br />
Still many people try to use Agile in all cases, mostly because it is "more fun to do". Well, if it was about having fun we would probably spend our time riding a roller-coaster rather that sitting in our offices. So it is not about fun you get in the process, it is rather about the fun we get successfully launching the system, seeing it doing something useful and helpful. This is the kind of fun that I personally prefer.<br />
<br />
The road to this goal itself is also important but as much as it does not compromise the goal itself. For example, choosing Agile for a mission-critical system may become fun in development but a huge frustration in the end. The devastating effect will be so big that you would not remember a minute of fun you have had in the process.<br />
<br />
Agile is definitely attractive to the developers because it allows to jump into the coding not bothering doing boring routine work. It allows to skip the hardest efforts such as trying to think ahead, measure risks and probabilities. But it comes at the cost of missing important aspects of system design or requirements which will be hard to add on later, when the shortage is revealed. So be flexible. It is good to have more then one tool if conditions change.<br />
<br />
Quick turnover cycles also attract stakeholders. They can see results quicker and try out the system earlier. It enables them making corrections if their understanding of the business processes was not optimal. Which in turns makes unsteady requirements even more volatile and Agile even more efficient. But this is only in theory. The reality is more complex as stakeholders fail to understand what it takes sometimes to convert a prototype into a production solution. It may not be easy to convince your boss that the system that he can see working is not ready to be released after few fixes. You must be prepared and keep delivering the message about what they see consistently. Otherwise you have a big chance to lose this battle and deal with evolving prototype kind of project with no time available for refactoring. I have been thought a project that took few weeks to be coded into Alfa but costed us six months to fix up and refactor. You have a good chance not to repeat our mistake.<br />
<br />
All in all, Agile or not should not be your personal preference. It is not a religion or us against them. This is simply a tool that you should be using wisely. You have choices and whether you make them right will most likely define the success of your future project. So, choose insightfully and enjoy project success.<br />
<br />
<br />
<br /></div>
Anonymoushttp://www.blogger.com/profile/03428406119776865921noreply@blogger.com0tag:blogger.com,1999:blog-7362727475792978259.post-68108082705874884702014-08-15T01:53:00.001-07:002014-08-15T01:53:11.297-07:00Need more automated tests? - No problem<div dir="ltr" style="text-align: left;" trbidi="on">
Many want to add automated test harness to their tool-set. Some start. Few succeed. There are many reasons for this unfortunate trend to develop, but I want to focus on just one - automated tests are expensive on resources. You simply need to invest more time and efforts into making it happen or you are most likely set to fail.<br />
<br />
Despite hiring more engineers to write tests looks like an obvious option, unless your are Google and do not really care about money, it is rarely something that you can sell to your bosses. So, the point is to make the best use of the resources you already have. All those people who are working hard running manual tests could have been used as an additional workforce. Not only would it increase the number of tests dramatically, it would probably increase their motivation and enthusiasm by doing really cool stuff and learning a bit of programming.<br />
<br />
This is good that we advanced so far in thinking but there is another problem. What if those people do not have the required experience? Indeed, I would not expect them to start writing an effective and reliable locator method from the start. But as far as they know how to write a cycle - they are good enough. All you need is to re-balance the tasks so as to make the best use of either 1. highly technical personnel, guru and 2. people capable of doing some of coding.<br />
<br />
In case when first group of engineers is involved in all stages of automation you probably waste their time and experience on dealing with tasks that can be performed by group 2. Moreover some tasks in automation may be even more suitable for people with manual testing experience, like creating new test scenarios. So it seems like creating test sequences is better to be done by people from the group less experienced in automation, but more savvy in manual test design and execution, knowing concepts of equivalent portioning and boundary conditions. Whereas technical aspects, such as locator engineering and test architecture design should be left in hands on gurus.<br />
<br />
This will allow you automation champions to spend more time doing more complex tasks, leaving the simple stuff to their colleagues from manual testing wing.<br />
<br />
In practice this schema can be implemented by doing test design with stubs created by automation team, followed by test case implementation by manual testing team. Tests do not work until automation team implements all the accessibility and validation functions. Until implemented the function should report themselves as not implemented.<br />
<br />
I have successfully employed this schema more than once. Hopefully this will be of help for someone else out there.<br />
<br />
Happy test automation!<br />
<br /></div>
Anonymoushttp://www.blogger.com/profile/03428406119776865921noreply@blogger.com0tag:blogger.com,1999:blog-7362727475792978259.post-47547770399995489432012-10-21T22:31:00.001-07:002012-10-21T22:31:13.161-07:00J-Meter, first impressions<div dir="ltr" style="text-align: left;" trbidi="on">
Today I had a chance to take a look at J-Meter, a load tests tool, which most important feature is that it's free.<br />
<br />
It took up to 10 minutes of my time to generate a simple HTTP request load test. In this sense, I would not call the tool UI intuitive. But once you've done your first test you should have no problems in the future. It just takes time to get used to unusual way of handling test components. Instead of enabling or using controllers and entities you simply add them to your test plan.<br />
<br />
I liked the way you add more summary and reporting to your test. You may enable only those reporting ways that you prefer. However I found the charting slightly difficult to use and cheap-looking. But to me this is not a big problem as I usually value table output over charts.<br />
<br />
Overall impression is that tool is capable of helping you out with simple load tests. But I would not recommend it for testing big and complex systems. You better look at commercial competitors.<br />
<br />
In case when your financial restrictions prevail this is a good choice. But be prepared to spend more time for generating and supporting the tests than it would have been should you use a more advanced tool.</div>
Anonymoushttp://www.blogger.com/profile/03428406119776865921noreply@blogger.com3tag:blogger.com,1999:blog-7362727475792978259.post-46521046172786521132012-10-21T22:11:00.000-07:002012-10-21T22:11:14.105-07:00Automated testing (to be or not to be)<div dir="ltr" style="text-align: left;" trbidi="on">
Many want to do automated testing. Not many start doing so. Few succeed. The reason why hides in the way we used to do our work and how we assess the performance. We prefer to see the results straight away, on the spot, now. Whereas it takes a while for automation to start paying back. The difference in time and efforts before it starts doing so can be recognized as a waste. In other words you would get an immediate result if you'd manually test your application instead of re-writing map files after UI change. Defects found and removed from the system is what is being scaled against investment in automation that will start paying back in months.<br />
<br />
On the other hand, having automated tests saved many projects putting them back on track timely. The beauty of automation is that you so not need to make trade-offs, select regression tests carefully, adjust plans, and procure more resources if you found that more testing is required. You just run them all (except for the situation when there are too many or your resources are limited).<br />
<br />
The dilemma grows even bigger when you project size grows. For big projects this is even more difficult to find resources for automation, the lead time is even longer, however the outcome is usually more tangible. You should have firm intention, high motivation, and be prepared for a challenge if you want your automation to start paying back one day. Below are simple recommendation for those who started on this path:<br />
<br />
- Get commitment from the management, sell off the idea.<br />
- Set right expectations in stakeholders (automation will start paying back when we reach X% of tests automated; usually about 30 if you start from the most important ones).<br />
- Plan efforts for automation (don't expect people to spend their free time due to pure enthusiasm).<br />
- Stick to the plans, treat automation goals as project goals, equal in the priority.<br />
- Allow enough contingency buffers in your plans, so automation will not suffer just because something happened and your plan does not have any fat to cope with the situation.<br />
- Get skilled hands to work on automation (test automation is more of programming that testing, so make sure people who do it are rather developers).<br />
- Follow best practices in code engineering. It will save you massive efforts in maintenance. Make test code isolated from accessibility functions and GUI maps.<br />
- Run your tests often not to allow them get outdated, so as it is not reasonable to invest in the updating. A test that sits n the shelf a year will unlikely work any more. Now imagine that you have got thousands shelf-ware tests.<br />
- Use data-driven and control-driven approach.<br />
- Involve more people by implementing pseudo-languages (a command driven test with a language that anyone can easily use to create test sequence; such a sequence drives the test code responding to the commands and data parameters in it).<br />
- Consistently deliver the message that automation is not an immediate ROI. Nonetheless it's got one of the biggest ROI in the software industry.<br />
<br />
If you follow this you would save yourself tonnes of nerves.<br />
<br />
Good luck!<br />
<br />
<br /></div>
Anonymoushttp://www.blogger.com/profile/03428406119776865921noreply@blogger.com0tag:blogger.com,1999:blog-7362727475792978259.post-38695031061131119702012-10-02T18:07:00.001-07:002012-10-02T18:07:12.961-07:00Meteor approach<div dir="ltr" style="text-align: left;" trbidi="on">
Yesterday I've finally fulfilled my wish and tried out Meteor. This is a new framework for developing web applications using JavaScript as the main language.<br />
<br />
I just loved how easy it is to create a site and how few lines of code it requires. I also liked the way how it makes the changes immediately reflected in the running application.<br />
<br />
But the most valuable tome is the ability to move the functionality between client and server with no efforts. There are actually three folders: one for server, one for client, and one for both. Moving stuff between them you change the architecture of your system. This may be very interesting for balancing complex systems load. For example, you have a client-server system which should support 1000 simultaneous users. You are kind of limited on the amount of horse power under the hood, the server is rather weak. So you may decide to move as much of computation as reasonable to the client side. In the traditional system it would require a careful planning and decent programming. In Meteor this is just a matter of Cut/Paste the Try. So you can easily adopt trial and error method.<br />
<br />
Meteor is built on templates. Everything is defined as a template and it requires quite a bit of abstract thinking if you want to design a new system from scratch. be prepared to start thinking in different categories.<br />
<br />
But Meteor is not only a framework. It's a Cloud. It takes just one command line call to deploy your application in a cloud. very easy and robust.<br />
<br />
Meteor uses a non-relational database in the back-end. I hope they will implement connection to other database engines in the future.<br />
<br />
Of the disadvantages I would mention using JavaScript, which is not object-oriented (despite some may argue, f.e. <a href="http://www.javascriptkit.com/javatutors/oopjs.shtml">http://www.javascriptkit.com/javatutors/oopjs.shtml</a>). Hopefully they will consider new replacement from Microsoft (TypeScript). Also there is only one database engine available yet (correct me if I am wrong). which also puts limitations on the system. We know that changing DB engine is not an option for many very complex systems. Allowing use of engines like Oracle, MS SQL Server, and DB2 would make that new framework more attractive to the enterprise software produces, including my company.<br />
<br />
System is still in development, so don't rely on it if you need to make a commercial package. The documentation is scarce but you may find several examples and tutorial videos on the Internet. It is definitely good enough for evaluation and playing around with it. Believe me it's a pure fun :)<br />
<br />
If you want to read more, just visit their site at <a href="http://meteor.com/main">http://meteor.com/main</a>.</div>
Anonymoushttp://www.blogger.com/profile/03428406119776865921noreply@blogger.com2tag:blogger.com,1999:blog-7362727475792978259.post-79505543427857007532012-09-21T20:28:00.001-07:002012-09-21T20:28:22.810-07:00CTO - Rethinking the priorities<div dir="ltr" style="text-align: left;" trbidi="on">
Do you know what is takes of a person to jump up from the quality assurance world into the leading production role? I do as after having more than 12 years of quality management experience I got an opportunity to head up the entire development operation.<br />
<br />
This always looks easy when you are judging based on a limited understanding of the complexity f someone's else job. The best football players are always those sitting on the sofa. You have probably seen your boss acting and thought that you could do no worse. Actually you don't know until you try it out. I was thinking somewhat the same too.<br />
<br />
Now I learned the difference and it's huge. I never knew how much of a company success depends on the personality of its leaders. Being a leader is the responsibility. The team is very sensitive to your own conditions. They see how you do and try to do the same. If you go lazy, the team does the same. If you are working hard the team catches up.<br />
<br />
But the most complex thing was wear a new role on the team. Instead of quality perspective only I have got budget and business goals to drive my actions. I learned how to compromise quality when it is required. Yes, I did those obscene for which I hated CTOs with whom I worked before. This does not mean I am a bad person now (hope you don't think so:)). This only means that I understood and adopted a new role.<br />
<br />
The moral of this story is that we should always be flexible and be prepared for a change. If we don't we will hardly be able to feast on the opportunities.<br />
<br />
Good luck in changing the world through changing yourself!<br />
<br /></div>
Anonymoushttp://www.blogger.com/profile/03428406119776865921noreply@blogger.com0tag:blogger.com,1999:blog-7362727475792978259.post-60940924781442090322011-10-05T07:44:00.000-07:002011-10-05T07:45:04.377-07:00The interview reveals it allHave you ever repented of a wrong choice that you've made on the interview? If you haven't then you've done not enough screening or you are not a human being :)<br />
<br />
To begin with, interviews last for about 40 minutes in average and the mission is to get to know a person. I doubt it can be done in such a short time to the full extent despite all the efforts. As we know a person reveals best in the specific circumstances, the ability to cope with stress is only visible under stress, the ability to play in a team can only be seen in a team. But we cannot simulate all those conditions This means that we have to use the only means that we have at hand.<br />
<br />
First of all, we ask questions and evaluate responses. It gives us some idea on the type of a person that we talk to. But this is only a part of the full story. The most important is to watch the person carefully and see what his or her body and mimic tell you. Body language can speak better than a candidate himself.<br />
<br />
By paying due attention to not only what is said but how is said by a interviewee, you can even learn whether what is said is true or lie. Changes in the intonation, strange abrupt movements, grimaсes, looks sideways - are the clues to note.<br />
<br />
Another thing to do is to compare what you are told with what you see. For example, if a candidate is wearing a stained clothes but keeps telling you about how diligent and accurate he is, you have a good reason to doubt the words. There should not be any conflict between your perception of a candidate and the story that he tells you. If there is any, don't hesitate and ask at the interview. Not doing it would be a big mistake and means only the postponing a problem for later.<br />
<br />
Last but not least, always trust your sixth sense. Never give job to someone to whom you have the slightest disbelief. I did it myself in the past for a few times and I regret it later pretty much. To my credit I also rejected much more candidates only based on that slight doubt and I never regret any of those choices. So, this is obviously more painful to make a wrong choice then not to make the right one.<br />
<br />
Hope this helps all of you who are looking for bright minds over there!<br />
<br />
<br />Anonymoushttp://www.blogger.com/profile/03428406119776865921noreply@blogger.com0tag:blogger.com,1999:blog-7362727475792978259.post-90664080239572188332011-09-28T05:14:00.000-07:002011-09-28T05:15:35.915-07:00Customers to interview your employeesWorking in an outsourcing company I face different requirements from the customer side, including the need to screen the candidates themselves. Despite the reason of this is very clear to me, I cannot agree with this approach due to many reasons. Below I'll try to explain why I think that we should not indulge customer to interview employees before signing them on to the project.<br />
<br />
To begin with no one knows your employees better than you. As a manager you have a long record of achievements and know the weaknesses and strong points about a candidate. You know the specific of the project and can match them against the qualities of the employee. So, you have all the means to choose the right candidate better than the customer. Involving the latter in the cycle seems redundant in this respect.<br />
<br />
In addition to this, during the life we all learn the people who live in same area pretty well. Oppositely, we know near nothing of the people who live in a completely different environment, cultural and economical. What would you expect to learn about a person who come from the very different culture, having no possibility to read his body language correctly? This is a bad idea to screen candidates of different culture not having someone who can read the candidate effectively.<br />
<br />
Finally, the desire to choose candidates is the sign of doubts in your qualification or trustworthiness, which is not a good thing for building an open and relationships between contractors.<br />
<br />
In the conclusion I would like to recommend everyone to avoid involving customers into the process of selecting project teams, unless those customers have the profound knowledge of the culture, a good experience of doping reviews, and take your opinion of the candidates really seriously, so they can make a balanced decision. In most of cases, this is enough to just select the teams on your own. All the customers should care about is the result. And this is your responsibility to provide it, so you must have all the means needed at your disposal, including recruiting and hiring.Anonymoushttp://www.blogger.com/profile/03428406119776865921noreply@blogger.com0tag:blogger.com,1999:blog-7362727475792978259.post-74087441145821471332011-07-12T00:20:00.001-07:002011-07-12T00:30:05.087-07:00CMM - a long way to perfectionLately one of the customers expressed the great desire to step on improvement path. They have chosen CMM for a beacon. I appreciated their choice and proposed my help as I was-there-done-that so to speak.<br /><br />First they have assess as being at CMM2 already which caused a lot of suspicious on my side. First of all, they do not have plans. Even if they do they never follow those. Second, they do not have requirements in any form. Third is the communication. News, issues, problems, goals and the rest are just broad-casted to everyone in hope that a person to whom the message is addressed will somehow guess it. In sum, the whole project performed by another contractor (not my company) looks like a mess or a chaos. The chance that a good product appears out of it is as big as the chance that our country's football team takes the gold in world championships.<br /><br />I estimated the organization as being at initial level of maturity model and suggested to stick to the selected list of improvements that I like to provide here to your attention. If you have any comments or feedback just let me know. You opinion is important to me.<br /><br />I sat down and though of the following changes to be made right away. There are no details so far, just a list, so if there is any ambiguity please ask me for the clarification.<br /><br />1.<span style="font-weight:bold;"> Planning</span><br />a. There must be a plan and everyone must think it’s important<br />b. Plans must be realistic<br />c. Risks should be taken into account while planning<br />d. I can provide a template for the start<br />2. <span style="font-weight:bold;">Product requirements engineering</span><br />a. Elaborated before the development starts<br />b. Reviewed by all parties involved<br />c. Corrected accordingly to review issues and adjusted to the needs of everyone<br />d. Numbered uniquely<br />e. Versioning for requirement documents<br />3.<span style="font-weight:bold;"> Development</span><br />a. Prototyping<br />i. Throw away, do not evolve<br />ii. Once you have a solution then sit down and design how to implement it into real product from the scratch!<br />b. Architecture design prior to coding<br />c. Module design before coding<br />d. Review design (peer or by system architect)<br />e. Continuous code review<br />f. Test before letting it out (unit or developer testing)<br />g. Make issues visible by means of metrics, so everyone knows that a failure will be seen to others<br />4. <span style="font-weight:bold;">Testing</span><br />a. Test planning<br />b. Test strategy elaboration (test plan)<br />c. Test design (test cases)<br />d. Iterative testing<br />e. Regression testing<br />5. <span style="font-weight:bold;">Tracking changes</span><br />a. Make changes visible to everyone<br />b. Adjust plans and risks timely<br />c. Make trade offs<br />6. <span style="font-weight:bold;">Release procedure</span><br />a. Feature freeze date<br />b. Code freeze date<br />c. Make only really important changes and fix really important issues<br />7. <span style="font-weight:bold;">Communication</span><br />a. Communicate the goals clearly and at all levels (let them know the stakes)<br />b. No broadcasting, there should be one (known to everyone) person to answer a specific question <br />c. Defined project roles<br />d. Single points of contact on planning, requirements, development and testing<br />e. Reporting and metrics<br />f. Periodic team meetings (Skype, phone calls)<br />g. Focus the team on one thing at a time<br /><br />Look forward to your feedback!Anonymoushttp://www.blogger.com/profile/03428406119776865921noreply@blogger.com0tag:blogger.com,1999:blog-7362727475792978259.post-57277879768913719342011-06-23T04:32:00.001-07:002011-06-23T04:43:27.417-07:00CEO, are you ready to change?Many want to get better in sense of product quality their organization produces. Few actually get successful. Many of those who don't blame their managers for not performing to the expected level and bla-bla-bla. Meanwhile, the problem may be in the leader him- or herself.<br /><br />The goal of making better quality implies changes throughout the organization. The head is not an exception. The problem with bosses is their belief they can drive things with only desire. Well my daughter is 4 yours old and she also believe she can ;) When you are about to start changes in the company start from yourself. This is very easy to think that someone else will do all the hard job. Ho one will be in position to do this if the problem that prevents changes is at the top because ho one has authority to affect boss' behavior.<br /><br />Late changes is a killer of quality processes. Even agile can't stand late changes. If you are boss then you must learn "enough is enough" principle. Learn to distinguish "a must" from "nice to have" to avoid forcing your team and processes to collapse into late changes nightmare. More important things may be affected because what boss wants comes first attitude.<br /><br />Yes, most of top guys are very selfish and addicted to the thing that they are the only persons who know how to drive things. This is far not always so. Let other drive for a while and see what happens. Sometimes you even have to become followers. Listen to what quality people tell you very carefully and trust them when you are even not sure they do what you think is right. They are people who know their work better than you. Don't pretend you can cook better than a chief at your favorite restaurant ;)<br /><br />Sorry, for being a bit clumsy. I have little time. Now back to work and remember - ENOUGH IS ENOUGH :)Anonymoushttp://www.blogger.com/profile/03428406119776865921noreply@blogger.com0tag:blogger.com,1999:blog-7362727475792978259.post-60293818756384800052011-06-08T07:32:00.001-07:002011-06-08T07:33:50.439-07:00Load testingToday I have written to a customer on what we usually do about load/performance testing. I decided to put it here should I need it again as well as to help you organize our load testing activities.<br /><br />***<br /><br />Load testing usually start from learning about the customer's problem. Every load testing session is unique and this is very important to start moving right direction from the beginning.<br /><br />After learning the purpose of testing we develop testing strategy. Test strategy include the definition of load scenarios (how many virtual users are to be involved, where to put the load in the system (at which hierarchy level), what type of scripts to use (simulative or fast), etc.)<br /><br />Then we start working on scenarios. Scenarios are the individual scripts which will be played back by virtual users. Customer input is vital because domain knowledge is the key to creating the right set of scenarios.<br /><br />Then we execute several test runs with different load level to see how server reacts and to make sure that load is adequate and test results are not affected by configuration or communication issues. Usually it takes from 5 to 10 runs to finalize test plans and conditions.<br /><br />A very tight communication with development representative and deployment team is very important. We have to make sure the testing is performed in clean conditions, whereas no one else can interfere and alter test results.<br /><br />During the testing we usually set up server-side monitors to find the resource-bottleneck, if any.<br /><br />***<br /><br />Having done all above you will make sure that the problem is solved, not just a load test performed.Anonymoushttp://www.blogger.com/profile/03428406119776865921noreply@blogger.com0tag:blogger.com,1999:blog-7362727475792978259.post-45117771892559636552011-06-01T06:12:00.000-07:002011-06-01T06:53:26.854-07:00Risk management in Test PlanningDid you ever ask yourself what testing does in the big perspective? Surely you did :) My answer would be: testing is reducing the risk that users will face any issue with the software. In this respect this is very close to what other engineering specialists do. Same way they reduce risk that building collapses on a severe earthquake or that a car will suddenly be on flame while you drive.<br /><br />Did you ever wonder what techniques other engineers use? Well, I guess most of didn't, in which case this article will be of help.<br /><br />I have worked with the software that implemented one of most used strategy for risk reduction - Failure Mode and Effect Analysis (hereafter FMEA for the sake of conciseness).<br /><br />The key in risk management is keeping the possible bad effects in sight. So, it's all about perception. You need to imagine what can go wrong with your application in user hands and build up the strategy how to prevent that particular risk from happening. In case of car manufacturing there can be the risk of losing a wheel at a high speed. Engineers will think of special means to prevent a wheel from spinning away even if the nuts get loose. Solving one such problem engineers advance to the next one, starting from most severe one (severity is this case is a combination of probability and impact).<br /><br />Now back to the software testing. The risk that our users may face are caused by software defects. Of course this is unrealistic to foresee the defects. But we can foresee the consequences of malfunctions. Let's start from the very beginning. The very first thing a user do is trying to set up the application. So, the worst thing that may happen is setup failure preventing further use of the software. We have found the failure mode, but this is not enough to start creating prevention strategy as this risk is too obscure. The point is to be as precise in description mode as possible.<br /><br />The setup may fail in many different ways:<br /><br />- Setup failure in the default setup conditions<br />- Setup failure due to changing setup options<br />- Setup failure in unattended mode<br />- Setup failure while running through the deployment center<br />- Setup failure due to software compatibility <br />- Setup failure due to hardware compatibility <br />- Setup failure due to old version compatibility<br />- Setup racing failure<br />- Setup performance is unacceptable low<br /><br />Now we have the list of possible failure scenarios that can be addressed by testing. Each of the items above has a different combination of probability and impact. For example, "Setup failure in the default setup conditions" may have low probability but highest impact. Meanwhile, risk "Setup failure while running through the deployment center" may have lower impact but the highest probability.<br /><br />FMEA has a lot of templates that will help to summarize and analyze this information. You can easily find the on the internet. Most of those will be overburdened with the information you will hardly need in analysis, so I suggest my own variant of the table:<br /><br />## | Failure mode | Impact | Probability | Prevention | Comments |<br /><br />Prevention depends on the context, so I can only provide you several examples.<br /><br />One of the systems that I worked on with test team was a very old and big client-server. The reliability was the real problem, so I have put this risk on a table and started to think of the ways to change things to better. The probability of the failure mode was estimated as medium, the impact was highest. Prevention included non-stop automated reliability tests on a dedicated server 24x7. In result, it helped to find major issues that could never be found by other types of testing.<br /><br />So, the bottom line is:<br /><br />- Strategies developed in other industries work in software development too, so don't just neglect those finding only because we-are-so-different. This is not the case, nor the excuse.<br /><br />- Try to foresee possible failure scenarios.<br /><br />- Build up prevention strategy (which can include not testing only, but all process stages)<br /><br />- Define a plan where all the required prevention steps will be listed.<br /><br />- Work to the plan but keep an eye on FMEA table. Things may change as you go. So, the correction may be needed.<br /><br /><br />Hope this helps! I would be happy to learn what you think.Anonymoushttp://www.blogger.com/profile/03428406119776865921noreply@blogger.com0tag:blogger.com,1999:blog-7362727475792978259.post-47164182866263316962011-04-22T01:39:00.000-07:002011-06-01T07:26:34.703-07:00Estimation of testingIf you need to ground testing estimates on development estimates then read on.<br /><br />This is definitely not the best way of producing testing estimation. It would be more correct to ask development and testing do their estimates independently. Later on you can use both estimates to analyze the difference and to arrange those properly.<br /><br />In most of cases testing takes from 30% to 35% of development estimates. Taking 35% you will lend enough time for your team to complete the goals on time and with due quality.<br /><br />But be careful! There can be tasks, which execution may run out of the initial estimates. For example:<br /><br />• Performance testing<br />• Load testing<br />• Compatibility testing<br />• Testing on a real (big) amount of data or in real hardware<br />• Reliability testing<br />• Test automation<br />• Complex environment setup<br />• Complex business area (business context)<br /><br />All above as well as the risks and any kind of exotic testing should be estimated <span style="font-weight:bold;">separately</span> and the result should be added to the initial rough estimates.<br /><br /><br />Here is the full algorithm as I see it:<br /><br />1. Both developers and tester do their estimates separately.<br />2. Then estimates are compared and the difference is being explained.<br />3. If the ratio in estimates is as expected you are done.<br />4. If not - the difference is explained and a corrective actions are taken.<br /><br /><br />Notes:<br />• Do not take the biggest "just in case" - this is inefficient.<br />• Do not take the "most trustful" - explain. <br /><br /><br />The biggest ratio I have ever met in my career was 41% of development efforts. It was due to heavy use of test automation and with complex test environment.<br /><br />Happy estimation! :)Anonymoushttp://www.blogger.com/profile/03428406119776865921noreply@blogger.com0tag:blogger.com,1999:blog-7362727475792978259.post-87390959057775005142011-01-14T05:37:00.000-08:002011-01-14T05:51:33.170-08:00Performance AppraisalsMany of you have heard of this, some were even appraised and few where directly involved in creation of such reviews. No doubt, reviewing someone's contribution helps to develop skills required to drive the team to strategic goals as well as to avoid silly mistakes. But today I am not going to judge upon the process of performance reviews, nor I am here to express ideas on how to do it right. The mere fact I am writing this is to resolve a potential risk for those of you who just start to implement this process.<br /><br />Some believe that performance appraising (PA) is a great tool in managing someone's... expectations of the compensation. So, it's... wrong! <br /><br />We should not mess together things that are better to keep apart (herring and milk so to say), things that serve different purposes. Compensation is a way to keep employee from leaving the company. PA is a tool in hands of a manager but it is written for the employee. These goals are not the same. If you pretend they are, you will end up having a logical inconsistency because if you introduce salary parameter into equation then you will inevitably write a review which will serve your goals on keeping the salaries down or keeping the employee. Anyways there will be no "written for employee" thing anymore.<br /><br />So, don't mess it up. Write reviews in order to help people to develop the required skills and fix the problems. Use salary to keep and motive people to move ahead. No need to blend it all together if you want to stay mentally healthy ;)<br /><br />If I confused things for you just leave me a note. It's my bad and I will do my best to help you out :)Anonymoushttp://www.blogger.com/profile/03428406119776865921noreply@blogger.com0tag:blogger.com,1999:blog-7362727475792978259.post-83962144130353593902010-10-13T05:51:00.000-07:002010-10-13T06:33:11.651-07:00ISC UI testing architectureSeveral days ago, while working on a following test automation project for a desktop application an idea how to make it right the first time has struck me. This is the first time I am writing on this matter, so be my co-authors and provide any thoughts which happen to come to your mind while reading this. Any feedback will be greatly appreciated.<br /><br />Dealing with UI looks simple at the first glance but it is rather tricky afterwards. All the time you have to do some UI testing (confirmation messages, cancel buttons, input error messages and the like) you have to step back and to change (refactor) the code that you have already wrote.<br /><br />For example, you have created a function that opens a project file in your application. It takes the name of the file for the input parameter. Then it click menu File/Open, fills in file path and click button Ok.<br /><br />You created the tests that rely of that function. Several tests may open different files and validate their content. But now you need to create a test, which will open an incorrect file. In result you shall see a message telling you what is wrong with it. But your original function does rely on smooth flawless file opening. It does not take into account any errors which may come up. So, we go back to the original file opening function and refactor it in order to fit both needs (usually it is done by creating a new function that does only part of the job). <br /><br />This is only on example of hundreds or even thousands for a big project. And any time you have to step back, do changes and test the changes. This is tricky and error-prone.<br /><br /><span style="font-weight:bold;">Instead I am suggesting DOING THINGS RIGHT THE FIRST TIME - Invoker-Setter-Confirmer (ISC) test architecture.</span><br /><br />ISC is a UI test architecture that allows you to think in terms of functional bricks of which you can build any kind of UI based tests. You will not need to go back afterward, I promise. If you do, I am gonna eat my hat :)<br /><br />ISC stands for the set of functions, each with its own purpose described below.<br /><br /><span style="font-weight:bold;">Invokers</span> - functions responsible for making a UI element to appear on the screen. In most cases it can be done with more than one way (File Open dialog may be caller through menu, toolbar, accelerators and hot keys).<br /><br /><span style="font-weight:bold;">Setters</span> - functions responsible for setting input values into UI element. For example, find dialog requests user to set a string to find, direction of the search and other properties. All those values shall be set through a setter functions.<br /><br /><span style="font-weight:bold;">Confirmers</span> - functions which do some actions with UI element. For a dialog they click a button or close it with Esc or Alt+F4. Just like invocation the confirmation can be done in different ways.<br /><br />The best way to explain it is to show an example. Here is goes.<br /><br />Everyone has a Notepad program (Mac users, I am very sorry). Let's create ISC-based library for Find dialog.<br /><br />// code is in Java Script<br /><br />// constants<br />notepad = Aliases.notepad;<br />wndNotepad = notepad.wndNotepad;<br /><br />ACCELERATOR = 1;<br />MENU = 2;<br />HOTKEYS = 3;<br /><br />OK = 10;<br />CANCEL = 11;<br />ESC = 12;<br />ALTF4 = 13;<br /><br />//////////////////////////////////////<br />// Invoker<br />//////////////////////////////////////<br />function InvokerDlgFind(method) {<br /> switch(method) {<br /> case ACCELERATOR :<br /> wndNotepad.Keys("[Ctrl]F");<br /> break;<br /> case MENU :<br /> wndNotepad.MainMenu.Click("Edit|Find...");<br /> break;<br /> case HOTKEYS :<br /> wndNotepad.Keys("[Alt]EF");<br /> break;<br /> default:<br /> InvokerDlgFind(MENU);<br /> break;<br /> }<br /> // No more code. Just show this thing on<br /> // the screen and leave.<br />}<br /><br />//////////////////////////////////////<br />// Setter<br />//////////////////////////////////////<br />function SetDlgFind(toFind, case, direction) {<br /> dlgFind.Edit.wText = toFind;<br /> dlgFind.checkMatchCase.ClickButton(case); <br /> if(direction) {<br /> dlgFind.radioUp.ClickButton();<br /> } else {<br /> dlgFind.radioDown.ClickButton();; <br /> }<br /> // that's it! Setters do not do anything else.<br />}<br /><br />//////////////////////////////////////<br />// Confirmer<br />//////////////////////////////////////<br />function ConfirmDlgFind(method) {<br /> switch(method) {<br /> case OK :<br /> notepad.dlgFind.btnOK.ClickButton();<br /> break;<br /> case CANCEL : <br /> notepad.dlgFind.btnCancel.ClickButton();<br /> break;<br /> case ESC : <br /> notepad.dlgFind.Keys("[ESC]");<br /> break;<br /> case ALTF4 : <br /> notepad.dlgFind.Keys("[Alt][F4]");<br /> break;<br /> default:<br /> ConfirmDlgFind(OK);<br /> break;<br /> }<br />}<br /><br />// Now how it looks in the tests<br /><br />function Test_Find_Succeeded() {<br /> // open test file<br /><br /> InvokeDlgFind(MENU);<br /> SetDlgFind("123", false, true);<br /> ConfirmDlgFind(OK);<br /><br /> // verify find result<br />}<br /><br />function Test_Find_NotFound() {<br /> // open test file<br /><br /> InvokeDlgFind(MENU);<br /> SetDlgFind("456", false, true);<br /> ConfirmDlgFind(OK);<br /><br /> // verify message "not found"<br />}<br /><br />function Test_Find_EmptyInput() {<br /> // open test file<br /><br /> InvokeDlgFind(MENU);<br /> SetDlgFind("", false, true);<br /> <br /> // verify button is disabled<br />}<br /><br />Hope this helps. Will be glad to hear from you on this matter.Anonymoushttp://www.blogger.com/profile/03428406119776865921noreply@blogger.com0tag:blogger.com,1999:blog-7362727475792978259.post-80511455427729941642010-09-28T04:04:00.000-07:002010-09-28T04:19:31.693-07:00Defect tracking workflowLately I was involved in creating yet another defects tracking workflow for a big outsourcing company. The goal was to define a standard way of tracking defects keeping in mind the support for defect analysis and prevention.<br /><br />The task per se does not look too difficult. In most of cases, the standard workflow that your DTS has embedded will do the job four you. But it does not in our case. The workflow for defects defined as default in JIRA is too minimalistic. We used to have additional states and transitions that we want to be noticed and filed by the system.<br /><br />So we have come up with several additional states. Some default states were renamed. Some transition rules were added and permissions changed. But I do not want to get into a boring description of how we were doing it. I want to outline what I think is most important in building workflows:<br /><br />1. Keep it simple, stupid!<br /><br />The all times rule of thumb is more than just applicable here. We can ideate dozens of states and hundreds of names for transitions in pursue for the perfection. But do we really need to get perfect in this case? get back to the intention that you had starting all this. The intentions were: have means to automate defect tracking to make sure nothing is wasted or lost; have data records to support learning from mistakes; have means to control the project effectively. That's it! So, if you have enough states and transitions to satisfy those requirements - stop right there, don't go any further.<br /><br />2. More flexibility, more problems<br /><br />If you allow to much flexibility in sense of who does what in the DTS you lend yourself and your colleagues for numerous mistakes. This is always better to let people do only those actions that they are supposed to, no more. In terms of defining workflows it gets down to defining user groups and assigning permitted actions for those groups. Once you've done it you are sure that no issue will go a wrong path.<br /><br />3. Self explanatory, intuitive names<br /><br />States, transitions, priority and severity of issues - all this must not require additional explanation. Name "Deferred" or "Postponed" is better than "Not for fixing" or "Not important".<br /><br />4. Test it twice before going live!<br /><br />Have somebody else to go through the workflow before letting others use it. I did for my last installment and I wasn't surprised to fix 6 critical issues in it despite I was sure I passed it through myself.<br /><br />Happy workflow engineering! :)Anonymoushttp://www.blogger.com/profile/03428406119776865921noreply@blogger.com0tag:blogger.com,1999:blog-7362727475792978259.post-60060459824396954002010-09-20T03:06:00.000-07:002010-09-20T03:07:55.706-07:00S60 emulator connection problemIf you experience this problem the first thing to try is:<br /><br /><span style="font-weight:bold;">- In Eclipse go to Window / Preferences / Debug and set timeouts to 100000.</span><br /><br />If it does not help then try...<br /><br /><span style="font-weight:bold;">- to start emulator manually in Dedug mode and then start debugging from Eclipse.<br /></span><br /><br />In case the latter did not help and you receive something like "You could start only one instance of..." then <span style="font-weight:bold;">close emulator and start it again</span>.Anonymoushttp://www.blogger.com/profile/03428406119776865921noreply@blogger.com0tag:blogger.com,1999:blog-7362727475792978259.post-39877222827082564692010-09-15T00:26:00.000-07:002010-09-15T00:29:00.153-07:00TestComplete 7.X refuses to recognize .NET objects?If you cannot see .NET objects with appropriate icon in Object Browser, then most likely you have no corresponding plug-in installed or you have .NET 4.0. Check you extension settings and install .NET plugin. In the later case uninstalling .NET 4.0 will not solve the problem. You will need to re-install whole system. Alas!Anonymoushttp://www.blogger.com/profile/03428406119776865921noreply@blogger.com0tag:blogger.com,1999:blog-7362727475792978259.post-91980070313165661852010-09-15T00:25:00.000-07:002010-09-15T00:26:25.412-07:00LoadRunner crashes on recording?Here is the cure...<br /><br />1. Control Panel / System<br />2. Advanced<br />3. Performance Settings<br />4. Data Execution Prevention<br />5. Turn on DEP for essential Windows programs and services only.<br />6. Restart!<br /><br />That's it :)Anonymoushttp://www.blogger.com/profile/03428406119776865921noreply@blogger.com0tag:blogger.com,1999:blog-7362727475792978259.post-24462021663135743752010-09-10T05:07:00.001-07:002010-09-10T05:11:15.394-07:00Load testing is not easyRecently I have convinced in it myself yet another time. The task looked as simple as generating load on a site accepting several files for parameters. As usual it was easy to record and parametrize scripts, debug and plan the first load.<br /><br />The difficulties appear during the testing. Every time when I approach load testing the results kind of amaze me. They are not what I would expect. This time was no different. I was amazed and did at least 5 times more test execution than planned originally.<br /><br />Thanks to my managerial experience I have lend myself some time for contingencies. So it worked well and I met the deadline :)<br /><br />Every time you plan for load testing keep in mind that this is investigation rather than determined work in sense that we put in it when we approach planning.Anonymoushttp://www.blogger.com/profile/03428406119776865921noreply@blogger.com0tag:blogger.com,1999:blog-7362727475792978259.post-22766376970815524052010-08-31T00:48:00.000-07:002010-08-31T01:20:37.490-07:00What a developer wants?After so many years of driving testing and QA processes I have some possibilities to realize and rights to publish here some of ideas on how things are working from the inside. One of such things is what developers ask of a QA manager.<br /><br />My top 5 are following:<br /><br />1. Change defect tracking system<br /><br />2. Stop reporting duplicates and non-defects<br /><br />3. Do no find defects too late<br /><br />4. Stop reporting minor/cosmetic defects in such a number<br /><br />5. Test design is not review-able<br /><br />Now back to the details =)<br /><br /><span style="font-weight:bold;">Change the defects tracking system</span> I am always happy when people come to me with their ideas which they think will help them doing their work better. However, I don't like when it stems from the "I don't know what is wrong but I feel that something needs to be changed" intention.<br /><br />In the past, developers came to me complaining that it takes too much time to work with defects. The only solution they saw was to change the tracking system. I asked in respond what exactly does take time when they work with it. As it turned out the reason of their complaints is not in the system per se but in the time they had to spend understanding the defect and trying to reproduce it. No defect tracking system can change that, so they went out in peace with the idea to leave the old system. Others developers came after... period =)<br /><br /><span style="font-weight:bold;">Stop reporting duplicates and non-defects</span> Yes, this is a problem. But let's see how big it is. On my memory we reported not more than 1% of bad defects. Is that so huge to be whining about at each managers meeting? Nope. Then what was it?... I'll tell you. This is an excuse for not doing own job right. Kind of "hey! they also have problems". It makes them look better in they eyes. What a shame! =)<br /><br /><span style="font-weight:bold;">Do no find defects too late</span> Another problem for testers. We have to find serious problems as soon as they appear in the code. There is no excuse... Wait a minute! What issue are speaking about? That one that developers introduced in the same build? How do you think testers could find it earlier?... We hear such acquisitions too many times. Make sure you take the blame for your own mistakes.<br /><br /><span style="font-weight:bold;">Stop reporting minor/cosmetic defects in such a number</span> The answer is "stop reading them". It's easy =)<br /><br /><span style="font-weight:bold;">Test design is not review-able</span> In majority of cases they just don't care to put some efforts in this. This is merely a laziness that cannot be an excuse :) However, providing a summary of your tests design is always helpful. Remember, those who read your design help you making it better, so it's in your interest to make it easier to them.Anonymoushttp://www.blogger.com/profile/03428406119776865921noreply@blogger.com0tag:blogger.com,1999:blog-7362727475792978259.post-74097584266752573662010-08-31T00:34:00.000-07:002010-08-31T00:43:33.487-07:00Certification... Again?!Today I responded to the question about certification one of IT professionals here in Belarus. She was interested in my opinion about the certification as it is. I once told to one of testers who came to me for the interview that it is important that one cares to have one. On another hand I said many times that I don't care if one has a certificate up his or her sleeves. <br /><br />I will try to explain it here. Once and for all =)<br /><br />Firstly, I repeat I don't believe in certification because it is a try to provide a universal approach and solution to everything. Who does believe that it is possible? I personally don't.<br /><br />What I believe is personal abilities to think, to solve problems and to actively drive to the goals. This is what I am looking in people. Not just a prove they have heard something about the matter.<br /><br />The only reason I said this is important is because a person who acquired it cared to manage her career, minded to get new knowledge, which are good intentions. However, reading a professional book would do the same, not to say it would be better than most of certification programs.<br /><br />Hopefully, it helps =)<br /><br />P.S. From business perspective it also doesn't matter. Testers with and without certification are equally profitable for the company, so the compensations are the same. The fact that the company has engineers with certificates does not help at winning new projects.Anonymoushttp://www.blogger.com/profile/03428406119776865921noreply@blogger.com0tag:blogger.com,1999:blog-7362727475792978259.post-60891282669387976742010-04-28T01:09:00.000-07:002010-04-28T01:23:43.371-07:00"Look into the roots"One of my colleagues who wanted to leave has claimed that the company has done something wrong to him, so he could not stand being in it any more. After 30 minutes of talking to him I could not make an idea what the reason of his complaints is as well as the complaints themselves remained the mystery to me.<br /><br />He named such things like advertising that we are looking for a senior specialist and did not bother to suggest that position to him. That's was unfortunate because we considered him on very that position several months and he did not manage to impress the customer well enough. I asked "why didn't you come to me to discuss it?" He responded that "Anyways, this is not as big a problem as..."<br /><br />The next reason he called out was the lack of work in the crisis times. Well I accepted that was the case and many people were sitting on the bench whereas the company tried to find the work for them. They were underpaid but this was done to keep the team. Those who could not stand such conditions have found another job. But that colleague of mine didn’t. I asked him why and didn't get the response either. He used the same tactics and jumped to the next complain which was about his personal attitude to work. He insisted that it was not exciting enough. So this might be a case. Nonetheless this is not the type of a problem one could not decide with a manager. But he never came to me with this.<br /><br />In the end I decided that he complains not about the conditions but about his own behaviors in those conditions. I quickly figured that I can do nothing about it and let him go to find himself in another place (I purposely did not use word "better" here).<br /><br />What the wisdom we could elicit from this short story? Obviously, if we cannot stand something or don't like something about our works or in more general sense about our lives them go an change it. Do not wait until the boomerang to hit you in the back. <br /><br />And never fake the reason why you leave the company. Aside from not giving a chance for the company to fix the problem you make a bad impression of yourslef, so no one will miss you after all.Anonymoushttp://www.blogger.com/profile/03428406119776865921noreply@blogger.com0tag:blogger.com,1999:blog-7362727475792978259.post-11378503931096713902010-04-16T04:55:00.000-07:002010-04-16T05:59:34.267-07:00Estimations in software testingToday I happened to read through the training course on estimates on testing. The method described was based on assuming the quantity of test cases. Knowing test cases you can relatively easily predict how much time you would need to execute them. But...<br /><br />The trainer lacked some underlying knowledge of making the estimates. I tried to pretend I am a newbie who came to the training with goal to learn new things. After such a training I would risk to get further from the truth than I was before. I could have my own undertsnading of the matter, which is more correct than the provided. <br /><br />Trainers beware! Your first commandment is "do not harm"! =)<br /><br />Some tips of estimates:<br /><br />- Consider all tasks including preparation, communication etc.<br />- Weight all factors influencing the tasks<br />- Break down task list into smaller tasks (2-3 days)<br />- Consider all possibilities what can go wrong<br />- Think of the risks<br />- Watch out of the optimism<br />- Know your resources<br />- Do estimates with more than one method and analyze the difference<br />- If you ask an expert, do not refrain to only one<br />- Never provide point estimates<br />- Provide estimation in a range<br />- Check out the estimate against other projects and analyze the differece<br />- Re-think risks<br />- Provide assumptions within the estimates<br />- Provide estimate with the level of confidence you have in them<br />- Present what you need to make the estimation more precise<br />- Validate estimation with other managers<br />- Check your estimate against estimates of other teams (testing vs. development, documentation vs. testing, etc.) and analyze the difference<br />- Add buffers for illness, turnover and other force major<br />- Beware of faulty level of precision (3 man days vs. 2.997 man days)<br /><br />Good luck! :)Anonymoushttp://www.blogger.com/profile/03428406119776865921noreply@blogger.com0