%in Bahrain+277-882-255-28 abortion pills for sale in Bahrain
Why should we use SIMPLE FACTORY pattern even when we have one class only?
1. Why should we use SIMPLE FACTORY pattern
even when we have one class only?
Based on DateTime (PHP) and PHPUnit
by Rafal Ksiazek, IT Leader
https://github.com/harpcio
2. Real example (or maybe not):
Application for an airline company
based in Europe
Requirements:
…
User should be able to create a flight route
...
3. Without SF With SF
public function createFlightRoute(User $user, $startTime, ...)
{
$route = new FlightRoute();
$route->setCreateTime(new DateTime());
$route->setStartTime(new DateTime($startTime));
$route->setEndTime(new DateTime($endTime));
$route->setStartPlace($startPlace);
$route->setEndPlace($endPlace);
$route->setCargo($cargo);
$route->setCreatedBy($user);
...
return $route;
}
class DateTimeFactory implements DateTimeFactoryInterface
{
public function create(
$time = 'now', DateTimeZone $timeZone = null
) {
return new DateTime($time, $timeZone);
}
}
…
public function __construct(..., DateTimeFactoryInterface $dateTimeFactory)
{
….
$this->dateTimeFactory = $dateTimeFactory;
}
public function createFlightRoute(User $user, $startTime, ...)
{
$route = new FlightRoute();
$route->setCreateTime($this->dateTimeFactory->create());
$route->setStartTime($this->dateTimeFactory->create($startTime));
$route->setEndTime($this->dateTimeFactory->create($endTime));
$route->setStartPlace($startPlace);
$route->setEndPlace($endPlace);
$route->setCargo($cargo);
$route->setCreatedBy($user);
...
return $route;
}
4. There is one thing we can be sure of:
CHANGE
So be prepared!
5. New client requirement!
Move our application to the new
powerful dedicated server
in US (Detroit)
The programmer copies the code and databases,
checks that everything works (twice!)
… but he forgets about timezones
A few hours later, first unhappy customers began to call the company
6. The blocker task!
The programmer changes the timezone on Detroit's server to European
timezone in one minute!
But we got
new client requirement!
For security, application should be independent of
the server's timezone
7. Without SF With SF
… somewhere in configuration
define('APP_TIME_ZONE', 'Europe/NoExistingCity')
… in „n” classes:
public function createFlightRoute(User $user, $startTime, ...)
{
$route = new FlightRoute();
$route->setCreateTime(
new DateTime('now', new DateTimeZone(APP_TIME_ZONE))
);
$route->setStartTime(
new DateTime($startTime, DateTimeZone(APP_TIME_ZONE))
);
$route->setEndTime(
new DateTime($endTime, DateTimeZone(APP_TIME_ZONE))
);
$route->setStartPlace($startPlace);
$route->setEndPlace($endPlace);
$route->setCargo($cargo);
$route->setCreatedBy($user);
...
return $route;
}
… somewhere in configuration
define('APP_TIME_ZONE', 'Europe/NoExistingCity')
… in only ONE class:
class DateTimeFactory implements DateTimeFactoryInterface
{
public function create($time = 'now', DateTimeZone $timeZone = null) {
if (null === $timeZone) {
$timeZone = new DateTimeZone(APP_TIME_ZONE);
}
return new DateTime($time, $timeZone);
}
}
8. … after hours of discussion and calculation of the cost of the failure, we got:
New client requirement!
All functionalities based on dates
should be fully tested
9. Without SF With SF
… in the test class:
public function setUp() {
$this->testedObject = ...
}
public function testCreateFlightRoute() {
$createTime = new DateTime('now', DateTimeZone(APP_TIME_ZONE));
$result = $this->testedObject->createFlightRoute($user, $startTime, ...);
$this->assertSame(
$result->getCreateTime()->format('Y-m-d H:i:s'),
$createTime->format('Y-m-d H:i:s')
);
}
But sometimes our tests are FAILED!
Someone know why?
… in the test class:
public function setUp() {
$this->testedObject = ...
}
public function testCreateFlightRoute() {
$this->dateTimeFactoryMock = $this->getMock(...)
$createTime = new DateTime('now', APP_TIME_ZONE);
$this->dateTimeFactoryMock->expects($this->at(0))
->method('create')
->willReturn($createTime);
$result = $this->testedObject->createFlightRoute($user, $startTime, ...);
$this->assertSame($result->getCreateTime(), $createTime);
}
Always PASSED!
10. Without SF With SF
Pros:
● We'll build our application „faster”*
(initially, anyway)
* yes, couple of minutes less per class is really an irrefutable fact
Cons:
● Each change will cost us a lot:
– time for implementation & bugs fixing
– customer confidence
– money
● When we'll start writing tests - we'll have to use
simple factory
– otherwise we will have broken builds from time to
time
Pros:
● We're saving (days|hours|minutes) of our time,
but also our client’s time (bugs)
– Do you remember the "n" classes we had to
change?
– In how many places can we potentially make
mistakes that way? How much time will we spend on
manual testing of all classes that we've changed?
● We can write tests for our classes in a proper
way - we will not have any failed builds ever
Cons:
● We need 1-3 minutes to create simply factory
class and inject it into our class
11. But what about creating not breakable tests?
class DateTimeFactoryMock() implements DataTimeFactoryInterface
{
public function __construct(array $nowTimes)
{
$this->nowTimes = $nowTimes;
}
public function create($time = 'now', DateTimeZone $timeZone = null)
{
if (null === $timeZone) {
$timeZone = new DateTimeZone(APP_TIME_ZONE);
}
if ('now' === $time) {
$time = array_shift($this->nowTimes);
}
return new DateTime($time, $timeZone);
}
}
... in test class
public function setUp()
{
$this->nowTime1 = '2012-01-01 12:00:00';
$dateTimeFactory = new DateTimeFactoryMock([$this->nowTime1]);
$this->testedObject = new AirRouteManager($dateTimeFactory);
}
public function testCreateFlightRoute()
{
$result = $this->testedObject->createFlightRoute($user, $startTime, ...);
...
$this->assertSame($result->getCreateTime()->format('Y-m-d H:i:s'), $this->nowTime1);
}
12. What about KISS
Simple Factory classes are very simple and stupid,
but I can obviously come up with an even simpler
and stupider class..
class A() {
public function doNothing() {
// yeah, this method really does nothing!
}
}
...but I'm afraid, that this class won't do us much good
13. What about YAGNI
Yes, YAGNI is about functionalities.. and we'll use
this functionality everywhere!
Yes! Everywhere, where we want the new
instances..