Tuesday, January 29, 2013

When your code's names are running afoul of ReSharper, it has a reason

Why ReSharper keep on suggesting to name the SocialFeedBOVM as SocialFeedBovm, PersonID as PersonId?


Following Microsoft guidelines, any acronyms more than two characters should be treated as a word in their own right.


XmlWriter instead of XMLWriter. System.Web.Mvc instead of System.Web.MVC.

LaserSword instead of LASERSword. Y'know, laser is an acronym http://en.wikipedia.org/wiki/Laser


Two letter acronyms should be written in all uppercase, e.g.:

IOWriter, not IoWriter. TRSocialFeedAI, not TrSocialFeedAi

LaserAI, not LaserAi. AILaserIOSword, not AiLaserIoSword

System.Data.DBConcurrencyException, not System.Data.DbConcurrencyException



Id is not an acronym, it's an abbreviation, so it should be PersonId, not PersonID.


For the ajax technology name, Microsoft invented XMLHttpRequest, they can be forgiven on that. XML was the vogue by the turn of the century, it should stand out on your marketing materials, library's naming conventions, etc. XML was good on the resume too, and so was JAVA (name derived from Java coffee, it's not an acronym. Just Another Vague Acronym is just a retronym) ^_^ Y'know JAVA will stand out as one of your skills when it is written in all uppercase, I digress.




But I think Microsoft was drunk when they made the rules for ID/Id:



ID
System.Runtime.InteropServices._Activator.GetIDsOfNames()
System._AppDomain.GetIDsOfNames()
System.Runtime.InteropServices._Attribute.GetIDsOfNames()
System.Type.GetTypeFromProgID()
System.Threading.Thread.ThreadID
System.Threading.Thread.GetDomainID()
System.Runtime.Serialization.ObjectHolder.ContainerID
System.Globalization.Calendar.ID
System.Globalization.CultureInfo.InvariantCultureID
System.Web.UI.Control.ClientID
System.Web.UI.Control.UniqueID

Id
System.AppDomain.GetCurrentThreadId()
System.AppDomain.GetIdForUnload()
System.AppDomain.IsDomainIdValid()
System.AppDomain.GetId()
System.Attribute.TypeId
System.TypeLoadException.ResourceId
System.Reflection.AssemblyAlgorithm.AssemblyAlgorithmAttribute.AlgorithmId
System.Runtime.Remoting.Lifetime.Lease.GetNextId()
System.Xml.Xpath.XPathNavigator.UniqueId
System.Data.OleDb.DBPropSet.PropertyId





Microsoft is drunk on DB acronym too. Following their own naming guidelines, they got the OLE right, it's a three letter acronym, hence should be written as Ole, but why on earth Microsoft written DB as Db? It should be written as System.Data.OleDB

Hmm.. I think we can't criticize them on those stuff, they called it naming guidelines, not naming rules. On things like this, there are no hard and fast rules, there are only guidelines (that was somehow being broken liberally), programming is being elevated to an art form :p





Sources:

http://msdn.microsoft.com/en-us/library/ms229043.aspx

http://10rem.net/articles/net-naming-conventions-and-programming-standards---best-practices

Wednesday, January 23, 2013

ReSharper always reminds us how pampered we .NET developers are


class Program
{
 static void Main(string[] args)
 {
  var list = new List<Person>();
  
  // ReSharper suggests to convert this code...
  var people = Mate.Create<Person>(list);
  
  // ...to the following code. .NET can infer the type, thus <Person> can be removed:
  var people = Mate.Create(list);
 }
}

public static class Mate
{
 public static IEnumerable<T> Create<T>(IEnumerable<T> list)
 {
  var ee = new ExcelExport<T>();

  return list;
 }
}

public class Person
{
   
}

public class ExcelExport<T>
{       
}

Sunday, January 13, 2013

Can we rewire our brain?

Like instead of...

private int MaxVLAllowed { get; set; }


...we do this instead:

int MaxVLAllowed { get; set; }


Instead of convincing ourselves "there could" be a nullable primary key...
create table Person
(
PersonID int identity(1,1) not null primary key,
PersonName varchar(100) not null
);


...we believe there's only one form of truth, i.e. primary key cannot be nullable
create table Person
(
PersonID int identity(1,1) primary key,
PersonName varchar(100) not null
);



