KiGG Design And Architecture – Part 3 The Core

by mosessaur| 29 December 2009| 4 Comments

Introduction

In part 2, we explored KiGG project structure. I gave a short brief and summary about each project in the solution. And briefly discussed the relation between them.

In this part we are going to start going much deeper. Staring with the Core, and this might take several parts by itself as the Core is huge and contains lots of stuff that worth to be discussed.

Namespaces

Before starting it worth to mention that the core is free of any default implementation that depends on and external or third party assemblies. Now I’m going to start by listing namespaces inside Kigg.Core project with brief of each namespace:

  • Kigg: The root namespace. This namespace is the default namespace. Contains all common classes that might be needed for other namespaces including extensions, utilities and helpers.
  • Kigg.DomainObjects: This is the domain model namespace. Interfaces for all domain classes are defined in this namespace; e.g. IStory, ICategory, IUser etc...
  • Kigg.Infrastructure: Infrastructure root namespaces. Contains infrastructure application support classes and interfaces that when implemented will provide specific infrastructure implementation. Such as event aggregation, logging and caching. Logging and caching are defined as interfaces. However basic implementation is done with Enterprise library caching and logging application blocks. These implementations are located in different assembly. As mentioned above, the core is free of any default implementation that depends on and external or third party assemblies.
  • Kigg.Repository: Inside this namespace, all possible repositories that will be used across the application are defined as interfaces with no specific implementation. Except for decorator repositories (applying Decorator Pattern) which are used to apply caching and logging.
  • Kigg.Service: Common services used by different kigg sections. Services consumes repositories and infrastructure.
  • Kigg.Infrastructure.DomainRepositoryExtensions: This is a bridge assembly between DomainObjects and Repositories. Repositories usually returns instances of interfaces defined under DomainObjects namespace. At the same time, Domain objects might need to perform few operation based on data provided by repositories. To remove direct dependency from domain objects to repositories few extension methods made for specific domain objects. These extension methods access the repositories.

Extensions

KiGG provide sets of utilities and extensions that encapsulate common functionalities. As these stuff should be available to every project that references Core project it is added within the Core. And because it should be available to all namespaces implicitly, it is added to the root namespace Kigg.

Few examples of extensions to .Net System libraries are:

  • EnumerableExtension: Provides extension methods to any IEnumerable<T>. e.g. ForEach extension method that acts as simple shortcut for foreach loop.
  • CollectionExtension: Provides extension methods to any ICollection<T>. e.g. IsNullOrEmpty extension methods that check if the collection is null or has no items (empty).

There are some other extensions for .Net System classes that you can explore.

Another extensions are provided for Domain Objects. Because these extensions are related only to DomainObjects, they are located under Kigg.DomainObjects. These extensions are:

  • StoryExtension: Contains few helpful extensions such as IsNew which checks if the story is new or not. Another extension SmallThumbnail that consumes the IThumbnail to generate a small thumb snapshot image of the story web page.
  • UserExtension: Contains few helpful extensions such IsAdministrator and IsBot methods which are used to check if the user belongs to those specific roles.
  • TagContainerExtension: Contains few helpful extensions such as HasTags method that checks if the specified contain contains certain passed tags to this method or not. Tag Containers are stories and users.

Helpers

About Check & Argument classes:
Helpers contains developer helper classes such as Check & Argument. These classes are for developer support only and not intended to be exposed to public usage. You use these classes validate parameters passed to methods. Argument class is a nested class of Check. In future if there are addition things that belongs to Check other than arguments should be added as nested class inside Check.

  1. public class Check
  2. {
  3.     internal Check(){}
  4.  
  5.     public class Argument
  6.     {
  7.         internal Argument(){}
  8.         public static void IsNotEmpty(Guid argument, string argumentName)
  9.         {
  10.             if (argument == Guid.Empty)
  11.             {
  12.                 throw new ArgumentException("\"{0}\" cannot be empty guid.".FormatWith(argumentName), argumentName);
  13.             }
  14.         }
  15.     }
  16. }

