Message from discussion
De thin controllers y detached entities
Received: by 10.14.95.199 with SMTP id p47mr2322355eef.3.1335461623391;
Thu, 26 Apr 2012 10:33:43 -0700 (PDT)
X-BeenThere: symfony_barcelona@googlegroups.com
Received: by 10.14.100.66 with SMTP id y42ls309635eef.1.gmail; Thu, 26 Apr
2012 10:33:42 -0700 (PDT)
Received: by 10.14.188.12 with SMTP id z12mr2315889eem.8.1335461622818;
Thu, 26 Apr 2012 10:33:42 -0700 (PDT)
Received: by 10.14.188.12 with SMTP id z12mr2315885eem.8.1335461622777;
Thu, 26 Apr 2012 10:33:42 -0700 (PDT)
Return-Path: <theu...@gmail.com>
Received: from mail-ey0-f169.google.com (mail-ey0-f169.google.com [209.85.215.169])
by gmr-mx.google.com with ESMTPS id y52si3451770eef.2.2012.04.26.10.33.42
(version=TLSv1/SSLv3 cipher=OTHER);
Thu, 26 Apr 2012 10:33:42 -0700 (PDT)
Received-SPF: pass (google.com: domain of theu...@gmail.com designates 209.85.215.169 as permitted sender) client-ip=209.85.215.169;
Authentication-Results: gmr-mx.google.com; spf=pass (google.com: domain of theu...@gmail.com designates 209.85.215.169 as permitted sender) smtp.mail=theu...@gmail.com; dkim=pass header...@gmail.com
Received: by mail-ey0-f169.google.com with SMTP id l1so417255eaa.28
for <symfony_barcelona@googlegroups.com>; Thu, 26 Apr 2012 10:33:42 -0700 (PDT)
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
d=gmail.com; s=20120113;
h=mime-version:in-reply-to:references:from:date:message-id:subject:to
:content-type;
bh=CY1yRJ6QE76tLuiSsEx73tYFq6Vwe0GuY0lmL0bwoeQ=;
b=jK9Sgn3qkAOdyb8G0X68yMshHm/7ttOFMx38io25ypA5nWtX6CwypO94jfMEAorTLZ
jBQEw5yy7RReqzqlxxDn5lPNUPCzgMJy5VOE6haW/pL/9TEADavI8ioZRaS5mvBkERRo
cJARZ+7ETCI4aqUaR9//jIsLrB6ZuHOTKY6yG4ByHMASmkm+0gfEa5aftIEe+vILv78E
IHDlXkAZdmdzp6FtuSg5kCWIR0HoMzGiCP7jEsfXxuv92BIVMpVAuJMQOBOAtUSdh9hy
02rK0j2mgp7zX+Y97bHw8enVdP7/3erD4p0+KkzrQSurslcMxBZpX9710zZc2aaQ5JdH
IbZg==
Received: by 10.14.97.7 with SMTP id s7mr1969235eef.63.1335461622567; Thu, 26
Apr 2012 10:33:42 -0700 (PDT)
MIME-Version: 1.0
Received: by 10.213.4.134 with HTTP; Thu, 26 Apr 2012 10:33:22 -0700 (PDT)
In-Reply-To: <CAHqyEODnL+RaWNu_8JEqFdQiZ4zKOF4uDsp9UiDnPnVjtRm...@mail.gmail.com>
References: <31741529.693.1335271885519.JavaMail.geo-discussion-forums@vbez18>
<24981821.432.1335283994509.JavaMail.geo-discussion-forums@vbfg3> <CAHqyEODnL+RaWNu_8JEqFdQiZ4zKOF4uDsp9UiDnPnVjtRm...@mail.gmail.com>
From: theUniC <theu...@gmail.com>
Date: Thu, 26 Apr 2012 19:33:22 +0200
Message-ID: <CAO86=Xc3w0EH06eGu7wJRqyZJF9K+J27wgCxLY3NwO0tUur...@mail.gmail.com>
Subject: Re: De thin controllers y detached entities
To: symfony_barcelona@googlegroups.com
Content-Type: multipart/alternative; boundary=bcaec517a7729fd4aa04be98634b
--bcaec517a7729fd4aa04be98634b
Content-Type: text/plain; charset=windows-1252
Content-Transfer-Encoding: quoted-printable
Hola,
La verdad es que la persistencia tampoco deber=EDa ir ligada a la capa de
repositorios, pues los repositorios solo deber=EDan responsabilizarse de la
extracci=F3n de entidades del domain model -- *
http://martinfowler.com/eaaCatalog/repository.html*
En todo caso, tal c=F3mo comenta Ronny, deber=EDan tener su propia capa!
Un saludo!
Christian.
El 26 de abril de 2012 19:01, Francesc Ros=E0s
<francescrosasbos...@gmail.com>escribi=F3:
> Ronny, s=ED de momento estoy liado quitando la l=F3gica del negocio de lo=
s
> controladores. El siguiente paso seguramente ser=EDa el que comentas, ext=
raer
> la persistencia en forma de repositorios (m=E1s que nada para facilitar e=
l
> testeo de estos servicios).
>
> Y gracias por los ejemplos, la verdad es que cuesta encontrar los que
> pasan del simple "controlador manipula entidades".
>
> El 24 d=92abril de 2012 18:13, Ronny L=F3pez <ro...@pricebets.com> ha esc=
rit:
>
> Hola,
>>
>> En teor=EDa la interfaz que exponga la capa de servicio debe estar
>> desligada totalmente de la persistencia.
>>
>> En el caso que planteas, a los clientes del TweetService no les conciern=
e
>> como este servicio gestione la persistencia de los objetos que maneja
>> internamente.
>>
>> Piensa por ejemplo, que hoy se pueden estar persistiendo los tweets en
>> MySQL, a trav=E9s de Doctrine ORM, pero que ma=F1ana puedes decidir camb=
iar a
>> MongoDB a trav=E9s de Doctrine ODM, o a Redis a trav=E9s de un cliente d=
e Redis
>> propio.
>>
>> Entonces, si el servicio maneja la persistencia de forma interna, ningun=
o
>> de sus clientes se ver=E1 afectado ante un cambio de este tipo.
>>
>> Unos buenos ejemplos a seguir en este tipo de dise=F1o de "modelo de dat=
os
>> abstracto", son el FOSUserBundle y el FOSCommentBundle.
>>
>> Aqu=ED se interactua con los objetos del modelo a trav=E9s de un "Manage=
r",
>> el CommentManager por ejemplo. El CommentManager tiene una interfaz bien
>> defina, la cual es totalmente independiente de la persistencia:
>> https://github.com/FriendsOfSymfony/FOSCommentBundle/blob/master/Model/C=
ommentManagerInterface.php
>>
>> Entonces, existe una implementaci=F3n abstracta
>> https://github.com/FriendsOfSymfony/FOSCommentBundle/blob/master/Model/C=
ommentManager.phpe implementaciones especializadas en diferentes tipos de p=
ersistencia, por
>> ejemplo, una basada en Doctrine:
>> https://github.com/FriendsOfSymfony/FOSCommentBundle/blob/master/Entity/=
CommentManager.php
>>
>> Es cierto que este tipo de dise=F1o require m=E1s trabajo de dise=F1o y
>> programaci=F3n, pero la robustez y desacoplamiento que aporta a una
>> aplicaci=F3n medianamente compleja es importante.
>>
>> Saludos,
>> Ronny.
>>
>>
>>
>> El martes, 24 de abril de 2012 14:51:25 UTC+2, Francesc Ros=E0s escribi=
=F3:
>>
>>> Hola symfoneros, estoy trabajando en un proyecto en Symfony2 + Doctrine=
2
>>> y los controllers se me est=E1n engordando ya demasiado con tareas que
>>> entiendo que pertenecen al modelo.
>>>
>>> Hab=EDa pensado que para aligerarlos podr=EDa empezar con extraer todo =
el
>>> c=F3digo que pertenece al modelo en forma de servicios. As=ED si por ej=
emplo
>>> tengo un action del controller que (pongamos que estamos en Twitter) cr=
ea
>>> un tuit a partir de un formulario y notifica a todos los seguidores, la
>>> idea ser=EDa crear un servicio (e.g. twitter.tweets) con un m=E9todo
>>> publish($tweet). El controller seguir=EDa instanciando y trabajando con=
un
>>> objeto Tweet pero no tendr=EDa ning=FAn $em->flush() ni nada por el est=
ilo.
>>>
>>> Las ventajas vendr=EDan a ser estas:
>>>
>>> - El controller hace s=F3lo de pasarela entre el usuario y el modelo
>>> - El modelo se puede reutilizar en otros contextos (en procesos
>>> batch, por ejemplo)
>>> - Puedo cambiar la implementaci=F3n del modelo sin afectar a los
>>> controllers (e.g. pasar de usar una base de datos a un web service)
>>>
>>> Uno de los aspectos que me genera m=E1s dudas es la forma de encapsular
>>> correctamente los cambios sobre las entities. Doctrine por defecto recu=
erda
>>> los cambios que se hacen en las entidades y ah=ED pierdo la encapsulaci=
=F3n que
>>> me da el servicio ya que al hacer un $em->flush() se aplicar=EDan todos=
los
>>> cambios que se hayan podido hacer en cualquier entidad y sin mucho cont=
rol
>>> sobre qu=E9 quiero aplicar y qu=E9 no en la base de datos.
>>>
>>> Para evitar esto hab=EDa pensado en algo as=ED:
>>>
>>> class TweetsService
>>> {
>>> function publish(Tweet $tweet)
>>> {
>>> $this->getEntityManager()->**clear();
>>> $this->getEntityManager()->**merge($tweet);
>>> $this->getEntityManager()->**flush();
>>>
>>> $this->notifyFollowers($tweet)**;
>>> }
>>> }
>>>
>>> B=E1sicamente olvida todos los cambios hechos en las entidades (el
>>> clear() hace un detach() de todas ellas) y aplica s=F3lo los que nos
>>> interesan.
>>>
>>> C=F3mo veis esta aproximaci=F3n? Me estoy liando s=F3lo? Va a afectar m=
ucho en
>>> el rendimiento? Con las pruebas que he hecho hasta ahora la cosa funcio=
na
>>> pero no me gustar=EDa encontrarme con problemas m=E1s adelante.
>>>
>>> Un saludo.
>>>
>>
>
--bcaec517a7729fd4aa04be98634b
Content-Type: text/html; charset=windows-1252
Content-Transfer-Encoding: quoted-printable
<div class=3D"gmail_extra">Hola,</div><div class=3D"gmail_extra"><br></div>=
<div class=3D"gmail_extra">La verdad es que la persistencia tampoco deber=
=EDa ir ligada a la capa de repositorios, pues los repositorios solo deber=
=EDan responsabilizarse de la extracci=F3n de entidades del domain model --=
<b><a href=3D"http://martinfowler.com/eaaCatalog/repository.html">http://m=
artinfowler.com/eaaCatalog/repository.html</a></b></div>
<div class=3D"gmail_extra"><br></div><div class=3D"gmail_extra">En todo cas=
o, tal c=F3mo comenta Ronny, deber=EDan tener su propia capa!</div><div cla=
ss=3D"gmail_extra"><br></div><div class=3D"gmail_extra">Un saludo!</div><di=
v class=3D"gmail_extra">
Christian.<br><br><div class=3D"gmail_quote">El 26 de abril de 2012 19:01, =
Francesc Ros=E0s <span dir=3D"ltr"><<a href=3D"mailto:francescrosasbosqu=
e...@gmail.com" target=3D"_blank">francescrosasbos...@gmail.com</a>></span>=
escribi=F3:<br>
<blockquote class=3D"gmail_quote" style=3D"margin:0 0 0 .8ex;border-left:1p=
x #ccc solid;padding-left:1ex"><div class=3D"gmail_extra">Ronny, s=ED de mo=
mento estoy liado quitando la l=F3gica del negocio de los controladores. El=
siguiente=A0paso=A0seguramente ser=EDa el que comentas, extraer la persist=
encia en forma de repositorios (m=E1s que nada para facilitar el testeo de =
estos servicios).</div>
<div class=3D"gmail_extra"><br></div><div class=3D"gmail_extra">Y gracias p=
or los ejemplos, la verdad es que cuesta encontrar los que pasan del simple=
"controlador manipula entidades".</div><div class=3D"gmail_extra=
">
<br><div class=3D"gmail_quote">El 24 d=92abril de 2012 18:13, Ronny L=F3pez=
<span dir=3D"ltr"><<a href=3D"mailto:ro...@pricebets.com" target=3D"_bl=
ank">ro...@pricebets.com</a>></span> ha escrit:<div><div class=3D"h5"><b=
r><blockquote class=3D"gmail_quote" style=3D"margin:0 0 0 .8ex;border-left:=
1px #ccc solid;padding-left:1ex">
Hola,=A0<div><br></div><div>En teor=EDa la interfaz que exponga la capa de =
servicio debe estar desligada totalmente de la persistencia.</div><div><br>=
</div><div>En el caso que planteas,=A0a los clientes del TweetService no le=
s concierne como este servicio gestione la persistencia de los objetos que =
maneja internamente.=A0</div>
<div><br></div><div>Piensa por ejemplo, que hoy se pueden estar persistiend=
o los tweets en MySQL, a trav=E9s de Doctrine ORM, pero que ma=F1ana puedes=
decidir cambiar a MongoDB a trav=E9s de Doctrine ODM, o a Redis a trav=E9s=
de un cliente de Redis propio.</div>
<div><br></div><div>Entonces, si el servicio maneja la persistencia de form=
a interna, ninguno de sus clientes se ver=E1 afectado ante un cambio de est=
e tipo.</div><div><br></div><div>Unos buenos ejemplos a seguir en este tipo=
de dise=F1o de "modelo de datos abstracto", son el FOSUserBundle=
y el FOSCommentBundle.</div>
<div><br></div><div>Aqu=ED se interactua con los objetos del modelo a trav=
=E9s de un "Manager", el CommentManager por ejemplo. El CommentMa=
nager tiene una interfaz bien defina, la cual es totalmente independiente d=
e la persistencia:=A0<a href=3D"https://github.com/FriendsOfSymfony/FOSComm=
entBundle/blob/master/Model/CommentManagerInterface.php" target=3D"_blank">=
https://github.com/FriendsOfSymfony/FOSCommentBundle/blob/master/Model/Comm=
entManagerInterface.php</a></div>
<div><br></div><div>Entonces, existe una implementaci=F3n abstracta=A0<a hr=
ef=3D"https://github.com/FriendsOfSymfony/FOSCommentBundle/blob/master/Mode=
l/CommentManager.php" target=3D"_blank">https://github.com/FriendsOfSymfony=
/FOSCommentBundle/blob/master/Model/CommentManager.php</a> e implementacion=
es especializadas en diferentes tipos de persistencia, por ejemplo, una bas=
ada en Doctrine: <a href=3D"https://github.com/FriendsOfSymfony/FOSCommentB=
undle/blob/master/Entity/CommentManager.php" target=3D"_blank">https://gith=
ub.com/FriendsOfSymfony/FOSCommentBundle/blob/master/Entity/CommentManager.=
php</a></div>
<div><br></div><div>Es cierto que este tipo de dise=F1o require m=E1s traba=
jo de dise=F1o y programaci=F3n, pero la robustez y=A0desacoplamiento que a=
porta a una aplicaci=F3n medianamente compleja es importante.=A0</div><div>=
<br></div>
<div>Saludos,</div><div>Ronny.</div><div><br></div><div><br></div><div><br>=
El martes, 24 de abril de 2012 14:51:25 UTC+2, Francesc Ros=E0s escribi=F3=
:<div><div><blockquote class=3D"gmail_quote" style=3D"margin:0;margin-left:=
0.8ex;border-left:1px #ccc solid;padding-left:1ex">
Hola symfoneros, estoy trabajando en un proyecto en Symfony2 + Doctrine2 y =
los controllers se me est=E1n engordando ya demasiado con tareas que entien=
do que pertenecen al modelo.<div><br></div><div>Hab=EDa pensado que para al=
igerarlos podr=EDa empezar con extraer todo el c=F3digo que pertenece al mo=
delo en forma de servicios. As=ED si por ejemplo tengo un action del contro=
ller que (pongamos que estamos en Twitter) crea un tuit a partir de un form=
ulario y notifica a todos los seguidores, la idea ser=EDa crear un servicio=
(e.g. twitter.tweets) con un m=E9todo publish($tweet). El controller segui=
r=EDa instanciando y trabajando con un objeto Tweet pero no tendr=EDa ning=
=FAn $em->flush() ni nada por el estilo.</div>
<div><br></div><div>Las ventajas vendr=EDan a ser estas:</div><div><ul><li>=
<span style=3D"line-height:normal">El controller hace s=F3lo de pasarela en=
tre el usuario y el modelo</span><br></li><li><span style=3D"line-height:no=
rmal">El modelo se puede reutilizar en otros contextos (en procesos batch, =
por ejemplo)</span></li>
<li><span style=3D"line-height:normal">Puedo cambiar la implementaci=F3n de=
l modelo sin afectar a los controllers (e.g. pasar de usar una base de dato=
s a un web service)</span></li></ul></div><div>Uno de los aspectos que me g=
enera m=E1s dudas es la forma de encapsular correctamente los cambios sobre=
las entities. Doctrine por defecto recuerda los cambios que se hacen en la=
s entidades y ah=ED pierdo la encapsulaci=F3n que me da el servicio ya que =
al hacer un $em->flush() se aplicar=EDan todos los cambios que se hayan =
podido hacer en cualquier entidad y sin mucho control sobre qu=E9 quiero ap=
licar y qu=E9 no en la base de datos.</div>
<div><br></div><div>Para evitar esto hab=EDa pensado en algo as=ED:</div><d=
iv><br></div>
<div><font face=3D"'courier new', monospace">class TweetsService</f=
ont></div><div><font face=3D"'courier new', monospace">{</font></di=
v><div><font face=3D"'courier new', monospace">=A0 =A0 function pub=
lish(Tweet $tweet)</font></div>
<div><font face=3D"'courier new', monospace">=A0 =A0 {</font></div>=
<div><font face=3D"'courier new', monospace">=A0 =A0 =A0 =A0 $this-=
>getEntityManager()-><u></u>clear();</font></div><div><font face=3D"&=
#39;courier new', monospace">=A0 =A0 =A0 =A0 $this->getEntityManager=
()-><u></u>merge($tweet);</font></div>
<div><font face=3D"'courier new', monospace">=A0 =A0 =A0 =A0 $this-=
>getEntityManager()-><u></u>flush();</font></div><div><font face=3D"&=
#39;courier new', monospace"><br></font></div><div><font face=3D"'c=
ourier new', monospace">=A0 =A0 =A0 =A0 $this->notifyFollowers($twee=
t)<u></u>;</font></div>
<div><font face=3D"'courier new', monospace">=A0 =A0 }</font></div>=
<div><font face=3D"'courier new', monospace">}</font></div><div><di=
v><div><div><span style=3D"line-height:17px"><br></span></div></div></div><=
/div>
<div>
<span style=3D"line-height:17px">B=E1sicamente olvida todos los cambios hec=
hos en las entidades (el clear() hace un detach() de todas ellas) y aplica =
s=F3lo los que nos interesan.</span></div><div><span style=3D"line-height:1=
7px"><br>
</span></div><div><span style=3D"line-height:17px">C=F3mo veis esta aproxim=
aci=F3n? Me estoy liando s=F3lo? Va a afectar mucho en el rendimiento? Con =
las pruebas que he hecho hasta ahora la cosa funciona pero no me gustar=EDa=
encontrarme con problemas m=E1s adelante.</span></div>
<div><span style=3D"line-height:17px"><br></span></div><div><span style=3D"=
line-height:17px">Un saludo.</span></div></blockquote></div></div></div></b=
lockquote></div></div></div><br></div>
</blockquote></div><br></div>
--bcaec517a7729fd4aa04be98634b--