Instead of thinking that both of you and the computer are both OC buddies...
if ( (ans == 'Y') || (answer == 'y') )


...just believe you're the only person on earth who believes not putting parenthesis around a comparison expression is confusing:
if ( ans == 'Y' || answer == 'y' )


Instead of inner joining...
select *
from alpha
inner join beta on beta.alpha_id = alpha.alpha_id

...why not just join them? i.e. remove the noise keyword inner:
select *
from alpha 
join beta on beta.alpha_id = alpha.alpha_id


Instead of computing numbers like this...
+1 + +9 - +7 * +6


...it's in our conviction that a positive number is implied when we omit the positive sign:
1 + 9 - 7 * 6

Thursday, January 10, 2013

My musings on database deadlock issues part 2

Sometimes we can just throw(not waste) money at the problem to solve programming woes. It’s good that stackoverflow don’t have to buy Oracle in order to solve their database deadlocks issues, stackoverflow was built in the fortunate time(2007), it was built when SQL Server already has an MVCC option(SQL Server 2005), contrast that to Oracle which uses MVCC since version 3(built in 1983). The decision-makers at stackoverflow just flick a switch(switch their SQL Server database to use MVCC) to solve their database deadlock issues.


Oracle using MVCC as its only database transaction operation tells a lot, I can’t see MVCC as just all about row-versioning, they know the advantages far outweighs the disadvantages, hence them making MVCC the only database transaction operation supported by their database. If Oracle know the disadvantages can outweighs the advantages, they will not hardwire the MVCC architecture to their database.

We can’t fault companies like airlines and financial institutions if they choses Oracle over other RDBMSes; information correctness far matter most than anything else, which MVCC delivers properly, there are no dirty reads with MVCC. And performance is the natural byproduct of MVCC’s writers not blocking the readers and vice versa, sweet deal. MVCC delivers the trifecta of a very scalable database: correct information (delivers the I in ACID), no intermittent deadlocks, performance.


We can see for ourselves the mayhem that nolock can do to our queries(providing correct reports for that matter), it doesn’t even solve the deadlock issues, the very problem most of us are trying to solve with it: http://blogs.msdn.com/b/craigfr/archive/2007/06/12/query-failure-with-read-uncommitted.aspx

And we are already aware of the evil that SET TRANSACTION ISOLATION READ UNCOMMITTED can commit in the name of performance.


<microsoft-bashing> I will not expect Microsoft will put MVCC literature on SQL Server BOL, Microsoft doesn’t want to be looked upon as mere copycat or a johnny-come-lately. They will avoid things that will give them those impressions. Case in point, Materialized Views is the de facto nomenclature for er.. Materialized Views, but how do Microsoft named their materialized views feature? Microsoft want to be different, they named their Materialized Views as Indexed Views! I’m not surprised Microsoft didn’t put MVCC nor Materialized Views on their SQL Server documentation. For finding good information on something cannot be found on Microsoft’s official documentation, we can just use our trusted search engines</microsoft-bashing>


I’ll stop here, I’m turning into an MVCC salesman now, hahah :D



As with most things in life, we just have to decide which option that offers advantages that far outweighs its disadvantages. Some are even loading their whole database to memory in order to achieve performance, hardware is getting cheaper, I don’t even see that trend reversing ツ


Happy Coding! ツ

Wednesday, January 9, 2013

My musings on database deadlock issues

Dirty reads yields dirty information (pardon my tautology)



Making a correct program fast is easier than making a fast program correct. It’s the latter(fast, yet has incorrect information) what SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED delivers, it’s Microsoft’s work-around for deadlocks, instead of delivering true isolation.



Think of MVCC transaction isolation as users having their own database copy(or scratchpad? I’m not good at analogy) for their transactions, whatever writes they are doing to their database copy, deletes, inserts, updates, etc, just happens in their own database copy only and they doesn’t affect the official state of the database. This yields vast improvements when doing concurrent access(which is the norm) on your database, the writers(insert,update,delete) won’t ever affect other user’s SELECT, hence giving performance boost when accessing the official state of your database. Good for reports and information browsing, good for developers and clients alike.