Constants class:
Another helper common class, that supposed to hold all common constants used in all projects that form kigg solution. Currently it defines the CurrentCulture. It should also contains MaxDateTime, MinDateTime, CurrentVersion etc… Note that what is meant by constant not necessary be a constant type. for Example CurrentCulture return CultureInfo.CurrentCulture. So it is more like static shared information to all assemblies in this solution.

  1. public static class Constants
  2. {
  3.     public static readonly DateTime ProductionDate = new DateTime(2008, 1, 11);
  4.     public static CultureInfo CurrentCulture
  5.     {
  6.         get
  7.         {
  8.             return CultureInfo.CurrentCulture;
  9.         }
  10.     }
  11. }

SystemTime class:
Another form of constants but this time specific to Date & time.

  1. public static class SystemTime
  2. {
  3.     public static Func<DateTime> Now = () => DateTime.UtcNow;
  4. }

PagedResult class:
This class is very important. It represents a single page in a results set. It also holds information about total records in the whole results that this page page is part of. Very useful for applying paging front end web pages such as displaying page of stories.

  1. public class PagedResult<T>
  2. {
  3.     private readonly ReadOnlyCollection<T> _result;
  4.     private readonly int _total;
  5.  
  6.     public PagedResult(IEnumerable<T> result, int total)
  7.     {
  8.         Check.Argument.IsNotNull(result, "result");
  9.         Check.Argument.IsNotNegative(total, "total");
  10.  
  11.         _result = new ReadOnlyCollection<T>(new List<T>(result));
  12.         _total = total;
  13.     }
  14.  
  15.     public PagedResult() : this(new List<T>(), 0){}
  16.  
  17.     public ICollection<T> Result
  18.     {
  19.         get
  20.         {
  21.             return _result;
  22.         }
  23.     }
  24.     public int Total
  25.     {
  26.         get
  27.         {
  28.             return _total;
  29.         }
  30.     }
  31.     public bool IsEmpty
  32.     {
  33.         get
  34.         {
  35.             return _result.Count == 0;
  36.         }
  37.     }
  38. }

Configuration

KiGG provide many configuration parameters that can be supplied through configuration file. Or if you wish after knowing more about KiGG you can build these configuration to be stored and updated in database.

There is a special configuration settings interface that defines KiGG configurable system parameters such as number of stories to be displayed per page. For more details about different configuration settings I highly recommend that you read Overview of KiGG Configuration Settings in KiGG Deployment Guide Part 2.

IConfigurationSettings is the interface that defines those configurable parameters/properties of KiGG. This interface and its simple implementation declared under root namespace Kigg.

  1. public class ConfigurationSettings : IConfigurationSettings
  2. {
  3.     public string RootUrl
  4.     {
  5.         get;
  6.         set;
  7.     }
  8.  
  9.     public string WebmasterEmail
  10.     {
  11.         get;
  12.         set;
  13.     }
  14.  
  15.     public string SupportEmail
  16.     {
  17.         get;
  18.         set;
  19.     }
  20.  
  21.     public string DefaultEmailOfOpenIdUser
  22.     {
  23.         get;
  24.         set;
  25.     }
  26.  
  27.     public string SiteTitle
  28.     {
  29.         get;
  30.         set;
  31.     }
  32.  
  33.     public string MetaKeywords
  34.     {
  35.         get;
  36.         set;
  37.     }
  38.  
  39.     public string MetaDescription
  40.     {
  41.         get;
  42.         set;
  43.     }
  44.  
  45.     public int TopTags
  46.     {
  47.         get;
  48.         set;
  49.     }
  50.  
  51.     public int HtmlStoryPerPage
  52.     {
  53.         get;
  54.         set;
  55.     }
  56.  
  57.     public int FeedStoryPerPage
  58.     {
  59.         get;
  60.         set;
  61.     }
  62.  
  63.     public int CarouselStoryCount
  64.     {
  65.         get;
  66.         set;
  67.     }
  68.  
  69.     public int HtmlUserPerPage
  70.     {
  71.         get;
  72.         set;
  73.     }
  74.  
  75.     public int TopUsers
  76.     {
  77.         get;
  78.         set;
  79.     }
  80.  
  81.     public bool AutoDiscoverContent
  82.     {
  83.         get;
  84.         set;
  85.     }
  86.  
  87.     public bool SendPing
  88.     {
  89.         get;
  90.         set;
  91.     }
  92.  
  93.     public string PromoteText
  94.     {
  95.         get;
  96.         set;
  97.     }
  98.  
  99.     public string DemoteText
  100.     {
  101.         get;
  102.         set;
  103.     }
  104.  
  105.     public string CountText
  106.     {
  107.         get;
  108.         set;
  109.     }
  110.  
  111.     public float MinimumAgeOfStoryInHoursToPublish
  112.     {
  113.         get;
  114.         set;
  115.     }
  116.  
  117.     public float MaximumAgeOfStoryInHoursToPublish
  118.     {
  119.         get;
  120.         set;
  121.     }
  122.  
  123.     public bool AllowPossibleSpamStorySubmit
  124.     {
  125.         get;
  126.         set;
  127.     }
  128.  
  129.     public bool SendMailWhenPossibleSpamStorySubmitted
  130.     {
  131.         get;
  132.         set;
  133.     }
  134.  
  135.     public bool AllowPossibleSpamCommentSubmit
  136.     {
  137.         get;
  138.         set;
  139.     }
  140.  
  141.     public bool SendMailWhenPossibleSpamCommentSubmitted
  142.     {
  143.         get;
  144.         set;
  145.     }
  146.  
  147.     public string PublishedStoriesFeedBurnerUrl
  148.     {
  149.         get;
  150.         set;
  151.     }
  152.  
  153.     public string UpcomingStoriesFeedBurnerUrl
  154.     {
  155.         get;
  156.         set;
  157.     }
  158.  
  159.     public decimal MaximumUserScoreToShowCaptcha
  160.     {
  161.         get;
  162.         set;
  163.     }
  164.  
  165.     public int StorySumittedThresholdOfUserToSpamCheck
  166.     {
  167.         get;
  168.         set;
  169.     }
  170. }

