Datum jako služba – dobrý nápad?

Upozornění: Tohle vlákno je hodně staré a informace nemusí být platné pro současné Nette.
fh
Člen | 18
+
0
-

Zdravím. Titulek vystihuje základní podstatu dotazu. Různé části systému vyžadují aktuální čas a z hlediska testování a DI by ho měly dostávat oproti jeho vytváření. Alespoň nepovinným setterem. Tak to bublá až nahoru, kde ho musím vytvořit. Z toho mi vyplývá, že i aktuální datum by mělo být jako služba a tak mohu také z jednoho místa dostat aplikaci do jiného času právě třeba pro účely testování. Je to dobrý nápad?

PS: Mohl bych pak kdekoliv v aplikaci pro porovnání aktuálního času s jistotou používat ===.

Majkl578
Moderator | 1364
+
0
-

Také jsem nad něčím podobným přemýšlel, pokud všude budu vytvářet nový čas, mohou vzniknout nekonzistence (ač to není moc pravděpodobné). Asi bych použil něco jako DateTimeProvider. Problém ale může být s neúmyslnou změnou zvenčí (někdo zapomene clone před modify a je to), protože DateTime není immutable. Takže a) možná spíš factory podle prototypu (vytvořeného při startu aplikace), b) freezable datetime?

Filip Procházka
Moderator | 4668
+
0
-

Určitě je to dobrý nápad. Napadlo mě něco jako

// return Nette\Datetime::from($this->getHeader('Request-Time'))
$datetime = $httpRequest->getTime();
Majkl578
Moderator | 1364
+
0
-

Osobně bych do toho HTTP request netahal, např. kvůli CLI.
Maximálně jako implementaci nějakého IDateTimeProvider rozhraní (HttpDateTimeProvider využívající Http\Request a hlavičku, NativeDateTimeProvider využívající new DateTime()).

Majkl578
Moderator | 1364
+
0
-

Zkusil jsem udělat jednoduchý Proof of Concept, je to na GitHubu. Co myslíte?

fh
Člen | 18
+
0
-

Majkl578 napsal(a):

Také jsem nad něčím podobným přemýšlel, pokud všude budu vytvářet nový čas, mohou vzniknout nekonzistence (ač to není moc pravděpodobné). Asi bych použil něco jako DateTimeProvider. Problém ale může být s neúmyslnou změnou zvenčí (někdo zapomene clone před modify a je to), protože DateTime není immutable. Takže a) možná spíš factory podle prototypu (vytvořeného při startu aplikace), b) freezable datetime?

Freezable DateTime se mi líbí. I když možná rovnou immutable. Otázka je, jestli by všechny stav měnicí metody měly vracet klon nebo vyhazovat výjimku? Pro jednodušší použití by se mi líbilo, kdyby vracely klon. Pak by se docela pohodlně použila třeba metoda add(). Akorát původní add() vrací DateTime i tak, aby byla fluent, což by mohlo mást. Ale na to by si asi člověk zvyknul.

Jan Tvrdík
Nette guru | 2595
+
0
-

@fh: Mít čas jako služby se mi líbí.

@Majkl578: Metodu IDateTimeProvider::getDateTimePrototype() bych přejmenoval na getDateTime(). Prototyp je ten klonovaný DateTime (název $dateTimePrototype je tedy v pořádku).

fh
Člen | 18
+
0
-

@Majkl578: Obecně vracet ihned klony se mi moc nelíbí. Přicházím o identitu a tím pádem o ===. Klon by mi mohla vrátit služba v případě změny nebo by mohla mít metodu např. cloneMutable().

Editoval fh (25. 3. 2013 14:55)

Majkl578
Moderator | 1364
+
0
-

@Jan Tvrdík: Předpokládám, že to přejmenování jsi myslel naopak. Dávalo by to smysl, pokud by (aktuálně) getDateTime nevracelo klon.

@fh: Ale afaik nepřicházíš o možnost weak comparison, tj. ==. Problém je, že PHP stále nemá immutable DateTime (do 5.5 se taky nedostalo). Otázka tedy je, jak ideálně vyřešit zmražení daného DateTime objektu. Šance, že ten objekt někde v aplikaci neúmyslně změníš, je relativně vysoká, právě kvůli zrádnosti mutable rozhraní.
Uvažoval jsem nad něčím podobným, co nabízí Nette\FreezableObject, tj. FreezableDateTime, to by asi šlo.

Jan Tvrdík
Nette guru | 2595
+
0
-

@Majkl578: To přejmenování jsem myslel tak, jak jsem ho napsal. BaseControl::getControlPrototype() taky nevrací klon.

Jinak DateTimeImmutable se do PHP 5.5 dostalo, viz https://github.com/….0beta1/NEWS. Uvažovalo se o zrušení, ale nakonec k němu nedošlo, ne?

fh
Člen | 18
+
0
-

Majkl578 napsal(a):

@fh: Ale afaik nepřicházíš o možnost weak comparison, tj. ==. Problém je, že PHP stále nemá immutable DateTime (do 5.5 se taky nedostalo). Otázka tedy je, jak ideálně vyřešit zmražení daného DateTime objektu. Šance, že ten objekt někde v aplikaci neúmyslně změníš, je relativně vysoká, právě kvůli zrádnosti mutable rozhraní.
Uvažoval jsem nad něčím podobným, co nabízí Nette\FreezableObject, tj. FreezableDateTime, to by asi šlo.

Ale weak comparison je mi v tu chvíli asi ne moc užitečný, protože to jestli jsou dvě data stejného typu zjišťovat nepotřebuji. Šlo mi o porovnání zda čas je ten aplikační čas. I když spíš než o identitu jde o hodnotu, ale stejně. Bez identity budu hodnoty data porovnávat složitěji. A když bude immutable, mohu se na hodnotu spolehnout. Řekl bych že immutable je v tomto případě lepší než freezable, ale to je asi víc akademická debata. Imutable udělám z freezable v konstruktoru a je vyřešeno, to je pravda…

