Skip to content
Benjamin edited this page Oct 8, 2019 · 12 revisions

General Standards

  • Configure your code editor to insert (4) spaces instead of tabs.
  • Delete unused code instead of commenting it out.
  • One file per class.
  • The filename must match the class or enum name.
  • Avoid creating/using partial classes.
  • Always use DateTime.UtcNow.
  • Extension Methods:
    • Extension methods should be in a single file when extending a single class. The file and class should be called [classname]Extensions.
  • Repositories
    • Use Create, Read, Update and Delete prefixes for methods (CRUD).
  • Services
    • Use Load / Save.
  • General naming for loading & saving:
    • object Load(int id);
    • object LoadByParentObjectId(int parentId);

Naming Standards

General Naming

Name instances after the class name, e.g.

Foo foo;
Bar bar;

Only differentiate variable names when you need to, e.g.

Foo first;
Foo second;

var

Use the keyword var whenever possible.

Return Values

Prefer having only one return statement in functions. Define the return value as result.

var result = new Foo();
// ...
return result;

Acceptable exceptions to this rule are when your doing validation/assertions at the start of your function.

if (x < 0) return 0;
// ...
return result;

Single Letter Variable Names

Don't use single letter or abreviated variable names. E.g. use var person = new Person(); instead of var p = new Person();

Unless:

  • Using geometry (e.g. x, y, z)
  • Iterators in for...loops (i, j, k)

Scoping rules

  • Private Variables: fooName
  • Public Variables: FooName
  • Camel casing variables: Follow the rules, e.g. Ebay instead of eBay for a class name.
  • Constants (private or public): FooConstantName
  • Use of base/this qualifiers: FooMethod() not base.FooMethod() or this.FooMethod() unless you need to.
  • Acronyms: use http, dvd, url, etc instead of HTTP.

Boolean variables

  • Use the prefix Is (or is) - e.g. var isFoo = false;
  • Named positive, not negative - e.g. IsAllowedToDelete and NOT IsDeniedDeleteAccess

Nullable types

Use one nullable property int? etc... instead of int Foo & bool FooSpecified (or IsFooSpecified).

You can use nullable arguments.

Classes

By convention all our classes are organised with const variables first, followed by any dependencies, then the constructor(s) then methods. Dispose and copy methods are at the end of class.

Example:

public class Foo
{
    public const string Key = "foo";
    public const string CollectionKey = "foos";
    private const string Thing = "thing";
        
    #region Dependencies

    public IService Service { get; set; }

    #endregion

    public Foo()
    {
    }

    public int MethodOne(int foo)
    {
        // ...
    }
}

Unit tests

Use automatic mocking where possible.

When making assertions be as explicit as possible.

    public class FooTest : AutoMockingTest
    {
        private Foo foo;
    
        [SetUp]
        public void SetUp()
        {
            foo = Create<Foo>();
        }

        [Test]
        public void TestFooBar()
        {
            var bar = new BarFactory.Create();

            var result = foo.FooTheBar(bar);

            // not Assert.AreEqual(bar.FirstThing, result.FirstThing);
            Assert.AreEqual("First Thing", result.FirstThing);
            Assert.AreEqual(2, result.SecondThing);
        }
    }

Controllers

ViewBag

Use the ViewBag to avoid magic strings, have a unit test to assert values have been set correctly. Use a strongly typed model if you have lots of entries in the ViewBag.

public FooController
{
    public ViewData List()
    {
        // Unit test this line
        ViewBag.Foo = new Foo();
    }
}

Strings

When concatenating more than two strings together, use string.Format().

When possible prefer interpolated strings to string.Format().

var username = "User " + seed;
var output = string.Format("User {0} blah", seed);
var value = $"Hello {person.Firstname} {person.Lastname}!";

Use a StringBuilder object when concatenating string in a loop.

Use the @prefix when dealing with strings that one for than one line.

var query = @"SELECT Id, Created, Name
FROM TableName
WHERE Id = @id";

Out Parameters

Avoid using out parameters!

Inheritance

  • Avoid it!
  • Use Base prefix (not Abstract) for base class (e.g. public abstract class BasePerson {}).
  • Do not re-test inherited code.

For loops

For loops always starts at i = 0:

for (var i = 0; i < list.Count; i++) { ... }

