Search

Categories

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Send mail to the author(s) E-mail

# Sunday, 16 February 2014

Install via NuGet into the Repositories project, and IntegrationTests project

Only the Person is the AggregateRoot.. so only need a DbSet<T> properties and later on repository for that.

Then he is creating a Factory pattern for repositories

Configuring your Model’s Business Rules

Property level validation using attributes

Using fluent API

IValidateableObject – Object Level Validation

 

Database Initialization and Migrations

sdf

Base Repository Class

asd

Search

asdf

Unit Of Work

asfd

IDateTracking

asdf

Improving Error Messages

asdf

| | # 

Entities

The canonical example is the Personclass. If two Personinstances have the same name, do you consider them to represent the same person?
Most likely not, as the name would not uniquely identify the person, and there’s a high probability that even though
these instances contain the same name they refer to two different people in the real world

Value Objects

A Value Object on the other hand is identified by its properties and the values they contain. The canonical example
here is Address: two instances of Addressthat contain the data “327 Washington Blvd Venice, California 90291” are
most likely considered the same; they don’t have (or need) an identity on their own.

image
And People class inherits off CollectionBase.  Notice Address is missing as app doesn’t need it.

 

namespace DLayer.Infrastructure
{
    public abstract class DomainEntity<T>
    {
        /// <summary>
        /// Gets or sets the unique ID of the entity in the underlying data store.
        /// </summary>
        public T Id { get; set; }
        /// <summary>
        /// Checks if the current domain entity has an identity.
        /// </summary>
        /// <returns>True if the domain entity is transient (i.e. has no identity yet),
        /// false otherwise.
        /// </returns>
        public bool IsTransient()
        {
            return Id.Equals(default(T));
        }
    }
}
public class Person : DomainEntity<int>
{
}

default returns the type’s default value. 

So using Id, whereas usually I prefer to use PersonId

He does low level annotations at the Entity level eg Required:

[TestMethod]
public void FirstAndLastNameResultsInFullName()
{
    var person = new Person() { FirstName = "Imar", LastName = "Spaanjaars" };
    person.FullName.Should().Be("Imar Spaanjaars");
}

[TestMethod]
public void EmptyFirstNameReturnsLastName()
{
    var person = new Person() { LastName = "Spaanjaars" };
    person.FullName.Should().Be("Spaanjaars");
}

[TestMethod]
public void EmptyLastNameReturnsFirstName()
{
    var person = new Person() { FirstName = "Imar" };
    person.FullName.Should().Be("Imar");
}

[TestMethod]
public void AllEmptyReturnsEmpty()
{
    var person = new Person();
    person.FullName.Should().Be(string.Empty);
}

and implementation:

public class Person : DomainEntity<int>
{
    [Required]
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public DateTime DateOfBirth { get; set; }
    public PersonType Type { get; set; }

    public string FullName
    {
        get
        {
            string temp = FirstName ?? string.Empty;
            if (!string.IsNullOrEmpty(LastName))
            {
                if (temp.Length > 0)
                {
                    temp += " ";
                }
                temp += LastName;
            }
            return temp;
        }
    }
}

Notice how the tests will pass as we’re not worried about IValidateable yet.

Also as this is a readonly property EF will ignore it.

namespace DLayer.Model
{
  /// <summary>
  /// Represents an e-mail address in the system.
  /// </summary>
    public class EmailAddress : DomainEntity<int>
    {
        /// <summary>
        /// Gets or sets the text of the e-mail address.
        /// </summary>
        [Required]
        [EmailAddressAttribute]
        public string EmailAddressText { get; set; }

        /// <summary>
        /// Gets or sets the type of the e-mail address.
        /// </summary>
        public ContactType ContactType { get; set; }

        /// <summary>
        /// Gets or sets the owner (a Person) of the e-mail address.
        /// </summary>
        public Person Owner { get; set; }

        /// <summary>
        /// Gets or sets the ID of the owner (a Person) of the e-mail address.
        /// </summary>
        public int OwnerId { get; set; }
    }
}

