tag:blogger.com,1999:blog-57308800387267832822024-02-20T16:44:10.423+01:00Malditos programadores!Sobre informática, metodología, programación y demás aspectos relacionados, en entornos Microsoft.Antoniohttp://www.blogger.com/profile/07910602532207054705noreply@blogger.comBlogger4125tag:blogger.com,1999:blog-5730880038726783282.post-64794060495014907982012-05-22T01:32:00.001+02:002012-10-19T20:49:21.111+02:00Patrones de diseño: implementando Abstract Factory<h3>Los patrones molan, si sabes cómo usarlos, más.</h3> <p align="justify"><font size="3">Hace algún tiempo compramos en la oficina el libro “</font><a href="http://www.ediciones-eni.com/libros/patrones-de-diseo-para-c-los-23-modelos-de-diseo-descripcion-y-soluciones-ilustradas-en-uml-2-y-c/.40bc52187944332a330fdb74bb49af73.html" target="_blank"><font size="3">Patrones de diseño para C#</font></a><font size="3">”. Este libro detalla los 23 modelos de diseño fundamentales y aunque aún no he tenido tiempo de leerlo al completo, lo que he visto está bien explicado y es sencillo de entender.</font></p> <p align="justify"><font size="3">No es mi intención debatir los beneficios que se obtiene al utilizar <a href="http://es.wikipedia.org/wiki/Patr%C3%B3n_de_dise%C3%B1o" target="_blank">patrones de diseño</a>, de eso seguro que puedes encontrar muchísima información en miles de blogs.</font></p> <p align="justify"><font size="3">Sin embargo, si lo que buscas son ejemplos de cómo (pero sobretodo porqué) implementar un patrón de diseño desde cero, ahí amigo, seguro que lo tienes más difícil.</font></p> <p align="justify"><font size="3">Los ejemplos que yo he encontrado, muchas veces son excesivamente formales, y se centran en explicar el patrón en sí, implementando algún ejemplo concreto sobre la definición formal del patrón.</font></p> <p align="justify"><font size="3">Mi idea es partir de un escenario en el que el código es correcto, en términos funcionales, pero no es correcto en el sentido de que incumple varios <a href="http://es.wikipedia.org/wiki/SOLID_(object-oriented_design)" target="_blank">principios SOLID</a>, y además en el momento en el que las especificaciones cambien, va a ser también más complicado de mantener.</font></p> <p align="justify"><font size="3">Veremos que para optimizar el escenario propuesto, el patrón que mejor encaja es el denominado “Factoría Abstracta”. Trataré de explicar porqué, y reescribiremos el código hasta tener la implementación del patrón completada. </font></p> <p align="justify"><font size="3">De esta manera, podremos evaluar los beneficios que vamos a obtener al usar la Factoría Abstracta, nuestro código ganará calidad, nosotros algo de ego (no mintáis, malditos geeks!), a partir del momento en el que decidáis incorporar el uso de patrones a vuestros proyectos, miles de gatitos dormirán tranquilos… y a nosotros no nos “sangrarán” los ojos al ver nuestro ahora precioso código.</font></p> <p align="justify"><font size="3">Bueno, al turrón! y ánimo, que me ha salido un “troncho” de post que no es para unas prisas ;-D</font></p> <a name='more'></a> <h3 align="justify">Se abre el telón.</h3> <p align="justify"><font size="3">Y nos encontramos con una aplicación que envía mails. Dichos mails están formados por diferentes secciones predefinidas. Por ejemplo, el mail que envía información de un pedido está formado por:</font></p> <ul> <li> <div align="justify"><font size="3">Una sección de cabecera del pedido</font></div> <li> <div align="justify"><font size="3">Las líneas del pedido</font></div> <li> <div align="justify"><font size="3">Información del cliente</font></div> <li> <div align="justify"><font size="3">Información de la visita realizada</font></div></li></ul> <p align="justify"><font size="3">De esta manera, en función de las distintas secciones existentes, el usuario puede formar los mails con la información que desea, y en tiempo de ejecución el mail renderiza su contenido según las secciones que lo forman, y se queda listo para enviar. Vamos a ver la estructura del proyecto:</font></p> <p align="justify"><font size="3">Tenemos un enumerado para las distintas secciones existentes: </font></p> <div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:9D7513F9-C04C-4721-824A-2B34F0212519:9f61d576-a193-46aa-9387-771dac707175" class="wlWriterSmartContent"><pre style="background-color: white; width: 550px; font-family: consolas; height: 125px; overflow: scroll"><div><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--><span style="color: #008080">1</span> <span style="color: #000000"> </span><span style="color: #0000ff">Public</span><span style="color: #000000"> </span><span style="color: #0000ff">Enum</span><span style="color: #000000"> MailSectionType </span><span style="color: #0000ff">As</span><span style="color: #000000"> </span><span style="color: #0000ff">Integer</span><span style="color: #000000"><br></span><span style="color: #008080">2</span> <span style="color: #000000"> CustomerInfo<br></span><span style="color: #008080">3</span> <span style="color: #000000"> OrderInfo<br></span><span style="color: #008080">4</span> <span style="color: #000000"> OrderLines<br></span><span style="color: #008080">5</span> <span style="color: #000000"> VisitInfo<br></span><span style="color: #008080">6</span> <span style="color: #000000"> </span><span style="color: #0000ff">End Enum</span></div></pre><!-- Code inserted with Steve Dunn's Windows Live Writer Code Formatter Plugin. http://dunnhq.com --></div><br><br /><p><font size="3">La clase que representa la sección del mail:</font></p><br><br /><div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:9D7513F9-C04C-4721-824A-2B34F0212519:65833511-f1fe-42fb-9a87-9e9c931acd1d" class="wlWriterSmartContent"><img style="border-right-width: 0px; width: 550px; border-top-width: 0px; border-bottom-width: 0px; height: 410px; border-left-width: 0px" src="http://lh4.ggpht.com/-7VFAu7_RPpA/T7vH6rkK_SI/AAAAAAAAAFU/TLZzJbSXBmc/transformedimage%25255B9%25255D.png?imgmax=800"></div><br><br /><p><font size="3">Ahora, la clase que representa el mail:</font></p><br><br /><div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:9D7513F9-C04C-4721-824A-2B34F0212519:98ce7e91-88f5-4182-ae1d-8eb7b9cee37e" class="wlWriterSmartContent"><img style="border-right-width: 0px; width: 550px; border-top-width: 0px; border-bottom-width: 0px; height: 350px; border-left-width: 0px" src="http://lh3.ggpht.com/-U9vLVA0YTpA/T7vH9ImfMXI/AAAAAAAAAFc/FVmvSxSdCvI/transformedimage%25255B16%25255D.png?imgmax=800"></div><br><br /><p align="justify"><font size="3">La clase que forma los mails, y que es precisamente la que vamos a modificar. Fijaos en la función <em>GetMailSectionText</em> y ese <em>Select Case</em> tan “bonico”. </font></p><br><br /><p><font size="3"></font></p><br><br /><div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:9D7513F9-C04C-4721-824A-2B34F0212519:3b0501de-dbf4-447e-9562-a0be223d13ed" class="wlWriterSmartContent"><img style="border-right-width: 0px; width: 550px; border-top-width: 0px; border-bottom-width: 0px; height: 500px; border-left-width: 0px" src="http://lh4.ggpht.com/-w0WjISxy-R8/T7vH_ekzuII/AAAAAAAAAFk/hqpftT1M_f4/transformedimage%25255B34%25255D.png?imgmax=800"></div><br><br /><p><font size="3">Y por último, un modulo que pone todo esto en marcha.</font></p><br><br /><div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:9D7513F9-C04C-4721-824A-2B34F0212519:1811ee79-8901-404a-9ff2-f6d944f2d15e" class="wlWriterSmartContent"><img style="border-right-width: 0px; width: 550px; border-top-width: 0px; border-bottom-width: 0px; height: 450px; border-left-width: 0px" src="http://lh3.ggpht.com/-fHdZrCLEwLw/T7vIBemONWI/AAAAAAAAAFs/k35SkbLdXmA/transformedimage%25255B69%25255D.png?imgmax=800"></div><br><br /><p align="justify"><font size="3">Si ejecutamos el proyecto, veremos que para cada definición de mail, el programa pinta correctamente su contenido, presentando cada una de las secciones que lo forman. Entonces… ¿qué es lo que no es correcto? ¿dónde podemos mejorar nuestro código?</font></p><br><br /><p align="justify"><font size="3">Vamos a por ello, amiguitos…</font></p><br><br /><h3 align="justify">Maldita sea! pero si esto funciona!!</h3><br><br /><p align="justify"><font size="3">Efectivamente y no! </font></p><br><br /><p align="justify"><font size="3">Imagina que el método <em>GetMailSectionText </em>de la clase <em>MailManager</em>, realiza para cada <em>Case</em> un acceso a datos distinto y formatea cada sección de manera diferente, para finalmente retornarla. </font></p><br><br /><p align="justify"><font size="3">En ese caso, vemos que nos estamos saltando uno de los principios SOLID, concretamente el <a href="http://en.wikipedia.org/wiki/Single_responsibility_principle">principio de responsabilidad única</a>, (SRP: Single Responsibility Principle).</font></p><br><br /><p align="justify"><font size="3">Dicho principio establece que cada clase debe tener una única responsabilidad, y que esa responsabilidad debe estar completamente encapsulado por la clase.</font></p><br><br /><p align="justify"><font size="3">Como vemos, la clase MailManager, y concretamente su función GetMailSectionText hace bastantes más cosas de las que debería</font></p><br><br /><p align="justify"><font size="3">Imagina además que el número de secciones no es de cuatro como en el ejemplo, sino mucho mayor, y que para añadir más leña al fuego es muy probable que esta colección de secciones aumente con el tiempo.</font></p><br><br /><p align="justify"><font size="3">Entonces merece la pena darle una buena pensada a ese código, e implementar una solución que encapsule correctamente las responsabilidades que hemos encontrado, que sea tolerante a las modificaciones, y que en caso de que éstas se produzcan nos permita extenderlas fácilmente.</font></p><br><br /><p align="justify"><font size="3">El maestro Robert C. Martin, en su magnifico libro <a href="http://www.amazon.es/Clean-Code-Handbook-Software-Craftsmanship/dp/0132350882">Clean Code</a> (¿No lo has leído? estás tardando!) comenta que no puede con los bloques <em>Switch</em> (el equivalente al <em>Select Case</em> de java), y que sólo los tolera cuando aparecen como entrada a una implementación de Abstrac Factory (ya pensabas que no aparecería, ehhh… jeje), para devolver objetos polimórficos pertenecientes a una misma familia (lo cualo??).</font></p><br><br /><p align="justify"><font size="3">No vamos a ver el modelo formal estático de Abstract Factory, puedes verlo detalladamente <a href="http://es.wikipedia.org/wiki/Abstract_Factory">aqui</a>.</font></p><br><br /><p align="justify"><font size="3">Pero si que vamos a realizar el modelo estático para nuestro ejemplo. A por ello!</font></p><br><br /><h3 align="justify">Deconstruyendo Abstract Factory (Ferrán Adriá Style)</h3><br><br /><p><font size="3">Lo primero que vamos a hacer es identificar dentro de nuestro código, los elementos del patrón, y detallar las conversiones que vamos a realizar. El patrón Factoría Abstracta tiene los siguientes elementos:</font></p><br><br /><ul><br><br /><li><font size="3">Factoría abstracta</font> <br><br /><li><font size="3">Factorías concretas </font><br><br /><li><font size="3">Producto abstracto</font> <br><br /><li><font size="3">Productos concretos</font></li></ul><br><br /><p align="justify"><font size="3">El patrón Factoría permite crear objetos complejos, ocultando el proceso de creación a las clases cliente. Además, dichos objetos complejos pertenecen a una misma familia</font></p><br><br /><p align="justify"><font size="3">En nuestro caso, los objetos “complejos” a crear son de la clase MailSection. Lo que vamos a hacer es crear una clase abstracta MailSection, de la que heredarán los siguientes objetos concretos:</font></p><br><br /><ul><br><br /><li><font size="3">CustomerInfoMailSection</font> <br><br /><li><font size="3">OrderInfoMailSection</font> <br><br /><li><font size="3">OrderLinesMailSection</font> <br><br /><li><font size="3">VisitInfoMailSection</font></li></ul><br><br /><p><font size="3">Nuestra clase “<em>ProductoAbstracto” </em>es la siguiente:</font></p><br><br /><div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:9D7513F9-C04C-4721-824A-2B34F0212519:3995a0ff-8575-40c4-bfc0-e1b269b6e727" class="wlWriterSmartContent"><img style="border-right-width: 0px; width: 560px; border-top-width: 0px; border-bottom-width: 0px; height: 410px; border-left-width: 0px" src="http://lh6.ggpht.com/-fROgDYks7FE/T7vIDjd4PVI/AAAAAAAAAF0/jwtQHQxnuLE/transformedimage%25255B81%25255D.png?imgmax=800"></div><br><br /><p><font size="3">Y las clases “<em>Producto Concreto”</em> las siguientes:</font></p><br><br /><div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:9D7513F9-C04C-4721-824A-2B34F0212519:cb879c8d-22ca-40cf-a59e-cb6a7db5f3fc" class="wlWriterSmartContent"><img style="border-right-width: 0px; width: 560px; border-top-width: 0px; border-bottom-width: 0px; height: 610px; border-left-width: 0px" src="http://lh3.ggpht.com/-SluGxQwrH1g/T7vIFtIpczI/AAAAAAAAAF8/-eiHfsgNNS0/transformedimage%25255B86%25255D.png?imgmax=800"></div><br><br /><p align="justify"><font size="3">Pero… ¿y las factorías? Pues vamos a extraer una factoría concreta de cada una de las secciones de nuestro select case de la función <em>GetMailSectionText</em>, de esta manera:</font></p><br><br /><div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:9D7513F9-C04C-4721-824A-2B34F0212519:c6623923-ad70-4621-8a71-45a32c93e43a" class="wlWriterSmartContent"><img style="border-right-width: 0px; width: 550px; border-top-width: 0px; border-bottom-width: 0px; height: 600px; border-left-width: 0px" src="http://lh3.ggpht.com/-8AVNwYuw8xk/T7vIIc76BkI/AAAAAAAAAGE/sJOY1fkCGyc/transformedimage%25255B72%25255D.png?imgmax=800"></div><br><br /><p align="justify"><font size="3">Y como nuestro patrón necesita de una factoría abstracta, vamos a obtener esta por generalización de las anteriores. Aquí la tenemos!</font></p><br><br /><div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:9D7513F9-C04C-4721-824A-2B34F0212519:24d63a9a-51e8-4326-8855-a4f57d6da8ea" class="wlWriterSmartContent"><img style="border-right-width: 0px; width: 550px; border-top-width: 0px; border-bottom-width: 0px; height: 100px; border-left-width: 0px" src="http://lh3.ggpht.com/-oq6_p4KOIxA/T7vIKbMCRBI/AAAAAAAAAGM/zFDKElGtir0/transformedimage%25255B50%25255D.png?imgmax=800"></div><br><br /><p><font size="3">Vamos a ver el resto de factorías:</font></p><br><br /><div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:9D7513F9-C04C-4721-824A-2B34F0212519:931fa13d-2c4c-4c97-8ba3-1daf60663314" class="wlWriterSmartContent"><img style="border-right-width: 0px; width: 560px; border-top-width: 0px; border-bottom-width: 0px; height: 600px; border-left-width: 0px" src="http://lh5.ggpht.com/-xI5j54xzYP0/T7vIN6JeV_I/AAAAAAAAAGU/ub6S2yMqqn4/transformedimage%25255B63%25255D.png?imgmax=800"></div><br><br /><p align="justify"><font size="3">Como vemos, cada factoría retorna un producto abstracto, pero internamente utiliza su producto concreto “asociado”, para la creación. La magia del polimorfismo, amigos!!</font></p><br><br /><p align="justify"><font size="3">Aquí podemos ver nuestro <a href="http://sdrv.ms/JQ3XAz" target="_blank">modelo estático al completo</a></font></p><br><br /><p align="justify"><font size="3">Y ahora… tachaaan! vamos a modificar la clase <em>MailManager</em> para utilizar todo lo que hemos creado. </font></p><br><br /><p align="justify"><font size="3">La esencia es eliminar el código del <em>Select Case</em>, y modificar la función <em>ComposeMail</em> para utilizar nuestro flamante método <em>GetMailSectionFactory</em> (polimórfico tú, polimórfico yo…). De esta manera, la función utiliza la factoría acorde al tipo solicitado, que es capaz de crear el objeto <em>MailSection</em> concreto solicitado.</font></p><br><br /><p align="justify"><font size="3">Sin embargo, hacia fuera el cliente sólo trata con los objetos abstractos <em>MailSectionFactory</em> y <em>MailSection</em>, quedando toda la complejidad de la creación de objetos encapsulada en las factorías.</font></p><br><br /><p align="justify"><font size="3">Finalmente queda así:</font></p><br><br /><div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:9D7513F9-C04C-4721-824A-2B34F0212519:2b8a3a6e-3422-4c9a-ae19-dff90177ea67" class="wlWriterSmartContent"><img style="border-right-width: 0px; width: 560px; border-top-width: 0px; border-bottom-width: 0px; height: 600px; border-left-width: 0px" src="http://lh5.ggpht.com/-FPQvcivLlyg/T7vIRkufnfI/AAAAAAAAAGc/7CIomfg_Ius/transformedimage%25255B66%25255D.png?imgmax=800"></div><br><br /><p align="justify"><font size="3">Igualita que antes, a que si!!</font></p><br><br /><p align="justify"><font size="3">En el cliente, podemos poner todo esto en marcha de nuevo:</font></p><br><br /><div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:9D7513F9-C04C-4721-824A-2B34F0212519:a9b1f04b-5a1c-4392-a279-77c0bcc203fb" class="wlWriterSmartContent"><img style="border-right-width: 0px; width: 550px; border-top-width: 0px; border-bottom-width: 0px; height: 595px; border-left-width: 0px" src="http://lh4.ggpht.com/-QLn9I51GF64/T7vIVoqOFtI/AAAAAAAAAGk/CT7k6cpNJTc/transformedimage%25255B92%25255D.png?imgmax=800"></div><br><br /><p align="justify"><font size="3">Y si ejecutamos, veremos los mails creados, primero el de pedido y luego el de cliente:</font></p><br><br /><p align="justify"><a href="http://lh3.ggpht.com/-Zk4o7V9QBi4/T7vIZtWZukI/AAAAAAAAAGs/OX7xCdwGBvc/s1600-h/image%25255B3%25255D.png"><img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="image" border="0" alt="image" src="http://lh6.ggpht.com/-gLXXcjr3lsc/T7vIcGNmYxI/AAAAAAAAAG0/bfqsvtf5EDk/image_thumb%25255B1%25255D.png?imgmax=800" width="575" height="285"></a></p><br><br /><p align="justify"><a href="http://lh4.ggpht.com/-UaZ4QR8QFUQ/T7vIfAIQKkI/AAAAAAAAAG8/NJLjjwO9Nv4/s1600-h/image%25255B7%25255D.png"><img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="image" border="0" alt="image" src="http://lh4.ggpht.com/-dVq_pVr0BIk/T7vIg5JhECI/AAAAAAAAAHE/W-VbJyx0sCw/image_thumb%25255B3%25255D.png?imgmax=800" width="583" height="286"></a></p><br><br /><p align="justify"><font size="3">Objetivo conseguido! tenemos nuestra flamante factoría a pleno rendimiento <img style="border-bottom-style: none; border-left-style: none; border-top-style: none; border-right-style: none" class="wlEmoticon wlEmoticon-winkingsmile" alt="Guiño" src="http://lh3.ggpht.com/-luJGndhzhMY/T7vIiivFzuI/AAAAAAAAAHM/5-wDzl_y2ic/wlEmoticon-winkingsmile%25255B2%25255D.png?imgmax=800"></font></p><br><br /><h3>Recapituling, my friend</h3><br><br /><p> </p><br /><p><font size="3">Enumerar beneficios para el ejemplo: </font></p><br /><ul><br /><li><font size="3">Potenciamos el principio SRP</font> <br /><li><font size="3">Separamos el código de creación del código que utiliza dichos objetos </font><br /><li><font size="3">Mejora la ingeniería del software, el uso de patrones de diseño eleva el nivel del equipo de desarrollo</font> <br /><li><font size="3">Mejora la calidad y estructura</font> <br /><li><font size="3">Reducimos el acoplamiento entre objetos</font></li></ul><br /><p><font size="3">Enlace a </font><a href="http://geeks.ms/blogs/gperez/archive/2009/08/24/patrones-de-dise-241-o-screencast-capitulo-2-patr-243-n-factory.aspx"><font size="3">http://geeks.ms/blogs/gperez/archive/2009/08/24/patrones-de-dise-241-o-screencast-capitulo-2-patr-243-n-factory.aspx</font></a><font size="3"> Patrón factoría de Chalalo</font></p><br /><p><font size="3">Pasos para incluir una nueva sección:</font></p><br /><ul><br /><li><font size="3">Implementar una nueva clase que herede de MailSection, y que será nuestro nuevo producto concreto.</font> <br /><li><font size="3">Implementar una nueva factoría concreta, que heredará de MailSectionFactory. Esta nueva factoría creará objetos de la nueva MailSection</font></li></ul> Antoniohttp://www.blogger.com/profile/07910602532207054705noreply@blogger.com3tag:blogger.com,1999:blog-5730880038726783282.post-8096103851807985822011-09-19T01:52:00.001+02:002012-10-19T20:48:39.031+02:00Del software y sus estimaciones: Los puntos de función.<h4> </h4> <h2><font size="3" face="Calibri">Erase una vez, las valoraciones económicas.</font></h2> <p align="justify"><font size="3" face="Calibri">Una mañana cualquiera, después de una reunión de una hora: </font> <p align="justify"><font size="3" face="Calibri">- Bueno, pues creo que con todo lo que hemos hablado, tendrás claro lo que necesitamos. </font></p> <p align="justify"><font size="3" face="Calibri">- Hombre, aún hay algún punto que aclarar, lo que me has contado del proceso de importación de ficheros Excel hay que concretarlo un poco más. </font> <p align="justify"><font size="3" face="Calibri">- Pero hombre, si eso es subir unos ficheritos a la web con los pedidos de los clientes y listo ¿no?. </font> <p align="justify"><font size="3" face="Calibri">- Bueno, eso parece a priori. Pero hay alguna que otra laguna... ¿que pasa con los productos no visibles? ¿y si se modifica el Excel? ¿todo el mundo puede subir ficheros?, entiendo que no... pero desde luego tenemos que profundizar un poco... vamos, creo yo. </font> <p align="justify"><font size="3" face="Calibri">- Bueno, seguro que cuando te pongas con ello, lo veremos más claro. </font> <p align="justify"><font size="3" face="Calibri">- Ya, ya... pero es que también tenemos que ver la parte del gestor de contenidos. Como idea está bien, pero no es sencillo y tenemos que definir bien lo que necesitan los usuarios. Creo que no nos vendrían mal un par de reuniones más. </font> <p align="justify"><font size="3" face="Calibri">- A ver, eso también lo hemos visto. Échale un vistazo a Joomla o a Umbraco y te haces a la idea. Claro que no necesitamos tanto... pero por ahí irán los tiros. Además, tengo que reunirme con dirección para presentar el proyecto y necesito que me des tu valoración. <br><br>- ¿Valoración? </font></p> <p align="justify"><font size="3" face="Calibri">- Si, por supuesto aproximada. Necesito una cifra para este viernes... y que me digas aproximadamente (risilla maquiavélica) cuanto vais a tardar. </font> <p align="justify"><font size="3" face="Calibri">- (con síntomas evidentes de resignación) Veré que podemos hacer... </font> <p align="justify"><font size="3" face="Calibri">¿Os suena todo esto? A mi más de lo que me gustaría, la verdad. Podría ser una conversación cualquiera, de un cliente cualquiera con un pobre desarrollador cualquiera... maldita sea! nos ha tocado a nosotros! </font> <p align="justify"><font size="3" face="Calibri">Al final, al pobre desarrollador le toca utilizar métodos cuando menos dudosos, para dar una “Valoración aproximada”... como podemos ver </font><a href="http://sinergiasincontrol.blogspot.com/2008/07/17-21072008-estimaciones-imaginativas.html"><font size="3" face="Calibri">aquí.</font></a><font size="3" face="Calibri"> </font> <p align="justify"><font size="3" face="Calibri">Y digo yo ¿Debe ser así? Todos sabemos que es muy difícil estimar correctamente el coste inicial de un proyecto de software, más aún si pretendemos (y deberíamos) que este software cumpla unos mínimos de calidad, la tarea se presenta ardua y complicada</font>. </p> <a name='more'></a> <p align="justify"> </p> <h2><font size="3" face="Calibri">Hacer software no es hacer churros, aunque el resultado pueda aproximarse.</font></h2> <p align="justify"><font size="3" face="Calibri">Cualquier software que desarrollemos, tiene que cumplir las siguientes premisas: </font></p> <ul> <li> <div align="justify"><font size="3" face="Calibri">Debe alcanzar unas determinadas funcionalidades. </font></div> <li> <div align="justify"><font size="3" face="Calibri">Respetando los plazos (impuestos o propuestos). </font></div> <li> <div align="justify"><font size="3" face="Calibri">Respetando el presupuesto económico. </font></div></li></ul> <p align="justify"><font size="3" face="Calibri">Así expuesto y resumidito, queda fenomenal. Pero claro, la realidad es cuando menos.... pues eso, muy real. </font></p> <p align="justify"><font size="3" face="Calibri">Además, llevar a buen puerto cualquier desarrollo implica conocer los riesgos que, a priori, nos podemos encontrar por el camino. Voy a enumerar los que considero más relevantes: </font> <ul> <li> <div align="justify"><font face="Calibri"><font size="3"><strong>El tamaño y la duración</strong>: cuanto más grande sea un proyecto, más posibilidades de error y fracaso existen. </font></font></div> <li> <div align="justify"><font face="Calibri"><font size="3"><strong>La tecnología</strong>: si el equipo conoce la tecnología a utilizar tendremos menos riesgo. además, el ritmo de cambio de la misma convierte en difícil la utilización de la experiencia técnica anterior, porque rápidamente se queda obsoleta.</font></font></div> <li> <div align="justify"><font face="Calibri"><font size="3"><strong>Dificultad de determinar las especificaciones</strong>: a menudo contamos con unas especificaciones muy difusas e inciertas sobre el sistema que debemos construir. A las primeras de cambio, podemos encontrarnos con unos requisitos crecientes, difíciles de contener sin unas buenas especificaciones.</font></font></div> <li> <div align="justify"><font face="Calibri"><font size="3"><strong>La calidad y estabilidad de las especificaciones</strong>: Los requisitos de adaptación a la realidad y la complejidad del trato con los futuros usuarios de la aplicación, provoca que nunca se pueda estar seguro de la estabilidad de las especificaciones, hecho que introduce incertidumbre y riesgo en cualquier proyecto. El dominio de nuestro software puede cambiar en cualquier momento, y con él, todas nuestras especificaciones.</font></font></div> <li> <div align="justify"><font face="Calibri"><font size="3"><strong>Mal análisis del problema</strong>: esto conducirá a una descomposición del proyecto en actividades y tareas que no es eficiente, e incluso a una definición incorrecta de los límites del proyecto.</font></font></div> <li> <div align="justify"><font face="Calibri"><font size="3"><strong>Falta de capacidad de decisión</strong> (comunicación deficiente con el cliente) que provoca que demasiadas cuestiones queden sin respuesta, y que nos obligará a trabajar sobre hipótesis provisionales, que cuando son incorrectas o falsas, retrasan y ponen en peligro todo el proyecto.</font></font></div> <li> <div align="justify"><font face="Calibri"><font size="3"><strong>Reusabilidad de los sistemas</strong>: nuestro software debe tener una duración elevada, y debe ser modificable y escalable, para adaptarse al entorno siempre cambiante de la informática de gestión.</font></font></div></li></ul> <p align="justify"><font size="3" face="Calibri">Como veis, los aspectos a tener en cuenta para llegar a nuestro destino no son pocos. Pero si pensabais que esto es un problema relativamente reciente... nada más lejos de la realidad. </font> <p align="justify"><font size="3" face="Calibri">Ya en el año 1968 se empezó a detectar un problema central e intrínseco de los proyectos informáticos de construcción de software: diseñar, construir y mantener software seguro, fiable y de calidad es una actividad siempre llena de dificultades. No es una crisis momentánea, algunos autores lo denominan “una verdadera enfermedad crónica”.</font><br><br></p> <h2><font size="3" face="Calibri">¿El cambio es nuestro amigo? no mucho, pero siempre está con nosotros.</font></h2> <p align="justify"><font size="3" face="Calibri">Una de las características inherentes al desarrollo de software es la complejidad... así que... eso ya lo sabíamos, nos gusta resolver problemas, y por eso nos metimos en estos “fregaos”. Un proyecto de software es casi algo vivo, no se puede planificar ni tratar como una actividad lineal. Debemos estar preparados para el más que previsible cambio. </font> <p align="justify"><font size="3" face="Calibri">Lo primero para poder absorber de una manera lo menos traumática posible los cambios es descomponer el proyecto en diferentes fases. De hecho, y en dado el carácter completamente crucial que tienen las especificaciones del software a construir, algunos autores recomiendan dividir un proyecto informático en dos proyectos consecutivos: </font> <ul> <li> <div align="justify"><font size="3" face="Calibri">Un primer proyecto que tenga como objetivo funcional principal establecer simplemente las especificaciones detalladas de lo que después se debe programar e instalar.</font></div></li></ul> <ul> <li> <div align="justify"><font size="3" face="Calibri">Un segundo proyecto, generalmente con un volumen de esfuerzo y un coste más elevado, que cubra la etapa de programación y pruebas, una vez se han determinado con cierto detalle en el primer proyecto, las especificaciones y las funcionalidades concretas que deben implementarse.</font></div></li></ul> <p align="justify"><font size="3" face="Calibri">(Sinceramente, creo que me moriré sin ver esa fantástica y práctica división...) </font> <p align="justify"><font size="3" face="Calibri">Una buena división en etapas nos permitirá tratar cada fase como un pequeño subproyecto, y de esta manera también protegeremos del cambio (en la medida de lo posible) cada una de las distintas etapas. </font> <p align="justify"><font size="3" face="Calibri">Y después de todo esto... seguimos con la valoración. De una manera muy básica, lo que nos va a tocar es dividir nuestro proyecto en actividades, valorar cada etapa o tarea por separado (normalmente en horas), sumar horas... multiplicar por nuestro precio/hora... y... ¿listo? </font> <p align="justify"><font size="3" face="Calibri">No tan rápido, Mac Gregor... Acabamos de encontrar el primer problema: planificar y valorar de una manera lo más próxima a la realidad, un proyecto de software. </font> <p align="justify"><font size="3" face="Calibri">Para ello debemos encontrar un método de valoración que nos ayude a controlar dos aspectos clave de nuestro próximo desarrollo de software: la duración y la complejidad… Pues existe! </font></p> <p align="justify"><font size="3" face="Calibri">Bienvenido al mundo de los puntos de función, atrevido lector.</font></p> <h2 align="justify"><font size="3" face="Calibri">Los puntos de función. Nuestros “nuevos” amiguitos.</font></h2> <p align="justify"><font size="3" face="Calibri">Los puntos de función (Function Points) fueron definidos en el año 1979 por J.Albretch. Son métricas que se centran en las funcionalidades que debe incluir el producto final, no en su tamaño. Vamos a conocerlos! </font> <p align="justify"><font size="3" face="Calibri">Uno de los criterios de diseño iniciales para los puntos de función fue proveer un mecanismo que tanto los usuarios como los desarrolladores pudiesen utilizar para definir los requerimientos funcionales de un sistema. </font> <p align="justify"><font size="3" face="Calibri">Se determinó que la mejor manera de comprender las necesidades de los usuarios era enfocar el problema desde la perspectiva de como ellos ven los resultados producidos por el sistema. Por ello, una de las primeras metas del análisis de puntos de función es evaluar las capacidades del sistema desde el punto de vista de un usuario. Para conseguir esa meta, el análisis se basa en analizar las distintas maneras de interactuar que tiene un usuario con el sistema. </font> <p align="justify"><font size="3" face="Calibri">Desde la perspectiva de un usuario, cualquier software le ayuda a realizar su trabajo basándose en <strong>cinco funciones básicas</strong>: dos de ellas se refieren a los requerimientos de datos del usuario final, <strong>(Data Funcions)</strong> y las otras tres se refieren a la necesidad del usuario de acceder a los datos <strong>(Transactional Functions)</strong>. </font> <p align="justify"><font size="3" face="Calibri">Cada uno de los cinco tipos de componentes funcionales tiene una valoración, que se establece en baja, media y alta. Esta valoración se traduce en un valor en puntos para cada componente. </font> <p align="justify"><font size="3" face="Calibri">Por tanto, la estimación de proyectos de software mediante el análisis de los puntos de función se basa en transformar los elementos que forman nuestro futuro software (valorando además complejidad) a puntos, según la valoración que se otorga a cada componente. Vamos a ver más en detalle los cinco elementos que propone J.Albretch.</font></p> <h2 align="justify"><font size="3" face="Calibri">Data Functions. los datos.</font></h2> <p align="justify"><strong>Ficheros lógicos internos </strong>(Logical Internal <font size="3" face="Calibri">File o LIF): Archivos internos que residen dentro del sistema y que se mantienen mediante el sistema (por ejemplo, mediante una pantalla de mantenimiento). Pueden ser identificados claramente, y que siempre se mantienen dentro de los límites de la aplicación (son internos y propios a ella). Se pueden identificar con las tablas de la base de datos.</font></p> <p align="justify"><font face="Calibri"><font size="3"><strong>Ficheros de interfaces externas </strong>(External Interface File o EIF): Grupo de datos interrelacionados y que pueden ser identificados por los usuarios, pero en este caso proceden de fuera de los límites de la aplicación. Ni son mantenidos por el sistema ni creados por él. Un ejemplo puede ser un fichero ASCII que debemos importar a nuestro sistema, o con el que debemos interactuar.</font></font></p> <p align="justify"><font size="3" face="Calibri">La complejidad funcional de estos dos elementos, se determina a partir de dos conceptos:</font></p> <p align="justify"><font face="Calibri"><font size="3"><strong>Data Element Type (DET)</strong>: El número de elementos (campos) de un fichero.</font></font></p> <p align="justify"><font face="Calibri"><font size="3"><strong>Record Element Type (RET)</strong>: El número de registros elementales diferentes. Este concepto es fácilmente identificable, si pensamos por ejemplo, en una tabla de base de datos que guarda canciones y podcasts (por ejemplo) en una misma tabla, y que mediante un campo [Tipo] los diferencia. Estaríamos hablando de un fichero con un RET de 2 (Canciones y podcasts).</font></font></p> <p align="justify"><font size="3" face="Calibri">Estos dos conceptos debemos tenerlos en cuenta para cada función de datos que localicemos. Así, la complejidad de las características funcionales sale de una tabla como la que sigue:</font></p> <div align="center"> <table border="0" cellspacing="0" cellpadding="2" width="400" align="center"> <tbody> <tr> <td valign="top" width="100"> </td> <td valign="top" width="100"> <p align="center"><strong>1 a 19 DET</strong></p></td> <td valign="top" width="100"> <p align="center"><strong>20 a 50 DET</strong></p></td> <td valign="top" width="100"> <p align="center"><strong>51 DET o más</strong></p></td></tr> <tr> <td valign="top" width="100"> <p align="left"><strong>1 RET</strong></p></td> <td valign="top" width="100"> <p align="center">Baja </p></td> <td valign="top" width="100"> <p align="center">Baja </p></td> <td valign="top" width="100"> <p align="center">Media</p></td></tr> <tr> <td valign="top" width="100"> <p align="left"><strong>2 a 5 RET</strong></p></td> <td valign="top" width="100"> <p align="center">Baja </p></td> <td valign="top" width="100"> <p align="center">Media</p></td> <td valign="top" width="100"> <p align="center">Alta</p></td></tr> <tr> <td valign="top" width="100"> <p align="left"><strong>6 RET o más</strong></p></td> <td valign="top" width="100"> <p align="center">Media</p></td> <td valign="top" width="100"> <p align="center">Alta</p></td> <td valign="top" width="100"> <p align="center">Alta</p></td></tr></tbody></table></div> <p align="justify"><font size="3" face="Calibri">En función de la complejidad, tenemos esta otra tabla para asignar los valores a aplicar para nuestro cálculo:</font></p> <div align="center"> <table border="0" cellspacing="0" cellpadding="2" width="400" align="center"> <tbody> <tr> <td valign="top" width="100"> <p align="center"> </p></td> <td valign="top" width="100"> <p align="center"><strong>Baja</strong></p></td> <td valign="top" width="100"> <p align="center"><strong>Media</strong></p></td> <td valign="top" width="100"> <p align="center"><strong>Alta</strong></p></td></tr> <tr> <td valign="top" width="100"> <p align="center"><strong>LIF</strong></p></td> <td valign="top" width="100"> <p align="center">x 7</p></td> <td valign="top" width="100"> <p align="center">x 10</p></td> <td valign="top" width="100"> <p align="center">x 15</p></td></tr> <tr> <td valign="top" width="100"> <p align="center"><strong>EIF</strong></p></td> <td valign="top" width="100"> <p align="center">x 5</p></td> <td valign="top" width="100"> <p align="center">x 7</p></td> <td valign="top" width="100"> <p align="center">x 10</p></td></tr></tbody></table></div> <p align="justify"><font size="3" face="Calibri">Esto significa, que si hemos localizado dos ficheros LIF de complejidad baja, su valor es 2 x 7 = 14 Puntos de función sin ajustar.</font></p> <h2><font size="3" face="Calibri">Transactional Functions. Los procesos.</font></h2> <p align="justify"><font size="3" face="Calibri">Vamos a ver ahora los otros tres elementos que deberemos valorar. Estas tres funciones son las siguientes:</font></p> <p align="justify"><font face="Calibri"><font size="3"><strong>Entradas Externas </strong>(External Inputs o EI): hacen referencia a los tratamientos que procesan datos o información de control introducidos en la aplicación desde fuera de sus límites. El actor (ojo, no solo usuarios!) introduce datos en el sistema que pueden ser para agregar, modificar o eliminar un archivo o información de control del sistema. Son <strong>entradas a la aplicación</strong>. Si localizamos un EI, casi seguro que tendremos uno o varios LIF asociados.</font></font></p> <p align="justify"><font face="Calibri"><font size="3"><strong>Salidas Externas </strong>(External Output o EO): cualquier proceso elemental que genere datos o información de control que salta de los límites de la aplicación. Equivale a las <strong>salidas que genera la aplicación </strong>y pueden utilizar <strong>uno o más </strong>ficheros LIF o EIF para llevar a cabo su cometido. Ejemplos de uso pueden ser actualizaciones de ficheros o para creaciones de un reports o ficheros. Si tenemos un EO, seguro que tenemos un LIF.</font></font></p> <p align="justify"><font face="Calibri"><font size="3"><strong>Consultas Externas </strong>(External Queries o EQ): es un proceso elemental con procesos de entrada y salida, donde se rescatan datos de uno o más archivos lógicos internos o de interfaz externos. los datos de entrada no actualizan ni mantienen ningún archivo, y los datos de salida no contienen datos calculados. Dentro de este tipo de transacciones encontramos los <strong>listados y las búsquedas. </strong></font></font></p> <p align="justify"><font size="3" face="Calibri">Si os habéis fijado, es sencillo confundir las Salidas Externas (EQ) con las Consultas Externas (EQ). Para ello, podemos aplicar una sencilla regla: las EQ no realizan ninguna operación sobre los ficheros que tengan relacionados y no ofrecen datos calculados.</font></p> <p align="justify"><font size="3" face="Calibri">Para determinar la complejidad de las transacciones, debemos tener en cuenta los siguientes conceptos:</font></p> <p align="justify"><font face="Calibri"><font size="3"><strong>Data Element Type (DET)</strong>: conocemos este concepto, ya que es lo mismo que en las funciones de datos: se corresponde con los campos que tiene el fichero afectado.</font></font></p> <p align="justify"><font face="Calibri"><font size="3"><strong>File Type Referenced (FTR):</strong> número de archivos lógicos internos (LIF) o archivos de interfaz externa (EIF) que utilizamos en la transacción objeto de nuestra valoración.</font></font></p> <p align="justify"><font size="3" face="Calibri">Y ahora que ya tenemos todos los elementos, veamos nuestras tablas de complejidad:</font></p> <p align="justify"><font face="Calibri"><font size="3">Esta es válida para las <strong>Entradas Externas</strong> <strong>(EI):</strong></font></font></p> <div align="center"> <table border="0" cellspacing="0" cellpadding="2" width="400" align="center"> <tbody> <tr> <td valign="top" width="100"><strong></strong></td> <td valign="top" width="100"><strong>1-4 DET</strong></td> <td valign="top" width="100"><strong>5-15 DET</strong></td> <td valign="top" width="100"><strong>+15 DET</strong></td></tr> <tr> <td valign="top" width="100"><strong>0-1 FTR</strong></td> <td valign="top" width="100">Baja</td> <td valign="top" width="100">Baja</td> <td valign="top" width="100">Media</td></tr> <tr> <td valign="top" width="100"><strong>2 FTR</strong></td> <td valign="top" width="100">Baja</td> <td valign="top" width="100">Media</td> <td valign="top" width="100">Alta</td></tr> <tr> <td valign="top" width="100"><strong>3 o +3 FTR</strong></td> <td valign="top" width="100">Media</td> <td valign="top" width="100">Alta</td> <td valign="top" width="100">Alta</td></tr></tbody></table></div> <p><font size="2"><font size="3" face="Calibri">Esta otra, para las <strong>Salidas Externas (EO) </strong>y para las </font><strong><font size="3" face="Calibri">Consultas Externas (EQ)</font>:</strong></font></p> <table border="0" cellspacing="0" cellpadding="2" width="402" align="center"> <tbody> <tr> <td valign="top" width="100"><strong></strong></td> <td valign="top" width="100"><strong>1-4 DET</strong></td> <td valign="top" width="100"><strong>6-19 DET</strong></td> <td valign="top" width="100"><strong>+19 DET</strong></td></tr> <tr> <td valign="top" width="100"><strong>0-1 FTR</strong></td> <td valign="top" width="100">Baja</td> <td valign="top" width="100">Baja</td> <td valign="top" width="100">Media</td></tr> <tr> <td valign="top" width="100"><strong>2-3 FTR</strong></td> <td valign="top" width="100">Baja</td> <td valign="top" width="100">Media</td> <td valign="top" width="100">Alta</td></tr> <tr> <td valign="top" width="100"><strong>+3 FTR</strong></td> <td valign="top" width="100">Media</td> <td valign="top" width="100">Alta</td> <td valign="top" width="100">Alta</td></tr></tbody></table> <p><font size="3" face="Calibri">Y esta última la utilizaremos para asignar un valor a nuestros elementos en función de la complejidad obtenida:</font></p> <table border="0" cellspacing="0" cellpadding="2" width="402" align="center"> <tbody> <tr> <td valign="top" width="100"><strong><font size="3" face="Calibri"></font></strong></td> <td valign="top" width="100"><strong>Salidas Externas (EO)</strong></td> <td valign="top" width="100"><strong>Consultas Externas (EQ)</strong></td> <td valign="top" width="100"><strong>Entradas Externas (EI)</strong></td></tr> <tr> <td valign="top" width="100"> <p align="left"><strong>Baja</strong></p></td> <td valign="top" width="100"> <p align="center">x 4</p></td> <td valign="top" width="100"> <p align="center">x 3</p></td> <td valign="top" width="100"> <p align="center">x 3</p></td></tr> <tr> <td valign="top" width="100"><strong>Media</strong></td> <td valign="top" width="100"> <p align="center">x 5</p></td> <td valign="top" width="100"> <p align="center">x 4</p></td> <td valign="top" width="100"> <p align="center">x 4</p></td></tr> <tr> <td valign="top" width="100"><strong>Alta</strong></td> <td valign="top" width="100"> <p align="center">x 7</p></td> <td valign="top" width="100"> <p align="center">x 6</p></td> <td valign="top" width="100"> <p align="center">x 6</p></td></tr></tbody></table> <p><font size="3" face="Calibri">Igual que antes, si tenemos por ejemplo una Salida Externa (EO) que utiliza dos ficheros (tiene un FTR de 2) y que tiene 10 campos (10DET) estableceríamos su complejidad como Baja, estableciendo su valor en puntos de función en 1 x 5 = 5.</font></p> <h2><font size="3" face="Calibri">Aún hay más: factores de ajuste</font></h2> <p align="justify"><font size="3" face="Calibri">Hemos visto los elementos principales a tener en cuenta para realizar una estimación de la carga de un proyecto de software mediante los puntos de función. </font></p> <p align="justify"><font size="3" face="Calibri">Si realizamos el análisis de un aplicativo teniendo en cuenta sólo los cinco elementos que hemos presentado, obtendremos los denominados <strong>puntos de función sin ajustar</strong> (Unadjusted Function Points). Es el primer paso para tener una valoración en puntos de función definitiva.</font></p> <p align="justify"><font size="3" face="Calibri">El señor J.Albretch ya pensó que las características funcionales indicadas no agotaban todas las posibilidades de definir funcionalmente un software de aplicación. Debido a eso, añadió que se debían tener en cuenta las características generales del sistema. </font></p> <p align="justify"><font size="3" face="Calibri">Albretch propone catorce características funcionales, que se evalúan de 1 a 5 de la siguiente manera:</font></p> <p align="justify"><font size="3" face="Calibri">0 – No presente o sin influencia<br>1 – Influencia incidental<br>2 – Influencia moderada<br>3 – Influencia media<br>4 – Influencia significativa<br>5 – Fuerte influencia</font></p> <p align="justify"><font size="3" face="Calibri">Las catorce características propuestas son</font>:</p> <div align="center"> <table border="0" cellspacing="0" cellpadding="2" width="503" align="center"> <tbody> <tr> <td valign="top" width="200"><strong>Característica</strong></td> <td valign="top" width="301"><strong>Descripción</strong></td></tr> <tr> <td valign="top" width="200"> <p align="left">Comunicación de datos</p></td> <td valign="top" width="301"> <p align="left">¿Cuantas facilidades de comunicación hay disponibles para ayudar con el intercambio de información con la aplicación o el sistema?</p></td></tr> <tr> <td valign="top" width="200"> <p align="left">Procesamiento distribuido de los datos</p></td> <td valign="top" width="301"> <p align="left">¿Cómo se manejan los datos y las funciones de procesamiento distribuido?</p></td></tr> <tr> <td valign="top" width="200"> <p align="left">Rendimiento</p></td> <td valign="top" width="301"> <p align="left">¿Existen requerimientos de velocidad o tiempo de respuesta?</p></td></tr> <tr> <td valign="top" width="200"> <p align="left">Configuraciones fuertemente utilizadas</p></td> <td valign="top" width="301"> <p align="left">¿Que tan intensivamente se utiliza la plataforma de hardware donde se ejecutará la aplicación o el sistema?</p></td></tr> <tr> <td valign="top" width="200"> <p align="left">Frecuencia de las transacciones</p></td> <td valign="top" width="301"> <p align="left">¿Con qué frecuencia se ejecutan las transacciones? diarias, semanales, mensuales…</p></td></tr> <tr> <td valign="top" width="200"> <p align="left">Entrada de datos On-line</p></td> <td valign="top" width="301"> <p align="left">¿Qué porcentaje de la información se ingresa on-line?</p></td></tr> <tr> <td valign="top" width="200"> <p align="left">Eficiencia del usuario final</p></td> <td valign="top" width="301"> <p align="left">¿se designa la aplicación para maximizar la eficiencia del usuario final?</p></td></tr> <tr> <td valign="top" width="200"> <p align="left">Actualizaciones on-line</p></td> <td valign="top" width="301"> <p align="left">¿Cuantos archivos lógicos internos se actualizan por una transacción on-line?</p></td></tr> <tr> <td valign="top" width="200"> <p align="left">Procesamiento complejo</p></td> <td valign="top" width="301"> <p align="left">¿Hay procesamientos lógicos o matemáticos intensos en la aplicación?</p></td></tr> <tr> <td valign="top" width="200"> <p align="left">Reusabilidad</p></td> <td valign="top" width="301"> <p align="left">La aplicación se desarrolla para suplir una o muchas de las necesidades de los usuarios</p></td></tr> <tr> <td valign="top" width="200"> <p align="left">Facilidad de instalación</p></td> <td valign="top" width="301"> <p align="left">¿Es muy difícil la instalación y la conversión al nuevo sistema?</p></td></tr> <tr> <td valign="top" width="200"> <p align="left">Facilidad de operación</p></td> <td valign="top" width="301"> <p align="left">¿cómo de efectivos y automatizados son los procedimientos de arranque, parada, backup y restore del sistema?</p></td></tr> <tr> <td valign="top" width="200"> <p align="left">Instalación en distintos lugares</p></td> <td valign="top" width="301"> <p align="left">¿La aplicación fue concebida para su instalación en múltiples sitios y organizaciones?</p></td></tr> <tr> <td valign="top" width="200"> <p align="left">Facilidad de cambio</p></td> <td valign="top" width="301"> <p align="left">La aplicación fue concebida para facilitar los cambios sobre la misma</p></td></tr></tbody></table></div> <p><font size="3" face="Calibri">Si desconocemos alguna de estas características cuando estemos realizando nuestro análisis, podemos utilizar un valor medio (2,5) para su valoración.</font></p> <p><font size="3" face="Calibri">La suma de la valoración de todas las características generales de nuestro sistema, arroja una cantidad, que se denomina <strong>grado total de influencia (Total degree of influence). </strong>Con ese grado y mediante la siguiente fórmula:</font></p> <p align="center"><font size="3" face="Calibri"><strong>PCA = 0,65 + (0,01 * TDI)</strong></font></p> <p><font size="3" face="Calibri">Obtendremos el <strong>ajuste por la complejidad del proceso</strong> (PCA, Processing Complexity Adjustment).</font></p> <h2><font size="3" face="Calibri">Pues muy bonito! y después de esto… ¿Qué?</font></h2> <p align="justify"><font size="3" face="Calibri">Pues bien, ya tenemos todos los elementos necesarios! por un lado, hemos realizado el cálculo de cada una de las funcionalidades de nuestro sistema, con lo que ya tenemos el total de puntos de función sin ajustar (TUFP, Total unadjusted function points) de nuestro sistema.</font></p> <p align="justify"><font size="3" face="Calibri">Por otro, hemos evaluado las características funcionales de nuestros sistema, y hemos valorado su incidencia sobre el mismo, obteniendo el grado total de influencia. Gracias a ese grado total de influencia, podemos calcular los puntos de función de nuestro sistema, con la fórmula:</font></p> <p align="center"><font size="3" face="Calibri"><strong>FP = TUFP * PCA</strong></font></p> <p align="justify"><font size="3" face="Calibri">Lo hemos conseguido! tenemos la valoración de nuestro proyecto de software en puntos de función! Ahora sólo tenemos que pasar los puntos de función a horas, para poder calcular costes, valoración para el cliente y poder planificar nuestro proyecto.</font></p> <p align="justify"><font size="3" face="Calibri">Lo ideal es contar con una base estadística y datos de productividad propios, que pueden haber sido obtenidos en proyectos anteriores del mismo tipo, y con equipos de desarrollo de características similares.</font></p> <p align="justify"><font size="3" face="Calibri">Ojala lo tuviésemos todo!! todo llegará, pero mientras llega, tened en cuenta que una productividad de 2 o 3 horas por punto de función es lo habitual.</font></p> <p align="justify"><font size="3" face="Calibri">Por este motivo (y muchos otros), es tan importante disponer de la documentación de gestión y de los datos de productividad de proyectos informáticos anteriores. </font></p> <h2 align="justify"><font size="3" face="Calibri">Concluyendo, que es gerundio</font></h2> <p align="justify"><font size="3" face="Calibri">Siempre he sentido cierta obsesión por obtener una valoración de los proyectos de software en los que he participado <strong>lo más cercana a la realidad</strong>. Si habéis visto el enlace que hay al principio del post, en la mayoría de las ocasiones es casi una labor de brujería y adivinación.</font></p> <p align="justify"><font size="3" face="Calibri">Los motivos son muy diversos, aunque principalmente me encuentro con que los usuarios a los que va dirigido el software o bien los responsables de solicitarlo no nos dan unas especificaciones todo lo formales que nos gustaría, bien por falta de tiempo, por desconocimiento de los procesos a mecanizar o por el entorno cambiante en el que nos toca desarrollar. En otras ocasiones somos nosotros, los que en un alarde de optimismo pensamos que somos capaces de multiplicar los panes, los peces, los teclados, las líneas de código… y a veces hasta a nosotros mismos!!</font></p> <p align="justify"><font size="3" face="Calibri">Esto no es <strong>ni bueno ni malo</strong>, simplemente <strong>es una realidad</strong> con la que tenemos que lidiar, lo mejor que podemos y sobre todo con todo el <strong>rigor </strong>del que seamos capaces.</font></p> <p align="justify"><font size="3" face="Calibri">Desde luego, contar con un método establecido y estándar para realizar estimaciones ya es un gran paso. La mayoría de nosotros hemos realizado valoraciones basándonos en nuestra propia experiencia, y en la experiencia que hemos tenido en los proyectos que hemos realizado. Esto implica de manera directa que, en una misma empresa, dependiendo de quien valore un proyecto tendremos desviaciones más o menos notables.</font></p> <p align="justify"><font size="3" face="Calibri">Y digo yo, ¿pero no es el mismo software? ¿no debe cumplir las mismas especificaciones? ¿que demonios pasa aquí!!?</font></p> <p align="justify"><font size="3" face="Calibri">Pues pasa que las metodologías “in house” (nombre bonito donde los haya), o el “mira Mariano, a ver por donde sopla el viento” es lo que tienen, y que si deseamos profesionalizarnos, debemos huir de ellas y tender a adoptar en la medida en la que podamos metodologías estándar, testeadas y de probada capacidad.</font></p> <p align="justify"><font size="3" face="Calibri">La <strong>valoración y estimación</strong> de un proyecto de software <strong>es una parte vital </strong>dentro del ciclo de vida <strong>del desarrollo de software</strong>, y puede significar la diferencia entre el éxito y el infierno del fracaso, las horas extra, los clientes cabreados y los programadores frustrados.</font></p> <p align="justify"><font size="3" face="Calibri">No se a vosotros, pero a mi los infiernos no me motivan (salvo que sea el nombre de un bar).</font></p> <p align="justify"><font size="3" face="Calibri">Por otro lado, una vez que el proyecto comienza, no hay marcha atrás, y sólo nos queda realizar un correcto seguimiento del mismo. Hay que prepararse para el cambio.</font></p> <p align="justify"><font size="3" face="Calibri">Un <strong>seguimiento efectivo </strong>nos permitirá efectuar controles regulares y medir las desviaciones entre la realidad y aquello que se ha planificado anteriormente. con estos datos, debe reelaborarse tanto la estimación (a partir de los datos reales de productividad que se toman del equipo humano que interviene en el proyecto) como la planificación (por los cambios en la estimación del esfuerzo necesario, y también por los posibles desajustes en la disponibilidad de los recursos). </font></p> <p align="justify"><strong><font size="3" face="Calibri">Hay que tener muy en cuenta que c</font><font size="3" face="Calibri">ualquier estimación de cargas, riesgos y costes para el desarrollo de software, es una conjetura, y por tanto posiblemente sea falsa. Las estimaciones y planificaciones deben revisarse, y cuando convenga, corregirse. </font></strong></p> <p align="justify"><font size="3" face="Calibri">Casi ná… vamos con pies de barro, montando software por el mundo! y encima nos encanta! Definitivamente, estamos fatal.</font></p> <p align="justify"><font size="3" face="Calibri">Si habéis aguantado, Muchas gracias! Creo firmemente que la aplicación del análisis y estimaciones mediante puntos de función puede reportar sin ninguna duda, más beneficios que cualquier otra metodología “casera”. </font></p> <p align="justify"><font size="3" face="Calibri">Sin embargo, adolece de lo mismo que casi todas: si no tenemos unas buenas especificaciones, vamos dados. Nuestra labor fundamental en esta fase es hacer todo lo posible por obtenerlas!</font></p> <p align="justify"><font size="3" face="Calibri">Espero que os haya resultado interesante, y que os haya abierto una vía más para clarificar una tarea ya de por sí complicada, como puede ser la valoración de software.</font></p> <p align="justify"><font size="3" face="Calibri">Para el próximo post, un ejemplo de todo lo expuesto aquí.</font></p> <p><font size="3" face="Calibri">Un cordial saludo!</font></p> Antoniohttp://www.blogger.com/profile/07910602532207054705noreply@blogger.com2tag:blogger.com,1999:blog-5730880038726783282.post-50960696723460210612011-08-24T17:47:00.000+02:002012-10-19T20:50:43.654+02:00Uso de Interfaces en aplicaciones n-capas<p> </p> <p align="justify"><font size="3" face="Calibri">Hola a todos.</font></p> <p align="justify"><font size="3" face="Calibri">Ayer tuve una discusión sana con mi compañero Sergio (podéis seguir su magnífico blog </font><a href="http://panicoenlaxbox.blogspot.com/"><font size="3" face="Calibri">aquí</font></a><font face="Calibri"><font size="3">), acerca de las arquitecturas n-capas, y más concretamente del uso de “interfaces“para la comunicación entre capas.</font> </font></p> <p align="justify"><font size="3" face="Calibri">La discusión giraba en torno a lo que es una “Interfaz”, como concepto, en el contexto de comunicaciones entre capas. La idea que primero nos viene a la cabeza, es que la interfaz es lo que la capa expone a modo de servicios (métodos y clases públicas) para comunicarse con otras capas. </font></p> <p align="justify"><font size="3" face="Calibri">Y si bien esa idea es completamente correcta y cierta, tenemos que tener en cuenta que las interfaces (entendidas aquí como elementos dentro de una programación orientada a objetos), también nos proporcionan un contrato a cumplir por las clases que las implementen. ejemplos los tenemos a miles (IComparable, IEnumerable, IQueryable, .. y </font><a href="http://panicoenlaxbox.blogspot.com/2011/07/interfaces-must-know.html"><font size="3" face="Calibri">unas cuantas más</font></a><font size="3" face="Calibri">)</font></p> <p align="justify"><font size="3" face="Calibri">Pues bien, el propósito de este post es mostrar cómo las interfaces nos pueden ayudar a conseguir cierto nivel de desacoplamiento entre capas, con todos los beneficios que eso nos trae: testeabilidad, división de responsabilidades, y otros muchos.</font></p> <p align="justify"><font size="3" face="Calibri">Bueno, vamos al turrón. </font></p> <a name='more'></a> <p align="justify"><font size="3" face="Calibri">Para comenzar, he preparado un pequeño proyecto con tres componentes:</font></p> <p><a href="http://lh3.ggpht.com/-8jrTVlVnhaQ/TlUbM346WaI/AAAAAAAAADg/0eYP8P7Eyk0/s1600-h/image%25255B6%25255D.png"><img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: block; float: none; border-top-width: 0px; border-bottom-width: 0px; margin-left: auto; border-left-width: 0px; margin-right: auto; padding-top: 0px" title="image" border="0" alt="image" src="http://lh3.ggpht.com/--xJjeTAidpM/TlUbNX3YHDI/AAAAAAAAADk/FXclyqI64IA/image_thumb%25255B1%25255D.png?imgmax=800" width="244" height="227"></a></p> <ul> <li> <div align="justify"><font size="3" face="Calibri">DAL: ensamblado que alberga un pequeño modelo de Entity Framework, y una clase ClienteDAL con un par de métodos que recuperan datos del modelo. </font></div> <li> <div align="justify"><font size="3" face="Calibri">BLL: capa de “negocio” que referencia a DAL y que tiene una clase ClienteBLL que hace uso de la capa DAL. El cómo utiliza BLL a DAL es el quid de todo este post. </font></div> <li> <div align="justify"><font size="3" face="Calibri">Presentacion: en este caso, es una simple aplicación de consola que hace uso de la clase ClienteBLL para mostrar un listado de clientes en la consola. la capa de presentación referencia tanto a Dal como a BLL, por facilidad de uso y para acceder a las entidades del modelo de Entity Framework.</font></div></li></ul> <p><font size="3" face="Calibri">El código de la clase ClienteDAL es:</font></p><pre style="border-bottom: #cecece 1px solid; border-left: #cecece 1px solid; padding-bottom: 5px; background-color: #fbfbfb; min-height: 40px; padding-left: 5px; width: 500px; padding-right: 5px; overflow: auto; border-top: #cecece 1px solid; border-right: #cecece 1px solid; padding-top: 5px"><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 11px"> 1: <span style="color: #0000ff">Public</span> <span style="color: #0000ff">Class</span> ClienteDAL<br></pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 11px"> 2: <br></pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 11px"> 3: <span style="color: #0000ff">Dim</span> _context <span style="color: #0000ff">As</span> <span style="color: #0000ff">New</span> DataContext<br></pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 11px"> 4: <br></pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 11px"> 5: <span style="color: #0000ff">Public</span> <span style="color: #0000ff">Function</span> GetClientePorIdCliente(<span style="color: #0000ff">ByVal</span> id <span style="color: #0000ff">As</span> <span style="color: #0000ff">String</span>) <span style="color: #0000ff">As</span> Clientes<br></pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 11px"> 6: <br></pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 11px"> 7: <span style="color: #0000ff">Return</span> (From c <span style="color: #0000ff">In</span> _context.Clientes()<br></pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 11px"> 8: Where c.IdCliente = id).SingleOrDefault()<br></pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 11px"> 9: <br></pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 11px"> 10: <span style="color: #0000ff">End</span> <span style="color: #0000ff">Function</span><br></pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 11px"> 11: <br></pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 11px"> 12: <span style="color: #0000ff">Public</span> <span style="color: #0000ff">Function</span> GetAll() <span style="color: #0000ff">As</span> IEnumerable(<span style="color: #0000ff">Of</span> Clientes)<br></pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 11px"> 13: <br></pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 11px"> 14: <span style="color: #0000ff">Return</span> (From c <span style="color: #0000ff">In</span> _context.Clientes()).AsEnumerable()<br></pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 11px"> 15: <br></pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 11px"> 16: <span style="color: #0000ff">End</span> <span style="color: #0000ff">Function</span><br></pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 11px"> 17: <br></pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 11px"> 18: <span style="color: #0000ff">End</span> <span style="color: #0000ff">Class</span><br></pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 11px"> 19: </pre></pre><br><br /><p><font size="3" face="Calibri">El de ClienteBLL</font></p><pre style="border-bottom: #cecece 1px solid; border-left: #cecece 1px solid; padding-bottom: 5px; background-color: #fbfbfb; min-height: 40px; padding-left: 5px; width: 500px; padding-right: 5px; overflow: auto; border-top: #cecece 1px solid; border-right: #cecece 1px solid; padding-top: 5px"><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 11px"> 1: <span style="color: #0000ff">Public</span> <span style="color: #0000ff">Class</span> ClienteBLL<br></pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 11px"> 2: <br></pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 11px"> 3: <span style="color: #0000ff">Public</span> <span style="color: #0000ff">Function</span> GetClientePorIdCliente(<span style="color: #0000ff">ByVal</span> id <span style="color: #0000ff">As</span> <span style="color: #0000ff">String</span>) <span style="color: #0000ff">As</span> InterfacesyCapas.DAL.Clientes<br></pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 11px"> 4: <br></pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 11px"> 5: <span style="color: #0000ff">Dim</span> clienteDAL <span style="color: #0000ff">As</span> <span style="color: #0000ff">New</span> InterfacesyCapas.DAL.ClienteDAL<br></pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 11px"> 6: <span style="color: #0000ff">Return</span> clienteDAL.GetClientePorIdCliente(id)<br></pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 11px"> 7: <br></pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 11px"> 8: <span style="color: #0000ff">End</span> <span style="color: #0000ff">Function</span><br></pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 11px"> 9: <br></pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 11px"> 10: <span style="color: #0000ff">Public</span> <span style="color: #0000ff">Function</span> GetAll() <span style="color: #0000ff">As</span> IEnumerable(<span style="color: #0000ff">Of</span> InterfacesyCapas.DAL.Clientes)<br></pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 11px"> 11: <br></pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 11px"> 12: <span style="color: #0000ff">Dim</span> clienteDAL <span style="color: #0000ff">As</span> <span style="color: #0000ff">New</span> InterfacesyCapas.DAL.ClienteDAL<br></pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 11px"> 13: <span style="color: #0000ff">Return</span> clienteDAL.GetAll<br></pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 11px"> 14: <br></pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 11px"> 15: <span style="color: #0000ff">End</span> <span style="color: #0000ff">Function</span><br></pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 11px"> 16: <br></pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 11px"> 17: <span style="color: #0000ff">End</span> <span style="color: #0000ff">Class</span><br></pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 11px"> 18: </pre></pre><br><br /><p><font size="3" face="Calibri">Y la aplicación de consola:</font></p><pre style="border-bottom: #cecece 1px solid; border-left: #cecece 1px solid; padding-bottom: 5px; background-color: #fbfbfb; min-height: 40px; padding-left: 5px; width: 500px; padding-right: 5px; overflow: auto; border-top: #cecece 1px solid; border-right: #cecece 1px solid; padding-top: 5px"><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 11px"> 1: <span style="color: #0000ff">Module</span> <span style="color: #0000ff">Module</span>1<br></pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 11px"> 2: <br></pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 11px"> 3: <span style="color: #0000ff">Sub</span> Main()<br></pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 11px"> 4: <br></pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 11px"> 5: <span style="color: #0000ff">Dim</span> clienteBLL <span style="color: #0000ff">As</span> <span style="color: #0000ff">New</span> InterfacesyCapas.BLL.ClienteBLL<br></pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 11px"> 6: <span style="color: #0000ff">For</span> <span style="color: #0000ff">Each</span> t <span style="color: #0000ff">In</span> clienteBLL.GetAll<br></pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 11px"> 7: Console.WriteLine("<span style="color: #8b0000">cliente {0} de nombre {1}</span>", t.IdCliente, t.Nombre)<br></pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 11px"> 8: <span style="color: #0000ff">Next</span><br></pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 11px"> 9: Console.ReadLine()<br></pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 11px"> 10: <br></pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 11px"> 11: <span style="color: #0000ff">End</span> <span style="color: #0000ff">Sub</span><br></pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 11px"> 12: <br></pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 11px"> 13: <span style="color: #0000ff">End</span> <span style="color: #0000ff">Module</span><br></pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 11px"> 14: </pre></pre><br><br /><p><font size="3" face="Calibri">Vamos a ver las métricas de código para la clase ClienteBLL, a ver qué nos dice. Con el botón derecho del ratón, buscamos la opción “Calcular métricas de código” o desde el menú “Analizar” buscamos la misma opción.</font></p><br><br /><p><a href="http://lh3.ggpht.com/-jhF3AUKIFbw/TlUbO4amUjI/AAAAAAAAADo/otxIFVN4nkE/s1600-h/image%25255B11%25255D.png"><img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: block; float: none; border-top-width: 0px; border-bottom-width: 0px; margin-left: auto; border-left-width: 0px; margin-right: auto; padding-top: 0px" title="image" border="0" alt="image" src="http://lh4.ggpht.com/-d3sT2heaa8s/TlUbPoKUw2I/AAAAAAAAADs/AQnm2i69IvM/image_thumb%25255B4%25255D.png?imgmax=800" width="385" height="148"></a></p><br><br /><p><font size="3" face="Calibri">Ojo, esta opción sólo esta disponible para Visual Studio Ultimate o Premium (gracias Mookie!), por lo que no podremos ver estos resultados si no disponemos de alguna de estas versiones. Sorry!</font></p><br><br /><p><font size="3" face="Calibri">Vemos el resultado obtenido:</font></p><br><br /><p><a href="http://lh3.ggpht.com/-W1U6Zv_XAIE/TlUb-0m-QKI/AAAAAAAAADw/JtUCLcgK2Uo/s1600-h/SNAGHTML1529e57%25255B4%25255D.png"><img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: block; float: none; border-top-width: 0px; border-bottom-width: 0px; margin-left: auto; border-left-width: 0px; margin-right: auto; padding-top: 0px" title="SNAGHTML1529e57" border="0" alt="SNAGHTML1529e57" src="http://lh6.ggpht.com/-qxf5D0iDujs/TlUb__wpl1I/AAAAAAAAAD0/PrnywquAt8E/SNAGHTML1529e57_thumb%25255B1%25255D.png?imgmax=800" width="549" height="195"></a></p><br><br /><p align="justify"><font size="3" face="Calibri">A nosotros nos interesa la medida “Acoplamiento de clases” (</font><a href="http://msdn.microsoft.com/es-es/library/bb385914%28v=vs.90%29.aspx"><font size="3" face="Calibri">ver mas métricas</font></a><font size="3" face="Calibri">). Vamos a ver si somos capaces de bajar ese valor. Hay que intentarlo! Lo primero que se nos puede ocurrir, es que en vez de instanciar en cada método a la clase <em>ClienteDal</em>, la clase <em>ClienteBLL</em> reciba un objeto <em>ClienteDal</em> en su contructor. dicho objeto <em>ClienteDal</em> deberá ser instanciado entonces desde la capa de presentación. Vamos a ver las modificaciones que deberíamos realizar y a ver qué obtenemos:</font></p><br><br /><p align="justify"><font size="3" face="Calibri">Nuestra clase <em>ClienteBLL</em> se modifica, con un nuevo constructor que permite establecer un objeto clienteDal, con el que funcionar a nivel interno</font>.</p><pre style="border-bottom: #cecece 1px solid; border-left: #cecece 1px solid; padding-bottom: 5px; background-color: #fbfbfb; min-height: 40px; padding-left: 5px; width: 500px; padding-right: 5px; overflow: auto; border-top: #cecece 1px solid; border-right: #cecece 1px solid; padding-top: 5px"><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 11px"> 1: <span style="color: #0000ff">Public</span> <span style="color: #0000ff">Class</span> ClienteBLL<br></pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 11px"> 2: <br></pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 11px"> 3: <span style="color: #0000ff">Dim</span> _clienteDal <span style="color: #0000ff">As</span> InterfacesyCapas.DAL.ClienteDAL<br></pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 11px"> 4: <br></pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 11px"> 5: <span style="color: #0000ff">Public</span> <span style="color: #0000ff">Sub</span> <span style="color: #0000ff">New</span>(clienteDal <span style="color: #0000ff">As</span> InterfacesyCapas.DAL.ClienteDAL)<br></pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 11px"> 6: _clienteDal = clienteDal<br></pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 11px"> 7: <span style="color: #0000ff">End</span> <span style="color: #0000ff">Sub</span><br></pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 11px"> 8: <br></pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 11px"> 9: <span style="color: #0000ff">Public</span> <span style="color: #0000ff">Function</span> GetClientePorIdCliente(<span style="color: #0000ff">ByVal</span> id <span style="color: #0000ff">As</span> <span style="color: #0000ff">String</span>) <span style="color: #0000ff">As</span> InterfacesyCapas.DAL.Clientes<br></pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 11px"> 10: <br></pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 11px"> 11: <span style="color: #0000ff">Return</span> _clienteDal.GetClientePorIdCliente(id)<br></pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 11px"> 12: <br></pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 11px"> 13: <span style="color: #0000ff">End</span> <span style="color: #0000ff">Function</span><br></pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 11px"> 14: <br></pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 11px"> 15: <span style="color: #0000ff">Public</span> <span style="color: #0000ff">Function</span> GetAll() <span style="color: #0000ff">As</span> IEnumerable(<span style="color: #0000ff">Of</span> InterfacesyCapas.DAL.Clientes)<br></pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 11px"> 16: <br></pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 11px"> 17: <span style="color: #0000ff">Return</span> _clienteDal.GetAll<br></pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 11px"> 18: <br></pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 11px"> 19: <span style="color: #0000ff">End</span> <span style="color: #0000ff">Function</span><br></pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 11px"> 20: <br></pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 11px"> 21: <span style="color: #0000ff">End</span> <span style="color: #0000ff">Class</span><br></pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 11px"> 22: </pre></pre><br><br /><p align="justify"><font size="3" face="Calibri">Modificamos también nuestra pequeña aplicación para que tenga en cuenta estos cambios</font>:</p><pre style="border-bottom: #cecece 1px solid; border-left: #cecece 1px solid; padding-bottom: 5px; background-color: #fbfbfb; min-height: 40px; padding-left: 5px; width: 500px; padding-right: 5px; overflow: auto; border-top: #cecece 1px solid; border-right: #cecece 1px solid; padding-top: 5px"><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 11px"> 1: <span style="color: #0000ff">Module</span> <span style="color: #0000ff">Module</span>1<br></pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 11px"> 2: <br></pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 11px"> 3: <span style="color: #0000ff">Sub</span> Main()<br></pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 11px"> 4: <br></pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 11px"> 5: <span style="color: #0000ff">Dim</span> clienteDAL <span style="color: #0000ff">As</span> <span style="color: #0000ff">New</span> InterfacesyCapas.DAL.ClienteDAL<br></pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 11px"> 6: <span style="color: #0000ff">Dim</span> clienteBLL <span style="color: #0000ff">As</span> <span style="color: #0000ff">New</span> InterfacesyCapas.BLL.ClienteBLL(clienteDAL)<br></pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 11px"> 7: <span style="color: #0000ff">For</span> <span style="color: #0000ff">Each</span> t <span style="color: #0000ff">In</span> clienteBLL.GetAll<br></pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 11px"> 8: Console.WriteLine("<span style="color: #8b0000">cliente {0} de nombre {1}</span>", t.IdCliente, t.Nombre)<br></pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 11px"> 9: <span style="color: #0000ff">Next</span><br></pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 11px"> 10: Console.ReadLine()<br></pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 11px"> 11: <br></pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 11px"> 12: <span style="color: #0000ff">End</span> <span style="color: #0000ff">Sub</span><br></pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 11px"> 13: <br></pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 11px"> 14: <span style="color: #0000ff">End</span> <span style="color: #0000ff">Module</span><br></pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 11px"> 15: </pre></pre><br><br /><p><font size="3" face="Calibri">Y si volvemos a ver las métricas de código, algo hemos conseguido!!</font></p><br><br /><p><a href="http://lh6.ggpht.com/-LzAjlkUhXw8/TlUcAZ-7GrI/AAAAAAAAAD4/3TcY0lqj-zE/s1600-h/SNAGHTML15d410c%25255B4%25255D.png"><img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="SNAGHTML15d410c" border="0" alt="SNAGHTML15d410c" src="http://lh4.ggpht.com/-vOY5W-E84kE/TlUcA47DvFI/AAAAAAAAAD8/XRGSZctm8xA/SNAGHTML15d410c_thumb%25255B1%25255D.png?imgmax=800" width="533" height="198"></a></p><br><br /><p align="justify"><font size="3" face="Calibri">Pero nuestro afán optimizador, no conoce límites.. y queremos el “más difícil todavía!”. La idea es que especifiquemos mediante una interfaz en la capa BLL, las operaciones que debe cumplir el objeto que pasamos a nuestro <em>ClienteBLL</em> para que todo funcione. Vamos a ir viéndolo en partes (Jack the Ripper, rule 1).</font></p><br><br /><p align="justify"><font size="3" face="Calibri">1. Creamos nuestra interfaz, en BLL, especificando las operaciones que las clases que deseen hablar con nuestra BLL deben cumplir</font>.</p><pre style="border-bottom: #cecece 1px solid; border-left: #cecece 1px solid; padding-bottom: 5px; background-color: #fbfbfb; min-height: 40px; padding-left: 5px; width: 600px; padding-right: 5px; overflow: auto; border-top: #cecece 1px solid; border-right: #cecece 1px solid; padding-top: 5px"><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 11px"> 1: <span style="color: #0000ff">Public</span> <span style="color: #0000ff">Interface</span> IClienteOperaciones<br></pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 11px"> 2: <br></pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 11px"> 3: <span style="color: #0000ff">Function</span> GetClientePorIdCliente(<span style="color: #0000ff">ByVal</span> id <span style="color: #0000ff">As</span> <span style="color: #0000ff">String</span>) <span style="color: #0000ff">As</span> InterfacesyCapas.Entidades.Clientes<br></pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 11px"> 4: <span style="color: #0000ff">Function</span> GetAll() <span style="color: #0000ff">As</span> IEnumerable(<span style="color: #0000ff">Of</span> InterfacesyCapas.Entidades.Clientes)<br></pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 11px"> 5: <br></pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 11px"> 6: <span style="color: #0000ff">End</span> <span style="color: #0000ff">Interface</span><br></pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 11px"> 7: </pre></pre><br><br /><p align="justify">2. <font size="3" face="Calibri">Cambiamos nuestra clase <em>ClienteBLL</em>, para que ahora en su constructor, reciba un objeto que implemente la interfaz que acabamos de definir</font>:</p><pre style="border-bottom: #cecece 1px solid; border-left: #cecece 1px solid; padding-bottom: 5px; background-color: #fbfbfb; min-height: 40px; padding-left: 5px; width: 600px; padding-right: 5px; overflow: auto; border-top: #cecece 1px solid; border-right: #cecece 1px solid; padding-top: 5px"><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 11px"> 1: <span style="color: #0000ff">Public</span> <span style="color: #0000ff">Class</span> ClienteBLL<br></pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 11px"> 2: <br></pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 11px"> 3: <span style="color: #0000ff">Dim</span> _clienteQueCumpleElContrato As IClienteOperaciones<br></pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 11px"> 4: <br></pre><pre style="background-color: #ffff00; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 11px"> 5: <span style="color: #0000ff">Public</span> <span style="color: #0000ff">Sub</span> New(ByVal cliente As IClienteOperaciones)<br></pre><pre style="background-color: #ffff00; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 11px"> 6: _clienteQueCumpleElContrato = cliente<br></pre><pre style="background-color: #ffff00; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 11px"> 7: <span style="color: #0000ff">End</span> <span style="color: #0000ff">Sub</span><br></pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 11px"> 8: <br></pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 11px"> 9: <span style="color: #0000ff">Public</span> <span style="color: #0000ff">Function</span> GetClientePorIdCliente(ByVal id As <span style="color: #0000ff">String</span>) As InterfacesyCapas.Entidades.Clientes<br></pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 11px"> 10: <br></pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 11px"> 11: Return _clienteQueCumpleElContrato.GetClientePorIdCliente(id)<br></pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 11px"> 12: <br></pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 11px"> 13: <span style="color: #0000ff">End</span> <span style="color: #0000ff">Function</span><br></pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 11px"> 14: <br></pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 11px"> 15: <span style="color: #0000ff">Public</span> <span style="color: #0000ff">Function</span> GetAll() As IEnumerable(Of InterfacesyCapas.Entidades.Clientes)<br></pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 11px"> 16: <br></pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 11px"> 17: Return _clienteQueCumpleElContrato.GetAll<br></pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 11px"> 18: <br></pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 11px"> 19: <span style="color: #0000ff">End</span> <span style="color: #0000ff">Function</span><br></pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 11px"> 20: <br></pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 11px"> 21: <span style="color: #0000ff">End</span> <span style="color: #0000ff">Class</span><br></pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 11px"> 22: </pre></pre><br><br /><p align="justify">3. <font size="3" face="Calibri">Quitamos la referencia a DAL que tenemos en BLL. Eso hará que el proyecto no nos compile, ya que BLL utiliza las entidades del modelo de Entity Framework que están en la capa DAL… ¿cual es la solución? pues sacar las entidades del modelo a otro ensamblado, que será compartido por DAL y BLL. El proceso es relativamente sencillo, y podéis verlo en este post, sobre </font><a href="http://geeks.ms/blogs/adiazmartin/archive/2010/05/11/entity-framework-self-tracking-paso-a-paso.aspx"><font size="3" face="Calibri">como generar entidades Self Tracking.</font></a></p><br><br /><p align="justify"><font size="3" face="Calibri">Una vez hecho esto (y después de renombrar, colocar correctamente las referencias nuevas y demás cosillas), ahora tenemos un nuevo ensamblado Entidades, y nuestro proyecto pinta así</font>:</p><br><br /><p><a href="http://lh5.ggpht.com/-13LVwVUpf2o/TlUcB8_Me6I/AAAAAAAAAEA/Q6SJXzZ9ueA/s1600-h/image%25255B18%25255D.png"><img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: block; float: none; border-top-width: 0px; border-bottom-width: 0px; margin-left: auto; border-left-width: 0px; margin-right: auto; padding-top: 0px" title="image" border="0" alt="image" src="http://lh3.ggpht.com/-T6QMXjzo5Eo/TlUcDVKIpQI/AAAAAAAAAEE/0dhkEXdIcSQ/image_thumb%25255B7%25255D.png?imgmax=800" width="251" height="329"></a></p><br><br /><p align="justify">4<font size="3" face="Calibri">. Ahora es cuando viene lo bueno. Como hemos quitado la referencia a DAL desde BLL, lo que tenemos que hacer es que DAL referencie a BLL, y la clase <em>ClienteDAL</em> implemente la interfaz <em>IClienteOperaciones</em>.</font></p><br><br /><p align="justify"><font size="3" face="Calibri">Si recordamos, la interfaz <em>IClienteOperaciones</em> estipulada como el contrato que debe cumplir cualquier clase que desee interactuar con <em>ClienteBLL</em>. Aunque de manera muy básica (no conozco aún los entresijos de la técnica) digamos que es una forma primitiva de utilizar la </font><a href="http://es.wikipedia.org/wiki/Inyecci%C3%B3n_de_Dependencias"><font size="3" face="Calibri">inyección de dependencias</font></a><font face="Calibri"><font size="3">. Veamos la implementación de la interfaz en <em>ClienteDAL</em></font></font>:</p><pre style="border-bottom: #cecece 1px solid; border-left: #cecece 1px solid; padding-bottom: 5px; background-color: #fbfbfb; min-height: 40px; padding-left: 5px; width: 600px; padding-right: 5px; overflow: auto; border-top: #cecece 1px solid; border-right: #cecece 1px solid; padding-top: 5px"><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 11px"> 1: <span style="color: #0000ff">Public</span> <span style="color: #0000ff">Class</span> ClienteDAL<br></pre><pre style="background-color: #ffff00; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 11px"> 2: Implements InterfacesyCapas.BLL.IClienteOperaciones<br></pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 11px"> 3: <br></pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 11px"> 4: <span style="color: #0000ff">Dim</span> _context As New DataContext<br></pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 11px"> 5: <br></pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 11px"> 6: <span style="color: #0000ff">Public</span> <span style="color: #0000ff">Function</span> GetClientePorIdCliente(ByVal id As <span style="color: #0000ff">String</span>) As InterfacesyCapas.Entidades.Clientes Implements BLL.IClienteOperaciones.GetClientePorIdCliente<br></pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 11px"> 7: <br></pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 11px"> 8: Return (From c <span style="color: #0000ff">In</span> _context.Clientes()<br></pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 11px"> 9: Where c.IdCliente = id).SingleOrDefault()<br></pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 11px"> 10: <br></pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 11px"> 11: <span style="color: #0000ff">End</span> <span style="color: #0000ff">Function</span><br></pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 11px"> 12: <br></pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 11px"> 13: <span style="color: #0000ff">Public</span> <span style="color: #0000ff">Function</span> GetAll() As IEnumerable(Of InterfacesyCapas.Entidades.Clientes) Implements BLL.IClienteOperaciones.GetAll<br></pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 11px"> 14: <br></pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 11px"> 15: Return (From c <span style="color: #0000ff">In</span> _context.Clientes()).AsEnumerable()<br></pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 11px"> 16: <br></pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 11px"> 17: <span style="color: #0000ff">End</span> <span style="color: #0000ff">Function</span><br></pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 11px"> 18: <br></pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 11px"> 19: <span style="color: #0000ff">End</span> <span style="color: #0000ff">Class</span><br></pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 11px"> 20: </pre></pre><br><br /><p align="justify"><font size="3" face="Calibri">Perfecto! Si ahora probamos nuestro proyecto, todo vuelve a funcionar, y si revisamos las métricas de código ¿qué obtendremos ahora?</font></p><br><br /><p><a href="http://lh4.ggpht.com/-4WZQsc6p4fM/TlUcD_rnLwI/AAAAAAAAAEI/hbOhCOBC1a8/s1600-h/SNAGHTML190cd35%25255B5%25255D.png"><img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: block; float: none; border-top-width: 0px; border-bottom-width: 0px; margin-left: auto; border-left-width: 0px; margin-right: auto; padding-top: 0px" title="SNAGHTML190cd35" border="0" alt="SNAGHTML190cd35" src="http://lh4.ggpht.com/-mCa_Xrzc7LI/TlUcEcZF2DI/AAAAAAAAAEM/ORp4C0RIoEk/SNAGHTML190cd35_thumb%25255B2%25255D.png?imgmax=800" width="586" height="218"></a></p><br><br /><p align="justify"><font size="3" face="Calibri">Pues parece ser que nuestro índice de acoplamiento de clases no ha bajado… pero sin embargo, el índice de mantenimiento ha subido notablemente. Pensemos en que hemos eliminado la referencia a DAL, pero que sin embargo hemos incluido una referencia a Entidades, con lo que nos hemos quedado casi igual… pero con un índice de mantenimiento mucho más interesante.</font></p><br><br /><p align="justify"><font size="3" face="Calibri">Entonces, que ¿beneficios podemos obtener con esta técnica? hemos hablado de que evidentemente al basar las interacciones entre capas en contratos, promovemos su aislamiento, así como el testeo de las capas. ¿Es esto cierto? vamos a ver un pequeño ejemplo (me estoy emocionando y extendiéndome más de la cuenta, creo yo… animo!).</font></p><br><br /><p align="justify"><font size="3" face="Calibri">Vamos a crear en Dal una clase <em>ClienteDALFake</em> que igualmente implemente la interfaz <em>IClienteOperaciones</em>, pero que no consulte la base de datos, sino que nos retorne objetos creados “ad hoc”. Vamos a ver si somos capaces</font>:</p><pre style="border-bottom: #cecece 1px solid; border-left: #cecece 1px solid; padding-bottom: 5px; background-color: #fbfbfb; min-height: 40px; padding-left: 5px; width: 600px; padding-right: 5px; overflow: auto; border-top: #cecece 1px solid; border-right: #cecece 1px solid; padding-top: 5px"><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 11px"> 1: <span style="color: #0000ff">Public</span> <span style="color: #0000ff">Class</span> ClienteDALFake<br></pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 11px"> 2: Implements InterfacesyCapas.BLL.IClienteOperaciones<br></pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 11px"> 3: <br></pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 11px"> 4: <span style="color: #0000ff">Dim</span> _context As New DataContext<br></pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 11px"> 5: <br></pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 11px"> 6: <span style="color: #0000ff">Public</span> <span style="color: #0000ff">Function</span> GetClientePorIdCliente(ByVal id As <span style="color: #0000ff">String</span>) As InterfacesyCapas.Entidades.Clientes Implements BLL.IClienteOperaciones.GetClientePorIdCliente<br></pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 11px"> 7: <br></pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 11px"> 8: <span style="color: #0000ff">Dim</span> cliente As New InterfacesyCapas.Entidades.Clientes()<br></pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 11px"> 9: cliente.IdCliente = "<span style="color: #8b0000">99</span>"<br></pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 11px"> 10: cliente.Nombre = "<span style="color: #8b0000">Cliente FAKE encontrado</span>"<br></pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 11px"> 11: Return cliente<br></pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 11px"> 12: <br></pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 11px"> 13: <span style="color: #0000ff">End</span> <span style="color: #0000ff">Function</span><br></pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 11px"> 14: <br></pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 11px"> 15: <span style="color: #0000ff">Public</span> <span style="color: #0000ff">Function</span> GetAll() As IEnumerable(Of InterfacesyCapas.Entidades.Clientes) Implements BLL.IClienteOperaciones.GetAll<br></pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 11px"> 16: <br></pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 11px"> 17: <span style="color: #0000ff">Dim</span> k As New List(Of InterfacesyCapas.Entidades.Clientes)<br></pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 11px"> 18: <br></pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 11px"> 19: <span style="color: #0000ff">Dim</span> clienteFake1 As New InterfacesyCapas.Entidades.Clientes<br></pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 11px"> 20: clienteFake1.IdCliente = "<span style="color: #8b0000">F1</span>"<br></pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 11px"> 21: clienteFake1.Nombre = "<span style="color: #8b0000">Cliente Fake 1</span>"<br></pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 11px"> 22: k.<span style="color: #0000ff">Add</span>(clienteFake1)<br></pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 11px"> 23: <br></pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 11px"> 24: <span style="color: #0000ff">Dim</span> clienteFake2 As New InterfacesyCapas.Entidades.Clientes<br></pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 11px"> 25: clienteFake2.IdCliente = "<span style="color: #8b0000">F2</span>"<br></pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 11px"> 26: clienteFake2.Nombre = "<span style="color: #8b0000">Cliente Fake 2</span>"<br></pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 11px"> 27: k.<span style="color: #0000ff">Add</span>(clienteFake2)<br></pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 11px"> 28: <br></pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 11px"> 29: <span style="color: #0000ff">Dim</span> clienteFake3 As New InterfacesyCapas.Entidades.Clientes<br></pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 11px"> 30: clienteFake3.IdCliente = "<span style="color: #8b0000">F3</span>"<br></pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 11px"> 31: clienteFake3.Nombre = "<span style="color: #8b0000">Cliente Fake 3</span>"<br></pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 11px"> 32: k.<span style="color: #0000ff">Add</span>(clienteFake3)<br></pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 11px"> 33: <br></pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 11px"> 34: <span style="color: #0000ff">Dim</span> clienteFake4 As New InterfacesyCapas.Entidades.Clientes<br></pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 11px"> 35: clienteFake4.IdCliente = "<span style="color: #8b0000">F4</span>"<br></pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 11px"> 36: clienteFake4.Nombre = "<span style="color: #8b0000">Cliente Fake 4</span>"<br></pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 11px"> 37: k.<span style="color: #0000ff">Add</span>(clienteFake4)<br></pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 11px"> 38: <br></pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 11px"> 39: Return k.AsEnumerable<br></pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 11px"> 40: <br></pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 11px"> 41: <span style="color: #0000ff">End</span> <span style="color: #0000ff">Function</span><br></pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 11px"> 42: <br></pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 11px"> 43: <span style="color: #0000ff">End</span> <span style="color: #0000ff">Class</span><br></pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 11px"> 44: </pre></pre><br><br /><p align="justify"><font size="3" face="Calibri">Amiguitos programadores, parece que lo hemos conseguido.</font></p><br><br /><p align="justify"><font size="3" face="Calibri">Ahora, vamos a retocar nuestra aplicación cliente, implementando una clase <em>ClientesFactoria</em>, que nos retornara o el cliente bueno, o el cliente Fake, dependiendo de si estamos en Tests o no (por ejemplo</font>):</p><pre style="border-bottom: #cecece 1px solid; border-left: #cecece 1px solid; padding-bottom: 5px; background-color: #fbfbfb; min-height: 40px; padding-left: 5px; width: 600px; padding-right: 5px; overflow: auto; border-top: #cecece 1px solid; border-right: #cecece 1px solid; padding-top: 5px"><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 11px"> 1: <span style="color: #0000ff">Public</span> <span style="color: #0000ff">Class</span> ClientesFactoria<br></pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 11px"> 2: <br></pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 11px"> 3: <span style="color: #0000ff">Public</span> <span style="color: #0000ff">Function</span> GetCliente(testing As Boolean) As BLL.IClienteOperaciones<br></pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 11px"> 4: <br></pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 11px"> 5: <span style="color: #0000ff">If</span> <span style="color: #0000ff">Not</span> testing <span style="color: #0000ff">Then</span><br></pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 11px"> 6: Return New InterfacesyCapas.DAL.ClienteDAL<br></pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 11px"> 7: <span style="color: #0000ff">Else</span><br></pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 11px"> 8: Return New InterfacesyCapas.DAL.ClienteDALFake<br></pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 11px"> 9: <span style="color: #0000ff">End</span> <span style="color: #0000ff">If</span><br></pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 11px"> 10: <br></pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 11px"> 11: <span style="color: #0000ff">End</span> <span style="color: #0000ff">Function</span><br></pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 11px"> 12: <br></pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 11px"> 13: <span style="color: #0000ff">End</span> <span style="color: #0000ff">Class</span><br></pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 11px"> 14: </pre></pre><br><br /><p align="justify"><font size="3" face="Calibri">Lo más interesante de esta clase, es que es una implementación del patrón Factoria (a mi manera y para este ejemplo, ojo), y que retorna objetos que implementan la interfaz <em>IClienteOperaciones</em>. Esto permite que si mañana tenemos cualquier otra implementación a incluir, podamos hacerlo sin demasiados problemas. Además, en el ejemplo que nos ocupa nos permite pasar del “Entorno real” al “Entorno de test” de una manera simplísima! Veamos la aplicación cliente:</font></p><pre style="border-bottom: #cecece 1px solid; border-left: #cecece 1px solid; padding-bottom: 5px; background-color: #fbfbfb; min-height: 40px; padding-left: 5px; width: 600px; padding-right: 5px; overflow: auto; border-top: #cecece 1px solid; border-right: #cecece 1px solid; padding-top: 5px"><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 11px"> 1: <span style="color: #0000ff">Sub</span> Main()<br></pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 11px"> 2: <br></pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 11px"> 3: <span style="color: #0000ff">Dim</span> estamosEnTest As Boolean = False<br></pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 11px"> 4: <br></pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 11px"> 5: <span style="color: #0000ff">Dim</span> clientesFactoria As New ClientesFactoria<br></pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 11px"> 6: <span style="color: #0000ff">Dim</span> clienteBLL As New InterfacesyCapas.BLL.ClienteBLL(clientesFactoria.GetCliente(estamosEnTest))<br></pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 11px"> 7: <span style="color: #0000ff">For</span> <span style="color: #0000ff">Each</span> t <span style="color: #0000ff">In</span> clienteBLL.GetAll<br></pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 11px"> 8: Console.WriteLine("<span style="color: #8b0000">cliente {0} de nombre {1}</span>", t.IdCliente, t.Nombre)<br></pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 11px"> 9: <span style="color: #0000ff">Next</span><br></pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 11px"> 10: <br></pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 11px"> 11: Console.ReadLine()<br></pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 11px"> 12: <br></pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 11px"> 13: <span style="color: #0000ff">End</span> <span style="color: #0000ff">Sub</span><br></pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 11px"> 14: </pre></pre><br><br /><p align="justify"><font size="3" face="Calibri">Y estos son los distintos resultados que obtenemos, cuando cambiamos nuestra variable </font><em><font size="3" face="Calibri">estamosEnTest</font>:</em></p><br><br /><p><a href="http://lh5.ggpht.com/-e2gBYSwMNZg/TlUcFG8T4kI/AAAAAAAAAEQ/GbnhDdk3s2M/s1600-h/SNAGHTML1aacbee%25255B4%25255D.png"><img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="SNAGHTML1aacbee" border="0" alt="SNAGHTML1aacbee" src="http://lh6.ggpht.com/-llqSfmpKgYY/TlUcF5AVb8I/AAAAAAAAAEU/YkV5wxy7B-A/SNAGHTML1aacbee_thumb%25255B1%25255D.png?imgmax=800" width="628" height="264"></a></p><br><br /><p align="justify"><font size="3" face="Calibri">Objetivo conseguido!!!</font></p><br><br /><p align="justify"><font size="3" face="Calibri">Como reflexión final, comentaros que este ejemplo es sólo una manera de presentar conceptos que a mi modo de ver no son precisamente sencillos (Inyección de dependencias, Inversión de Control, desacoplamiento, pruebas, DDD) pero que sin ninguna duda nos ayudarán a realizar software de mayor calidad. Como desarrolladores, creo que tenemos la obligación de estar al día en las tecnologías que van apareciendo (aunque “aparecer” signifique que ahora se ponen “de moda” en el mundo Microsoft, por ejemplo MVC) y evaluar seriamente las posibilidades que los nuevos lenguajes y Frameworks nos ofrecen.</font></p><br><br /><p align="justify"><font size="3" face="Calibri">Si habéis llegado hasta aquí, enhorabuena! os he soltado un rollo muy serio. Espero que al menos, vuestra perspectiva en el uso de Interfaces y otras técnicas haya comenzado a bullir en vuestra cabeza. En la mía lleva una temporada dando vueltas hasta hoy, que ha salido.</font></p><br><br /><p align="justify"><font size="3" face="Calibri">Podéis descargaros el </font><a href="https://skydrive.live.com/redir.aspx?cid=31ff6d110838625b&resid=31FF6D110838625B!683&authkey=sGg!8ivcn74%24"><font size="3" face="Calibri">código aqui</font></a></p><br><br /><p align="justify"><font size="3" face="Calibri">Un saludo y gracias!</font></p> Antoniohttp://www.blogger.com/profile/07910602532207054705noreply@blogger.com3tag:blogger.com,1999:blog-5730880038726783282.post-57149612284173642052011-05-20T01:32:00.000+02:002012-10-19T20:52:03.902+02:00Configuración de VS2010 para trabajar con Azure mediante entorno simulado.<p style="font-family: arial">Hola!</p><span style="font-family: arial"></span> <p style="font-family: arial">Este es mi primer post, y he decidido escribir sobre algo con lo que estamos ahora mismo trabajando/investigando: Windows Azure.</p> <p style="font-family: arial">¿y qué es eso? pues copieteando a la wikipedia: “Windows Azure Platform de Microsoft es una plataforma de servicios que ofrece computación en nube, entró en producción el 1 de enero de 2010. "Ofrece una amplia gama de servicios de internet que se pueden consumir tanto desde entornos locales o en entornos de internet" (aunque la plataforma en sí no está disponible para implementar en los entornos locales). Es significativo que es el primer paso de Microsoft en la computación en nube después del lanzamiento de Microsoft Online Services.”</p> <p style="font-family: arial">Vamos, a mi modo de ver, un megahosting de Microsoft, perfectamente integrado con todas sus herramientas de desarrollo y que nos permite desplegar aplicaciones en la nube de una manera muy rápida y aparentemente, sencilla… Pero claro, primero tendremos que configurar nuestro entorno de trabajo ¿no?. </p> <p style="font-family: arial">Microsoft nos da (que buenos son) la posibilidad de montar un entorno de simulación localmente, gracias a las herramientas de desarrollo de Azure y a su SDK. vamos a ver como montarlo y tener configuradito nuestro querido VS2010.</p> <a name='more'></a> <p style="font-family: arial">Vayamos por partes, como dijo no se quien:</p> <ul style="font-family: arial"> <li>Descarga e instalación de herramientas y SDK de Azure para VS 2010. (<a href="http://www.microsoft.com/windowsazure/">http://www.microsoft.com/windowsazure/</a>). Estas herramientas también se pueden descargar directamente desde el IDE de VS 2010. <li>Si es necesario, instalar los HotFix que Microsoft recomienda. <li>Instalación de SQL Express 2008 en la máquina de desarrollo. Es necesario para que Azure simule su almacenamiento Blob, Queue y Table. </li></ul> <p style="font-family: arial">Para comprobar que el entorno de desarrollo y la simulación local de Azure funcionan correctamente, realizaremos los siguientes pasos: </p> <p style="font-family: arial">Ejecutaremos el entorno de desarrollo como administrador: </p> <p style="font-family: arial"><a href="http://lh4.ggpht.com/_A15iCmadShQ/TKMx2mOq_II/AAAAAAAAABk/wrC7GkcNAAs/s1600-h/image%5B21%5D.png"><img style="border-right-width: 0px; display: block; float: none; border-top-width: 0px; border-bottom-width: 0px; margin-left: auto; border-left-width: 0px; margin-right: auto" title="image" border="0" alt="image" src="http://lh6.ggpht.com/_A15iCmadShQ/TKMx3-c73vI/AAAAAAAAABo/lccwaF1eixo/image_thumb%5B13%5D.png?imgmax=800" width="294" height="384"></a> </p> <p style="font-family: arial">Crearemos un proyecto de prueba desde VS 2010. El tipo de proyecto Windows Azure Cloud Service estará disponible después de instalar las herramientas de desarrollo y el SDK. </p> <p style="font-family: arial"></p> <p style="font-family: arial"><a href="http://lh3.ggpht.com/_A15iCmadShQ/TKMx4a2KfMI/AAAAAAAAABs/TW3SVCADK7I/s1600-h/image%5B16%5D.png"><img style="border-right-width: 0px; display: block; float: none; border-top-width: 0px; border-bottom-width: 0px; margin-left: auto; border-left-width: 0px; margin-right: auto" title="image" border="0" alt="image" src="http://lh6.ggpht.com/_A15iCmadShQ/TKMx5dLB4wI/AAAAAAAAABw/9OkJvlqI_Qc/image_thumb%5B10%5D.png?imgmax=800" width="545" height="378"></a> </p> <p style="font-family: arial">Añadiremos al proyecto un WebRole de VB o C#. </p> <p style="font-family: arial"></p> <p style="font-family: arial"><a href="http://lh3.ggpht.com/_A15iCmadShQ/TKMx6D_3eHI/AAAAAAAAAB0/xLAiJvFt8YQ/s1600-h/image%5B11%5D.png"><img style="border-right-width: 0px; display: block; float: none; border-top-width: 0px; border-bottom-width: 0px; margin-left: auto; border-left-width: 0px; margin-right: auto" title="image" border="0" alt="image" src="http://lh6.ggpht.com/_A15iCmadShQ/TKMx6xBD0nI/AAAAAAAAAB4/0YNJqZxLmY8/image_thumb%5B7%5D.png?imgmax=800" width="455" height="286"></a> </p> <p style="font-family: arial">Una vez hecho esto, tendremos (o deberíamos tener) los siguientes elementos en nuestra nueva solución </p> <p style="font-family: arial"></p> <p style="font-family: arial"><a href="http://lh3.ggpht.com/_A15iCmadShQ/TKMx7qb98lI/AAAAAAAAAB8/PacXwZA29go/s1600-h/image%5B6%5D.png"><img style="border-right-width: 0px; display: block; float: none; border-top-width: 0px; border-bottom-width: 0px; margin-left: auto; border-left-width: 0px; margin-right: auto" title="image" border="0" alt="image" src="http://lh6.ggpht.com/_A15iCmadShQ/TKMx8fjBa2I/AAAAAAAAACA/HiPfrFW0lL4/image_thumb%5B4%5D.png?imgmax=800" width="376" height="446"></a> </p> <p style="font-family: arial">A continuación podemos ejecutar el proyecto. El entorno de simulación de Azure se inicializará y tendremos en nuestra área de notificaciones un icono que nos permite comprobar el estado de los componentes de dicho entorno de simulación. </p> <p style="font-family: arial"><a href="http://lh4.ggpht.com/_A15iCmadShQ/TKMx85YFNRI/AAAAAAAAACE/Sh_tWYXkE1k/s1600-h/image%5B25%5D.png"><img style="border-right-width: 0px; display: block; float: none; border-top-width: 0px; border-bottom-width: 0px; margin-left: auto; border-left-width: 0px; margin-right: auto" title="image" border="0" alt="image" src="http://lh4.ggpht.com/_A15iCmadShQ/TKMx9W8vyYI/AAAAAAAAACI/nBOY3VW8We4/image_thumb%5B15%5D.png?imgmax=800" width="340" height="164"></a> </p> <p style="font-family: arial">¡Nuestro entorno está correctamente configurado! </p> <p style="font-family: arial">En lo siguientes post (si el tiempo, las ganas y demás factores alienantes me lo permiten), ampliaré conceptos sobre Azure y la manera de trabajar con él. De momento, palabras como Blob, Qeue, Table y otros conceptos “azurescos” los dejaremos para otro día.<br><br>Life is code!!</p> Antoniohttp://www.blogger.com/profile/07910602532207054705noreply@blogger.com0