The study - a sample EBC Again and again I am asked if I can provide a complete example of EBC, which I will do that here.
However, I have to say beforehand that I thought at first that the coding is sufficient by Ralf (Ralf's
EBC blog entries ) in order to identify the scope and benefits of the EBC. Since this is not so, I hereby make a first complete example available that were built on the basis of the first generation EBC and its Post from Christopher's (
Christophe review ) inspired.
The scenario
Christof described a board that calculates the gross value of an amount and then rounds the result to two decimal places. He was to bear in mind that a board contains an implicit logic in the wiring, resulting from the task. One could make the rounds before or after the calculation.
At this point I want to talk but no implicit or explicit logic in the board, but EBC present in a sample. I opted for the round after the calculation.
textual formulation of the components
quote from Christophe's post:
"Component A:
- calculating VAT from an input
- Input: any number
- Issue: Entry * value added tax rate (2% :-())
Part B:
- Task: Formatting the input
- Input: any numbers
- Issue: number with exactly 2 decimal places, if necessary suitably rounded
Both devices are connected to board "VAT" "
Graphic formulation - Wiring Diagram
This diagram shows the components and the interaction, ie the. Making the first requirement to calculate and then by rounding, dar.
I plead for a tool to have with the wiring is shown graphically, because this form of representation is much easier to understand than the underlying code.
The project
The Solution Project (Visual C # 2010 Express) I have to request such a way that is clear, where what happens. A project for the contracts, one for the implementation and one for the tests. So that it is running and can be tried once, I have not created a motherboard that instantiates the Tax Board and shall provide the parts.
Unfortunately I have to mix Concerns, because I have no further project for EBC is planned to open the framework, as a component, the numbers round, has now really looking to do with the calculation of gross value. But looking ahead I have the component and its carrying Contract de.ebc.Framework in the namespace for the event that it would later be such a framework.
The tests are still (!) Implemented with NUnit, but I prefer Behavior Driven Testing, and will probably get in the near future or NSpec MSpec back out of mothballs and then write all my tests with it. I find this kind of testing much easier to understand.
The Contracts
The Contracts define the components, that is not special, because now should be state of the art. The special feature of these contracts but the fact that no pins are defined and methods, functions and / or fields.
Good, the input pin is also a method, but that is the nature of the thing. In some way so the signal must be, the message will be introduced into the component. It must, however, a fundamental difference between the pins of a board and where the parts are made.
In some tests, I checked the readability of the code by using pin variations and found that the difference increases the readability.
here once a complete example using the method of Ralf;
/ / Variant 1 InPin
/ / In Contract:
public interface IComponent {
void In_InMessage ( TypeOfMessage message ) ;
}
/ / The board
public class MyBoard {
private Action \u0026lt; TypeOfMessge > _channelMethod ;
public MyBoard ( IComponent component) {
/ / wiring on the board
this . _channelMethod = component. In_InMessage ;
...
}
/ / Board InPin
public void In_BoardMessage ( MessageType message ) {
this . _channnelMethod ( message ) ;
}}
This version I think While quite nice, but I did not find it particularly easy to read. Just the need for an extra box _channelMethod "came to pass in order to define the message to the first of the first component InPin me bulky. Other tools such as wire
classes that connect the pins have not please me. So I have found by trial and error the following variant of sufficiently good.
EBC Pins
- namespace de.ebc.Framework
- {
- public delegate void InPin \u0026lt;TInput> (TInput inmessages);
- public delegate void OutPin \u0026lt;TOut> (Tout outMessage);}
-
How these pins can be integrated into the code you see in the following codeing.
I start with the definition of the board, on which the two parts are connected. Two pins on the board are defined. One receives the message (In_CalcToGross) and the other returns the result (Out_Gross). Attention, here is the InPin as Field have been defined from the said above reason.
EBC IVatBoard Contract
- namespace de.ebc.vatboard
-
- {/ / / \u0026lt;summary>
- / / / Defines a component that can handle VAT
- / / / \u0026lt;/ summary>
- public interface IVatBoard
- {
- / / / \u0026lt;summary>
- / / / Computes the gross value of a number
- /// </summary>
- /// <param name="netto"></param>
- InPin < Decimal > In_CalcToGross { get ; set ; }
-
- / / / \u0026lt;summary>
- / / / Is the gross returns
- / / / \u0026lt;/ summary>
- event OutPin \u0026lt; Decimal > Out_Gross;
- }}
-
The component that performs the calculation is defined by the interface IVatCalculator. Again, it is no surprise, because it describes only the required pins. However, a part of InPin not represented by a delegate, here again is a method used.
EBC IVatCalculator Contract
- namespace de.ebc.vatboard
- {
- / / / \u0026lt;summary>
- / / / Defines a component that calculates the gross value of a number
- / / / \u0026lt;/ summary> public
- interface IVatCalculator
- {
- / / / \u0026lt;summary>
- / / / Berchnet the gross value of a number
- ; / / / \u0026lt;/ summary>
- / / / \u0026lt;param name="netValue"> \u0026lt;/ param>
- void In_CalculateGross ( Decimal NetValue);
-
- / / / \u0026lt;summary>
- / / / Is the gross returns
- / / / \u0026lt;/ summary>
- event OutPin \u0026lt; Decimal > Out_Gross;
- ;}}
-
Now even the definition of the component that takes the rounding of numbers, and you are ready Contracts. Note that this contract is not the namespace of the VatBoards is assigned (for reasons of Separation of Concerns).
EBC IRoundDecimals Contract
- namespace de.ebc.Framework
-
- {/ / / \u0026lt;summary>
- can / / / Defines a component, round the numbers
- / / / \u0026lt;/ summary>
- ; public interface IRoundDecimals
- {
- / / / \u0026lt;summary>
- / / / number rounded to two decimal
- /// </summary>
- /// <param name="number"></param>
- void In_RoundingToTwoDecimals( Decimal number);
-
- / / / \u0026lt;summary>
- / / / Returns the number rounded back
- ; / / / \u0026lt;/ summary>
- event OutPin \u0026lt; ; Decimal > Out_RoundedNumber;
- }}
-
The Components (Parts and boards) What is to be expected, the components of the meat of the Contracts and it is waiting for us, again, no surprise.
First, the Board, which is home to the wiring.
EBC VatBoard
- namespace de.ebc.vatboard.Components
- {
- public class VatBoard : IVatBoard
- {
- public VatBoard( IVatCalculator vatCalculator, IRoundDecimals numberRounder)
- {
- / / InPin the Board with the first component wiring
- this In_CalcToGross = vatCalculator.In_CalculateGross;.
-
- / / Result for rounding to the next component forward
- vatCalculator.Out_Gross + = numberRounder.In_RoundingToTwoDecimals;
- ;
- / / round number return
- numberRounder.Out_RoundedNumber += this .OnOutRoundedNumber;
- }
-
- private void OnOutRoundedNumber( Decimal number) {
- this .Out_Gross(number);
- }
-
- public InPin < Decimal > In_CalcToGross {
- get ;
- set;}
-
-
- public event OutPin \u0026lt; decimal> = Out_Gross delegate {};}
-
- }
Here is visible, why I have a Delegeate InPin use, because I can now InPin connect the board directly with the InPin of the first component, no code noise.
Now just the two working components:
EBC VatCalculator
- namespace de.ebc.vatboard.Components
- {
- public class VatCalculator : IVatCalculator
- {
- public VatCalculator ( decimal vatInPercent) {
- this .VatInPercent = vatInPercent;
- }
-
- public Decimal VatInPercent { get ; private set ; }
-
- public void In_CalculateGross( decimal netValue)
- {
- Decimal gross = GetGross(netValue);
- this .Out_Gross(gross);
- }
-
- private decimal GetGross( decimal netValue)
- {
- return netValue * (1 + VatInPercent / 100);
- }
-
- public event OutPin < decimal > Out_Gross = delegate { };
- }
- }
und
EBC RoundDecimals
- namespace de.ebc.vatboard.Components
- {
- public class RoundDecimals : IRoundDecimals
- {
- public event OutPin < decimal > Out_RoundedNumber = delegate { };
-
- public void In_RoundingToTwoDecimals( decimal number)
- {
- decimal roundedNumber = RoundNumber(number);
- this .Out_RoundedNumber(roundedNumber);
- }
-
- private decimal RoundNumber( decimal number)
- {
- return Decimal Round (number, 2);.
- }
- }}
-
Yes, it can be refactored, I see it now, but for the example is not relevant now.
When I wrote the code well, it needs no further explanation of what happened here. And to determine this, I will make no further comment, because I hope for what the reader ;-)
The testing of the solution Testing is simple, because I can test each component individually through their paces. I could also try all the modules for the test and create. I have not done here.
As mentioned NUnit is used, what will I think change in the near future.
Testing of VatCalculator component is a fixed net value of 12 to send into the component into it, only to receive the gross value and evaluate.
testing VatCalculator
- [ TestFixture ]
- public class TestVatCalculator : WithVatCalculator
- {
- [ Test ]
- public void Calculate_For_Number_12()
- {
- decimal netValue = 12;
- decimal vat = this .VatCalculator.VatInPercent;
- decimal shouldBrutto = (netValue * (1+vat/100));
-
- this .VatCalculator.Out_Gross += brutto =>
- {
- Assert AreEqual (should gross, gross).
- };
-
- ;. this VatCalculator.In_CalculateGross (NetValue);
- }}
-
Yes well, it's not really the Brain Burner, but it illustrates the ease with which an EBC can be tested.
The second Component, the curvature component, we tested the same way.
testing RoundDecimals
- [ TestFixture ]
- public class TestRounding : WithRoundDecimals
- {
- [ Test ]
- public void Round_To_Two_Decimals () {
-
- ; decimal aNumber = 12.34567m;
- this .RoundDecimals.Out_RoundedNumber += roundedNumber =>
- {
- Assert .AreEqual(12.35m, roundedNumber);
- }; .
-
- this RoundDecimals.In_RoundingToTwoDecimals (aNumber);}
-
- }
The solution as an application And how the whole thing looks in the application context?
I chose the example of the Console, which is not really about rachend and then the call to the following terms:
VatBoard as application
- namespace de.ebc.VatMainBoard
- {
- class Program
- {
- static void Main( string [] args)
- {
-
- Decimal vat = 16m;
-
- IVatCalculator vatCalculator = new VatCalculator (vat);
- IRoundDecimals numberRounder = new RoundDecimals ();
-
- IVatBoard vatBoard = new VatBoard (vatCalculator, rounder number);
-
- / / Result output
- vatBoard.Out_Gross + = large => {
- Console .WriteLine(gross);
- };
-
- string netValueString = Console .ReadLine();
- Decimal netValue = 0;
-
- Decimal .TryParse(netValueString, out netValue);
- vatBoard.In_CalcToGross(netValue);
-
- Console ReadLine ();.
- }
- }}
-
And not lose many words because it is just an example and it should explain itself, otherwise I've just not written well.
The project can be downloaded from CodePlex at the following link
EBC samples.
Well then ran times and forth with the comments.
Jan (ek)