Hmm – XML comments cluttering up I’d say.  Also ambiguous Owner and OwnerId… why not Person and PersonId.?

Foreign Key Properties

This is Owner and OwnerId above
So we can shortcut..ie don’t need this:

var emailAddress = new EmailAddress { ... };
emailAddress.Owner = _personRepository.FindById(123)

can have this:

var emailAddress = new EmailAddress { ... };
emailAddress.OwnerId = 123

which could save a trip to the db eg when creating a new email address and all we have is the personId passed in the query string.

ValueObject

public class Address : ValueObject<Address>
{
    #region Constructors

    /// <summary>
    /// Initializes a new instance of the Address class.
    /// The constructor is marked private because we want other consuming code to use the overloaded constructor.
    /// However, EF still needs a parameterless constructor.
    /// </summary>
    private Address() { }

    /// <summary>
    /// Initializes a new instance of the Address class.
    /// </summary>
    /// <param name="street">The street of this address.</param>
    /// <param name="city">The city of this address.</param>
    /// <param name="zipCode">The zip code of this address.</param>
    /// <param name="country">The country of this address.</param>
    /// <param name="contactType">The type of this address.</param>
    public Address(string street, string city, string zipCode, string country, ContactType contactType)
    {
        Street = street;
        City = city;
        ZipCode = zipCode;
        Country = country;
        ContactType = contactType;
    }

    /// <summary>
    /// Gets the street of this address.
    /// </summary>
    public string Street { get; private set; }

    /// <summary>
    /// Gets the zip code  of this address.
    /// </summary>
    public string ZipCode { get; private set; }

    /// <summary>
    /// Gets the city of this address.
    /// </summary>
    public string City { get; private set; }

    /// <summary>
    /// Gets the country of this address.
    /// </summary>
    public string Country { get; private set; }

    /// <summary>
    /// Gets the contact type of this address.
    /// </summary>
    public ContactType ContactType { get; private set; }

    /// <summary>
    /// Determines if this address can be considered to represent a "null" value.
    /// </summary>
    // <returns>True when all four properties of the address contain null; false otherwise.
    public bool IsNull
    {
        get
        {
            return (string.IsNullOrEmpty(Street) && string.IsNullOrEmpty(ZipCode) && string.IsNullOrEmpty(City) && string.IsNullOrEmpty(Country));
        }
    }
}

Make it immutable

EF not Deleting Collections

var person = myContext.People.First(x => x.Id = id);
person.EmailAddresses.Clear();
myContext.SaveChanges()

This doesn’t delete the associated EmailAddresses.  EF just clears the FK that points to the Person (from each EmailAddress).  Trick is to use IHasOwner our own custom interface to detect.

So EmailAddress and PhoneNumber implement IHasOwner (which is why we use Owner in those classes)

Implementing Equality Comparison

eg we’re going to need to see if 2 addresses are the same eg business and personal of a person.

eg see if a person is being entered twice

quite complex here…

Creating Collections

he’s got a CollectionBase

going towards:

Person person = new Person();
person.EmailAddresses.Add("imar@spaanjaars.com", ContactType.Business)

Automatic Tracking of Creation and Modification Dates

Instead of:

myPerson.DateModified = DateTime.Now

hmm can get EF to automatically manage these properties

public class Person : DomainEntity<int>, IDateTracking
namespace DLayer.Model
{
    /// <summary>
    /// Defines an interface for objects whose creation and modified dates are kept track of.
    /// </summary>
    public interface IDateTracking
    {
        /// <summary>
        /// Gets or sets the date and time the object was created.
        /// </summary>
        DateTime DateCreated { get; set; }

        /// <summary>
        /// Gets or sets the date and time the object was last modified.
        /// </summary>
        DateTime DateModified { get; set; }
    }
}

Putting It All Together

eg a Person should be given collection classes for EmailAddress and PhoneNumber classes.  All these properties should be instantiated in the constructor so can access them immediately.