Foreach Loops

Don’t mix foreach loops and Linq.

foreach(var customer in customers.Where(c => c.Status == Status.Something))
{
    // ...
}

Do this instead:

foreach(var customer in customers)
{
    // Skip customers without something 
    if (customer.Status != Status.Something) continue;    
    
    // ...
}

Linq

Use this format for Linq statements:

var things = thing.Where(t => t.Thing)
                  .OrderBy(t => t.Thing);

Object Initialisers

Format as follow when two or more properties are initalised:

var customer = new Customer
               {
                    Name =Bob,
                    Lastname =Smith};

Func

Refrain from using func parameters. They make debugging and understanding the code more difficult.

When you are allowed to use a func:

  • Trivial anonymous functions
  • Using reflection to avoid magic strings
  • HtmlExtensions

Javascript / jQuery

Never use .checked (on variable representing a checkbox) to check if it's checked or not: it will NOT work in IE. Use jQuery $(..).checked(true) instead.

Avoid $.get(); when the request parameters rarely change but the content returned does: IE and proxies will cache the answer and behaviour will be broken. Use $.post(); instead.

Write JavaScript like it's JavaScript, use:

if (condition) {
    foo();
}

NOT

if (condition)
{
    foo();
}

And:

Use single quotes: foo('bar'); Never: use eval(json) to convert JSON to a JS object. Use $.parseJSON(json) instead.

Outputting JSON in the view

DO NOT output the JSON with a hidden input <input type="hidden" value="${json}" /> or a hidden div <div id="json" style="display:none">${json}</div>.

DO ouput it in an 'application/json' script tag:

<script id="json" type="application/json">${json}</script>

Then in javascript you can do

var json = $('#json').html();
var myData = $.parseJSON(json); 

Dapper .NET

Use parameters in SQL string instead of injecting values directly in the query.

var isDeleted = 0;
const string sql = @”SELECT Id FROM TableName WHERE Deleted = @IsDeleted”;
var result = connection.Query<int>(sql, new { IsDeleted = isDeleted });

SQL

BETWEEN

When selecting rows between fromDate and untilDate, use

WHERE [Created] BETWEEN @from AND @until

rather than

WHERE [Created] > @from AND [Created] <= @Until

GROUP BY

When grouping by time interval, use:

T-SQL:

GROUP BY DATEADD(MONTH, DATEDIFF(MONTH, 0, Created),0)

mysql:

DATE_ADD('1900-01-01 00:00:00', INTERVAL TIMESTAMPDIFF(DAY, '1900-01-01 00:00:00', Created) DAY)

The mysql operation above can be pretty CPU intensive. Denormalising the value to a CreatedDay DATE column might be a better option.

LIKE

When using the LIKE text search function, check the type of the column your are working off, if it is NVARCHAR don't forget the N prefix on your 'value%'.

SELECT *
FROM Item i
WHERE i.Title LIKE(N'%boo%')

If you are using like with a parameter, sanitize your string and surround it with the relevant % (e.g. "%foo%") then refer to it using a parameter.

var foo = $"{foo.Keep("0123456789")}%";

var query = @"SELECT *
FROM Item i
WHERE i.Title LIKE @foo"

// ...

return connection.Query<Item>(query, new {foo});

WITH (NOLOCK)

To avoid locking the tables use WITH (NOLOCK) when relevant when selecting data.

SELECT *
FROM Item i WITH (NOLOCK)
WHERE Id = @id

If having to add WITH (NOLOCK) to your statements is not an option you can wrap your calls with a READUNCOMMITED transaction.

using (var connection = Context.Connection())
using (var transaction = connection.BeginTransaction(IsolationLevel.ReadUncommitted))
{
    return connection.Query<string>("SELECT Name FROM Item WHERE Id = @id", new {id}, transaction);
}

Depending on the underlying database engine, this may or may not be faster. Mysql can be slower with READUNCOMMITED statements than T-SQL.

Be also aware that WITH (NOLOCK) or READUNCOMMITED will return data that hasn't been committed yet!

GIT

Delete files from the repo when deleting them from the project

Name branches in lower case with hyphens for spaces, e.g. : feature-branch-foo

Use git style commit messages, e.g.

Title less than 52 chars
[blank line]
- point 1
- point 2