Majkl578
Moderator | 1364
+
0
-

@fh:

protože to jestli jsou dvě data stejného typu zjišťovat nepotřebuji

K tomu weak comparison neslouží.

Šlo mi o porovnání zda čas je ten aplikační čas.

Opravdu? A nezajímá tě spíš, jestli hodnota je stejná?

Bez identity budu hodnoty data porovnávat složitěji.

Jakto? Objekt není stejný, ale hodnoty ano. Tedy identita neprojde, ale weak comparison ano.

$a = new DateTime();
$b = clone $a;

var_dump($a === $b); // FALSE
var_dump($a == $b); // TRUE

Řekl bych že immutable je v tomto případě lepší než freezable

Souhlasím a vývojáři PHP taky, neshodli se ale na tom, jak to čistě implementovat (kandidát do 5.5 bylo DateTimeImmutable extendující DateTime, což ale nedává smysl a jiná cesta je naopak BC break, proto se to do 5.5 nedostalo).

Filip Procházka
Moderator | 4668
+
0
-

Položím vám záludnou otázku – koukali jste někdo, jak se to řeší v jiných jazicích/frameworcích? :)

mkoubik
Člen | 728
+
0
-

Podle mě to řešíte moc složitě, já používám toto (jen jako náhradu za volání konstruktoru) a funguje to skvěle:

class Calendar extends \Nette\Object implements ICalendar
{
    /** @return \DateTime */
    public function now()
    {
        return new \DateTime;
    }

    /** return \DateTime */
    public function datetime($time)
    {
        return new \DateTime($time);
    }
}
Majkl578
Moderator | 1364
+
0
-

mkoubik napsal(a):

Podle mě to řešíte moc složitě, já používám toto (jen jako náhradu za volání konstruktoru) a funguje to skvěle:

Což ale vůbec neřeší ten základní problém, že skrz systémem nemusí být stejný čas, např. pokud aplikace běží déle než sekundu.

enumag
Člen | 2118
+
0
-

@Filip Procházka: Můžeš nás zasvětit, znalče? :-)

fh
Člen | 18
+
0
-

Majkl578: Pravda, měl jsem zafixovanou mylnou představu o chování == u objektů. Teď je to jasné, stačilo by. Teď už jen tu neměnnost:) Jinak jak psal @Jan Tvrdík, tak tady se zdá, že to v PHP je.

Editoval fh (25. 3. 2013 17:42)

Majkl578
Moderator | 1364
+
0
-

Aha, myslel jsem, že to odstranili, alespoň se o tom bavili, viz tento thread v php.internals.

Majkl578
Moderator | 1364
+
0
-

Ještě ad DateTimeImmutable. Ačkoliv si myslím, že v PHP poměrně dost chybí, aktuální implementace je katastrofa vedoucí k BC breakům (proč jen mě to u PHP nepřekvapuje). Vyplnil jsem bug report s žádostí o odstranění z 5.5.

fh
Člen | 18
+
0
-

Majkl578: Hmm.. Tak to asi zmizi.. Zatim to teda v logu neni. Na zaklade toho mailing listu je otazka jak to implementovat. Aby to tise vracelo klony je teda kvuli LSP asi nevhodne. Asi by to melo hazet v upravovacich metodach vyjimky a mit nejakou tu metodu cloneMutable, co by vratila klasicky DateTime.

Filip Procházka
Moderator | 4668
+
0
-

enumag napsal(a):

@Filip Procházka: Můžeš nás zasvětit, znalče? :-)

Já přece nepsal, že to vím :)


Já to teď řeším tak, že mám volitelný argument u metod, kvůli testovatelnosti

public function foo($arg, \Datetime $now = NULL)
{
	$now = $now ?: new \Datetime();
Jan Tvrdík
Nette guru | 2595
+
0
-

@Filip Procházka: Mám to podobně, ale mít to centrálně vyřešené jednou službou mi dává smysl.

Filip Procházka
Moderator | 4668
+
0
-

To rozhodně, proto jsem navrhoval kouknout ke konkurenci. Přece jenom, není potřeba vymýšlet kolo.

Nechtěl by autor vlákna sepsat RFC? :)

mkoubik
Člen | 728
+
0
-

Majkl578 napsal(a):
Což ale vůbec neřeší ten základní problém, že skrz systémem nemusí být stejný čas, např. pokud aplikace běží déle než sekundu.

Ok, špatně jsem to pochopil. Tohle řeší jen problém testování kódu ve kterém je new \DateTime().

fh
Člen | 18
+
0
-

Filip Procházka napsal(a):

To rozhodně, proto jsem navrhoval kouknout ke konkurenci. Přece jenom, není potřeba vymýšlet kolo.

Nechtěl by autor vlákna sepsat RFC? :)

Jako RFC pro immutable DateTime do PHP? Šlo mi spíš o obecný přístup k času jako službě. Natolik to zmáknuté nemám:)

fh
Člen | 18
+
0
-

Mimochodem, jak byste u immutable DateTime řešili metodu getTimezone()? Asi bych to udělal stejně jako DateTime, tedy vracela by immutable objekt DateTimeZone, který by měl metodu cloneMutable(). Názory?

Majkl578
Moderator | 1364
+
0
-

DateTimeZone je read-only objekt (nejde měnit), takže je to imho celkem jedno.

fh
Člen | 18
+
0
-

Majkl578 napsal(a):

DateTimeZone je read-only objekt (nejde měnit), takže je to imho celkem jedno.

A jo. Přemýšlím a nezkouším:)