public class Person : DomainEntity<int>, IDateTracking
  {
    #region Constructors

    /// <summary>
    /// Initializes a new instance of the Person class.
    /// </summary>
    public Person()
    {
      EmailAddresses = new EmailAddresses();
      PhoneNumbers = new PhoneNumbers();
      HomeAddress = new Address(null, null, null, null, ContactType.Personal);
      WorkAddress = new Address(null, null, null, null, ContactType.Business);
    }

    #endregion

    #region Properties

    /// <summary>
    /// Gets or sets the date and time the object was created.
    /// </summary>
    public DateTime DateCreated { get; set; }

    /// <summary>
    /// Gets or sets the date and time the object was last modified.
    /// </summary>
    public DateTime DateModified { get; set; }

    /// <summary>
    /// Gets or sets the first name of this person.
    /// </summary>
    [Required]
    public string FirstName { get; set; }

    /// <summary>
    /// Gets or sets the last name of this person.
    /// </summary>
    [Required]
    public string LastName { get; set; }

    /// <summary>
    /// Gets or sets the date of birth of this person.
    /// </summary>
    public DateTime DateOfBirth { get; set; }

    /// <summary>
    /// Gets or sets the type of person.
    /// </summary>
    public PersonType Type { get; set; }

    /// <summary>
    /// Gets or sets the home address of this person.
    /// </summary>
    public Address HomeAddress { get; set; }

    /// <summary>
    /// Gets or sets the work address of this person.
    /// </summary>
    public Address WorkAddress { get; set; }

    /// <summary>
    /// Gets or sets the e-mail addresses of this person.
    /// </summary>
    public EmailAddresses EmailAddresses { get; private set; }

    /// <summary>
    /// Gets or sets the phone numbers of this person.
    /// </summary>
    public PhoneNumbers PhoneNumbers { get; set; }

    /// <summary>
    /// Gets the full name of this person.
    /// </summary>
    public string FullName
    {
      get
      {
        string temp = FirstName ?? string.Empty;
        if (!string.IsNullOrEmpty(LastName))
        {
          if (temp.Length > 0)
          {
            temp += " ";
          }
          temp += LastName;
        }
        return temp;
      }
    }

XML comments hide in VS with http://visualstudiogallery.msdn.microsoft.com/03141ea7-c35e-4533-b05b-9e60545e93eb

Defining Repository Interface

namespace Spaanjaars.Infrastructure
{
  /// <summary>
  /// Defines various methods for working with data in the system.
  /// </summary>
  public interface IRepository<T, K> where T : class
  {
    /// <summary>
    /// Finds an item by its unique ID.
    /// </summary>
    /// <param name="id">The unique ID of the item in the database.</param>
    /// <param name="includeProperties">An expression of additional properties to eager load. For example: x => x.SomeCollection, x => x.SomeOtherCollection.</param>
    /// <returns>The requested item when found, or null otherwise.</returns>
    T FindById(K id, params Expression<Func<T, object>>[] includeProperties);

    /// <summary>
    /// Returns an IQueryable of all items of type T.
    /// </summary>
    /// <param name="includeProperties">An expression of additional properties to eager load. For example: x => x.SomeCollection, x => x.SomeOtherCollection.</param>
    /// <returns>An IQueryable of the requested type T.</returns>
    IQueryable<T> FindAll(params Expression<Func<T, object>>[] includeProperties);

    /// <summary>
    /// Returns an IQueryable of items of type T.
    /// </summary>
    /// <param name="predicate">A predicate to limit the items being returned.</param>
    /// <param name="includeProperties">An expression of additional properties to eager load. For example: x => x.SomeCollection, x => x.SomeOtherCollection.</param>
    /// <returns>An IEnumerable of the requested type T.</returns>
    IEnumerable<T> FindAll(Expression<Func<T, bool>> predicate, params Expression<Func<T, object>>[] includeProperties);

    /// <summary>
    /// Adds an entity to the underlying collection.
    /// </summary>
    /// <param name="entity">The entity that should be added.</param>
    void Add(T entity);

    /// <summary>
    /// Removes an entity from the underlying collection.
    /// </summary>
    /// <param name="entity">The entity that should be removed.</param>
    void Remove(T entity);

    /// <summary>
    /// Removes an entity from the underlying collection.
    /// </summary>
    /// <param name="id">The ID of the entity that should be removed.</param>
    void Remove(K id);
  }
}

Summary of this section

- very interesting way the model is being built up and tested.

| | # 
# Monday, 28 October 2013
( DDD )

Powerpoint here

Gave an internal presentation on DDD

| | # 
# Wednesday, 23 October 2013
( DDD )

I couldn’t get his master version working, and wanted to get a simpler version working.  So am taking a fork from around BusinessLogic2. 

So we’re going to have a Service layer, and MVC4 layer on top of that.

image
Always good to see UI!!! Standard template UI is ‘responsive’.

@model BB.SmsQuiz.Web.Models.CompetitionViewModel

@{
    ViewBag.Title = "Index";
}

<h2>Index</h2>

<p>
    @Html.ActionLink("Create New", "Create")
</p>
<table>
    <tr>
        <th></th>
    </tr>

@foreach (var item in Model.Competitions) {
    <tr>
        <td>
            @item.Question
            @Html.ActionLink("Edit", "Edit", new { /* id=item.PrimaryKey */ }) |
            @Html.ActionLink("Details", "Details", new { /* id=item.PrimaryKey */ }) |
            @Html.ActionLink("Delete", "Delete", new { /* id=item.PrimaryKey */ })
        </td>
    </tr>
}

</table>

Strongly typed in the UI.  Not sure why he has a wrapper around the IEnumerable<Competition>

public class CompetitionController : Controller
    {
        ICompetitionService competitionService;

        public CompetitionController() : this(new CompetitionService()) { }
        /// <summary>
        /// Initializes a new instance of the <see cref="CompetitionController" /> class.
        /// </summary>
        /// <param name="competitionService">The competition service.</param>
        public CompetitionController(ICompetitionService competitionService)
        {
            this.competitionService = competitionService;
        }

        public ActionResult Index()
        {
            var viewModel = new CompetitionViewModel();
            viewModel.Competitions = competitionService.GetCompetitions().Competitions;

            return View("Index", viewModel);
        }
    }

Poor mans Dependency Injection – simple, which allows easy testing:

http://www.contentedcoder.com/2012/12/consuming-domain-model-10-years-of-net.html  - Moq  in #10

[TestMethod]
        public void IndexReturnsViewModelWithCompetitions()
        {
            var controller = new CompetitionController(new StubCompetitionService());

            // Act
            var result = controller.Index() as ViewResult;

            // Assert
            Assert.AreEqual("Index", result.ViewName);
            Assert.IsInstanceOfType(result.Model, typeof(CompetitionViewModel));
            Assert.AreEqual(10, ((CompetitionViewModel)result.Model).Competitions.Count());
        }

        private class StubCompetitionService : ICompetitionService
        {
            public GetCompetitionsResponse GetCompetitions()
            {
                var response = new GetCompetitionsResponse();

                var list = new List<CompetitionItem>();

                for (int i = 1; i < 11; i++)
                {
                    list.Add(new CompetitionItem() { Question = "Question #" + i.ToString() });
                }

                response.Competitions = list;

                return response;
            }
        }

Unit testing the Web controller with a stub.  Later we’ll use Moq to help out.

Currently DataAccess is being done by raw SQL ADO.Net

| | # 
( DDD )

“Designed to read data really fast with simple object mapping”

So what about object creation, transaction management, unit or work?  So, we’ll use EF for this.

So essentially using EF Code First, and then Dapper for high perf reads.

| | # 
# Tuesday, 22 October 2013
( DDD )

http://www.contentedcoder.com/2012/12/choosing-data-access-implementation-10.html

  • Must be performant: Our application will be subject to surges, so we need our database read/writes to be as performant as possible.
  • No use of code generation/designers or configuration files: I've had bad experiences with config/designers when these files are committed to source control and many developers are making changes to these files.
  • Convention over configuration and automation of common actions: A LOT of changes will be made to these classes/methods by potentially many developers so we want to promote convention.
  • To limit abstractions and have control over the domain specific language (DSL): It's always preferable to code in a specific DSL such a SQL especially when writing complex queries.
  • Use a relational database: our first implementation needs to run on SQL Server.
  • Allow a possible move to a cloud computing database provider in the future: To scale the database it may need to be moved to a cloud computing provider such as Azure and use a NoSql approach.

Going to use a manual implementation of a repository to get data

http://www.contentedcoder.com/2012/12/how-to-unit-test-repository.html – ‘Integration’ testing a Repository / Data Access Layer

  • No data dependencies. This test can be run against a blank database and will pass. It constructs all the data is needs for assertions.
  • Tests the main CRUD operations in sequence.
  • Although designed to run in a sequence, each test can be run standalone when debugging if required.
  • Can be run against any implementation of the ICompetitionRepository interface without having to change the test. E.g. If the concrete implementation is rewritten no code changes need to be made to the test.

ADO

Pros
  • Complete control over code. We have 100% control over every line of code.
  • Explicit use of DSL i.e. SQL queries have to be manually constructed.
  • Allows easy switching between in-line SQL or stored procedures.
  • No code generators or configuration files are used.
Cons
  • Complete control over code. The fact that we have full control means we need to write every line of code.
  • Lots of repetitive code. Almost all objects that need to be saved to the data store will have similar looking CRUD operations which we will need to write.
  • We need to write a separate repository methods for all queries.
  • We need to manually code all parameter and property mapping for our SQL queries.

This is pure, good old-fashioned coding. But it can be repetitive and will require granular changes for any future developments.

    public class CompetitionRepositoryADO : ICompetitionRepository
    {
        const string ConnectionString = @"server=.\SQL2012;database=SmsQuiz;Trusted_Connection=True;";

        public IEnumerable<Competition> GetCompetitions()
        {
            var competitions = new List<Competition>();

            using (var cn = new SqlConnection(ConnectionString))
            {
                var cmd = new SqlCommand("SELECT * FROM Competitions", cn);
                cn.Open();
                using (SqlDataReader reader = cmd.ExecuteReader())
                {
                    while (reader.Read())
                    {
                        var competition = new Competition
                        {
                            Question = reader["Question"].ToString(),
                            ClosingDate = (DateTime)reader["ClosingDate"],
                            CompetitionKey = reader["CompetitionKey"].ToString()
                        };

                        /* more properties removed for brevity */

                        competitions.Add(competition);
                    }
                }
            }

            return competitions;
        }

asdf

[TestClass]
    public class CompetitionRepositoryIntegrationTests
    {
        private ICompetitionRepository repository;
        private readonly Guid competitionID = new Guid("872715e8-c83b-e311-bf60-8280f70b7113");

        [TestInitialize]
        public void SetUp()
        {
            repository = new CompetitionRepositoryADO();
        }

        [TestMethod]
        public void GetCompetitions_Given_ShouldReturnListOfCompetitions()
        {
            IEnumerable<Competition> items = repository.GetCompetitions();

            Assert.IsTrue(items.Any());

            Assert.AreEqual("123xx", items.FirstOrDefault().CompetitionKey);
        }

DataAccessTests (Integration)

image
Good to test each layer of the app.  Very possible to do Unit tests, and (fewer) Integration tests on each.

EF Code First

As DB tables do not match our domain model, have to do mappings

Pros
  • Automates repetitive tasks such as parameter and property mapping.
  • The LINQ query to SQL syntax enables quick creation of query variants.
  • Abstracts away specific SQL Queries potentially making future database moves easier since we're not tied to any specific DSL.
  • Could be insanely productive for plain POCO classes.
Cons
  • Abstracts away specific SQL Queries. This can lead to some serious performance issues if we allow an abstraction to craft our SQL queries.
  • Has designer, configuration, or code generation files.
  • Is a black box. Do we really want the most critical part of our application to be heavily reliant on a black box we do not own?

Trade Off

ORMS are good when lots of small queries with minor differences.  However complex queries can become a problem… complex SQL generated.

Best of both worlds?  Use a micro orm

| | # 
( DDD )

Screen Shot 2012 11 29 at 12 10 24
We have this Domain Model that needs to be consumed – UI and db!

https://github.com/bbraithwaite/SmsQuiz/tree/Added-ServiceLayer

Screen Shot 2012 11 29 at 13 45 42
Application = Service Layer (aka Onion architecture)

For driving this out, just using an Interface as don’t know how we’re going to persist data yet

[TestClass]
    public class CompetitionServiceTests
    {
        [TestMethod]
        public void GetCompetitionsReturnsAListOfOpenCompetitions()
        {
            var service = new CompetitionService(new StubCompetitionRespository());

            GetCompetitionsResponse response = service.GetCompetitions();

            Assert.AreEqual(10, response.Competitions.Count());
        }
    }

    public class StubCompetitionRespository : ICompetitionRepository
    {
        public IEnumerable<Competition> GetCompetitions()
        {
            var list = new List<Competition>();

            for (int i = 1; i < 11; i++)
            {
                list.Add(new Competition() { Question = "Question #" + i.ToString() });
            }

            return list;
        }
    }

Test code passing in a Stub repository – so just testing this layer.

   public class CompetitionService
    {
        ICompetitionRepository _repository;

        // Poor mans di
        public CompetitionService(ICompetitionRepository repository)
        {
            _repository = repository;
        }

        public GetCompetitionsResponse GetCompetitions()
        {
            var response = new GetCompetitionsResponse();

            IEnumerable<Competition> competitions = _repository.GetCompetitions();

            // mapping code
            // Use AutoMapper? instead of this
            var items = new List<CompetitionItem>();

            for (int i = 0; i < competitions.Count(); i++)
            {
                items.Add(ConvertToItem(competitions.ElementAt(i)));
            }

            response.Competitions = items;

            return response;
        }

        // Use AutoMapper? instead of this
        private static CompetitionItem ConvertToItem(Competition competition)
        {
            var item = new CompetitionItem {Question = competition.Question};
            return item;
        }
    }

Service layer returning GetCompetitions.

    public class GetCompetitionsResponse
    {
        /// <summary>
        /// Gets or sets the competitions.
        /// </summary>
        /// <value>
        /// The competitions.
        /// </value>
        public IEnumerable<CompetitionItem> Competitions { get; set; }
    }

    public class CompetitionItem
    {
        public string Question { get; set; }
    }

The ‘DTO’ simple POCOS – rather than sending up complex models..

| | # 
( DDD )

Enough tests?

A simpler way of determining code coverage as you write tests is to count the IF, And, Or, Case, For and While statements.

Great refactoring in here.

| | # 
( DDD )

Prevent WinnerSelector.PickWinner() logic being called twice

3.AddedDomainEventsFinal – is the code

Talks about SRP

| | # 
( DDD )

To send an email/sms when a competition winner is selected we could put a method on Competition (assuming that CompetitionWinner has been set on the class)

image
Class diagram

 

Talks about factory patterns..but prefers domain events as no dependency.. and less complexity.

The trick is to raise some form of event that will be handled by some kind of service outside of the domain model. All we care about is that the event is raised in the correct context and that the parameters we expect are passed in. The concept is known as a Domain Event.

He’s written an extender for MSTEST

http://www.nuget.org/packages/MSTestExtensions/ – looks like rollback is included (like xunit)

Roughly 7 items in a class.. then split out.. so now have a WinnerSelector class which accepts CompetitionStatistics as a parameter. (and its possibly hundreds/thousands of Entrants)

image
Seems like a pub/sub implementation

| | # 
( DDD )

Interestingly he abstracted out CompetitionStatistics, to keep Competition class simple.. ie less than 7 properties.

image

Using Mocks inbound to CompetitionStatistics to test calculations:

image
So this class accepts a list of entrants, and a competition.  Then this class figures out all the statistics for the Competition.  Accepts Mock objects inbound which makes testing easy

image
Mocks to pass into CompetitionStatistics class for unit testing.

| | # 
# Monday, 21 October 2013
( DDD )

A key to being an effective programmer is maximising the portion of a program that you can safely ignore while working on any one section of code. Classes are the primary tool for accomplishing that objective.

Initially am finding the class structure difficult to understand, however it is becoming clearer with diagrams

image
By splitting into small classes, makes it easy to change.

    [TestMethod]
        public void EntrantIsValid()
        {
            // Arrange
            var entrant = new Entrant
                {
                    Answer = "A",
                    CompetitionKey = "WINPRIZE",
                    Source = EntrantSource.Sms,
                    Contact = new EntrantContact("123123123", EntrantContactType.Sms)
                    //Contact = new SmsContact("02345612345")
                };

            // Act
            bool isValid = entrant.IsValid;

            // Assert
            Assert.IsTrue(isValid);            
        }

The Contact details for an Entrant can be of different types eg Sms, Email.  So he has split EntrantContact into 2 classes – which makes less ‘Switchy’ code in the EntrantContact.  SRP!

public bool IsValid()
        {
            if (ContactType == EntrantContactType.Email)
            {
                return true;
            }

            if (ContactType == EntrantContactType.Sms)
            {
                return true;
            }

            return false;
        }
public class Entrant : IValidatable
    {
        /// <summary>
        /// Gets or sets the answer.
        /// </summary>
        /// <value>
        /// The answer.
        /// </value>
        public string Answer { get; set; }

        /// <summary>
        /// Gets or sets the competition key.
        /// </summary>
        /// <value>
        /// The competition key.
        /// </value>
        public string CompetitionKey { get; set; }

        /// <summary>
        /// Gets or sets the contact.
        /// </summary>
        /// <value>
        /// The contact.
        /// </value>
        public EntrantContact Contact { get; set; }

        /// <summary>
        /// Gets or sets the entry date.
        /// </summary>
        /// <value>
        /// The entry date.
        /// </value>
        public DateTime EntryDate { get; set; }

        /// <summary>
        /// Gets or sets the source e.g. SMS, Email.
        /// </summary>
        /// <value>
        /// The source.
        /// </value>
        public EntrantSource Source { get; set; }

        /// <summary>
        /// Gets a value indicating whether this instance is valid.
        /// </summary>
        /// <value>
        ///   <c>true</c> if this instance is valid; otherwise, <c>false</c>.
        /// </value>
        public bool IsValid
        {
            get
            {
                return (!string.IsNullOrEmpty(Answer) &&
                        !string.IsNullOrEmpty(CompetitionKey) &&
                        EntryDate != DateTime.MinValue &&
                        Source != EntrantSource.NotSet &&
                        // This is interesting as depending on what kind of contact, depends on the IsValid method called
                        Contact.IsValid
                        );
            }
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="Entrant" /> class.
        /// </summary>
        public Entrant()
        {
            this.EntryDate = DateTime.Now;
        }
    }

Contact.IsValid… smell due to tight coupling.. although don’t have to pass what kind of Contact it is.  Interface better? 
XML Comments annoying – am hiding in VS

| | # 
# Monday, 14 October 2013
( DDD )

http://www.contentedcoder.com/2012/11/aspnet-10-years-on-my-journey.html

New Requirements

Code Review

http://www.contentedcoder.com/2012/11/the-code-review-aspnet-10-years-on-2.html 

Code duplication

Use fiddler to find possible security flaws eg posting again

“It's a common idiom that re-writing your software is the biggest mistake you will ever make, however in this instance keeping this code would be a bigger mistake.”

Performance

http://www.contentedcoder.com/2012/11/performance-review-aspnet-10-years-on-3.html

  • Average pages/s
  • Average page response time

Change Access to SQL Express.

If no VS Ultimate, then WCAT, JMeter (Java)

Tools and Methodologies

http://www.contentedcoder.com/2012/11/modern-day-expectations-of-web.html

C# as easier to find devs

MVC as don’t intend to use Webworm's controls.

API (as need a method to accept SMS messages over HTTP) – JSON using Web API

Designing for Tablet – if a custom app, then need API access.  So eat own dogfood, an.. possibly Knockout or Backbone.

Continuous deployment – deploy early and often

Testing – MSTest

Business Logic

http://www.contentedcoder.com/2012/11/creating-your-first-business-logic.html

ADT – Abstract DataType – collection of data and operations htat work on that data

CC  (Code Complete)- A key to being an effective programmer is maximising the portion of a program that you can safely ignore while working on any one section of code. Classes are the primary tool for accomplishing that objective.

SRP – Single Responsibility Principle - There should never be more than one reason for a class to change.

Begin with a test

Nouns for property names

Enums

Code Smell: Most times you see a switch statement you should consider polymorphism.

Code: https://github.com/bbraithwaite/SmsQuiz/tree/First-Business-Logic   delete the 2 files which are not there in the sln.

Business Logic 2

http://www.contentedcoder.com/2012/11/creating-business-logic-part-2-aspnet.html

Use Domain Model rather than BLL (Business Logic Layer)

https://github.com/bbraithwaite/SmsQuiz/tree/Second-Business-Logic

Adding Domain Events to Business Logic

http://www.contentedcoder.com/2012/11/adding-domain-events-to-business-logic.html

Factory Pattern?

No use Events.. so testable (will use IoC later)

https://github.com/bbraithwaite/SmsQuiz/tree/Added-Domain-Events-Final

State Pattern

http://www.contentedcoder.com/2012/11/state-pattern.html

Every IF statement you write is a potential bug.

Open / Closed Principle - Software entities (classes, modules, functions, etc.) should be open for extension, but closed for modification

Test stubs

https://github.com/bbraithwaite/SmsQuiz/

Reviewing Domain Model

http://www.contentedcoder.com/2012/11/good-practices-when-reviewing-domain.html

  • Do you have enough Unit Test Coverage?
  • Are you suffering from Feature Envy?
  • Is your Code Too Expensive?
  • Remember: Tell, Don't Ask!
  • Scrutinise your Class Dependencies: new = Glue
  • Why it's a good idea to use an EntityBase
  • Are your unit tests crossing boundaries?
  • Use Extension Methods to contain Generic Functions
  • Unit Tests to the Rescue

85% code coverage

Cyclomatic complexity

Tell, Don’t Ask

EntityBase

Consuming the Domain Model

http://www.contentedcoder.com/2012/12/consuming-domain-model-10-years-of-net.html

Service layer

API Layer

Moq

https://github.com/bbraithwaite/SmsQuiz/tree/Added-ServiceLayer

Data Layer

http://www.contentedcoder.com/2012/12/choosing-data-access-implementation-10.html

SQLServer

Integration tests

Manual Implementation..pro’s and con’s

ORM Implementation..pros and cons

Dapper 1

http://www.contentedcoder.com/2012/12/creating-data-repository-using-dapper.html

Dapper 2

http://www.contentedcoder.com/2013/05/orms-don-reinvent-wheel.html

Dapper and EF

https://github.com/bbraithwaite/HybridOrm

Make all layers work – Replace Service Layer with HTTP API

http://www.contentedcoder.com/2013/02/replacing-service-layer-with-http-api.html

https://github.com/bbraithwaite/SmsQuiz/

Creating the Web API

http://www.contentedcoder.com/2013/03/creating-your-first-web-api.html

ASP.NET Web API – shipped with MVC4

Repository Pattern

Unit testing ASP.NET Web API (http://www.peterprovost.org/blog/2012/06/16/unit-testing-asp-dot-net-web-api)

Designing an MVC UI Layer for use with Web API

http://www.contentedcoder.com/2013/06/the-mvc-ui-layer.html

| | #