Skip to content

Commit

Permalink
working on the factory sample
Browse files Browse the repository at this point in the history
  • Loading branch information
abdullin committed Aug 28, 2012
1 parent 5c5f00c commit da2e4da
Showing 1 changed file with 217 additions and 48 deletions.
265 changes: 217 additions & 48 deletions E004-event-sourcing-basics/Program.cs
Original file line number Diff line number Diff line change
@@ -1,85 +1,254 @@
using System;
#region (c) 2010-2012 Lokad All rights reserved

// You must not remove this notice, or any other, from this software.
// This document is the property of LOKAD SAS and must not be disclosed.

#endregion

using System;
using System.Collections.Generic;
using System.Threading;

namespace E003_event_sourcing_basics
{
class Program
{
static void Main(string[] args)
{
// let's talk about entities.
// entity is something that has a name that is unique within a certain zone of interest
// or this area has only one instance of this entity.

// given name, we can always know how to find that entity (or a postal service will know that)
// We say that entity is identified by name. in software that name is called identifier or identity

// entity can change looks, behaviors, but it will still keep identifier. That's how we can find it.
// or send it a message.

// Now, let's talk about entities.

// in previous lessons we've learned that message is a remote and decoupled equivalent
// of a message call.

// So, now we will model entity called factory. We will write code that captures
// actions it can be commanded to carry out. However, we will express these as method
// calls instead of the commands. Names of method calls will be same as names of commands
// parameters will match to the members.

// it will be shorter right now (besides, you'll learn than message == method call),
// besides, this approach will have additional meaning in real development down the road.


public sealed class FactoryImplementation1
{
// this is linguistically equivalent to command that is sent to this factory
// public class AssignEmployeeToFactory
// {
// public string EmployeeName { get; set; }
// }
public void AssignEmployeeToFactory(string employeeName) {}
public void TransferShipmentToCargoBay(string shipmentName, CarPart[] parts) {}
public void UnloadShipmentFromCargoBay(string employeeName) {}
public void ProduceCar(string employeeName, string carModel) {}
}
}


public sealed class ProductBasketState
{
public ProductBasketState(IEnumerable<object> events)
// these methods will contain following elements (which can be really complex
// or can be optional)
// Checks (check if operation is allowed)
// some work that might involve calculations, thinking, access to some tooling
// Event that we write to journal to mark the work as being done.


public sealed class FactoryImplementation2
{
Products = new Dictionary<string, double>();
foreach (var e in events)
// this is linguistically equi
public void AssignEmployeeToFactory(string employeeName)
{
// CheckIfEmployeeCanBeAssignedToFactory(employeeName);
// DoPaperWork();
// RecordThatEmployeeAssignedToFactory(employeeName);
}

public void TransferShipmentToCargoBay(string shipmentName, CarPart[] parts)
{
// CheckIfCargoBayHasFreeSpace(parts);
// DoRealWork("unloading supplies...");
// DoPaperWork("Signing that shipment acceptance form");
// RecordThatSuppliesAreAvailableInCargoBay()
}

public void UnloadShipmentFromCargoBay(string employeeName)
{
Mutate(e);
// DoRealWork("passing supplies");
// RecordThatSuppliesWereUnloadedFromCargoBay()
}

public void ProduceCar(string employeeName, string carModel)
{
// CheckIfWeHaveEnoughSpareParts
// CheckIfEmployeeIsAvailable
// DoRealWork
// RecordThatCarWasProduced
}
}

public void Mutate(object e)

// Now let's "unwrap" AssignEmployeeToFactory
// we'll start by adding a list of employees

public class FactoryImplementation3
{
((dynamic) this).When((dynamic) e);
// THE Factory Journal!
public List<IEvent> JournalOfFactoryEvents = new List<IEvent>();


List<string> _ourListOfEmployeeNames = new List<string>();


public void AssignEmployeeToFactory(string employeeName)
{
Print("?> Command: Assign employee {0} to factory", employeeName);
// CheckIfEmployeeCanBeAssignedToFactory(employeeName);
if (_ourListOfEmployeeNames.Contains(employeeName))
{
// yes, this is really weird check, but this factory has really strict rules.
// manager should've remembered that
RecordThat(new EmployeeKickedOutOfFactory()
{
EmployeeName = employeeName,
Reason = string.Format("the name of '{0}' only one employee can have", employeeName)
});
return;
}

if (employeeName == "bender")
{
RecordThat(new EmployeeKickedOutOfFactory()
{
EmployeeName = employeeName,
Reason = "Guys with name 'bender' are trouble."
});
return;
}

DoPaperWork("Assign employee to the factory");

RecordThat(new EmployeeAssignedToFactory()
{
EmployeeName = employeeName
});
// DoPaperWork();
// RecordThatEmployeeAssignedToFactory(employeeName);
}

void DoPaperWork(string workName)
{
Print(" > Work: papers... {0}... ", workName);
Thread.Sleep(2000);

}
void RecordThat(IEvent e)
{
// we record by jotting down notes in our journal
JournalOfFactoryEvents.Add(e);
// we also announce this event inside factory.
// so that all workers will immediately know
// what is going inside
((dynamic) this).AnnounceInsideFactory((dynamic) e);

// ok, we also print to console, just because we want to know
Print("!> Event: {0}", e);
}





void AnnounceInsideFactory(EmployeeAssignedToFactory e)
{
_ourListOfEmployeeNames.Add(e.EmployeeName);
}
void AnnounceInsideFactory(EmployeeKickedOutOfFactory e)
{
// this is a trick. Don't care about it for now
}
}

public IDictionary<string, double> Products { get; private set; }
public class EmployeeAssignedToFactory : IEvent
{
public string EmployeeName;

public void When(ProductAddedToShoppingBasket e)
public override string ToString()
{
return string.Format("new worker joins our forces: '{0}'", EmployeeName);
}
}
public class EmployeeKickedOutOfFactory : IEvent
{
if (!Products.ContainsKey(e.Name))
public string EmployeeName;
public string Reason;

public override string ToString()
{
Products[e.Name] = 0;
return string.Format("'{0}' is not allowed, because '{1}'", EmployeeName, Reason);
}
Products[e.Name] += e.Quantity;
}
}

public interface ICommand {}
// let's run this implementation
public static void RunFactoryImplementation3()
{
var factory = new FactoryImplementation3();
factory.AssignEmployeeToFactory("yoda");
factory.AssignEmployeeToFactory("luke");
factory.AssignEmployeeToFactory("yoda");
factory.AssignEmployeeToFactory("bender");
}

public interface IEvent {}

[Serializable]
public class AddProductToShoppingBasket : ICommand
{
public string Name;
public double Quantity;





static void Main(string[] args)
{
// let's try running this
RunFactoryImplementation3();
}

static void Print(string format, params object[] args)
{
if (format.StartsWith("!"))
Console.ForegroundColor = ConsoleColor.DarkGreen;
else if (format.StartsWith("?"))
{
Console.ForegroundColor = ConsoleColor.DarkBlue;
Console.WriteLine();
}
else if (format.StartsWith(" >"))
Console.ForegroundColor = ConsoleColor.DarkYellow;
else Console.ForegroundColor = ConsoleColor.Gray;
Console.WriteLine(format, args);
}
}
[Serializable]
public class ProductAddedToShoppingBasket : IEvent

public interface IEvent
{
public string Name;
public double Quantity;

}

[Serializable]
public class RemoveProductFromShoppingBasket : ICommand
public sealed class Factory
{
public string Name;
public double Quantity;
}
public void AssignEmployeeToFactory(string name) {}

public void ShipSuppliesToCargoBay(string shipment, CarPart[] parts) {}

[Serializable]
public class ApplyDiscountCardToBasket
{
public DiscountType Discount;
public void UnloadSuppliesFromCargoBay(string employee) {}

public void ProduceCar(string employee, string carModel) {}
}
public enum DiscountType

public sealed class CarPart
{
Standard, Premium, LoyalShopper
public string Name;
public int Quantity;
}

//public class DiscountAddedToProduct
//{
// public string Name;
// public double
//}
}
}

0 comments on commit da2e4da

Please sign in to comment.