Conclusion

This part already get long enough. In this part I covered different namespaces defined in KiGG Core project. I also explored the root namespace “Kigg” with extensions, helpers and configuration classes defined on it. Covering the Core might take several parts itself.

In next part I’ll explore the infrastructure namespace under KiGG Core project. I hope enjoyed this part and found it informative.

Comments (4) -

Chris
Chris United States on 12/24/2009 8:18 AM Great series on the KiGG architecture, Muhammad.

One thing I disagree with is the use of a ForEach extension method... it isn't really descriptive. Many of the extensions on IEnumerable<T> can be said to be one type of ForEach or another. In my Fluent.NET framework, I called the non-deferred version of the ForEach functionality Execute because that's what it does: executes an action for each element in the sequence.
Muhammad Mosa
Muhammad Mosa Egypt on 12/24/2009 9:46 AM I just had a look at fluentnet.codeplex.com it is pretty cool and when it grows up it can make a very useful set of extensions.

I guess you disagreement here is regarding method name? And for first instance, one might think of naming the method ForEach or use Each because it is just a simple shortcut for foreach loop!
Myself I cannot decide which is better, Execute or ForEach or even Each. All does the same thing, but everyone see the name from his point of view!
Myself, I follow the software specs, I mean KiGG was initiated with ForEach, in Shrinkr it is Each, and if I got a chance to be part of fluent.net I will follow Execute
Chris
Chris United States on 12/25/2009 10:23 AM My disagreement is entirely with the name, but if that's the way it started I see no reason to rename it either =).

I should look at Shrinkr's implementation. I was confused as to how to name the deferred version so I went with Iterate, but I consider that name to be rather horrible. If Shrinkr's Each is deferred I may change the name of Iterate to that.

You're welcome to join Fluent.NET. Its focus is creating extension methods where they should have been to begin with, making the .NET Framework more fluent in the process. So, it's easy to add something when you come across it, but time consuming to mature because it requires trolling the .NET framework =).
Muhammad Mosa
Muhammad Mosa Egypt on 12/26/2009 2:19 PM Regarding Each, this reminds me first time jQuery method 'each' because it performs an action for each element in the collection. Maybe this is where the name came from Smile

I want to Join the Fluent.Net! I know it will takes good time to mature.
I wonder if you heard about this website http://www.extensionmethod.net/ I guess it will be cool library in future as well

Pingbacks and trackbacks (6)+

Comments are closed