And MVCC yields correct information to boot. It’s hard not to swoon on that points alone(correct information); plus it’s fast, there’s no waiting/deadlocks incurring between writers and readers. It eludes me why SQL Server didn’t make MVCC the default.



Correctness should rule everything around us



“I find that deadlocks are difficult to understand and even more difficult to troubleshoot. Fortunately, it's easy enough to fix by setting read committed snapshot on the database for our particular workload. But I can't help thinking our particular database vendor just isn't as optimistic as they perhaps should be.“ -- http://www.codinghorror.com/blog/2008/08/deadlocked.html



SET READ_COMMITTED_SNAPSHOT ON (turns on MVCC) is what fixes the stackoverflow website’s performance issues. Jeff Atwood is the author of www.codinghorror.com and http://www.stackoverflow.com




nolock is no joy too, being able to read a row is not guaranteed with nolock(a more granular SET TRANSACTION ISOLATION READ UNCOMMITTED):
http://blogs.msdn.com/b/craigfr/archive/2007/06/12/query-failure-with-read-uncommitted.aspx

And try to reproduce the same scenario on the above link without nolock, and using MVCC settings, It Just Works™ :


ALTER DATABASE testDatabase SET ALLOW_SNAPSHOT_ISOLATION ON;
ALTER DATABASE testDatabase SET READ_COMMITTED_SNAPSHOT ON;

Tuesday, January 8, 2013

Convention-over-configuration rules everything around me

Given this kind of desired API for exporting strongly-typed model to Excel:

public ActionResult ExportEmployeesToExcel()
{
  
    IList<Employee> employees = new List<Employee>()
    {
    new Employee() { FirstName = "John", MiddleName = "Winston", LastName = "Lennon", Savings = 12345.67, SongsPercent = 0.301234},
    new Employee() { FirstName = "Paul", MiddleName = "Phoenix", LastName = "McCartney", Savings = 67891234.56, SongsPercent = 0.205678},
    new Employee() { FirstName = "George", MiddleName = "Stoic", LastName = "Harisson", Savings = 3456.78 },
    new Employee() { FirstName = "Ringo", MiddleName = "Drum", LastName = "Starr", Savings = 345.67 }
    };
    
    return ExcelResultFromList.Create<Employee>
                (list: employees, 
                filename: "Employees",
                mapAction: e =>
                                {
                                    e.Include(x => x.LastName).Label("Apelyido");
                                    e.Include(x => x.FirstName);
                                    e.Include(x => x.Savings).Format("#,#00.00");
                                    e.Include(x => x.SongsPercent / 100).Label("Song%").Format("0.000%");
                                });
} 


We would want to be able to pass a complex lambda expression on Include so it would be possible to divide a number (or any expression for that matter), in order to do that, we need to implement the API like this:

public ExportPart<T> Include(Func<T, object> exp)
{
    var emd = new ExportMetaData<T>();
    ExportList.Add(emd);

    var input = new ExportPart<T>(emd, exp);
    return input;
}


But since I'm a convention-over-configuration-loving .NETizen, I would love to make it a convention on the code that if I pass a simple lambda expression(e.g. x.LastName, x.FirstName) and I didn't specify an explicit Label, the code shall automatically use the name of the property as the default label for the column on the exported Excel file. With that being said, we shall need to tap the power of Expression:

public ExportPart<T> Include(Expression<Func<T, object>> exp)
{
    var emd = new ExportMetaData<T>();
    ExportList.Add(emd);

    var input = new ExportPart<T>(emd, exp);
    return input;
}

Then to get the Expression's string representation, just use this awesome PropertyPathVisitor from: http://www.thomaslevesque.com/2010/10/03/entity-framework-using-include-with-lambda-expressions/


To use:
string label = new PropertyPathVisitor().GetPropertyPath(exp);


We can make things more nicer by automatically splitting the PascalCase label, i.e. BusinessAddress label will be formatted as Business Address:


// http://stackoverflow.com/questions/3103730/is-there-a-elegant-way-to-parse-a-word-and-add-spaces-before-capital-letters

var r = new System.Text.RegularExpressions.Regex( 
@"  (?<=[A-Z])(?=[A-Z][a-z])    # UC before me, UC lc after me
|  (?<=[^A-Z])(?=[A-Z])        # Not UC before me, UC after me
|  (?<=[A-Za-z])(?=[^A-Za-z])  # Letter before me, non letter after me
", RegexOptions.IgnorePatternWhitespace);

  
string label = new PropertyPathVisitor().GetPropertyPath(exp);  
label = string.Join(" ", r.Split(label));


Now for the fun part, how can we run the lambda expression if it's from the genericize Expression? To do that, just use the Expression's Compile method to receive a Func delegate of the Expression's lambda expression:


Func<T, object> func = exp.Compile(); 
var rowValues = _list.Select(x => new { Value = func(x) });




To see how the Expression's Compile method works:

using System;
using System.Linq;
using System.Linq.Expressions;
 
public class Test
{
    public static void Main()
    {
        Func<int, object> hexConverter = x => "Value is " + x.ToString("X");
 
        Console.WriteLine("{0}", hexConverter(36));
 
        Expression<Func<int, object>> hexConverterExpression = x => "Good number is " + x.ToString("X");
 
        Func<int, object> hexConverterToo = hexConverterExpression.Compile();
 
        Console.WriteLine("{0}", hexConverterToo(36));
 
    }
}


Output:
Value is 24
Good number is 24


Live code: http://ideone.com/clh3mk




Expand to see a comprehensive example of Expression. Download the dependent EPPlus component to use code below:


namespace ExcelExporter
{
    using System.Linq.Expressions;
    using System.Web.Mvc;
    using ExpressionGetter;
 
 
    // Should I call this ExcelResultFromListFactory?
    public static class ExcelResultFromList
    {
        public static ExcelResultFromList<T> Create<T>(IEnumerable<T> list, string filename, Action<ExcelMapping<T>> mapAction)
        {
            var e = new ExcelMapping<T>();
            var r = new ExcelResultFromList<T>(list) { FileName = filename, ExcelMapping = e };
            mapAction(e);
            return r;
        }
    }
 
 
    public class ExcelResultFromList<T> : TalentReward.ESS.Code.ActionResults.ExcelResult
    {
        public ExcelMapping<T> ExcelMapping { get; set; }
 
 
        public IEnumerable<T> _list;
 
 
        public ExcelResultFromList(IEnumerable<T> list)
        {
            _list = list;
        }
 
 
        public override void ExecuteResult(ControllerContext context)
        {
 
            ExcelPackage = new ExcelPackage();
 
            ExcelWorksheet sheet = ExcelPackage.Workbook.Worksheets.Add("Export");
 
 
            if (_list.Count() > 0)
            {
                int ordinal = 0;
                foreach (ExportMetaData<T> eachEmd in ExcelMapping.ExportList)
                {
                    // Pre-C# 5 necessitates closing the enumerating variable in this loop scope. rationale:
                    // http://blogs.msdn.com/b/ericlippert/archive/2009/11/12/closing-over-the-loop-variable-considered-harmful.aspx
                    // This can be removed in C# 5:
                    var emd = eachEmd;
 
 
                    ++ordinal;
 
                    if (emd.Label != null)
                        sheet.Cells[1, ordinal].Value = emd.Label;
                    else
                    {
                        // http://stackoverflow.com/questions/3103730/is-there-a-elegant-way-to-parse-a-word-and-add-spaces-before-capital-letters
                        var r = new System.Text.RegularExpressions.Regex( 
                        @"  (?<=[A-Z])(?=[A-Z][a-z])    # UC before me, UC lc after me
                        |  (?<=[^A-Z])(?=[A-Z])        # Not UC before me, UC after me
                        |  (?<=[A-Za-z])(?=[^A-Za-z])  # Letter before me, non letter after me
                        ", RegexOptions.IgnorePatternWhitespace);
 
                        string label = new PropertyPathVisitor().GetPropertyPath(emd.Expression);
 
                        sheet.Cells[1, ordinal].Value = string.Join(" ", r.Split(label));
                    }
 
                    ExcelColumn ec = sheet.Column(ordinal);
 
                    if (!string.IsNullOrEmpty(emd.AllRowsFormat))
                        ec.Style.Numberformat.Format = emd.AllRowsFormat;
 
 
                    Func<T, object> func = emd.Expression.Compile();
                    sheet.Cells[2, ordinal].LoadFromCollection(_list.Select(y => new { Value = func(y) }));
 
                    if (emd.EachRowFormat != null)
                    {
                        var listCellMapping = _list.Zip(sheet.Cells[2, ordinal, 2 + _list.Count() - 1, ordinal],
                                                        (list, cell) => new { Cell = cell, EachRowFormat = emd.EachRowFormat(list) });
                        foreach (var item in listCellMapping)
                            item.Cell.Style.Numberformat.Format = item.EachRowFormat;
                    }
 
 
                    if (emd.WithSum)
                    {
                        string startingRowAddress = sheet.Cells[2, ordinal].Address;
                        string endingRowAddress = sheet.Cells[2 + _list.Count() - 1, ordinal].Address;
                        string formulaAddress = sheet.Cells[2 + _list.Count(), ordinal].Address;
 
                        sheet.Cells[formulaAddress].Formula = string.Format("SUM({0}:{1})", startingRowAddress, endingRowAddress);
                    }
 
                }
               
            }
 
            base.ExecuteResult(context);
        }
 
 
        // In this age of stackoverflow, who needs MSDN?
        // http://stackoverflow.com/questions/1196991/get-property-value-from-string-using-reflection-in-c-sharp
        static object GetPropValue(object src, string propName)
        {
            return src.GetType().GetProperty(propName).GetValue(src, null);
        }
    }
 
 
    public class ExcelMapping<T>
    {
        private readonly IList<ExportMetaData<T>> _exportList = new List<ExportMetaData<T>>();
        public IList<ExportMetaData<T>> ExportList
        {
            get { return _exportList; }
        }
 
        public ExportPart<T> Include(Expression<Func<T, object>> exp)
        {
            // string name = new PropertyPathVisitor().GetPropertyPath(p);
 
            var emd = new ExportMetaData<T>();
            ExportList.Add(emd);
 
            var input = new ExportPart<T>(emd, exp);
            return input;
        }
    }
 
    public class ExportPart<T>
    {
        readonly ExportMetaData<T> _emd;
 
        public ExportPart(ExportMetaData<T> exportMetaData, Expression<Func<T, object>> exp)
        {
            _emd = exportMetaData;
            _emd.Expression = exp;
        }
 
        public ExportPart<T> Format(string format)
        {
            _emd.AllRowsFormat = format;
            return this;
        }
 
        public ExportPart<T> Format(Func<T, string> format)
        {
            _emd.EachRowFormat = format;
            return this;
        }
 
        public ExportPart<T> Label(string label)
        {
            _emd.Label = label;
            return this;
        }
 
        public ExportPart<T> WithSum()
        {
            _emd.WithSum = true;
            return this;
        }
 
        // // just ready this in case EPPlus can compute column width in the future
        //public ExportPart<T> AutoFit(bool auto)
        //{
        //    _emd.AutoFit = auto;
        //    return this;
        //}
 
 
    }
 
 
    public class ExportMetaData<T>
    {
        public Expression<Func<T, object>> Expression { get; set; }
        public Func<T, string> EachRowFormat { get; set; }
        public string Label { get; set; }
        public string AllRowsFormat { get; set; }
        public bool WithSum { get; set; }
 
 
        // just ready this in case EPPlus can compute column width in the future
        // public bool AutoFit { get; set; }
 
    }
 
}
 
 
namespace ExpressionGetter
{
    using System.Linq.Expressions;
    using System.Text;
 
    // We can t make an apple pie from scratch, some ingredients have to come from somewhere:
 
    // PropertyPathVisitor sourced from: http://www.thomaslevesque.com/2010/10/03/entity-framework-using-include-with-lambda-expressions/
    class PropertyPathVisitor : ExpressionVisitor
    {
        private Stack<string> _stack;
 
        public string GetPropertyPath(Expression expression)
        {
            _stack = new Stack<string>();
            Visit(expression);
            return _stack
                .Aggregate(
                    new StringBuilder(),
                    (sb, name) =>
                        (sb.Length > 0 ? sb.Append(".") : sb).Append(name))
                .ToString();
        }
 
 
 
        protected override Expression VisitMember(MemberExpression expression)
        {
            if (_stack != null)
                _stack.Push(expression.Member.Name);
            return base.VisitMember(expression);
        }
 
 
    }
 
}


Happy Coding! ツ