tag:blogger.com,1999:blog-81137237080129517382024-02-19T06:04:40.703-04:00Tales of Agile AdoptionThis is a space for us to post and discuss common pitfalls, problems and stories about Agile methodologies implementation and adoption.
Yes we also will write about solutions, recommendations and more...Anonymoushttp://www.blogger.com/profile/12292838726080618300noreply@blogger.comBlogger50125tag:blogger.com,1999:blog-8113723708012951738.post-28031054819621470172018-05-25T06:38:00.001-04:002018-05-25T06:38:19.873-04:00"Tirar Código"<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEizHgqkV9LIDKdPGpjAjM1OKKA7GAGOaWIVY5YheEYHOmLLDe-s4t8KwA6i3EOYYsmdodxJF6-lz-uXqZugRv1_6vYSJqLoyO5JglcA2lgm-3x4OIJPFHfcpx1hkvcEItbSmUAtAdiIIUs/s1600/Tirar_Codigo_02.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="187" data-original-width="822" height="145" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEizHgqkV9LIDKdPGpjAjM1OKKA7GAGOaWIVY5YheEYHOmLLDe-s4t8KwA6i3EOYYsmdodxJF6-lz-uXqZugRv1_6vYSJqLoyO5JglcA2lgm-3x4OIJPFHfcpx1hkvcEItbSmUAtAdiIIUs/s640/Tirar_Codigo_02.png" width="640" /></a></div>
<span style="font-size: large;"><br /></span>
<span style="font-size: large;">Entre los años 1999 y 2000 me inicie en el mundo del desarrollo de software. Desde esos años vengo escuchando la frase “tirar código”. La misma hace referencia al acto de escribir código fuente o “programar”. No tengo claro de dónde viene la frase, ya que en el idioma Ingles (lingua franca de la Ingeniería de Software), se utilizan las frases <b>“to code”, “to write code”</b>, las cuales podrían traducirse como “codificar” (programar) y “escribir código”. </span><br />
<span style="font-size: large;"><br /></span>
<span style="font-size: large;">“Tirar código” es una frase común entre profesionales de distintas edades, se la he escuchado a personas nacidas en los 60 y llegando hasta el 2000. Un día, reflexionando sobre temas de calidad del software y mejores prácticas, me llego a la mente la frase y de pronto sonó inapropiada. En la República Dominicana cuando algo o alguien es “tirado” (adjetivo) tiene una connotación negativa: descuidado. “Pedro trabaja todo tirado”, o su versión más coloquial “Pedro trabaja to’ tira’o”, significa “Pedro es poco profesional o descuidado, no pone atención en los detalles”. </span><br />
<span style="font-size: large;"><br /></span>
<span style="font-size: large;">Anoche mientras le hacia la observación, repetida en muchos círculos, a un grupo de estudiantes universitarios de que cambien la frase “tirar código” por “escribir código”; me puse a pensar sobre cuales podrían ser los orígenes de la frase. Realmente me da mucha curiosidad el saber </span><br />
<span style="font-size: large;"><br /></span>
<b><i><span style="font-size: large;">¿Cómo pasamos de “to code / to write code” a “tirar código”?</span></i></b><br />
<span style="font-size: large;"><br /></span>
<span style="font-size: large;">Si alguien tiene, o cree tener, la respuesta o una idea favor escribir en los comentarios.</span>Anonymoushttp://www.blogger.com/profile/12292838726080618300noreply@blogger.com0tag:blogger.com,1999:blog-8113723708012951738.post-7245053502574565772017-10-29T12:16:00.001-04:002017-10-29T12:16:25.436-04:00Software: How do you know when it is Green, Ripe, or Rotten?<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgv-Z-wyIPcR9AlzVvzXupOdePCa9LXmmBiNPAtSM7jp2V6K9jgn0dMLjmo0irEe4p7fg4skL7TUzhSaX0UTGhJyR0lAwJ3YKg1T8vpsugg0SqvJwwQAGIGOsAf9Cqdq2UKUekzlZkTXp8/s1600/farmers-market-fruit-stand.jpg" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img alt="Farmers Market Fruit Stand, public domain image" border="0" data-original-height="1200" data-original-width="1600" height="480" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgv-Z-wyIPcR9AlzVvzXupOdePCa9LXmmBiNPAtSM7jp2V6K9jgn0dMLjmo0irEe4p7fg4skL7TUzhSaX0UTGhJyR0lAwJ3YKg1T8vpsugg0SqvJwwQAGIGOsAf9Cqdq2UKUekzlZkTXp8/s640/farmers-market-fruit-stand.jpg" title="Farmers Market Fruit Stand, public domain image" width="640" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">Farmers Market Fruit Stand, public domain image @ http://www.publicdomainpictures.net/view-image.php?image=149772&picture=farmers-market-fruit-stand<br />
<br />
<h2 style="text-align: left;">
<span style="font-size: x-large;">How to buy fruits?</span></h2>
<div style="text-align: left;">
<div>
<span style="font-family: inherit; font-size: large;">When I was a child, I spent a lot of time with my grandmother. She was raised in a remote agriculture community of my country. So she was very experienced with agriculture products. I love fruit juices and she love to consent all her grandchildren. One of the earlier lessons that I learned was how to pick a good, ready to eat, fruit. There were “easy” ones, like mangoes. Even a child can tell when a mango is not ready to eat yet, ripe, or overripe. But I also face more difficult challenges like melons and passion fruits. </span></div>
<div>
<span style="font-size: large;"><br /></span></div>
<div>
<span style="font-size: large;">Those two have a similar little trick, as my grandmother teach me. You have to evaluate the outer layer, or skin, and look for overripe signs. If the outer layer was looks ripe, but firm, then you have to evaluate the inside of the fruit, without open it. Here comes the trick: you must shake the fruit near one of your ears and try to “listen” for the seeds to bounce and hit the inner cavity. If you feel or hear the seeds bouncing then there are good chances that the fruit was ready to eat.</span></div>
<div>
<span style="font-size: large;"><br /></span></div>
<div>
<span style="font-size: large;">You must have similar stories with culture and region specifics variations. There are other kind of “passed-on” skills like how to buy the best used car with a limited budget.</span></div>
<div>
<span style="font-size: large;"><br /></span></div>
<div>
<span style="font-size: large;">Now you could be a ground-up woman or man. You may be a c-level executive, a manager or any organizational role facing the decision of buy software products and / or services. And here comes the question: <b><i>Do you know how to buy a software that is just “ready to eat”?</i></b></span></div>
</div>
<div style="text-align: left;">
<br /></div>
<h2 style="text-align: left;">
<span style="font-size: x-large;">How to buy software?</span></h2>
<div style="text-align: left;">
<div>
<span style="font-size: large;">Unfortunately, our elders did not taught us how to buy a good piece of software: a “healthy” one. Now we are facing that problem, and each day it becomes bigger and bigger. The average executive does not know how to evaluate the quality attributes of a software product. The more versed ones only know how to ask for aesthetics (visual), usability (easy to use, responsiveness, etc.), and functional quality. So they know how to assess if a software is “easy to use”, “looks pretty” (as of the industry and user-base standards), and if presents the functional characteristics they need (modules, features, etc.).</span></div>
<div>
<span style="font-size: large;"><br /></span></div>
<div>
<span style="font-size: large;">But there are other quality characteristics of a software products less obvious to the end user. To keep this discussion out of the technical (software engineering) jargon, just imagine (as with the fruits), that software products have an “inside” meat, that needs to be assessed as well. This quality characteristics of the “inside” parts of the software are called <b><i>Structural Quality Characteristics.</i></b> </span></div>
<div>
<span style="font-size: large;"><br /></span></div>
<div>
<span style="font-size: large;">So, if you are not versed on how to evaluate the “insides” (structural quality) of a software product, do not worry. There are quantitative evaluations and even standards that can throw light into this matter. The last question will be: How to connect all this with my reality?</span></div>
</div>
<div style="text-align: left;">
<br /></div>
<h2 style="text-align: left;">
<span style="font-size: x-large;">What to do?</span></h2>
<div style="text-align: left;">
<div>
<span style="font-size: large;">Let's say that you are a COO (Chief Operations Officers), or a CFO (Chief Financial Officers); and you are involved in a big project requiring the purchase of a very expensive software product. If you are not in a very specialized industry, there will be lots, or at least two, options. So you need to select the “mature” (not the green, or rotten) one. And remember that “mature” means “good in the outside and in the inside”. Here you need to ask for the experts.</span></div>
<div>
<span style="font-size: large;"><br /></span></div>
<div>
<span style="font-size: large;"><b><i>Your due diligence should be</i></b> to demand that your IT staff, external organization, or an individual consultant bring together an assessment process that translate all this stuff into a simple, quantitative, decision matrix.</span></div>
</div>
</td></tr>
</tbody></table>
Anonymoushttp://www.blogger.com/profile/12292838726080618300noreply@blogger.com0tag:blogger.com,1999:blog-8113723708012951738.post-47027400799724906692017-08-21T22:33:00.000-04:002017-08-21T22:33:04.690-04:00¿Por qué los equipos de Scrum tienen un tamaño limitado?<div style="text-align: justify;">
Visto desde distintos ángulos podemos ver diferentes explicaciones para la recomendación. Primero vemos cual es la recomendación (tomada de The Scrum Guide v2016, p6. Development Team Size):</div>
<b><i>El espíritu de la “regla”</i></b><br />
<blockquote class="tr_bq">
"Optimal Development Team size is small enough to remain nimble and large enough to complete significant work within a Sprint."</blockquote>
<br />
<b><i>El límite inferior: 3</i></b><br />
<blockquote class="tr_bq">
"Fewer than three Development Team members decrease interaction and results in smaller productivity gains."</blockquote>
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg4pBZNCPCKi2OviRc1kpmYEhWAodFQhKwZ_Pl-9uv_4HjE97dZqyhXoIDm_4_rXLfvIMz2c_qOtrQs87px61fbKDSKSGvGvw7O_U_wjTfSmNNoVkF7SZ0-Qt8apN5N45Ld9QETJB0i56A/s1600/Min_Team_Size.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" data-original-height="700" data-original-width="1412" height="197" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg4pBZNCPCKi2OviRc1kpmYEhWAodFQhKwZ_Pl-9uv_4HjE97dZqyhXoIDm_4_rXLfvIMz2c_qOtrQs87px61fbKDSKSGvGvw7O_U_wjTfSmNNoVkF7SZ0-Qt8apN5N45Ld9QETJB0i56A/s400/Min_Team_Size.png" width="400" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;"><i>Tamaño mínimo de un equipo de Scrum</i></td></tr>
</tbody></table>
<br />
<b><i>El límite superior: 9</i></b><br />
<blockquote class="tr_bq">
“Having more than nine members requires too much coordination.”</blockquote>
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgWs3ajvE_Bg5CgVXEJ47iIetivu2TbXmD_AytzKZqfO-e2m2jwlNY0uGkBR1ZbER3Oz5zB39TLbOE5py-ODXJWxGQZgNr5-z0q5gEEdZTpaE3sHdzua1if6K4OUXVTcF20xq8VIi7Ht0A/s1600/Max_Team_Size.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" data-original-height="707" data-original-width="1439" height="196" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgWs3ajvE_Bg5CgVXEJ47iIetivu2TbXmD_AytzKZqfO-e2m2jwlNY0uGkBR1ZbER3Oz5zB39TLbOE5py-ODXJWxGQZgNr5-z0q5gEEdZTpaE3sHdzua1if6K4OUXVTcF20xq8VIi7Ht0A/s400/Max_Team_Size.png" width="400" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;"><i>Tamaño máximo de un equipo de Scrum</i></td></tr>
</tbody></table>
<br />
<b><i>Integrantes: solo los ejecutores</i></b><br />
<blockquote class="tr_bq">
"The Product Owner and Scrum Master roles are not included in this count unless they are also executing the work of the Sprint Backlog." </blockquote>
<br />
<div style="text-align: justify;">
Así que, tendremos equipos con un mínimo de cinco (5) integrantes y un máximo de once (11). Debemos recordar que el equipo de Scrum se compone del Equipo de Desarrollo, el Scrum Master y el Product Owner. En este cálculo asumimos que el Scrum Master y el Product Owner no son ejecutores (no toman trabajo dentro del sprint backlog).</div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
En este artículo nos enfocaremos en el tema de los canales de comunicación. Para saber cuántos canales de comunicación tendremos en un equipo se utiliza la formula CM = ( n * (n - 1) ) / 2, donde n es la cantidad de integrantes del equipo. Volviendo a nuestros límites tenemos que:</div>
<div style="text-align: justify;">
</div>
<ul>
<li>Inferior <span style="font-family: Courier New, Courier, monospace;">n=5: CM = <b>10</b> dado por (5 * 4 ) / 2</span></li>
<li>Superior <span style="font-family: Courier New, Courier, monospace;">n=11: CM = <b>55</b> dado por (11 * 10) / 2</span></li>
</ul>
<br />
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
Es decir, que en un equipo de Scrum pudiéramos tener que manejar entre 10 y 55 canales de comunicación a lo interno del equipo. A esto súmele la interacción con entes externos. Recordemos también que se recomienda que el área principal de trabajo para un equipo de Scrum sea un espacio compartido por todos los miembros (colocación), esto entre otras cosas para aumentar la comunicación osmótica. En otras palabras, se busca que la comunicación sea abierta y que permee, y haya un máximo grado de sincronización entre los miembros. </div>
<br />
<div style="text-align: justify;">
Se busca que los miembros escuchen la mayor cantidad de información posible, aun esta no esté dirigida directamente a ellos. Dependiendo de la cultura del equipo esto puede suponer un alto grado de interrupciones a las labores individuales de cada miembro ya que fácilmente se puede romper su concentración cuando necesitan concentrarse en alguna tarea. </div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
La cantidad de canales de comunicación también dificulta la labor del Scrum Master. Este deberá poder gestionar impedimentos, mejorar la dinámica del equipo, llevar una bitácora mental de las distintas interacciones entre los miembros y sus oportunidades de mejora. </div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
En un equipo muy grande, la duración de las ceremonias tendría que extenderse para darle tiempo a cada miembro a tener una participación de calidad. Tomando el daily como ejemplo tenemos que cada miembro del equipo puede hablar hasta 1min:40secs en un equipo de 9 (máximo). A medida que la cantidad de miembros crece este tiempo se irá reduciendo.</div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
Un tema que puede ser analizado por su propio peso y que se relaciona con los canales de comunicación son los medios utilizados. Yo y mis compañeros de equipo utilizamos mayormente la comunicación oral, cara a cara, pero también utilizamos canales electrónicos como Slack. Imagine ahora que además de tener 55 canales de comunicación posibles “cara a cara” ahora también podemos hacer lo mismo en Slack. Podemos tener también grupos cerrados donde se manejen temas que pudieran interesar a todo el equipo. </div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
En resumen, la cantidad de miembros del equipo impacta de manera directa y positiva la cantidad de canales de comunicación totales. Con el aumento de los canales de comunicación vienen muchas complicaciones en cuanto a la autogestión de un equipo. Esta no es la razón única o principal para mantener un tamaño limitado sobre los equipos agiles, pero definitivamente es un factor de peso considerable.</div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
Como ilustración aquí se presentan la cantidad de canales para equipos de dos a cinco personas.</div>
<div style="text-align: justify;">
<br /></div>
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjwfnYaZNPOwFkURdvqh1OT68k0xGcr_ZnftvkXg5CPmrEO4M7VGbtgHy1O7-jbIufrGa9VDhGUlVgQ2OBIamYEz0ZeFAnyLke8IhyphenhyphenbVBpB5J_eTld__efvgADVosOZHn9aTANXA49I9zk/s1600/Slide24.GIF" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" data-original-height="720" data-original-width="1280" height="360" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjwfnYaZNPOwFkURdvqh1OT68k0xGcr_ZnftvkXg5CPmrEO4M7VGbtgHy1O7-jbIufrGa9VDhGUlVgQ2OBIamYEz0ZeFAnyLke8IhyphenhyphenbVBpB5J_eTld__efvgADVosOZHn9aTANXA49I9zk/s640/Slide24.GIF" width="640" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;"><i><br />Canales de comunicación: equipos de 2 a 5 integrantes</i></td></tr>
</tbody></table>
<div style="text-align: justify;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
</div>
<div class="separator" style="clear: both; text-align: center;">
</div>
Anonymoushttp://www.blogger.com/profile/12292838726080618300noreply@blogger.com0tag:blogger.com,1999:blog-8113723708012951738.post-60999924436523024142017-06-18T22:13:00.000-04:002017-06-18T22:18:35.155-04:00Requirements, Acceptance Criteria, and Scenarios<h2>
<span style="color: #212121; font-family: sans-serif; font-size: large;"><b>What they are?, How they differ?, How they are related?</b></span></h2>
<h3 style="color: #212121; font-family: sans-serif;">
<strong><span style="font-size: large;">Context</span></strong></h3>
<div style="color: #212121; font-family: sans-serif; font-size: 13px;">
We are building a very basic calculator, one that only supports the four basic operations: Addition, Subtraction, Multiplication, and Division.</div>
<div style="color: #212121; font-family: sans-serif; font-size: 13px;">
<br /></div>
<h3 style="color: #212121; font-family: sans-serif;">
<strong><span style="font-size: large;">Requirements</span></strong></h3>
<i style="font-size: small;">(from the SWEBOKv3 @ <a data-cke-saved-href="http://www4.ncsu.edu/~tjmenzie/cs510/pdf/SWEBOKv3.pdf" data-saferedirecturl="https://www.google.com/url?q=http://www4.ncsu.edu/~tjmenzie/cs510/pdf/SWEBOKv3.pdf&source=gmail&ust=1497643548387000&usg=AFQjCNHZlwv7BhEbNgNKeOSEqHPIiu-lBA" href="http://www4.ncsu.edu/~tjmenzie/cs510/pdf/SWEBOKv3.pdf" style="color: #7e57c2; position: relative; z-index: 0;" target="_blank">http://www4.ncsu.edu/~<wbr></wbr>tjmenzie/cs510/pdf/SWEBOKv3.<wbr></wbr>pdf</a>)</i>
<br />
<h4 style="color: #212121; font-family: sans-serif; font-size: 13px;">
<strong>What they are?</strong></h4>
<blockquote class="tr_bq" style="color: #212121; font-family: sans-serif; font-size: 13px;">
- At its most basic, a software requirement is a property that must be exhibited by something in order to solve some problem in the real world.</blockquote>
<div style="color: #212121; font-family: sans-serif; font-size: 13px;">
<br /></div>
<h4 style="color: #212121; font-family: sans-serif; font-size: 13px;">
<strong>What they do?</strong></h4>
<blockquote class="tr_bq" style="color: #212121; font-family: sans-serif; font-size: 13px;">
- Express the needs and constraints placed on a software product that contribute to the solution of some real-world problem.</blockquote>
<div style="color: #212121; font-family: sans-serif; font-size: 13px;">
<br /></div>
<div style="color: #212121; font-family: sans-serif; font-size: 13px;">
<strong>Properties:</strong></div>
<ul style="color: #333333; font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; font-size: 13px; margin: 0px 0px 10px 25px; padding: 0px;">
<li style="color: #212121; font-family: sans-serif; line-height: 20px;">An essential property of all software requirements is that they <em><strong>be verifiable</strong></em> as an individual feature as a functional requirement or at the system level as a nonfunctional requirement.</li>
<li style="color: #212121; font-family: sans-serif; line-height: 20px;">Priority rating</li>
<li style="color: #212121; font-family: sans-serif; line-height: 20px;">Uniquely identified</li>
</ul>
<div style="color: #212121; font-family: sans-serif; font-size: 13px;">
<strong><br /></strong></div>
<h4 style="color: #212121; font-family: sans-serif; font-size: 13px;">
<strong>Types (Categories) of Requirements</strong></h4>
<ul style="color: #333333; font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; font-size: 13px; margin: 0px 0px 10px 25px; padding: 0px;">
<li style="color: #212121; font-family: sans-serif; line-height: 20px;"><em><strong>Product:</strong></em> A product requirement is a need or constraint on the software to be developed (for example, “The software shall verify that a student meets all prerequisites before he or she registers for a course”).</li>
<li style="color: #212121; font-family: sans-serif; line-height: 20px;"><em><strong>Process:</strong></em> A process requirement is essentially a constraint on the development of the software (for example, “The software shall be developed using a RUP process”).</li>
<li style="color: #212121; font-family: sans-serif; line-height: 20px;"><em><strong>Functional:</strong></em> Functional requirements describe the functions that the software is to execute; for example, formatting some text or modulating a signal. They are sometimes known as capabilities or features. A functional requirement can also be described as one for which a finite set of test steps can be written to validate its behavior.</li>
<li style="color: #212121; font-family: sans-serif; line-height: 20px;"><em><strong>Nonfunctional:</strong></em> nonfunctional requirements are the ones that act to constrain the solution. Nonfunctional requirements are sometimes known as constraints or quality requirements.</li>
</ul>
<div style="color: #212121; font-family: sans-serif; font-size: 13px;">
<br /></div>
<h4 style="color: #212121; font-family: sans-serif; font-size: 13px;">
<strong>Examples</strong></h4>
<div style="color: #212121; font-family: sans-serif; font-size: 13px;">
We're going to map each of the basic arithmetic operations to a single requirement, so we'll have:</div>
<ul style="color: #333333; font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; font-size: 13px; margin: 0px 0px 10px 25px; padding: 0px;">
<li style="color: #212121; font-family: sans-serif; line-height: 20px;">Req-1: The calculator must support the Addition operation.</li>
<li style="color: #212121; font-family: sans-serif; line-height: 20px;">Req-2: The calculator must support the Subtraction operation.</li>
<li style="color: #212121; font-family: sans-serif; line-height: 20px;">Req-3: The calculator must support the Multiplication operation.</li>
<li style="color: #212121; font-family: sans-serif; line-height: 20px;">Req-4: The calculator must support the Division operation.</li>
</ul>
<div style="color: #212121; font-family: sans-serif; font-size: 13px;">
<strong><br /></strong></div>
<h3 style="color: #212121; font-family: sans-serif;">
<strong><span style="font-size: large;">Acceptance Criteria</span></strong></h3>
<div style="color: #212121; font-family: sans-serif; font-size: 13px;">
Set of statements indicating how to judge if a given [software] component or system satisfies certain requirement. Each element, criterion, is an specific statement.</div>
<div style="color: #212121; font-family: sans-serif; font-size: 13px;">
<br /></div>
<h4 style="color: #212121; font-family: sans-serif; font-size: 13px;">
<strong>Examples</strong></h4>
<div style="color: #212121; font-family: sans-serif; font-size: 13px;">
We, as math experts, know that these operations have certain "properties". We can think of these properties as rules or statements that further define some aspect of the requirement (arithmetic operation). So, now we'll take the Addition as the subject of our examples. We'll have one Criterion for each of the Addition Operation's properties.</div>
<ul style="color: #333333; font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; font-size: 13px; margin: 0px 0px 10px 25px; padding: 0px;">
<li style="color: #212121; font-family: sans-serif; line-height: 20px;">Cri-1-1: The calculator must comply with the Commutative property for the Addition operation.</li>
<li style="color: #212121; font-family: sans-serif; line-height: 20px;">Cri-1-2: The calculator must comply with the Associative property for the Addition operation.</li>
<li style="color: #212121; font-family: sans-serif; line-height: 20px;">Cri-1-3: The calculator must comply with the Identity property for the Addition operation.</li>
<li style="color: #212121; font-family: sans-serif; line-height: 20px;">Cri-1-4: The calculator must comply with the Distributive property, respect to the Multiplication, for the Addition operation.</li>
</ul>
<div style="color: #212121; font-family: sans-serif; font-size: 13px;">
<br /></div>
<h3 style="color: #212121; font-family: sans-serif;">
<strong><span style="font-size: large;">Scenarios</span></strong></h3>
<div style="color: #212121; font-family: sans-serif; font-size: 13px;">
Set of concrete examples used to validate a single Acceptance Criteria.</div>
<div style="color: #212121; font-family: sans-serif; font-size: 13px;">
<br /></div>
<h4 style="color: #212121; font-family: sans-serif; font-size: 13px;">
<strong>Examples</strong></h4>
<div style="color: #212121; font-family: sans-serif; font-size: 13px;">
Now we'll take the Commutative property for the Addition operation, as the subject of our examples of Scenarios. What we need are concrete Addition expressions that validate the "presence", or "proper implementation" of the Commutative property (Acceptance Criterion) for the Addition operation (Requirement).</div>
<ul style="color: #333333; font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; font-size: 13px; margin: 0px 0px 10px 25px; padding: 0px;">
<li style="color: #212121; font-family: sans-serif; line-height: 20px;">Sce-1-1-1: 4 + 2 = 2 + 4</li>
<li style="color: #212121; font-family: sans-serif; line-height: 20px;">Sce-1-1-2: 10 + 5 = 5 + 10</li>
<li style="color: #212121; font-family: sans-serif; line-height: 20px;">Sce-1-1-3: 1 + 2 + 3 = 3 + 2 + 1</li>
</ul>
<div>
<span style="color: #212121; font-family: sans-serif;"><span style="font-size: 13px;"><br /></span></span></div>
<div>
<h3>
<span style="color: #212121; font-family: sans-serif; font-size: large;">A picture is worth a thousand words</span></h3>
<span style="color: #212121; font-family: sans-serif; font-size: 13px;">Here is a breakdown structure of these three concepts:</span></div>
<div>
<span style="color: #212121; font-family: sans-serif; font-size: 13px;"><br /></span></div>
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhfKd7ULRzuc9-LQdctlCgxMiDAk7nCQKDcJBscRo-115fmzXRcj85vnW1GTe0u9D0R08achZtHVkspoBvzhilkl3d_3A0R7cYPMb_W8TJRFQv7qFkrpJKZUu7LfboQtTqcZxlyGwnTmMg/s1600/Reqs_Acceptance_Criteria_Scenarios.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" data-original-height="889" data-original-width="1600" height="355" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhfKd7ULRzuc9-LQdctlCgxMiDAk7nCQKDcJBscRo-115fmzXRcj85vnW1GTe0u9D0R08achZtHVkspoBvzhilkl3d_3A0R7cYPMb_W8TJRFQv7qFkrpJKZUu7LfboQtTqcZxlyGwnTmMg/s640/Reqs_Acceptance_Criteria_Scenarios.png" width="640" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;"><br />
<b><i>Requirements, Acceptance Criteria, and Scenarios breakdown</i></b></td></tr>
</tbody></table>
<div>
<br />
<br />
<strong style="color: #212121; font-family: sans-serif; font-size: 13px;"><br /></strong>
<br />
<h3 style="color: #212121; font-family: sans-serif;">
<strong><span style="font-size: large;">Summary</span></strong></h3>
<em style="color: #212121; font-family: sans-serif; font-size: 13px;"><strong>What they are? </strong></em><span style="color: #212121; font-family: sans-serif; font-size: 13px;">see above definitions.</span><br />
<br />
<em style="color: #212121; font-family: sans-serif; font-size: 13px;"><strong>How they differ?</strong></em><span style="color: #212121; font-family: sans-serif; font-size: 13px;"> </span><br />
<span style="color: #212121; font-family: sans-serif;"><span style="font-size: 13px;">Requirements are high level descriptions of system characteristics. Acceptance Criteria are elements used to comply with the "verifiable" property of requirements. Criteria must state how to determine if the software system had properly implemented the requirement.</span></span><br />
<br />
<span style="color: #212121; font-family: sans-serif;"><span style="font-size: 13px;">Often, acceptance criteria are not detailed enough to be useful in practice, so we need concrete examples of Input-Output, Input-Response Time, etc.; those are the Scenarios.</span></span><br />
<br />
<strong style="color: #212121; font-family: sans-serif; font-size: 13px;"><i>How are related?</i></strong><br />
<span style="color: #212121; font-family: sans-serif; font-size: 13px;">From the above descriptions, you can infer that they are three levels of details of the same thing: what we expect the system to do.</span><br />
<br />
<strong style="color: #212121; font-family: sans-serif; font-size: 13px;"><i>But, what's the deal with all this?</i></strong></div>
<ul style="color: #333333; font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; font-size: 13px; margin: 0px 0px 10px 25px; padding: 0px;">
<li style="color: #212121; font-family: sans-serif; line-height: 20px;">All actors of the SDLC process must understand what are, how they differ, and why are all three levels required.</li>
<li style="color: #212121; font-family: sans-serif; line-height: 20px;">Requirements / User Stories, without Criteria and Scenarios will be to subjective to be verifiable.</li>
<li style="color: #212121; font-family: sans-serif; line-height: 20px;">Criteria and Scenarios alone, will be too difficult to manage, without a grouping element (parent requirement).</li>
</ul>
<div style="color: #212121; font-family: sans-serif; font-size: 13px;">
The usage of all three levels bring a lot of benefits, such as better effort estimation of Stories, Criteria, and Tasks. They also bring some challenges about how to express, document and/or automate those validations. We can review all this in another article, here I just wanted to point out their difference and give some simple examples of each one.</div>
Anonymoushttp://www.blogger.com/profile/12292838726080618300noreply@blogger.com0tag:blogger.com,1999:blog-8113723708012951738.post-26577728669142627572017-06-18T22:12:00.000-04:002017-06-18T22:18:35.151-04:00Requerimientos, Criterios de Aceptación y Escenarios<h2>
<span style="color: #212121; font-family: sans-serif; font-size: large;">¿Qué son?, ¿En qué difieren?, ¿Cómo están relacionados?</span></h2>
<h3 style="color: #212121; font-family: sans-serif;">
<strong><span style="font-size: large;">Contexto</span></strong></h3>
<div style="color: #212121; font-family: sans-serif; font-size: 13px;">
Estamos construyendo una calculadora básica, la cual solo soporta las cuatro operaciones básicas: Adición, Sustracción, Multiplicación y División.</div>
<div style="color: #212121; font-family: sans-serif; font-size: 13px;">
<br /></div>
<h3 style="color: #212121; font-family: sans-serif;">
<strong><span style="font-size: large;">Requerimientos</span></strong></h3>
<i style="font-size: small;">(tomado del SWEBOKv3 @ <a data-cke-saved-href="http://www4.ncsu.edu/~tjmenzie/cs510/pdf/SWEBOKv3.pdf" data-saferedirecturl="https://www.google.com/url?q=http://www4.ncsu.edu/~tjmenzie/cs510/pdf/SWEBOKv3.pdf&source=gmail&ust=1497643548387000&usg=AFQjCNHZlwv7BhEbNgNKeOSEqHPIiu-lBA" href="http://www4.ncsu.edu/~tjmenzie/cs510/pdf/SWEBOKv3.pdf" style="color: #7e57c2; position: relative; z-index: 0;" target="_blank">http://www4.ncsu.edu/~<wbr></wbr>tjmenzie/cs510/pdf/SWEBOKv3.<wbr></wbr>pdf</a>)</i><br />
<h4 style="color: #212121; font-family: sans-serif; font-size: 13px;">
<strong>¿Qué son?</strong></h4>
<blockquote class="tr_bq" style="color: #212121; font-family: sans-serif; font-size: 13px;">
- En su forma mas básica, un requisito de software es una propiedad la cual debe ser exhibida por algo (componente / modulo / sistema / etc), con el objetivo de resolver un problema del mundo real.</blockquote>
<div style="color: #212121; font-family: sans-serif; font-size: 13px;">
<br /></div>
<h4 style="color: #212121; font-family: sans-serif; font-size: 13px;">
<strong>¿Que hacen?</strong></h4>
<blockquote class="tr_bq" style="color: #212121; font-family: sans-serif; font-size: 13px;">
- Expresan las necesidades y limitaciones colocadas sobre el producto de software, el cual contribuye a la solución de un problema del mundo real.</blockquote>
<div style="color: #212121; font-family: sans-serif; font-size: 13px;">
<br /></div>
<div style="color: #212121; font-family: sans-serif; font-size: 13px;">
<strong>Propiedades:</strong></div>
<ul style="color: #333333; font-family: "helvetica neue", helvetica, arial, sans-serif; font-size: 13px; margin: 0px 0px 10px 25px; padding: 0px;">
<li style="color: #212121; font-family: sans-serif; line-height: 20px;">Una propiedad esencial de todos los requerimientos de software es que <b><i>deben ser verificables </i></b>como una característica individual como requisito funcional, o a nivel de sistema como un requisito no funcional.</li>
<li style="color: #212121; font-family: sans-serif; line-height: 20px;">Deben ser estar priorizados.</li>
<li style="color: #212121; font-family: sans-serif; line-height: 20px;">Deben estar identificados de manera única.</li>
</ul>
<div style="color: #212121; font-family: sans-serif; font-size: 13px;">
<strong><br /></strong></div>
<h4 style="color: #212121; font-family: sans-serif; font-size: 13px;">
<strong><span style="color: #212121; font-family: sans-serif;"><span style="font-size: 13px;">Tipos (Categorías) de Requerimientos</span></span></strong></h4>
<ul style="margin: 0px 0px 10px 25px; padding: 0px;">
<li style="color: #212121; font-family: sans-serif; font-size: 13px; line-height: 20px;"><em><strong>de Producto:</strong></em> un requerimiento de producto es una necesidad o constreñimiento en el software a ser desarrollado (ejemplo, "El software debe verificar que el estudiante cumpla con todos los pre-requisitos antes de que el o ella se registre para un curso").</li>
<li style="color: #212121; font-family: sans-serif; font-size: 13px; line-height: 20px;"><em><strong>Proceso:</strong></em> un requerimiento de proceso es esencialmente un constreñimiento en el proceso de desarrollo de software (ejemplo: "El software sera desarrollado utilizando el proceso RUP").</li>
<li style="line-height: 20px;"><em><strong><span style="color: #212121; font-family: sans-serif;"><span style="font-size: 13px;">Funcional:</span></span></strong></em><span style="color: #212121; font-family: sans-serif;"><span style="font-size: 13px;"> los requerimientos funcionales describen las funciones que el software debe ejecutar; ejemplo: formatear un texto o modular una señal. A veces son conocidos como capacidades o características. un requerimiento funcional puede ser descrito como uno para el se puede escribir un conjunto de pasos de pruebas finito, a ser utilizado para validar su funcionamiento.</span></span></li>
<li style="line-height: 20px;"><em><strong><span style="color: #212121; font-family: sans-serif;"><span style="font-size: 13px;">No-funcional:</span></span></strong></em><span style="color: #212121; font-family: sans-serif;"><span style="font-size: 13px;"> los requerimientos no-funcionales son los que restringen la solución. Muchas veces se les conoce como constreñimientos o requisitos de calidad.</span></span></li>
</ul>
<div style="color: #212121; font-family: sans-serif; font-size: 13px;">
<br /></div>
<h4 style="color: #212121; font-family: sans-serif; font-size: 13px;">
<strong>Ejemplos</strong></h4>
<div style="color: #212121; font-family: sans-serif; font-size: 13px;">
Vamos a tomar cada una de las operaciones aritméticas básicas como un único requerimiento, así que tendremos:</div>
<ul style="color: #333333; font-family: "helvetica neue", helvetica, arial, sans-serif; font-size: 13px; margin: 0px 0px 10px 25px; padding: 0px;">
<li style="color: #212121; font-family: sans-serif; line-height: 20px;">Req-1: La calculadora debe soportar la operación Adición.</li>
<li style="color: #212121; font-family: sans-serif; line-height: 20px;">Req-2: La calculadora debe soportar la operación Sustracción.</li>
<li style="color: #212121; font-family: sans-serif; line-height: 20px;">Req-3: La calculadora debe soportar la operación Multiplicación.</li>
<li style="color: #212121; font-family: sans-serif; line-height: 20px;">Req-4: La calculadora debe soportar la operación División.</li>
</ul>
<div style="color: #212121; font-family: sans-serif; font-size: 13px;">
<strong><br /></strong></div>
<h3 style="color: #212121; font-family: sans-serif;">
<strong style="color: #212121; font-family: sans-serif;"><span style="font-size: large;">Criterios de </span></strong><span style="color: #212121; font-family: sans-serif; font-size: large;">Aceptación</span></h3>
<div style="color: #212121; font-family: sans-serif; font-size: 13px;">
Conjunto de sentencias las cuales indican como sera juzgado (evaluado) un componente de software dado para ver si satisface o no un requerimiento. Cada elemento, criterio, es una sentencia especifica.</div>
<div style="color: #212121; font-family: sans-serif; font-size: 13px;">
<br /></div>
<h4 style="color: #212121; font-family: sans-serif; font-size: 13px;">
<strong>Ejemplos</strong></h4>
<div style="color: #212121; font-family: sans-serif; font-size: 13px;">
Nosotros, como expertos en matemáticas, sabemos que las operaciones aritméticas básicas tienen ciertas "propiedades". Podemos pensar en esas propiedades como reglas o sentencias las cuales definen en mayor detalle algún aspecto del requerimiento (operación aritmética). Así que ahora tomaremos la operación (requerimiento) Adición como el sujeto de nuestros ejemplos. Tendremos un Criterio por cada una de las propiedades de la operación Adición.</div>
<ul style="color: #333333; font-family: "helvetica neue", helvetica, arial, sans-serif; font-size: 13px; margin: 0px 0px 10px 25px; padding: 0px;">
<li style="color: #212121; font-family: sans-serif; line-height: 20px;">Cri-1-1: La calculadora debe cumplir con la propiedad Conmutativa para la operación Adición.</li>
<li style="color: #212121; font-family: sans-serif; line-height: 20px;">Cri-1-2: La calculadora debe cumplir con la propiedad Asociativa para la operación Adición.</li>
<li style="color: #212121; font-family: sans-serif; line-height: 20px;">Cri-1-3: La calculadora debe cumplir con la propiedad Elemento Neutro para la operación Adición.</li>
<li style="color: #212121; font-family: sans-serif; line-height: 20px;">Cri-1-4: La calculadora debe cumplir con la propiedad Distributiva, respecto a la multiplicación, para la operación Adición.</li>
</ul>
<div style="color: #212121; font-family: sans-serif; font-size: 13px;">
<br /></div>
<h3 style="color: #212121; font-family: sans-serif;">
<strong><span style="font-size: large;">Escenarios</span></strong></h3>
<div style="color: #212121; font-family: sans-serif; font-size: 13px;">
Conjunto de ejemplos concretos utilizados para validar un único Criterio de Aceptación.</div>
<div style="color: #212121; font-family: sans-serif; font-size: 13px;">
<br /></div>
<h4 style="color: #212121; font-family: sans-serif; font-size: 13px;">
<strong>Ejemplos</strong></h4>
<div style="color: #212121; font-family: sans-serif; font-size: 13px;">
Ahora tomaremos la propiedad Conmutativa para la operación Adición, como nuestro sujeto. Lo que necesitamos son ejemplos concretos de expresiones de suma los cuales validen la "presencia", o "implementación correcta" de la propiedad Conmutativa (Criterio de Aceptación), para la operación Adición (Requerimiento).</div>
<ul style="color: #333333; font-family: "helvetica neue", helvetica, arial, sans-serif; font-size: 13px; margin: 0px 0px 10px 25px; padding: 0px;">
<li style="color: #212121; font-family: sans-serif; line-height: 20px;">Sce-1-1-1: 4 + 2 = 2 + 4</li>
<li style="color: #212121; font-family: sans-serif; line-height: 20px;">Sce-1-1-2: 10 + 5 = 5 + 10</li>
<li style="color: #212121; font-family: sans-serif; line-height: 20px;">Sce-1-1-3: 1 + 2 + 3 = 3 + 2 + 1</li>
</ul>
<div>
<span style="color: #212121; font-family: sans-serif;"><span style="font-size: 13px;"><br /></span></span></div>
<div>
<h3>
<span style="color: #212121; font-family: sans-serif; font-size: large;">Una imagen vale mas que mil palabras</span></h3>
<span style="color: #212121; font-family: sans-serif; font-size: 13px;">Aquí tenemos un desglose de los tres conceptos::</span></div>
<div>
<span style="color: #212121; font-family: sans-serif; font-size: 13px;"><br /></span></div>
<div class="separator" style="clear: both; text-align: center;">
</div>
<div>
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhUumrTyl2KZ6EsQuqbyRSfs-uexXBrawWcWV32l3iNeyNc7v6-nAo0ZCjmxYjxUH76YdGzEb_Z6KTdvc_YCDZcB8wptlXimbsjavRPc5hkDwtGcQTy7m4wG0rCITY2icyYAAz8a3GnjyE/s1600/Reqs_Acceptance_Criteria_Scenarios_es_do.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" data-original-height="900" data-original-width="1600" height="360" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhUumrTyl2KZ6EsQuqbyRSfs-uexXBrawWcWV32l3iNeyNc7v6-nAo0ZCjmxYjxUH76YdGzEb_Z6KTdvc_YCDZcB8wptlXimbsjavRPc5hkDwtGcQTy7m4wG0rCITY2icyYAAz8a3GnjyE/s640/Reqs_Acceptance_Criteria_Scenarios_es_do.png" width="640" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;"><b><i>Desglose de Requerimientos, Criterios de Aceptación y Escenarios</i></b></td></tr>
</tbody></table>
<br />
<br />
<strong style="color: #212121; font-family: sans-serif; font-size: 13px;"><br /></strong>
<h3 style="color: #212121; font-family: sans-serif;">
<strong><span style="font-size: large;">Resumen</span></strong></h3>
<span style="color: #212121; font-family: sans-serif; font-size: 13px;"><strong style="font-style: italic;">¿Qué son? </strong>ver definiciones anteriores</span><span style="color: #212121; font-family: sans-serif; font-size: 13px;">.</span><br />
<br />
<em style="color: #212121; font-family: sans-serif; font-size: 13px;"><strong>¿En que se diferencias?</strong></em><span style="color: #212121; font-family: sans-serif; font-size: 13px;"> </span><br />
<span style="color: #212121; font-family: sans-serif;"><span style="font-size: 13px;">Son descripciones de alto nivel de características de un sistema. Los Criterios de Aceptación son elementos utilizados para cumplir con la característica "verificable" de los requerimientos. Los criterios deben especificar como determinar si el sistema de software ha implementado correctamente el requerimiento.</span></span><br />
<br />
<span style="color: #212121; font-family: sans-serif;"><span style="font-size: 13px;">Con frecuencia, los criterios de aceptación no tienen el detalle suficiente para ser útiles en la practica, así que tenemos que utilizar ejemplos concretos como Entrada-Salida, Entrada-Tiempo de Respuesta, etc.; estos son los Escenarios.</span></span><br />
<br />
<strong style="color: #212121; font-family: sans-serif; font-size: 13px;"><i>¿Como se relacionan?</i></strong><br />
<span style="color: #212121; font-family: sans-serif; font-size: 13px;">De las descripciones anteriores, usted podrá inferir que son tres niveles de detalle de la misma cosa: que se espera que el sistema haga.</span><br />
<br />
<strong style="color: #212121; font-family: sans-serif; font-size: 13px;"><i>Y ¿Cual es el asunto de todo esto?</i></strong></div>
<ul style="color: #333333; font-family: "helvetica neue", helvetica, arial, sans-serif; font-size: 13px; margin: 0px 0px 10px 25px; padding: 0px;">
<li style="color: #212121; font-family: sans-serif; line-height: 20px;">Todos los actores del proceso de desarrollo de software deben entender que son, en que se diferencian y porque son necesarios los tres niveles.</li>
<li style="color: #212121; font-family: sans-serif; line-height: 20px;">Los Requerimientos / Historias de Usuario, sin sus Criterios de Aceptación y Escenarios serian muy subjetivos para ser verificables.</li>
<li style="color: #212121; font-family: sans-serif; line-height: 20px;">Los Criterios y Escenarios solos serian muy difíciles de manejar, sin un elemento de agrupación (requerimiento padre).</li>
</ul>
<div style="color: #212121; font-family: sans-serif; font-size: 13px;">
El uso de los tres niveles trae muchos beneficios, como mejores estimaciones de esfuerzo requerido para las Historias de Usuario, Criterios y Tareas. También traen algunos retos interesantes sobre como documentar o expresar automatizar todos estas esas validaciones. Podríamos revisar eso en otro articulo, aquí solo quise resaltar sus diferencias y dar algunos ejemplos simples de cada uno.</div>
Anonymoushttp://www.blogger.com/profile/12292838726080618300noreply@blogger.com0tag:blogger.com,1999:blog-8113723708012951738.post-29434500797449780052017-05-31T22:33:00.000-04:002017-05-31T22:33:41.062-04:00Valor de Negocio vs EsfuerzoLuego de una encuesta rápida ( <a href="https://plus.google.com/+LorenzoSolano/posts/U6ZSU5t22vA">https://plus.google.com/+LorenzoSolano/posts/U6ZSU5t22vA</a> ), en la cual se preguntaba sobre la relación entre los Puntos de Historia y el Valor de Negocio, quise hablar un poco sobre este mal entendido.<br />
<br />
<h2>
Definiciones Rápidas (contexto: Agile, Scrum, Desarrollo de Software)</h2>
<h3>
Valor de Negocio [Entregado]</h3>
Incremento en cierto aspecto de una organización, fruto de un cambio en algún producto de software. Ese aspecto puede ser una fuente de ingresos, mitigación de algún riesgo, etc.<br />
<br />
En palabras simples, el valor de negocio entregado luego de una iteración / sprint es el incremento en la capacidad del negocio para generar más dinero o evitar ciertas perdidas (financieras, de reputación, etc.).<br />
<br />
<h3>
Puntos de Historia</h3>
Esfuerzo percibido, por un equipo de desarrollo, como necesario para construir cierta característica en un sistema de software.<br />
<br />
Las ideas principales aquí son: percibido y un equipo de desarrollo [especifico]. Lo que esto significa es que el esfuerzo es una medida subjetiva, y que ese “sujeto” es un equipo de software en todo el universo. Usted no puede comparar un equipo a otro en términos de cuantos Puntos de Historia (esfuerzo) ellos le asignan a una característica a ser construida.<br />
<br />
<h2>
Los Puntos de Historia y el Valor de Negocio no tienen Relación</h2>
<h3>
Escenario</h3>
Imagine dos equipos de desarrollo de software, a los cuales se les da la tarea de estimar cuanto esfuerzo requieren (no horas / tiempo, no dinero), para construir la Característica X. Ambos equipos tienen exactamente el mismo contexto (imaginario por supuesto): ellos pertenecen a la misma organización, responden a los mismos interesados, trabajan con las mismas tecnologías y herramientas.<br />
<br />
Donde ellos difieren es en su nivel de experiencia. Así que, tenemos un Equipo de Principiantes y un Equipo de Expertos. Si usted les pregunta a los principiantes acerca del esfuerzo requerido para construir la Característica X, ellos responderán con un estimado mucho más alto que los expertos.<br />
<br />
Desde el punto de vista del dueño del negocio, el valor agregado a la organización por la Característica X (luego de ser construida), es el mismo sin importar quienes lo construyan. El negocio solo quiere su nueva funcionalidad, no importa cuán difícil o fácil sea para los constructores lograrlo.<br />
<br />
Utilizando un ejemplo menos abstracto; piense en que la cantidad de valor de negocio agregado por la Característica X, es un litro de agua fresca en el desierto. Imagine que su familia vive a una milla (1.6 KM) de distancia de la fuente de agua,<br />
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiF8S5iRJaMFr9IyrgOe3sCuuqGMJIOIilmqEAP_hDPy4JwoboH_XrlE49olGNcsP9ue2IpCG5rCDjVmDFDy3vHTyMG_5x-w-E-F1zZXxk_XWNLKiBRgElyi4DLToibJnos7tCc0a8_uCg/s1600/BayudaDesertWell.jpg" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" data-original-height="683" data-original-width="1024" height="266" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiF8S5iRJaMFr9IyrgOe3sCuuqGMJIOIilmqEAP_hDPy4JwoboH_XrlE49olGNcsP9ue2IpCG5rCDjVmDFDy3vHTyMG_5x-w-E-F1zZXxk_XWNLKiBRgElyi4DLToibJnos7tCc0a8_uCg/s400/BayudaDesertWell.jpg" width="400" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;"><i><b>( fuente de agua: contenedor del "valor de negocio" )</b><br />Bayuda Desert Well by Clemens Schmillen CC. https://commons.wikimedia.org/wiki/File:BayudaDesertWell.jpg</i></td></tr>
</tbody></table>
<br />
y que usted necesita ese litro de agua para cocinar las comidas del día. Ese es su valor de negocio, usted necesita el agua no importa como la consiga.<br />
<br />
Ahora viene el esfuerzo: si usted debe ir caminando y traer el agua a su casa, el esfuerzo requerido seria alto.<br />
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhXhufVtlR0_g2PDoDyaLm4dfxB00x-DkH7HSydwwiGzdSteVxYKaWw-WIeZSz5lkblBuS7MqBhIt6B4UQcUNHi_pBA1sCFSd1JlVuQE8NDdGnlmkoIn1_NKlWfwBqGQflgwJSE2jn0fEM/s1600/Desert_Walk.jpg" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" data-original-height="680" data-original-width="1024" height="212" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhXhufVtlR0_g2PDoDyaLm4dfxB00x-DkH7HSydwwiGzdSteVxYKaWw-WIeZSz5lkblBuS7MqBhIt6B4UQcUNHi_pBA1sCFSd1JlVuQE8NDdGnlmkoIn1_NKlWfwBqGQflgwJSE2jn0fEM/s320/Desert_Walk.jpg" width="320" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;"><i><b>( esfuerzo requerido por el "Equipo de Principiantes" )</b><br />Desert walk https://www.flickr.com/photos/maartmeester/5130198174 by Maarten van Maanen @ Flickr.com</i></td></tr>
</tbody></table>
<br />
Pero, si usted utiliza un camello para ir y buscar el agua, entonces la tarea se vuelve más fácil.<br />
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh00Cf-XODdFVPBpvu1oipcb-6Z4FRH7hKtTGgybdrH9EMSCMKb2AkyTxhRgKJMNEHXVxY7QH2h1wiYjmvjYHjDFDTTF0NxhmqV-eQXwL2QfxbYyyH2knyO-iNIXClmHnrWLEgDhxcKIOY/s1600/camel-692648_1920.jpg" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" data-original-height="683" data-original-width="1600" height="136" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh00Cf-XODdFVPBpvu1oipcb-6Z4FRH7hKtTGgybdrH9EMSCMKb2AkyTxhRgKJMNEHXVxY7QH2h1wiYjmvjYHjDFDTTF0NxhmqV-eQXwL2QfxbYyyH2knyO-iNIXClmHnrWLEgDhxcKIOY/s320/camel-692648_1920.jpg" width="320" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;"><i><b>( esfuerzo requerido por el "Equipo de Expertos" )</b><br />Camel at desert https://pixabay.com/en/camel-desert-sand-mongolia-692648/ by hbieser @ pixabay.com</i></td></tr>
</tbody></table>
<br />
<br />
<h3>
Conclusiones</h3>
De esta comparación, inadecuada, me gustaría puntualizar algunas observaciones clave:<br />
<ul>
<li>No compare equipos utilizando su velocidad promedio (Puntos de Historia por Sprint)</li>
<li>No asuma que un equipo entrega más valor de negocio porque ellos tienen una “velocidad” más alta que otro</li>
<li>La velocidad de un equipo es solo para su uso</li>
<li>Usted puede comparar la velocidad pasada a la actual, analizar tendencias y responder a cambios bruscos en ella (incrementos o decrementos) como indicador de que algo está pasando: nuevos miembros, rotación, cambios en infraestructura tecnologías, etc. Obviamente, la comparación será entre medidas presentes y futuras DEL MISMO EQUIPO.</li>
</ul>
Anonymoushttp://www.blogger.com/profile/12292838726080618300noreply@blogger.com0tag:blogger.com,1999:blog-8113723708012951738.post-67327020166010591252017-05-31T21:56:00.000-04:002017-05-31T22:09:23.727-04:00Business Value vs EffortAfter a quick poll ( <a href="https://plus.google.com/+LorenzoSolano/posts/U6ZSU5t22vA">https://plus.google.com/+LorenzoSolano/posts/U6ZSU5t22vA</a> ), asking about the relation between Story Points and Business Value, I want talk about this misconception.<br />
<br />
<h2>
Quick Definitions (context: Agile, Scrum, Software Development)</h2>
<h3>
[Delivered] Business Value</h3>
Increase on certain aspect of an organization, due to a change on some software product. That aspect could be a revenue stream, risk mitigation, etc.<br />
In simple words, the delivered business value after an iteration / sprint is the increase on the business’s capacity to generate more money or to avoid certain losses (financial, reputational, etc.)<br />
<br />
<h3>
Story Points</h3>
The perceived amount of effort, for a development team, required to build certain feature into a software system.<br />
<br />
The main concepts here are: perceived, and a [specific] development team. What this means is that the effort is subjective measurement, and that the “subject” is one software team in the entire universe. You cannot compare one team to another in terms of how much Story Points (effort) they assign to a given feature to be built.<br />
<br />
<h2>
Story Points and Business Value are Unrelated</h2>
<h3>
Scenario</h3>
Image two software development teams given the task estimate how much effort (not hours / time, not money), they as a team, will require to build the Feature X. Both teams have the exact same context (imaginary of course): they belong to the same organization, respond to the same stakeholders, work with the same technology stack, and with the same tools.<br />
<br />
Where they differ is in their seniority (experience) level. So, we have a Beginner’s Team and a Senior’s Team. If you ask the beginners about the effort required to build Feature X, they will respond with an estimate much larger than the seniors.<br />
<br />
For the point of view of the business owner, the value added to the organization by the Feature X (after construction), is the same. They just want the new functionality, no matter how hard or easy is for the builders to do it.<br />
<br />
In a, less abstract, example; think of the amount of business value added by the Feature X, as a litter of fresh water in the desert. Imagine that your family lives one mile away from the water well,<br />
<br />
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi5b7NHJiMChCwMU2vbCqvoswSK2miiqb7DyL24Sokj-OF_wmlmR5KcdfBGyZ_m6ohdcsgyyVthw23JUjaxLezIs2DVr8zbL6lsIGl2KDAADf4SW5tmmPnz1cktiBqevemkdogMG5vg2P4/s1600/BayudaDesertWell.jpg" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" data-original-height="683" data-original-width="1024" height="265" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi5b7NHJiMChCwMU2vbCqvoswSK2miiqb7DyL24Sokj-OF_wmlmR5KcdfBGyZ_m6ohdcsgyyVthw23JUjaxLezIs2DVr8zbL6lsIGl2KDAADf4SW5tmmPnz1cktiBqevemkdogMG5vg2P4/s400/BayudaDesertWell.jpg" width="400" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;"><b><i>( water well: "business value" holder )</i></b><br />
<i>Bayuda Desert Well by Clemens Schmillen CC. https://commons.wikimedia.org/wiki/File:BayudaDesertWell.jpg</i></td></tr>
</tbody></table>
<br />
and that you need to get that litter of water to cook the day’s meals. That’s your business value, you just need the water no matter how you get it.<br />
<br />
Now comes the effort: if you must go by foot and bring the water to your house the effort required will be high.<br />
<br />
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh1vFgDlV19dsjS3f0ClJRDGDLmIe1TJrKrnWHqulFQXLo6RpskhoFFwORJQVFOi_x03JY6jv9JJpMKcGhbIHFDEgHEfgJ1uDFA1hKDE6ZxNsF2kmkQ9Og51SxYsrOqqOXGlcUfTEV35D8/s1600/Desert_Walk.jpg" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" data-original-height="680" data-original-width="1024" height="212" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh1vFgDlV19dsjS3f0ClJRDGDLmIe1TJrKrnWHqulFQXLo6RpskhoFFwORJQVFOi_x03JY6jv9JJpMKcGhbIHFDEgHEfgJ1uDFA1hKDE6ZxNsF2kmkQ9Og51SxYsrOqqOXGlcUfTEV35D8/s320/Desert_Walk.jpg" width="320" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;"><i><b>( effort required by the "Beginner's Team" )</b><br />Desert walk https://www.flickr.com/photos/maartmeester/5130198174 by Maarten van Maanen @ Flickr.com</i></td></tr>
</tbody></table>
<br />
But if you use a camel to go and get the water, the task becomes a little easy.<br />
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgf1QyLxvLpJIowlZVJrM7qe_GQETZGfGmrfxfs-n6bpjuiUfXbtfQiiyblRx50HWQwRUygvYYrle_xjdMlI2bVMXk21Fs4cait4BzhmZvJlZhOjeYOXhdP5YlvNLJNvecwHVV42e8NqEg/s1600/camel-692648_1920.jpg" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" data-original-height="683" data-original-width="1600" height="136" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgf1QyLxvLpJIowlZVJrM7qe_GQETZGfGmrfxfs-n6bpjuiUfXbtfQiiyblRx50HWQwRUygvYYrle_xjdMlI2bVMXk21Fs4cait4BzhmZvJlZhOjeYOXhdP5YlvNLJNvecwHVV42e8NqEg/s320/camel-692648_1920.jpg" width="320" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;"><i><b>( effort required by less Expert's Team )</b><br />Camel at desert https://pixabay.com/en/camel-desert-sand-mongolia-692648/ by hbieser @ pixabay.com</i></td></tr>
</tbody></table>
<br />
<br />
<br />
<h3>
Conclusions</h3>
From this, inadequate, comparison I want to point out some key takeaways:<br />
<ul>
<li>Do not compare teams per their average velocity (Story Points per Sprint)</li>
<li>Do not assume that one team is delivering more business value because they have a higher “velocity” that another</li>
<li>A team’s velocity is only for their usage</li>
<li>You can compare past to actual velocity, analyze trends, and respond to abrupt changes on velocity (up or down) as an indicator that something is happening: new members, rotation, infrastructure / technology stack changes, etc. Obviously, the comparison will be between measurements of the SAME TEAM, past and present.</li>
</ul>
<br />
<br />Anonymoushttp://www.blogger.com/profile/12292838726080618300noreply@blogger.com0tag:blogger.com,1999:blog-8113723708012951738.post-10171697838755597282016-06-12T21:15:00.000-04:002016-06-12T21:15:58.219-04:00Professionalism or Class Suicide?<span style="font-family: Arial, Helvetica, sans-serif; font-size: large;">At SoftTopia each software product, from the smallest utility to the large enterprise application, has a Quality Label. That label indicates the product’s quality for the given release, both internally and externally. The external measure indicates how close to the original functional requirements is the final product. The internal measure indicates how easy is to keep the product alive over time, keeping it within the time and cost boundaries set by all stakeholders (maintainers, customers, owners, etc.).</span><br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiFuaqtgmFzBuMtnDQQoH96TDBfQnkH1VXpQn4uR8t7NUMelMb06jQIG3sd4C_SlBq_ts9D_T71R-ZI-AtPh8m8valYzh_XDiAy2c7YwWmnX_YLLzXVPXfaN-tPiqd1JWxQfdOls7ckFLw/s1600/software_pkg_grade_a.png" imageanchor="1" style="clear: right; float: right; margin-bottom: 1em; margin-left: 1em;"><img alt="Grade A Software Package" border="0" height="200" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiFuaqtgmFzBuMtnDQQoH96TDBfQnkH1VXpQn4uR8t7NUMelMb06jQIG3sd4C_SlBq_ts9D_T71R-ZI-AtPh8m8valYzh_XDiAy2c7YwWmnX_YLLzXVPXfaN-tPiqd1JWxQfdOls7ckFLw/s200/software_pkg_grade_a.png" title="Grade A Software Package" width="200" /></a></div>
<span style="font-family: Arial, Helvetica, sans-serif; font-size: large;"><br /></span>
<span style="font-family: Arial, Helvetica, sans-serif; font-size: large;">Let’s suppose that this “label” is an obligation at SoftTopia, so, no software product can be released without that information.</span><br />
<span style="font-family: Arial, Helvetica, sans-serif; font-size: large;"><br /></span>
<h4>
<span style="font-family: Arial, Helvetica, sans-serif; font-size: large;"><b><i>Case A</i></b></span></h4>
<span style="font-family: Arial, Helvetica, sans-serif; font-size: large;">SoftTopia had implemented that norm since the creation of the first software package, as they already had a quality oriented culture when they were hit by the technological revolution.</span><br />
<span style="font-family: Arial, Helvetica, sans-serif; font-size: large;"><br /></span>
<h4>
<span style="font-family: Arial, Helvetica, sans-serif; font-size: large;"><i>Case B (ours)</i></span></h4>
<span style="font-family: Arial, Helvetica, sans-serif; font-size: large;">The computer program was created in the 1840s, at SoftTopia. 175 years later, and with millions of software products in use, the SoftTopia leaders released the new quality norm. This is a free commerce society so they only demand the quality label to be placed on each product, but the customer is the one that decides which product to buy. Even though, some industries are regulated because of their impact on the society, like the health sector, hydrocarbons, government, foods, public transportation, civil aviation and defense.</span><br />
<span style="font-family: Arial, Helvetica, sans-serif; font-size: large;"><br /></span>
<h4>
<span style="font-family: Arial, Helvetica, sans-serif; font-size: large;">What happens next?</span></h4>
<span style="font-family: Arial, Helvetica, sans-serif; font-size: large;">•<span class="Apple-tab-span" style="white-space: pre;"> </span>What will the software professionals and businesses not able to create products according to the new norm do?</span><br />
<span style="font-family: Arial, Helvetica, sans-serif; font-size: large;">•<span class="Apple-tab-span" style="white-space: pre;"> </span>How will a government institution handle the fact of finding out that almost all of its suppliers deliver software with a quality level below the norm?</span><br />
<span style="font-family: Arial, Helvetica, sans-serif; font-size: large;">•<span class="Apple-tab-span" style="white-space: pre;"> </span>What will do the private sector when their customers realize that a good share of the operational costs is due to poor quality?</span><br />
<span style="font-family: Arial, Helvetica, sans-serif; font-size: large;">•<span class="Apple-tab-span" style="white-space: pre;"> </span>How will the universities and education institutions sell their software engineering syllabus after realizing that their graduates are not able to build software according to the new norm? </span><br />
<span style="font-family: Arial, Helvetica, sans-serif; font-size: large;"><br /></span>
<h4>
<span style="font-family: Arial, Helvetica, sans-serif; font-size: large;">Let’s now break the SoftTopia tale </span></h4>
<span style="font-family: Arial, Helvetica, sans-serif; font-size: large;">If, little by little, the software professionals and companies from the industry start to publish, voluntarily, the quality level of their products: <b><i>Will that be Professionalism or Suicide?</i></b></span><br />
<span style="font-family: Arial, Helvetica, sans-serif; font-size: large;"><br /></span>
<span style="font-family: Arial, Helvetica, sans-serif; font-size: large;">What do you think? …</span><br />
<div>
<br /></div>
Anonymoushttp://www.blogger.com/profile/12292838726080618300noreply@blogger.com2tag:blogger.com,1999:blog-8113723708012951738.post-87355661620740686582016-06-12T21:00:00.000-04:002016-06-12T21:00:21.664-04:00Profesionalismo o Suicido de Clases<div style="text-align: justify;">
<span style="font-family: Arial, Helvetica, sans-serif; font-size: large;">En SoftTopia cada producto de software, desde la más pequeña utilería hasta la aplicación empresarial más grande, cuentan con un Sello de Calidad. Ese sello mide la calidad del release del producto tanto interna como externa. La externa indica el grado de cumplimiento de las funcionalidades del paquete comparado con los requisitos de los clientes. La interna indica que tan fácil es de mantener vivo el proyecto respetando los parámetros de tiempo y costo esperados por los involucrados (mantenedores, clientes, propietarios, etc.).</span></div>
<div class="separator" style="clear: both; text-align: center;">
<span style="font-family: Arial, Helvetica, sans-serif; font-size: large;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEidU3-i8V00kQLrwKyaMUYcI6gH-Ge6YMaYZLrE7kWSDry2Yg4cmaipA_rl47UOPGVztaVuCXpHrk9qLb6QxKOmW6oTR5Seo-xfdb-aOBnuVgMw7IDMHE3rESxKjvKnGnZn2R_CsK5BQLU/s1600/software_pkg_grade_a.png" imageanchor="1" style="clear: right; float: right; margin-bottom: 1em; margin-left: 1em;"><img alt="Software Package Grade A" border="0" height="200" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEidU3-i8V00kQLrwKyaMUYcI6gH-Ge6YMaYZLrE7kWSDry2Yg4cmaipA_rl47UOPGVztaVuCXpHrk9qLb6QxKOmW6oTR5Seo-xfdb-aOBnuVgMw7IDMHE3rESxKjvKnGnZn2R_CsK5BQLU/s200/software_pkg_grade_a.png" title="Software Package Grade A" width="200" /></a></span></div>
<br />
<span style="font-family: Arial, Helvetica, sans-serif; font-size: large;"><br /></span>
<div style="text-align: justify;">
<span style="font-family: Arial, Helvetica, sans-serif; font-size: large;">Supongamos que ese “sello” es una normativa obligada en SoftTopia, por tanto, ningún software puede ser liberado sin esta información.</span></div>
<span style="font-family: Arial, Helvetica, sans-serif; font-size: large;"><br /></span>
<h4>
<span style="font-family: Arial, Helvetica, sans-serif; font-size: large;"><i>Caso A</i></span></h4>
<div style="text-align: justify;">
<span style="font-family: Arial, Helvetica, sans-serif; font-size: large;">SoftTopia implemento esa normativa desde la creación del primer paquete de software pues ellos ya tenían una cultura orientada a la calidad cuando los alcanzo la revolución tecnológica.</span></div>
<span style="font-family: Arial, Helvetica, sans-serif; font-size: large;"><br /></span>
<h4>
<span style="font-family: Arial, Helvetica, sans-serif; font-size: large;"><i>Caso B (nuestro)</i></span></h4>
<div style="text-align: justify;">
<span style="font-family: Arial, Helvetica, sans-serif; font-size: large;">El primer programa de computadoras en SoftTopia fue creado en los 1840s. 175 años después, y con millones de productos de software en uso, los líderes de SoftTopia lanzan la normativa de calidad. SoftTopia es una sociedad de libre comercio, así que solo exigen que la etiqueta de calidad este presente, pero son los clientes quienes deciden cual software comprar y utilizar. Sin embargo, algunas industrias son reguladas por su impacto en los procesos sociales, algunas de esas son: el sector salud, hidrocarburos, gobierno, producción de alimentos, transporte público, aviación civil e instituciones de defensa.</span></div>
<span style="font-family: Arial, Helvetica, sans-serif; font-size: large;"><br /></span>
<h4 style="text-align: justify;">
<span style="font-family: Arial, Helvetica, sans-serif; font-size: large;"><b>¿Que pasara luego?</b></span></h4>
<div style="text-align: justify;">
</div>
<ul>
<li><span style="font-family: Arial, Helvetica, sans-serif; font-size: large;">¿Qué harán los profesionales y empresas de desarrollo de software que no puedan crear productos con un nivel de calidad aceptable para el cliente regular?</span></li>
<li><span style="font-family: Arial, Helvetica, sans-serif; font-size: large;">¿Cómo manejara una empresa del estado al darse cuenta que casi todos sus suplidores entregan paquetes de software con una calidad por debajo de la exigida por la nueva regulación? </span></li>
<li><span style="font-family: Arial, Helvetica, sans-serif; font-size: large;">¿Qué harán las empresas privadas cuando sus clientes se den cuenta que un gran porcentaje de sus costos operativos son causados por los costos de mantenimiento de software sin calidad?</span></li>
<li><span style="font-family: Arial, Helvetica, sans-serif; font-size: large;">¿Cómo venderán sus programas de clases las universidades e instituciones de formación para ingenieros de software al darse cuenta de que sus egresados no están capacitados para cumplir la nueva normativa?</span></li>
</ul>
<br />
<div style="text-align: justify;">
<span style="font-family: Arial, Helvetica, sans-serif; font-size: large;"><br /></span></div>
<h4 style="text-align: justify;">
<span style="font-family: Arial, Helvetica, sans-serif; font-size: large;"><b>Rompamos ahora el cuento de SoftTopia</b></span></h4>
<div style="text-align: justify;">
<span style="font-family: Arial, Helvetica, sans-serif; font-size: large;">Si poco a poco, los propios profesionales del software y las empresas del sector empezaran a publicar, voluntariamente, el nivel de calidad interno de sus productos: <b><i>¿Seria esto profesionalismo o suicidio?</i></b> </span></div>
<div style="text-align: justify;">
<span style="font-family: Arial, Helvetica, sans-serif; font-size: large;"><br /></span></div>
<div style="text-align: justify;">
<span style="font-family: Arial, Helvetica, sans-serif; font-size: large;">¿Qué piensas? …</span></div>
<div>
<br /></div>
Anonymoushttp://www.blogger.com/profile/12292838726080618300noreply@blogger.com1tag:blogger.com,1999:blog-8113723708012951738.post-45533961005782221112016-06-05T08:00:00.001-04:002016-06-05T08:00:00.959-04:00Top Secret: Source Code or Underwear<h4>
<span style="font-family: "arial" , "helvetica" , sans-serif; font-size: large;">Questions</span></h4>
<b><i><span style="font-family: "arial" , "helvetica" , sans-serif; font-size: large;">Why after going to a coding dojo developers are reluctant to share their code in public (GitHub</span><span style="font-family: "arial" , "helvetica" , sans-serif; font-size: large;"> or similar)?</span></i></b><br />
<b><i><span style="font-family: "arial" , "helvetica" , sans-serif; font-size: large;"><br /></span><span style="font-family: "arial" , "helvetica" , sans-serif; font-size: large;">Is our coding style so secret that we can not share it?</span></i></b><br />
<b><i><span style="font-family: "arial" , "helvetica" , sans-serif; font-size: large;"><br /></span><span style="font-family: "arial" , "helvetica" , sans-serif; font-size: large;">It will be embarrassing if someone look at your unfinished and full of mistakes practice material?</span></i></b><br />
<b><i><span style="font-family: "arial" , "helvetica" , sans-serif; font-size: large;"><br /></span><span style="font-family: "arial" , "helvetica" , sans-serif; font-size: large;">Are we only allowed to produce "perfect" code?</span></i></b><br />
<b><i><span style="font-family: "arial" , "helvetica" , sans-serif; font-size: large;"><br /></span><span style="font-family: "arial" , "helvetica" , sans-serif; font-size: large;">Is your code as your underwear? </span></i></b><br />
<span style="font-family: "arial" , "helvetica" , sans-serif; font-size: large;"><b><i><br /></i></b></span><b><i><span style="font-family: "arial" , "helvetica" , sans-serif; font-size: large;"></span></i></b>
<br />
<div class="separator" style="clear: both; text-align: center;">
<b><i><span style="font-family: "arial" , "helvetica" , sans-serif; font-size: large;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhJIbSNWWCRuUJVX4-Vrc72HNg3AKUHFgztA3-yk3yqPLhf8Ejtx0zh0bw6MbIrZf58lSm_cGpjStr2fa-SY8g6YTMQXJ0np5MhmJHOVwmK5B1VS4n-_UCD1YmsqI5YtirykuRbFsT4eqg/s1600/underwear.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhJIbSNWWCRuUJVX4-Vrc72HNg3AKUHFgztA3-yk3yqPLhf8Ejtx0zh0bw6MbIrZf58lSm_cGpjStr2fa-SY8g6YTMQXJ0np5MhmJHOVwmK5B1VS4n-_UCD1YmsqI5YtirykuRbFsT4eqg/s1600/underwear.png" /></a></span></i></b></div>
<br />
<span style="font-family: "arial" , "helvetica" , sans-serif; font-size: large;"><br /></span>
<span style="font-family: "arial" , "helvetica" , sans-serif; font-size: large;">I don't know the answers to any of these questions, but if you do please comment about: <b><i>What blocks you from showing your, practice, code in a public repository?</i></b></span>Anonymoushttp://www.blogger.com/profile/12292838726080618300noreply@blogger.com0tag:blogger.com,1999:blog-8113723708012951738.post-66895941695941288812016-06-05T08:00:00.000-04:002016-06-05T08:00:17.626-04:00Ultra secreto: Código Fuente o Ropa interior<h4>
<span style="font-family: "arial" , "helvetica" , sans-serif; font-size: large;">Preguntas</span></h4>
<span style="font-family: "arial" , "helvetica" , sans-serif; font-size: large;"><b><i>¿Por qué luego de asistir a un coding dojo, los desarrolladores se reúsan a compartir su código en público (GitHub o similar)?</i></b></span><br />
<span style="font-family: "arial" , "helvetica" , sans-serif; font-size: large;"><b><i><br /></i></b></span>
<span style="font-family: "arial" , "helvetica" , sans-serif; font-size: large;"><b><i>¿Es nuestro estilo de codificación tan secreto que no lo podemos compartir?</i></b></span><br />
<span style="font-family: "arial" , "helvetica" , sans-serif; font-size: large;"><b><i><br /></i></b></span>
<span style="font-family: "arial" , "helvetica" , sans-serif; font-size: large;"><b><i>¿Sería vergonzoso si alguien mirara nuestro material de practica sin terminar y lleno de errores?</i></b></span><br />
<span style="font-family: "arial" , "helvetica" , sans-serif; font-size: large;"><b><i><br /></i></b></span>
<span style="font-family: "arial" , "helvetica" , sans-serif; font-size: large;"><b><i>¿Solo se nos permite producir código “perfecto”?</i></b></span><br />
<span style="font-family: "arial" , "helvetica" , sans-serif; font-size: large;"><b><i><br /></i></b></span>
<span style="font-family: "arial" , "helvetica" , sans-serif; font-size: large;"><b><i>¿Es tu código como tu ropa interior?</i></b></span><br />
<span style="font-family: "arial" , "helvetica" , sans-serif; font-size: large;"><b><i><br /></i></b></span>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEipFs0fyH-42ZaDc1SZ3Ik8hlGxFzXMiEAZdFjjdCPxWv4fp8aauZphfXG-rE_5N417Gm9eS_K4n_hbHjsfil18-bI5tP-uRm04_UqTmLmv3bNQkH4F3BzZckrhMBApPvCPIi8wjAm92mY/s1600/underwear.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEipFs0fyH-42ZaDc1SZ3Ik8hlGxFzXMiEAZdFjjdCPxWv4fp8aauZphfXG-rE_5N417Gm9eS_K4n_hbHjsfil18-bI5tP-uRm04_UqTmLmv3bNQkH4F3BzZckrhMBApPvCPIi8wjAm92mY/s1600/underwear.png" /></a></div>
<span style="font-family: "arial" , "helvetica" , sans-serif; font-size: large;"><br /></span>
<span style="font-family: "arial" , "helvetica" , sans-serif; font-size: large;">No conozco las respuestas a esas preguntas, pero si usted por favor comente al respecto: <b><i>¿Qué te impide mostrar tu código de practica en un repositorio público?</i></b></span><br />
<div>
<br /></div>
Anonymoushttp://www.blogger.com/profile/12292838726080618300noreply@blogger.com0tag:blogger.com,1999:blog-8113723708012951738.post-66267763644043395982016-06-04T22:35:00.000-04:002016-06-04T22:39:45.020-04:00Ideas Locas<span style="font-family: "arial" , "helvetica" , sans-serif;"><b><span style="font-size: x-large;">I</span></b><span style="font-size: large;">magina que </span><i style="font-size: x-large;">los Dioses del Código te dieron una varita </i></span><br />
<div class="separator" style="clear: both; text-align: center;">
<span style="font-family: "arial" , "helvetica" , sans-serif;"><i style="font-size: x-large;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi3mPX-8qDbzPULKRYp4YyQ1lEulX2Dp0754xVh9JnF7nI5m1Z3UAqN__0AYho_jBjdl78SyX1PJ0_oVPP0SMrzgZoQ-qj6CDsazhFiyahbEUwlYWLcZffq_OE-6BKKs8J_Y9clsd32axM/s1600/resources-wizard.png" imageanchor="1" style="clear: right; float: right; margin-bottom: 1em; margin-left: 1em;"><img alt="Varita mágica" border="0" height="200" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi3mPX-8qDbzPULKRYp4YyQ1lEulX2Dp0754xVh9JnF7nI5m1Z3UAqN__0AYho_jBjdl78SyX1PJ0_oVPP0SMrzgZoQ-qj6CDsazhFiyahbEUwlYWLcZffq_OE-6BKKs8J_Y9clsd32axM/s200/resources-wizard.png" title="Varita mágica" width="200" /></a></i></span></div>
<span style="font-family: "arial" , "helvetica" , sans-serif;"><i style="font-size: x-large;">mágica<b>*</b></i><span style="font-size: large;">. Esta impresionante herramienta te permite analizar, instantáneamente, una base de código y darle una puntación de </span></span><span style="font-family: "courier new" , "courier" , monospace; font-size: large;">0</span><span style="font-family: "arial" , "helvetica" , sans-serif; font-size: large;"> a </span><span style="font-family: "courier new" , "courier" , monospace; font-size: large;">10</span><span style="font-family: "arial" , "helvetica" , sans-serif; font-size: large;"> acerca de su mantenibilidad; donde cero (</span><span style="font-family: "courier new" , "courier" , monospace; font-size: large;">0</span><span style="font-family: "arial" , "helvetica" , sans-serif; font-size: large;">) significa imposible de cambiar y diez (</span><span style="font-family: "courier new" , "courier" , monospace; font-size: large;">10</span><span style="font-family: "arial" , "helvetica" , sans-serif; font-size: large;">) realmente fácil de cambiar.</span><br />
<span style="font-family: "arial" , "helvetica" , sans-serif; font-size: large;"><br /></span>
<span style="font-family: "arial" , "helvetica" , sans-serif; font-size: large;">De repente, recibes tres propuestas de consultorías de clientes distintos (A, B y C). Ellos te están requiriendo la implementación de nuevas funcionalidades en su producto principal. Utilizando tu varita mágica determinas que:</span><br />
<br />
<ul>
<li><span style="font-family: "arial" , "helvetica" , sans-serif; font-size: large;"><b>El Producto A</b> tiene un índice de mantenibilidad de </span><span style="font-family: "courier new" , "courier" , monospace; font-size: large;"><b>6</b></span><span style="font-family: "arial" , "helvetica" , sans-serif; font-size: large;">,</span></li>
<li><span style="font-family: "arial" , "helvetica" , sans-serif; font-size: large;"><b>El Producto B</b> tiene uno de </span><span style="font-family: "courier new" , "courier" , monospace; font-size: large;"><b>1.5</b></span><span style="font-family: "arial" , "helvetica" , sans-serif; font-size: large;">, y</span></li>
<li><span style="font-family: "arial" , "helvetica" , sans-serif; font-size: large;"><b>El Producto C</b> tiene un índice de mantenibilidad de </span><span style="font-family: "courier new" , "courier" , monospace; font-size: large;"><b>9</b></span></li>
</ul>
<span style="font-family: "arial" , "helvetica" , sans-serif; font-size: large;"><br /></span>
<span style="font-family: "arial" , "helvetica" , sans-serif; font-size: large;">Tus clientes potenciales te aclaran que sus respectivos productos son de misión critica y que el impacto de introducir nuevos defectos podría ser catastrófico. Por tanto, ellos van a transferir ese riesgo a ti: cualquier defecto encontrado durante un periodo de validación de dos meses deberá ser resuelto lo antes posible y sin costo alguno.</span><br />
<span style="font-family: "arial" , "helvetica" , sans-serif; font-size: large;"><br /></span>
<span style="font-family: "arial" , "helvetica" , sans-serif; font-size: large;">Asumiendo una estrategia de precios X (basada en tiempo, basada en esfuerzo, etc.), ¿podríamos</span><br />
<ul>
<li><span style="font-family: "arial" , "helvetica" , sans-serif; font-size: large;">Cobrarle al Cliente C la tarifa regular?</span></li>
<li><span style="font-family: "arial" , "helvetica" , sans-serif; font-size: large;">Cobrarle al Cliente A la tarifa regular ajustada (multiplicada) por algún factor basado en el riesgo (<i>inversamente proporcional al índice de mantenibilidad</i>)?</span></li>
<li><span style="font-family: "arial" , "helvetica" , sans-serif; font-size: large;"><i>Simplemente descartar el Cliente B y evitar el riesgo?</i></span></li>
</ul>
<span style="font-family: arial, helvetica, sans-serif; font-size: large;"><i><br /></i></span>
<h4>
<span style="font-family: "arial" , "helvetica" , sans-serif; font-size: large;">¿Me sigues?</span></h4>
<ul>
<li><span style="font-family: "arial" , "helvetica" , sans-serif; font-size: large;">¿Podríamos educar a nuestros clientes utilizando una estrategia de precios la cual refleje directamente el nivel de riesgo y esfuerzo que debamos asumir al trabajar con productos de software desordenados (baja mantenibilidad)?</span></li>
<li><span style="font-family: "arial" , "helvetica" , sans-serif; font-size: large;">Con el tiempo, y algunas experiencias duras, ¿Estarán nuestros clientes más vigilantes acerca de la calidad de su base de código, y tal vez comiencen a requerir mayor calidad a todos los desarrolladores, tanto a lo interno como fuera de su organización?</span></li>
</ul>
<span style="font-family: "arial" , "helvetica" , sans-serif;"><br /></span>
<span style="font-family: "arial" , "helvetica" , sans-serif;"><b><i>*</i></b> No esperes a los Dioses, puedes utilizar <a href="http://www.sonarqube.org/" target="_blank">SonarQube</a>, <a href="https://pmd.github.io/" target="_blank">PMD</a>, <a href="https://www.jetbrains.com/resharper/" target="_blank">ReSharper</a>, <a href="http://checkstyle.sourceforge.net/" target="_blank">Checkstyle</a>, y muchas otras.</span>Anonymoushttp://www.blogger.com/profile/12292838726080618300noreply@blogger.com0tag:blogger.com,1999:blog-8113723708012951738.post-70949986578713952522016-05-29T08:00:00.001-04:002016-05-29T08:00:30.008-04:00Otra razón para hacer Pair Programming<span style="font-family: "arial" , "helvetica" , sans-serif; font-size: large;">Unas semanas atrás nosotros (el equipo de desarrollo) estábamos pagando un poco de deuda técnica, antes de iniciar la sesión de codificación hicimos una pequeña reunión de planificación. Durante la reunión, les comunique a mis compañeros que realizaríamos las mejoras (refactoring) en parejas (pair programming).</span><br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiz0Q773Ps0zMOxcqC-WvmI-4B6RATibstPNBfwTIGM3UCdcvWSUUErFGpH9hX4-zqPgetvTXtpcvCHnQPozdx58Exx4DoIhXXYxJQUQ8f7wcYEW_27mhXMRSitEyVXKQiJvVCcZgioxsE/s1600/clean-311681_960_720.png" imageanchor="1" style="clear: right; float: right; margin-bottom: 1em; margin-left: 1em;"><img border="0" height="320" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiz0Q773Ps0zMOxcqC-WvmI-4B6RATibstPNBfwTIGM3UCdcvWSUUErFGpH9hX4-zqPgetvTXtpcvCHnQPozdx58Exx4DoIhXXYxJQUQ8f7wcYEW_27mhXMRSitEyVXKQiJvVCcZgioxsE/s320/clean-311681_960_720.png" width="265" /></a></div>
<span style="font-family: "arial" , "helvetica" , sans-serif; font-size: large;"><br /></span>
<span style="font-family: "arial" , "helvetica" , sans-serif; font-size: large;">Yo asigné las parejas y establecí un sistema de dos (2) rondas, durante cada ronda una pareja debía completar una tarea por cada integrante (desarrollador). Luego las parejas debían cambiar (de integrantes). Al final de la segunda ronda si algún desarrollador tenia trabajo pendiente, el (si todos hombres, aburrido), debería completar su trabajo trabajando solo. De esa manera durante el día de trabajo cada quien trabajaría con dos compañeros.</span><br />
<span style="font-family: "arial" , "helvetica" , sans-serif; font-size: large;"><br /></span>
<span style="font-family: "arial" , "helvetica" , sans-serif; font-size: large;">Luego de mie explicación de dos o tres minutos, alguien pregunto:</span><br />
<span style="font-family: "arial" , "helvetica" , sans-serif; font-size: large;"><b><i>- ¿Por qué debemos hacer pair programming?</i></b></span><br />
<span style="font-family: "arial" , "helvetica" , sans-serif; font-size: large;">- Porque quiero forzar la nivelación y transferencia de conocimientos, contesté</span><br />
<span style="font-family: "arial" , "helvetica" , sans-serif; font-size: large;"><br /></span>
<span style="font-family: "arial" , "helvetica" , sans-serif; font-size: large;">Esa pregunta se quedó en mi cabeza todo el día, primero porque para mí era tan obvia la respuesta y también porque había muchas otras razones: </span><br />
<br />
<ul>
<li><span style="font-family: "arial" , "helvetica" , sans-serif; font-size: large;">Aprender trucos del IDE</span></li>
<li><span style="font-family: "arial" , "helvetica" , sans-serif; font-size: large;">Doble chequeo de refactoring (complejo y con posibilidad de introducir errores)</span></li>
<li><span style="font-family: "arial" , "helvetica" , sans-serif; font-size: large;">Formación de lazos: el sentido de que estamos arreglando “nuestro” trabajo, no solo tratando con mi propia basura privada tirada en algún momento pasado</span></li>
<li><span style="font-family: "arial" , "helvetica" , sans-serif; font-size: large;">Etc.</span></li>
</ul>
<br />
<span style="font-family: "arial" , "helvetica" , sans-serif; font-size: large;"><br /></span>
<br />
<h4>
<span style="font-family: "arial" , "helvetica" , sans-serif; font-size: large;">Resultados y Ventajas</span></h4>
<br />
<ul>
<li><span style="font-family: "arial" , "helvetica" , sans-serif; font-size: large;">Pudimos reducir las violaciones reportadas por la herramienta de calidad en un 17%</span></li>
<li><span style="font-family: "arial" , "helvetica" , sans-serif; font-size: large;">En el proceso aprendimos nuevos trucos del IDE de los compañeros, o los descubrimos por vagancia (tratando de cambiar más código en menos tiempo)</span></li>
<li><span style="font-family: "arial" , "helvetica" , sans-serif; font-size: large;">Mejoramos archivos HTML al remover atributos no necesarios o elementos deprecados (por la especificación de HTML5)</span></li>
<li><span style="font-family: "arial" , "helvetica" , sans-serif; font-size: large;">Discutimos el por qué las violaciones, seleccionadas manualmente, para solucionar eran importantes y como podrían afectarnos en el futuro</span></li>
<li><span style="font-family: "arial" , "helvetica" , sans-serif; font-size: large;">Al final de la sesión todos acordamos en apartar un día de cada Sprint para pagar la deuda técnica vieja</span></li>
<li><span style="font-family: "arial" , "helvetica" , sans-serif; font-size: large;">Ahora todos estamos más vigilantes, durante las revisiones de código, ante nuevas violaciones a los estándares de codificación </span></li>
</ul>
<br />
<span style="font-family: "arial" , "helvetica" , sans-serif; font-size: large;"><br /></span>
<br />
<h4>
<span style="font-family: "arial" , "helvetica" , sans-serif; font-size: large;">Desventajas</span></h4>
<br />
<ul>
<li><span style="font-family: "arial" , "helvetica" , sans-serif; font-size: large;">Gran parte del tiempo lo gastamos en tareas tediosas y manuales</span></li>
<li><span style="font-family: "arial" , "helvetica" , sans-serif; font-size: large;">Para las 3 pm todos estábamos extenuados</span></li>
<li><span style="font-family: "arial" , "helvetica" , sans-serif; font-size: large;">Conflictos de sincronización: por el hecho de haber distribuido las “violaciones” por tipo, y no por archivo o clase, hubo una alta tasa de conflictos</span></li>
</ul>
<br />
<span style="font-family: "arial" , "helvetica" , sans-serif; font-size: large;"><br /></span>
<br />
<h4>
<span style="font-family: "arial" , "helvetica" , sans-serif; font-size: large;">Retrospectiva</span></h4>
<span style="font-family: "arial" , "helvetica" , sans-serif; font-size: large;">Puede ser mejor asignar el trabajo por archivo, o grupos de archivos. Así solo ocurrirán conflictos cuando la interfaz publica (de las clases) cambie.</span><br />
<span style="font-family: "arial" , "helvetica" , sans-serif; font-size: large;"><br /></span>
<span style="font-family: "arial" , "helvetica" , sans-serif; font-size: large;">También, una sesión de limpieza de código realizada por archivo o clase no es tan aburrida pues se manejan diferentes tipos de violaciones.</span>Anonymoushttp://www.blogger.com/profile/12292838726080618300noreply@blogger.com0tag:blogger.com,1999:blog-8113723708012951738.post-69628307185867479242016-05-29T08:00:00.000-04:002016-05-29T08:00:00.178-04:00Another reason for Pair Programming<span style="font-family: "arial" , "helvetica" , sans-serif; font-size: large;">Some weeks ago we ( the development team) were paying some technical debt, before the coding session we did some planning. While in the short planning meeting I told to my team mates that we'll be doing our refactoring in pairs (pair programming).</span><br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiEG9k5D_ojm3RjqMejpz-_ICDyCELP0ZUAE1N8lDB8E4bD3JCT7tUGkZXecUnYGzCIvRZt0dPOVNwmHNO32SN8V-o0zVDAFkfT4A17Loc_9qMS3_Ct3EGW9eDNws-adZphY3dh69AugEk/s1600/clean-311681_960_720.png" imageanchor="1" style="clear: right; float: right; margin-bottom: 1em; margin-left: 1em;"><img alt="Cleaner Developer" border="0" height="320" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiEG9k5D_ojm3RjqMejpz-_ICDyCELP0ZUAE1N8lDB8E4bD3JCT7tUGkZXecUnYGzCIvRZt0dPOVNwmHNO32SN8V-o0zVDAFkfT4A17Loc_9qMS3_Ct3EGW9eDNws-adZphY3dh69AugEk/s320/clean-311681_960_720.png" title="" width="265" /></a></div>
<span style="font-family: "arial" , "helvetica" , sans-serif; font-size: large;"><br /></span>
<span style="font-family: "arial" , "helvetica" , sans-serif; font-size: large;">I assigned the pairs and established two rounds, during each round a pair need to complete only one task per developer. Then pairs must switch. At the end of the second round if any developer had pending work he (yes all boys, boring), must complete it alone. That way during the day everyone get to work with two partners.</span><br />
<span style="font-family: "arial" , "helvetica" , sans-serif; font-size: large;"><br /></span>
<span style="font-family: "arial" , "helvetica" , sans-serif; font-size: large;">After my 2 to 3 minutes explanation someone asked: </span><br />
<b><i><span style="font-family: "arial" , "helvetica" , sans-serif; font-size: large;">- Why don we need to do pair programming?</span></i></b><br />
<span style="font-family: "arial" , "helvetica" , sans-serif; font-size: large;">- Because I want to force some knowledge transfer level, I said</span><br />
<span style="font-family: "arial" , "helvetica" , sans-serif; font-size: large;"><br /></span>
<span style="font-family: "arial" , "helvetica" , sans-serif; font-size: large;">That question got stuck in my head the hole day, first because for me the answer was so obvious and also because there were so many other reasons like:</span><br />
<br />
<ul>
<li><span style="font-family: "arial" , "helvetica" , sans-serif; font-size: large;">To learn IDE tricks</span></li>
<li><span style="font-family: "arial" , "helvetica" , sans-serif; font-size: large;">Double checking of (complex, and error prone) refactoring</span></li>
<li><span style="font-family: "arial" , "helvetica" , sans-serif; font-size: large;">Bounding: the sense that we are fixing "our" work, not just dealing with private garbage let by me</span></li>
<li><span style="font-family: "arial" , "helvetica" , sans-serif; font-size: large;">Etc.</span></li>
</ul>
<span style="font-family: "arial" , "helvetica" , sans-serif; font-size: large;"><br /></span>
<br />
<h4>
<span style="font-family: "arial" , "helvetica" , sans-serif; font-size: large;">Results & Pros</span></h4>
<div>
<ul>
<li><span style="font-family: "arial" , "helvetica" , sans-serif; font-size: large;">We manage to reduce the issues reported by our code quality tool by 17%</span></li>
<li><span style="font-family: "arial" , "helvetica" , sans-serif; font-size: large;">In the process we learned new IDE tricks from peers, or discovered by laziness (trying to change more code in less time)</span></li>
<li><span style="font-family: "arial" , "helvetica" , sans-serif; font-size: large;">We improve HTML files by removing unnecessary attributes or deprecated elements (by HTML5 spec)</span></li>
<li><span style="font-family: "arial" , "helvetica" , sans-serif; font-size: large;">We discuss why the, cherry-picked, list of violations to fix were important and how they could affect us in the future</span></li>
<li><span style="font-family: "arial" , "helvetica" , sans-serif; font-size: large;">By the end of the session we all agree to set apart one day of each sprint to paid old technical debt</span></li>
<li><span style="font-family: "arial" , "helvetica" , sans-serif; font-size: large;">Now everyone is more vigilant, during code reviews, for newly introduced violations to coding standards</span></li>
</ul>
<span style="font-family: "arial" , "helvetica" , sans-serif; font-size: large;"><br /></span>
<br />
<h4>
<span style="font-family: "arial" , "helvetica" , sans-serif; font-size: large;">Cons</span></h4>
</div>
<div>
<ul>
<li><span style="font-family: "arial" , "helvetica" , sans-serif; font-size: large;">Most of the time it was tedious manual labor</span></li>
<li><span style="font-family: "arial" , "helvetica" , sans-serif; font-size: large;">Around 3 pm everyone was exhausted</span></li>
<li><span style="font-family: "arial" , "helvetica" , sans-serif; font-size: large;">Merge conflicts: because I distributed "violations" by type, not by, physical, file or class there was a high frequency of conflicts</span></li>
</ul>
<span style="font-family: "arial" , "helvetica" , sans-serif; font-size: large;"><br /></span>
<br />
<h4>
<span style="font-family: "arial" , "helvetica" , sans-serif; font-size: large;">Retrospective</span></h4>
</div>
<div>
<span style="font-family: "arial" , "helvetica" , sans-serif; font-size: large;">Maybe it is better to assign work by file, or groups of files. That way the conflicts will only occur when public interfaces get touch.</span></div>
<div>
<span style="font-family: "arial" , "helvetica" , sans-serif; font-size: large;"><br /></span></div>
<div>
<span style="font-family: "arial" , "helvetica" , sans-serif; font-size: large;">Also, a per class / file cleaning session is not so boring because you get to handle different kinds of violations.</span></div>
Anonymoushttp://www.blogger.com/profile/12292838726080618300noreply@blogger.com0tag:blogger.com,1999:blog-8113723708012951738.post-83981626883303781612016-05-22T23:55:00.000-04:002016-05-28T22:21:14.876-04:00Canned Software<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg2gPuMpe5owUnSLa1FqCkzRWoZK7IzdkHuLPLM5-aJp2Ou2hLSgEdNuHuK4I8ma8ESFOExlDpwP1dUIPtU1gV7Uzv3ZydhxwkibK92av1LCOOcg1tVD2z80igR0Y8erBKZ229run-vKfE/s1600/canned_food.png" imageanchor="1" style="clear: right; float: right; margin-bottom: 1em; margin-left: 1em;"><span style="font-family: "arial" , "helvetica" , sans-serif; font-size: large;"><img border="0" height="200" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg2gPuMpe5owUnSLa1FqCkzRWoZK7IzdkHuLPLM5-aJp2Ou2hLSgEdNuHuK4I8ma8ESFOExlDpwP1dUIPtU1gV7Uzv3ZydhxwkibK92av1LCOOcg1tVD2z80igR0Y8erBKZ229run-vKfE/s200/canned_food.png" width="123" /></span></a><span style="font-family: "arial" , "helvetica" , sans-serif; font-size: large;">It’s the day you go shopping (groceries), you go to your preferred supermarket and start your routine. You take all fresh goods, and then head to the canned ones. Your children love canned chicken soup; you know it’s not as healthy as the home-made version, but you use it as a prize for good behavior.</span><br />
<span style="font-family: "arial" , "helvetica" , sans-serif; font-size: large;"><br /></span>
<span style="font-family: "arial" , "helvetica" , sans-serif; font-size: large;">They take a two-week supply and gave it for you to put all the cans in the shopping cart. You, as a responsible parent, inspect the cans one by one, looking for defects and the most important fact: the expiration date. You realize that all cans have the same taste, but they are from different brands. Some already had expired (last year!), some will expire in about a month, and finally you see a group of units with an expiration date about one year in the future. As everyone expects, you pick the last group (is always good to have some canned food if a zombie apocalypse occurs).</span><br />
<span style="font-family: "arial" , "helvetica" , sans-serif; font-size: large;"><br /></span>
<span style="font-family: "arial" , "helvetica" , sans-serif; font-size: large;">Now imagine, just for a moment, that instead of canned chicken soup, <u>you went to shop canned software</u>. And that software will be used to run your business, your brand new car, your home fire detection system, or something as delicate as a life support medical machine. </span><br />
<span style="font-family: "arial" , "helvetica" , sans-serif; font-size: large;"><br /></span>
<span style="font-family: "arial" , "helvetica" , sans-serif; font-size: large;">Continuing with this history, imagine that instead of an expiration date the software cans are labeled with two important information: what they do (functionalities) or ingredients if they were chicken soup; and what is the expected date when that software will no longer be maintained by its creators (expiration date). That last piece of information talks about the internal quality of the software. It says to you: How easy can this software be extended or fixed. Going back to the chicken soup if we have:</span><br />
<table cellpadding="0" cellspacing="0" class="tr-caption-container" style="float: right; margin-left: 1em; text-align: right;"><tbody>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh71zfCazFB0RYRpmZHosw9_7GT1yQs-Huo3gm1C7WKh7kWBCGJxm1jMl8x2fvrM2ySlrEjfqLbt8I4qLcLRJIkHc_UJVXjUISKVB1JtzhCCYGRnH1GpjTEhbF-HiETWoPZk78V-iHTdoA/s1600/canned_food_exp_01.png" imageanchor="1" style="clear: right; margin-bottom: 1em; margin-left: auto; margin-right: auto;"><span style="font-family: "arial" , "helvetica" , sans-serif; font-size: large;"><img alt="Bad Software Can" border="0" height="200" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh71zfCazFB0RYRpmZHosw9_7GT1yQs-Huo3gm1C7WKh7kWBCGJxm1jMl8x2fvrM2ySlrEjfqLbt8I4qLcLRJIkHc_UJVXjUISKVB1JtzhCCYGRnH1GpjTEhbF-HiETWoPZk78V-iHTdoA/s200/canned_food_exp_01.png" title="Bad Software Can" width="123" /></span></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;"><span style="font-family: "arial" , "helvetica" , sans-serif; font-size: large;">Rotten Software Can</span></td></tr>
</tbody></table>
<br />
<ul><span style="font-family: "arial" , "helvetica" , sans-serif; font-size: large;">
<li>A can of software (soup) with a past Expiration Date: that means that is not possible for the team working behind that software to fix, add, or change features because the product is a total mess (internally).</li>
<li>A can of software (soup) with an Expiration Date in the near future: this is a software system (project) that is already dying. Its internal quality is reaching the no return point. In a matter of month this system will no longer be maintainable by its team.</li>
<li>A can of software (soup) with an Expiration Date so distant that nobody can really say when it will happen: this system is the most reliable, extensible, less risky one. </li>
</span></ul>
<br />
<table cellpadding="0" cellspacing="0" class="tr-caption-container" style="float: right; text-align: right;"><tbody>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg9GF3m6EAWez6rYJyYhYr741OuC1IP5tCtwT6WMlKEHL0J24stgEboeGLxIdaOe_vLmNC0Wvjcjjov_7RQl115XmjkKrvXXZw9c3stthKLSiaoRt-taGNQxZT1gmtnrr7KOgsSfbePuz4/s1600/canned_food_exp_02.png" imageanchor="1" style="clear: right; display: inline !important; margin-bottom: 1em; margin-left: auto; margin-right: auto; text-align: center;"><span style="font-family: "arial" , "helvetica" , sans-serif; font-size: large;"><img alt="Good Software Can" border="0" height="200" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg9GF3m6EAWez6rYJyYhYr741OuC1IP5tCtwT6WMlKEHL0J24stgEboeGLxIdaOe_vLmNC0Wvjcjjov_7RQl115XmjkKrvXXZw9c3stthKLSiaoRt-taGNQxZT1gmtnrr7KOgsSfbePuz4/s200/canned_food_exp_02.png" title="Good Software Can" width="123" /></span></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;"><span style="font-family: "arial" , "helvetica" , sans-serif; font-size: large;">Fresh Software Can</span></td></tr>
</tbody></table>
<span style="font-family: "arial" , "helvetica" , sans-serif; font-size: large;">Of course we are assuming that the first quality feature (functional) is the same for the three scenarios. </span><br />
<span style="font-family: "arial" , "helvetica" , sans-serif; font-size: large;"></span><br />
<span style="font-family: "arial" , "helvetica" , sans-serif; font-size: large;"></span>
<span style="font-family: "arial" , "helvetica" , sans-serif; font-size: large;">The second quality feature (<b><i>expiration date</i></b>) is what is commonly called the <b><i>Maintainability Index</i></b>.</span><br />
<span style="font-family: "arial" , "helvetica" , sans-serif; font-size: large;"></span><br />
<span style="font-family: "arial" , "helvetica" , sans-serif; font-size: large;"></span>
<span style="font-family: "arial" , "helvetica" , sans-serif; font-size: large;"><i>So, please, the next time you need to buy a software system, check its expiration date, you don’t want to poison your business, home, car, or children.</i></span><br />
<span style="font-family: "arial" , "helvetica" , sans-serif; font-size: large;"><i><br /></i></span>
<br />
<h4>
<span style="font-family: "arial" , "helvetica" , sans-serif; font-size: large;">Maintainability Index: opinions and usefulness</span></h4>
<div>
<span style="font-family: "arial" , "helvetica" , sans-serif; font-size: large;">The usage of this metric is not universally accepted in the software industry. For example checkout <a href="https://avandeursen.com/2014/08/29/think-twice-before-using-the-maintainability-index/" target="_blank">(van Deursen 2014) Think Twice Before Using the "Maintainability Index"</a>, where the author exposes why he is not quite sure if the metric should be used. </span></div>
<div>
<span style="font-family: "arial" , "helvetica" , sans-serif; font-size: large;"><br /></span></div>
<div>
<span style="font-family: "arial" , "helvetica" , sans-serif; font-size: large;">The main concern is about the reference data (base-line) used to measure software systems. The maintainability index can be considered a relative metric. Is a common practice for software laboratories to test systems (for its internal quality properties), and use that data so build a ranking. If the baseline does not represent the universe of software products relevant for the subject of the analysis the output is not very useful.</span></div>
<div>
<span style="font-family: "arial" , "helvetica" , sans-serif; font-size: large;"><br /></span></div>
<div>
<span style="font-family: "arial" , "helvetica" , sans-serif; font-size: large;">Thankfully, labs like the <a href="https://www.sig.eu/" target="_blank">Software Improvement Group (SGI)</a> calibrates their base data yearly. </span></div>
Anonymoushttp://www.blogger.com/profile/12292838726080618300noreply@blogger.com0tag:blogger.com,1999:blog-8113723708012951738.post-17571162850514113602016-05-18T23:42:00.004-04:002016-05-28T22:21:04.565-04:00Crazy Ideas <a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjaOpqV8aKA9qUT7bqNqu-lCHEboItORa-oY2jHGQnCezJ3EmSxLkP_SGC35Fo6pldqPuuvfSNdClhsdm8It-istNVCG1G4jaLa4El-fBXxYqCzxw2UY6RIfcmgoBOTCAl877tOeYlL48c/s1600/resources-wizard.png" imageanchor="1" style="clear: right; float: right; margin-bottom: 1em; margin-left: 1em;"><img alt="magic wand" border="0" height="200" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjaOpqV8aKA9qUT7bqNqu-lCHEboItORa-oY2jHGQnCezJ3EmSxLkP_SGC35Fo6pldqPuuvfSNdClhsdm8It-istNVCG1G4jaLa4El-fBXxYqCzxw2UY6RIfcmgoBOTCAl877tOeYlL48c/s200/resources-wizard.png" title="magic wand" width="200" /></a><span style="font-family: "arial" , "helvetica" , sans-serif;"><span style="font-size: x-large;">I</span><span style="font-size: large;">magine</span><span style="font-size: large;"> that <i>the Gods of Code gave you a magic wand<b><span style="font-family: "courier new" , "courier" , monospace;">*</span></b></i>. This impressive tool allows you to instantly analyze a code base and give a score from <span style="font-family: "courier new" , "courier" , monospace;">0</span> to <span style="font-family: "courier new" , "courier" , monospace;">10</span> about its maintainability; where zero (<span style="font-family: "courier new" , "courier" , monospace;">0</span>) means <i>impossible to change</i>, and then (<span style="font-family: "courier new" , "courier" , monospace;">10</span>) <i>really easy to change</i>.</span></span><br />
<span style="font-family: "verdana" , sans-serif;"><br /></span>
<span style="font-family: "arial" , "helvetica" , sans-serif; font-size: large;">Suddenly, you receive three consulting proposals from distinct clients (A, B, and C). They are requesting you to implement some new features in their flag-ship product. <i>Using your magic wand, you determine that:</i></span><br />
<ul>
<li><span style="font-family: "arial" , "helvetica" , sans-serif; font-size: large;"><b>Product A</b> has a maintainability index of <b><span style="font-family: "courier new" , "courier" , monospace;">6</span></b>, </span></li>
<li><span style="font-family: "arial" , "helvetica" , sans-serif; font-size: large;"><b>Product B</b> has one of <b><span style="font-family: "courier new" , "courier" , monospace;">1.5</span></b>, and </span></li>
<li><span style="font-family: "arial" , "helvetica" , sans-serif; font-size: large;"><b>Product C</b> has a maintainability index of <b><span style="font-family: "courier new" , "courier" , monospace;">9</span></b> </span></li>
</ul>
<span style="font-family: "arial" , "helvetica" , sans-serif; font-size: large;"><br /></span>
<span style="font-family: "arial" , "helvetica" , sans-serif; font-size: large;">Your potential clients have stated that their product is mission critical and that the impact of introducing new defects (bugs) to that product can be catastrophic. Because of that they will transfer that risk to you: any new bug found during a two-month certification period need to be fixed ASAP and without any additional payment.</span><br />
<span style="font-family: "verdana" , sans-serif;"><br /></span>
<br />
<h4>
<span style="font-family: "arial" , "helvetica" , sans-serif; font-size: large;">
Assuming a pricing strategy X (time based, effort based, etc.), can we </span></h4>
<ul>
<li><span style="font-family: "arial" , "helvetica" , sans-serif; font-size: large;">Charge Client C the regular rate? </span></li>
<li><span style="font-family: "arial" , "helvetica" , sans-serif; font-size: large;">Charge Client A the regular rate adjusted (multiplied) by some risk based factor (<i>inversely proportional</i> to the maintainability index)? </span></li>
<li><span style="font-family: "arial" , "helvetica" , sans-serif; font-size: large;"><i>Just drop client B and avoid that risk?</i> </span></li>
</ul>
<h4>
<br /><span style="font-family: "arial" , "helvetica" , sans-serif; font-size: large;">Do you get where I’m going? </span></h4>
<ul>
<li><span style="font-family: "arial" , "helvetica" , sans-serif; font-size: large;">Can we educate our customers by using a pricing strategy that directly reflects the level of risk and effort we need to put in order to work with their messy piece of code? </span></li>
<li><span style="font-family: "arial" , "helvetica" , sans-serif; font-size: large;">With time, and some hard experiences, will our customer be more vigilant about the quality of their code base, and maybe start demanding more quality for all developers, inside or outside their organization? </span></li>
</ul>
<span style="font-family: "arial" , "helvetica" , sans-serif;"><br /></span>
<span style="font-family: "arial" , "helvetica" , sans-serif;"><br /></span>
<span style="font-family: "arial" , "helvetica" , sans-serif;"><b><span style="font-family: "courier new" , "courier" , monospace;">*</span></b> Don’t wait for the Gods, you can use <a href="http://www.sonarqube.org/" target="_blank">SonarQube</a>, <a href="https://pmd.github.io/" target="_blank">PMD</a>, <a href="https://www.jetbrains.com/resharper/" target="_blank">ReSharper</a>, <a href="http://checkstyle.sourceforge.net/" target="_blank">Checkstyle</a>, and many others.</span>Anonymoushttp://www.blogger.com/profile/12292838726080618300noreply@blogger.com0tag:blogger.com,1999:blog-8113723708012951738.post-59232814643516024092016-01-31T23:30:00.000-04:002016-05-28T22:20:50.836-04:00SOLID Principles summary for CodeCampSDQ 5.0 attendeesThis is a summary of the SOLID principles to be used as an index by the <b>CodeCampSDQ 5.0 (2016)</b> attendees.<br />
<br />
<h2>
Are you lost?</h2>
<div>
If you don't know what are the SOLID principles, or what is CodeCampSDQ please read the following two sections. If you were an attendee to the event and you are looking for the talk material jump to <b><i>What is SOLID?</i></b> </div>
<div>
<br /></div>
<h3>
What is CodeCampSDQ?</h3>
<div>
In summary (checkout the official site), CodeCampSDQ is</div>
<blockquote class="tr_bq">
Just a group of "idealistic dreamers" who think they can change the world, a CodeCampSDQ at once.</blockquote>
With the following mission (as of this writting)<br />
<blockquote class="tr_bq">
The technical conference CodeCampSDQ tries to educate the community of professional Information Technology (IT) of the Dominican Republic, fostering a spirit of collaboration and sharing of knowledge for our attendees.</blockquote>
The conference official site is <a href="http://codecampsdq.com/" target="_blank"><span style="font-size: large;">http://codecampsdq.com/</span></a> and Facebook page is <a href="https://www.facebook.com/CodeCampSDQ" target="_blank">https://www.facebook.com/CodeCampSDQ</a><br />
<br />
<h3>
Is the 5.0 (2016) a product version?</h3>
No, this means that is the event number five and happens on 2016.<br />
<br />
<br />
<h2>
What is SOLID?</h2>
Is a mnemonic acronym for five basic principles of object-oriented (OO) programming and design. The principles were stated by <b><i><a href="http://blog.cleancoder.com/" target="_blank"><span style="font-size: large;">Uncle Bob (Robert C. Martin)</span></a></i></b> in the early 2000s.<br />
<br />
<b><i><span style="font-size: large;">The initials stand for:</span></i></b><br />
<ul>
<li><span style="font-size: large;"><span style="font-family: "courier new" , "courier" , monospace;"><b>S:</b> </span>Single responsibility principle (SRP)</span></li>
<li><span style="font-size: large;"><span style="font-family: "courier new" , "courier" , monospace;"><b>O:</b> </span>Open/closed principle (OCP)</span></li>
<li><span style="font-size: large;"><span style="font-family: "courier new" , "courier" , monospace;"><b>L:</b> </span>Liskov substitution principle (LSP)</span></li>
<li><span style="font-size: large;"><span style="font-family: "courier new" , "courier" , monospace;"><b>I:</b> </span>Interface segregation principle (ISP)</span></li>
<li><span style="font-size: large;"><span style="font-family: "courier new" , "courier" , monospace;"><b>D:</b> </span>Dependency inversion principle (DIP)</span></li>
</ul>
<br />
<br />
<h2>
Extended version of each principle</h2>
I've done a summary of each principle presented in a problem-solution way. Each post has the following basic structure:<br />
<ul>
<li>Brief description of the principle</li>
<li>A sample code not honoring the principle aka <i>the Dirty version</i> </li>
<li>A rationalization about why the code is violating the principle, along with the proposed solution</li>
<li>The solution presented as <i>the Clean version</i>, and</li>
<li>Finally, and explanation about what is the relation of the principle with Agile Software Development</li>
</ul>
<br />
<div>
<b><i><span style="font-size: large;">This is the list of posts:</span></i></b></div>
<div>
<ul>
<li><a href="http://tales-of-agile-adoption.blogspot.com/2015/12/solid-principles-srp-and-dip-1-of-4.html" target="_blank"><span style="font-size: large;">SOLID Principles: SRP and DIP (1 of 4)</span></a></li>
<li><a href="http://tales-of-agile-adoption.blogspot.com/2016/01/solid-principles-ocp-2-of-4.html" target="_blank"><span style="font-size: large;">SOLID Principles: OCP (2 of 4)</span></a></li>
<li><a href="http://tales-of-agile-adoption.blogspot.com/2016/01/solid-principles-lsp-3-of-4.html" target="_blank"><span style="font-size: large;">SOLID Principles: LSP (3 of 4)</span></a></li>
<li><a href="http://tales-of-agile-adoption.blogspot.com/2016/01/solid-principles-isp-4-of-4.html" target="_blank"><span style="font-size: large;">SOLID Principles: ISP (4 of 4)</span></a></li>
</ul>
Some of them have small UML diagrams to help express the design.</div>
<div>
<br />
<br /></div>
<h2>
Where is the code?</h2>
All code samples used on the four posts are in a single GitHub repo <a href="https://github.com/lsolano/blog.solid.demo" target="_blank"><span style="font-size: large;">lsolano/blog.solid.demo</span></a><br />
<br />
<br />Anonymoushttp://www.blogger.com/profile/12292838726080618300noreply@blogger.com0tag:blogger.com,1999:blog-8113723708012951738.post-72390017460559277862016-01-18T08:16:00.003-04:002016-05-28T22:20:38.755-04:00SOLID Principles: ISP (4 of 4)<h2>
<span style="font-size: small; font-weight: normal;">If you missed the previous post from this series check it out</span><span style="font-size: small; font-weight: normal;"> </span><a href="http://tales-of-agile-adoption.blogspot.com/2016/01/solid-principles-lsp-3-of-4.html" style="font-size: medium; font-weight: normal;" target="_blank">SOLID Principles: LSP (3 of 4).</a></h2>
<h2>
Interface segregation principle: ISP</h2>
<h2>
<div>
<span style="font-size: small;">The principle states that</span></div>
<blockquote class="tr_bq" style="font-weight: normal;">
<span style="font-size: small;">"No client should be forced to depend on methods it does not use."</span></blockquote>
<div style="font-size: medium; font-weight: normal;">
<span style="font-size: small;"><span style="font-weight: normal;">In other words what the principle says is that components should be discrete: if you ask someone its name you don't want to know that he is divorced four times and likes Italian food.</span></span><br />
<span style="font-size: small;"><span style="font-weight: normal;"><br /></span></span>
<span style="font-size: small;"><span style="font-weight: normal;">Imaging you are working with an input mapped to a Camera, the stream of data coming from that source is <i>Read Only</i>, and <i>Non Seekable</i>. You have no way to "write" to the camera feed, or to seek the camera to a specific time; you only get to read or loose the data. But because you are using a general purpose IO framework you end up using an <span style="font-family: "courier new" , "courier" , monospace;">InputSream</span> with <span style="font-family: "courier new" , "courier" , monospace;">reset()</span> and <span style="font-family: "courier new" , "courier" , monospace;">mark() / seek()</span> methods.</span></span><br />
<span style="font-size: small;"><span style="font-weight: normal;"><br /></span></span>
<span style="font-size: small;"><span style="font-weight: normal;">What the ISP says for cases like this, is to split the interface into as many smaller ones as needed by the clients. The division is done looking at the "roles" the initial interface must play. In our case the <span style="font-family: "courier new" , "courier" , monospace;">InputStream</span> is playing a both the Read Only and Non Seekable roles. The first one is implicit by the name prefix "Input", so we don't need to create another one to indicate that is an Read Only stream. But for the second role we need a way to say that our stream does not allows seek operations. So we could split the <span style="font-family: "courier new" , "courier" , monospace;">InputStream</span> in two components: <span style="font-family: "courier new" , "courier" , monospace;">InputStream</span>, and <span style="font-family: "courier new" , "courier" , monospace;">SeekableStream</span>. The first one stays as is, with the seek-related methods removed. The second one will only have the seek-only methods on it.</span></span><br />
<span style="font-size: small;"><span style="font-weight: normal;"><br /></span></span></div>
</h2>
<h3>
Related Concepts</h3>
<div style="font-weight: normal;">
In the previous example we have an, initial, <span style="font-family: "courier new" , "courier" , monospace;">InputStream</span> playing to many roles: usually those interfaces are called <b><i>"Fat Interfaces"</i></b>.</div>
<div style="font-weight: normal;">
<br /></div>
<div style="font-weight: normal;">
After doing the cleaning process, we end up with two more specific interfaces one to only read and another allowing us to seek, those interfaces are called <b><i>"Slim Interfaces"</i></b>, or <b><i>"Role Interfaces"</i></b>, meaning they are describing a single role.</div>
<div style="font-weight: normal;">
<br /></div>
<div style="font-weight: normal;">
Of course, that does not means that we are unable to implement both interfaces in a single concrete component. But for clients expecting just one of the roles we can declare that the given component fulfills that role, and no more, by casting the concrete implementation with the needed role interface.</div>
<div style="font-weight: normal;">
<br /></div>
<div style="font-weight: normal;">
Something like this:</div>
<div style="background: #ffffff; border-width: .1em .1em .1em .8em; border: solid gray; overflow: auto; padding: .2em .6em; width: auto;">
<table><tbody>
<tr><td><pre style="line-height: 125%; margin: 0;">1
2
3
4
5</pre>
</td><td><pre style="line-height: 125%; margin: 0;"><span style="color: #bb0066; font-weight: bold;">CameraOrMediaInputStream</span> camInput <span style="color: #008800; font-weight: bold;">=</span> <span style="color: #008800; font-weight: bold;">new</span> <span style="color: #bb0066; font-weight: bold;">CameraOrMediaInputStream</span><span style="color: #333333;">(...);</span>
<span style="color: #bb0066; font-weight: bold;">CameraReader</span> camReader <span style="color: #008800; font-weight: bold;">=</span> <span style="color: #008800; font-weight: bold;">new</span> <span style="color: #bb0066; font-weight: bold;">CameraReader</span><span style="color: #333333;">((</span><span style="color: #bb0066; font-weight: bold;">InputStream</span><span style="color: #333333;">)</span><span style="line-height: 125%;">camInput</span><span style="color: #333333; line-height: 125%;">);</span>
<span style="color: #bb0066; font-weight: bold;">CameraOrMediaInputStream</span> mediaInput <span style="color: #008800; font-weight: bold;">=</span> <span style="color: #008800; font-weight: bold;">new</span> <span style="color: #bb0066; font-weight: bold;">CameraOrMediaInputStream</span><span style="color: #333333;">(...);</span>
<span style="color: #bb0066; font-weight: bold;">MediaReader</span> mediaReader <span style="color: #008800; font-weight: bold;">=</span> <span style="color: #008800; font-weight: bold;">new</span> <span style="color: #bb0066; font-weight: bold;">MediaReader</span><span style="color: #333333;">((</span><span style="color: #bb0066; font-weight: bold;">SeekableStream</span><span style="color: #333333;">)</span>mediaInput<span style="color: #333333;">);</span>
</pre>
</td></tr>
</tbody></table>
</div>
<br />
Casts are redundant in many OO languages but were added to imply the signature of both constructors expecting the steams.<br />
<br />
Be aware that "Role Interfaces", does not mean "Single Method Interfaces", a role may be fulfilled by a single method, or by sequence of calls to related methods.<br />
<br />
<h3>
Code sample</h3>
<blockquote class="tr_bq">
Code samples are on github repo <a href="https://github.com/lsolano/blog.solid.demo" target="_blank">lsolano/blog.solid.demo</a></blockquote>
The code was written using Scala 2.11.7 using the JVM 1.8.0u20. The example for this principle is an Automatic Teller Machine (ATM). Our ATM is located in an international airport so it must handle withdraws with currency conversions. The ATM also supports deposits using both cash and cheques.<br />
<br />
Here you have a summary of the use cases:<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgaloUgh33yD2lTNah25iULZO1sJSYywZn4ZKlGuY4eI_pIW0zzeeBrLcht3D4mVdRpmMKPxfRojg7ifJDWsr-eNsRbfBLR_PUxvY7PSY-LRR0lOkWAfH0cZEqEvWKEU-pu9g5dc6NFdz4/s1600/ISP_+Use_Cases.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgaloUgh33yD2lTNah25iULZO1sJSYywZn4ZKlGuY4eI_pIW0zzeeBrLcht3D4mVdRpmMKPxfRojg7ifJDWsr-eNsRbfBLR_PUxvY7PSY-LRR0lOkWAfH0cZEqEvWKEU-pu9g5dc6NFdz4/s1600/ISP_+Use_Cases.png" /></a></div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
The initial class diagram for these use cases are:<br />
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj49lovnj4T2xiydg98YVJ0vjb-5whK20TF3JC0uSDSOc4lgPIERxRhXTGqhVp-E9mxTrvTamjj8RhQnD7WzBc5FDczRZMlI1cw1LWZ9fHX80m_7j1WymHoZD1DTs3gHy8hVd5ru5H0-PE/s1600/ISP_Dirty_Classes.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img alt="Fat Interface" border="0" height="532" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj49lovnj4T2xiydg98YVJ0vjb-5whK20TF3JC0uSDSOc4lgPIERxRhXTGqhVp-E9mxTrvTamjj8RhQnD7WzBc5FDczRZMlI1cw1LWZ9fHX80m_7j1WymHoZD1DTs3gHy8hVd5ru5H0-PE/s640/ISP_Dirty_Classes.png" title="Fat Interface" width="640" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">Fat Interface</td></tr>
</tbody></table>
<br />
Here is the code for the "fat" <span style="font-family: "courier new" , "courier" , monospace;">ATMInteractor</span> component:
<br />
<div style="background: #ffffff; border-width: .1em .1em .1em .8em; border: solid gray; max-height: 350px; overflow: auto; padding: .2em .6em; width: auto;">
<table><tbody>
<tr><td><pre style="line-height: 125%; margin: 0;"> 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35</pre>
</td><td><pre style="line-height: 125%; margin: 0;"><span style="color: #008800; font-weight: bold;">class</span> <span style="color: #bb0066; font-weight: bold;">ATMInteractor</span><span style="color: #333333;">(</span>securityService<span style="color: #008800; font-weight: bold;">:</span> <span style="color: #333399; font-weight: bold;">SecurityService</span><span style="color: #333333;">,</span> withdrawalService<span style="color: #008800; font-weight: bold;">:</span> <span style="color: #333399; font-weight: bold;">WithdrawalService</span><span style="color: #333333;">,</span>
depositService<span style="color: #008800; font-weight: bold;">:</span> <span style="color: #333399; font-weight: bold;">AnyRef</span><span style="color: #333333;">,</span> currencyRatesService<span style="color: #008800; font-weight: bold;">:</span> <span style="color: #333399; font-weight: bold;">AnyRef</span><span style="color: #333333;">)</span> <span style="color: #333333;">{</span>
require<span style="color: #333333;">(</span>securityService <span style="color: #333333;">!=</span> <span style="color: #008800; font-weight: bold;">null</span><span style="color: #333333;">)</span>
require<span style="color: #333333;">(</span>withdrawalService <span style="color: #333333;">!=</span> <span style="color: #008800; font-weight: bold;">null</span><span style="color: #333333;">)</span>
require<span style="color: #333333;">(</span>depositService <span style="color: #333333;">!=</span> <span style="color: #008800; font-weight: bold;">null</span><span style="color: #333333;">)</span>
require<span style="color: #333333;">(</span>currencyRatesService <span style="color: #333333;">!=</span> <span style="color: #008800; font-weight: bold;">null</span><span style="color: #333333;">)</span>
<span style="color: #008800; font-weight: bold;">def</span> validate<span style="color: #333333;">(</span>request<span style="color: #008800; font-weight: bold;">:</span> <span style="color: #333399; font-weight: bold;">CustomerValidationRequest</span><span style="color: #333333;">)</span><span style="color: #008800; font-weight: bold;">:</span> <span style="color: #333399; font-weight: bold;">CustomerValidationResponse</span> <span style="color: #333333;">=</span> <span style="color: #333333;">{</span>
<span style="color: #008800; font-weight: bold;">val</span> validation <span style="color: #008800; font-weight: bold;">=</span> securityService<span style="color: #333333;">.</span>validateCustomer<span style="color: #333333;">(</span><span style="color: #bb0066; font-weight: bold;">PlasticInfo</span><span style="color: #333333;">(</span>request<span style="color: #333333;">.</span>secret<span style="color: #333333;">,</span> request<span style="color: #333333;">.</span>pin<span style="color: #333333;">))</span>
<span style="color: #bb0066; font-weight: bold;">CustomerValidationResponse</span><span style="color: #333333;">(</span>validation<span style="color: #333333;">.</span>valid<span style="color: #333333;">)</span>
<span style="color: #333333;">}</span>
<span style="color: #008800; font-weight: bold;">def</span> withdrawal<span style="color: #333333;">(</span>request<span style="color: #008800; font-weight: bold;">:</span> <span style="color: #333399; font-weight: bold;">WithdrawalRequest</span><span style="color: #333333;">)</span><span style="color: #008800; font-weight: bold;">:</span> <span style="color: #333399; font-weight: bold;">TransactionResponse</span> <span style="color: #333333;">=</span> <span style="color: #333333;">{</span>
<span style="color: #008800; font-weight: bold;">val</span> response <span style="color: #008800; font-weight: bold;">=</span> withdrawalService<span style="color: #333333;">.</span>withdrawal<span style="color: #333333;">(</span>com<span style="color: #333333;">.</span>malpeza<span style="color: #333333;">.</span>solid<span style="color: #333333;">.</span>isp<span style="color: #333333;">.</span>model<span style="color: #333333;">.</span><span style="color: #bb0066; font-weight: bold;">Withdrawal</span><span style="color: #333333;">(</span>request<span style="color: #333333;">.</span>pin<span style="color: #333333;">,</span> request<span style="color: #333333;">.</span>amount<span style="color: #333333;">))</span>
<span style="color: #008800; font-weight: bold;">val</span> failReason <span style="color: #008800; font-weight: bold;">=</span> response<span style="color: #333333;">.</span>reason <span style="color: #008800; font-weight: bold;">match</span> <span style="color: #333333;">{</span>
<span style="color: #008800; font-weight: bold;">case</span> <span style="color: #bb0066; font-weight: bold;">Some</span><span style="color: #333333;">(</span>r<span style="color: #333333;">)</span> <span style="color: #008800; font-weight: bold;">=></span> r <span style="color: #008800; font-weight: bold;">match</span> <span style="color: #333333;">{</span>
<span style="color: #008800; font-weight: bold;">case</span> com<span style="color: #333333;">.</span>malpeza<span style="color: #333333;">.</span>solid<span style="color: #333333;">.</span>isp<span style="color: #333333;">.</span>model<span style="color: #333333;">.</span><span style="color: #bb0066; font-weight: bold;">InsufficientBalance</span> <span style="color: #008800; font-weight: bold;">=></span> <span style="color: #bb0066; font-weight: bold;">InsufficientBalance</span>
<span style="color: #008800; font-weight: bold;">case</span> <span style="color: #008800; font-weight: bold;">_</span> <span style="color: #008800; font-weight: bold;">=></span> <span style="color: #bb0066; font-weight: bold;">CallBank</span>
<span style="color: #333333;">}</span>
<span style="color: #008800; font-weight: bold;">case</span> <span style="color: #008800; font-weight: bold;">_</span> <span style="color: #008800; font-weight: bold;">=></span> <span style="color: #bb0066; font-weight: bold;">CallBank</span>
<span style="color: #333333;">}</span>
<span style="color: #bb0066; font-weight: bold;">TransactionResponse</span><span style="color: #333333;">(</span>response<span style="color: #333333;">.</span>done<span style="color: #333333;">,</span> <span style="color: #bb0066; font-weight: bold;">Option</span><span style="color: #333333;">(</span>failReason<span style="color: #333333;">))</span>
<span style="color: #333333;">}</span>
<span style="color: #008800; font-weight: bold;">def</span> deposit<span style="color: #333333;">(</span>request<span style="color: #008800; font-weight: bold;">:</span> <span style="color: #333399; font-weight: bold;">AnyRef</span><span style="color: #333333;">)</span> <span style="color: #008800; font-weight: bold;">=</span> <span style="color: #333333;">???</span>
<span style="color: #333333;">}</span>
<span style="color: #008800; font-weight: bold;">object</span> <span style="color: #bb0066; font-weight: bold;">ATMInteractor</span> <span style="color: #333333;">{</span>
<span style="color: #008800; font-weight: bold;">def</span> apply<span style="color: #333333;">(</span>securityService<span style="color: #008800; font-weight: bold;">:</span> <span style="color: #333399; font-weight: bold;">SecurityService</span><span style="color: #333333;">,</span> withdrawalService<span style="color: #008800; font-weight: bold;">:</span> <span style="color: #333399; font-weight: bold;">WithdrawalService</span><span style="color: #333333;">,</span>
depositService<span style="color: #008800; font-weight: bold;">:</span> <span style="color: #333399; font-weight: bold;">AnyRef</span><span style="color: #333333;">,</span> currencyRatesService<span style="color: #008800; font-weight: bold;">:</span> <span style="color: #333399; font-weight: bold;">AnyRef</span><span style="color: #333333;">)</span><span style="color: #008800; font-weight: bold;">:</span> <span style="color: #333399; font-weight: bold;">ATMInteractor</span> <span style="color: #333333;">=</span> <span style="color: #333333;">{</span>
<span style="color: #008800; font-weight: bold;">new</span> <span style="color: #bb0066; font-weight: bold;">ATMInteractor</span><span style="color: #333333;">(</span>securityService<span style="color: #333333;">,</span> withdrawalService<span style="color: #333333;">,</span> depositService<span style="color: #333333;">,</span> currencyRatesService<span style="color: #333333;">)</span>
<span style="color: #333333;">}</span>
<span style="color: #333333;">}</span>
</pre>
</td></tr>
</tbody></table>
</div>
<br />
<h3>
What is wrong with this code: ISP?</h3>
Simply put, this component is doing to much. It handles all use cases: Customer Validation, Withdrawal, and Deposit. Because of that, it has to many dependencies (services).<br />
<br />
If you are validating a customer you don't need to know anything about Deposits or Withdrawals.<br />
<br />
<h2>
Cleaning the code</h2>
<h3>
Honoring the ISP</h3>
<div>
We need to split all these responsibilities and create specialized components able to handle each interaction (transaction). So we'll end up with three components named <span style="font-family: "courier new" , "courier" , monospace;">CustomerValidation</span>, <span style="font-family: "courier new" , "courier" , monospace;">Withdrawal</span>, and <span style="font-family: "courier new" , "courier" , monospace;">Deposit</span>; each one representing a use case. To keep this post short, the Deposit and Withdrawal with currency conversions scenarios were left out.</div>
<div>
<br />
This is the revised class diagram showing only the important components:</div>
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgEb4fvgpXc-mxcaFgIeXgJWiEP15QiJ_Q9N8zdt-AA8zZIMldZ5jde8T7-j4Wcz2Uauh9c0bqXU-jclNhdpHBPck2F90W5gQNTnfM2R9wYg_0D6rvPREkcTiFaJ7ZaNO5a4iGKloiwtCM/s1600/ISP_Clean_Classes.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img alt="Clean Interfaces" border="0" height="548" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgEb4fvgpXc-mxcaFgIeXgJWiEP15QiJ_Q9N8zdt-AA8zZIMldZ5jde8T7-j4Wcz2Uauh9c0bqXU-jclNhdpHBPck2F90W5gQNTnfM2R9wYg_0D6rvPREkcTiFaJ7ZaNO5a4iGKloiwtCM/s640/ISP_Clean_Classes.png" title="Clean Interfaces" width="640" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">Clean Interfaces</td></tr>
</tbody></table>
<div>
<br /></div>
<div>
<br /></div>
<div>
<b><i><span style="font-family: "courier new" , "courier" , monospace;">CustomerValidation</span> code:</i></b></div>
<div style="background: #ffffff; border-width: .1em .1em .1em .8em; border: solid gray; max-height: 350px; overflow: auto; padding: .2em .6em; width: auto;">
<table><tbody>
<tr><td><pre style="line-height: 125%; margin: 0;"> 1
2
3
4
5
6
7
8
9
10
11
12
13</pre>
</td><td><pre style="line-height: 125%; margin: 0;"><span style="color: #008800; font-weight: bold;">class</span> <span style="color: #bb0066; font-weight: bold;">CustomerValidation</span><span style="color: #333333;">(</span>securityService<span style="color: #008800; font-weight: bold;">:</span> <span style="color: #333399; font-weight: bold;">SecurityService</span><span style="color: #333333;">)</span> <span style="color: #333333;">{</span>
require<span style="color: #333333;">(</span>securityService <span style="color: #333333;">!=</span> <span style="color: #008800; font-weight: bold;">null</span><span style="color: #333333;">)</span>
<span style="color: #008800; font-weight: bold;">def</span> validate<span style="color: #333333;">(</span>request<span style="color: #008800; font-weight: bold;">:</span> <span style="color: #333399; font-weight: bold;">CustomerValidationRequest</span><span style="color: #333333;">)</span><span style="color: #008800; font-weight: bold;">:</span> <span style="color: #333399; font-weight: bold;">CustomerValidationResponse</span> <span style="color: #333333;">=</span> <span style="color: #333333;">{</span>
<span style="color: #008800; font-weight: bold;">val</span> validation <span style="color: #008800; font-weight: bold;">=</span> securityService<span style="color: #333333;">.</span>validateCustomer<span style="color: #333333;">(</span><span style="color: #bb0066; font-weight: bold;">PlasticInfo</span><span style="color: #333333;">(</span>request<span style="color: #333333;">.</span>secret<span style="color: #333333;">,</span> request<span style="color: #333333;">.</span>pin<span style="color: #333333;">))</span>
<span style="color: #bb0066; font-weight: bold;">CustomerValidationResponse</span><span style="color: #333333;">(</span>validation<span style="color: #333333;">.</span>valid<span style="color: #333333;">)</span>
<span style="color: #333333;">}</span>
<span style="color: #333333;">}</span>
<span style="color: #008800; font-weight: bold;">object</span> <span style="color: #bb0066; font-weight: bold;">CustomerValidation</span> <span style="color: #333333;">{</span>
<span style="color: #008800; font-weight: bold;">def</span> apply<span style="color: #333333;">(</span>securityService<span style="color: #008800; font-weight: bold;">:</span> <span style="color: #333399; font-weight: bold;">SecurityService</span><span style="color: #333333;">)</span> <span style="color: #008800; font-weight: bold;">=</span> <span style="color: #008800; font-weight: bold;">new</span> <span style="color: #bb0066; font-weight: bold;">CustomerValidation</span><span style="color: #333333;">(</span>securityService<span style="color: #333333;">)</span>
<span style="color: #333333;">}</span>
</pre>
</td></tr>
</tbody></table>
</div>
<div>
<br /></div>
<div>
<b><i><span style="font-family: "courier new" , "courier" , monospace;">Withdrawal</span> code:</i></b></div>
<div style="background: #ffffff; border-width: .1em .1em .1em .8em; border: solid gray; max-height: 350px; overflow: auto; padding: .2em .6em; width: auto;">
<table><tbody>
<tr><td><pre style="line-height: 125%; margin: 0;"> 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20</pre>
</td><td><pre style="line-height: 125%; margin: 0;"><span style="color: #008800; font-weight: bold;">class</span> <span style="color: #bb0066; font-weight: bold;">Withdrawal</span><span style="color: #333333;">(</span>withdrawalService<span style="color: #008800; font-weight: bold;">:</span> <span style="color: #333399; font-weight: bold;">WithdrawalService</span><span style="color: #333333;">)</span> <span style="color: #333333;">{</span>
require <span style="color: #333333;">(</span>withdrawalService <span style="color: #333333;">!=</span> <span style="color: #008800; font-weight: bold;">null</span><span style="color: #333333;">)</span>
<span style="color: #008800; font-weight: bold;">def</span> withdrawal<span style="color: #333333;">(</span>request<span style="color: #008800; font-weight: bold;">:</span> <span style="color: #333399; font-weight: bold;">WithdrawalRequest</span><span style="color: #333333;">)</span><span style="color: #008800; font-weight: bold;">:</span> <span style="color: #333399; font-weight: bold;">TransactionResponse</span> <span style="color: #333333;">=</span> <span style="color: #333333;">{</span>
<span style="color: #008800; font-weight: bold;">val</span> response <span style="color: #008800; font-weight: bold;">=</span> withdrawalService<span style="color: #333333;">.</span>withdrawal<span style="color: #333333;">(</span>com<span style="color: #333333;">.</span>malpeza<span style="color: #333333;">.</span>solid<span style="color: #333333;">.</span>isp<span style="color: #333333;">.</span>model<span style="color: #333333;">.</span><span style="color: #bb0066; font-weight: bold;">Withdrawal</span><span style="color: #333333;">(</span>request<span style="color: #333333;">.</span>pin<span style="color: #333333;">,</span> request<span style="color: #333333;">.</span>amount<span style="color: #333333;">))</span>
<span style="color: #008800; font-weight: bold;">val</span> failReason <span style="color: #008800; font-weight: bold;">=</span> response<span style="color: #333333;">.</span>reason <span style="color: #008800; font-weight: bold;">match</span> <span style="color: #333333;">{</span>
<span style="color: #008800; font-weight: bold;">case</span> <span style="color: #bb0066; font-weight: bold;">Some</span><span style="color: #333333;">(</span>r<span style="color: #333333;">)</span> <span style="color: #008800; font-weight: bold;">=></span> r <span style="color: #008800; font-weight: bold;">match</span> <span style="color: #333333;">{</span>
<span style="color: #008800; font-weight: bold;">case</span> com<span style="color: #333333;">.</span>malpeza<span style="color: #333333;">.</span>solid<span style="color: #333333;">.</span>isp<span style="color: #333333;">.</span>model<span style="color: #333333;">.</span><span style="color: #bb0066; font-weight: bold;">InsufficientBalance</span> <span style="color: #008800; font-weight: bold;">=></span> <span style="color: #bb0066; font-weight: bold;">InsufficientBalance</span>
<span style="color: #008800; font-weight: bold;">case</span> <span style="color: #008800; font-weight: bold;">_</span> <span style="color: #008800; font-weight: bold;">=></span> <span style="color: #bb0066; font-weight: bold;">CallBank</span>
<span style="color: #333333;">}</span>
<span style="color: #008800; font-weight: bold;">case</span> <span style="color: #008800; font-weight: bold;">_</span> <span style="color: #008800; font-weight: bold;">=></span> <span style="color: #bb0066; font-weight: bold;">CallBank</span>
<span style="color: #333333;">}</span>
<span style="color: #bb0066; font-weight: bold;">TransactionResponse</span><span style="color: #333333;">(</span>response<span style="color: #333333;">.</span>done<span style="color: #333333;">,</span> <span style="color: #bb0066; font-weight: bold;">Option</span><span style="color: #333333;">(</span>failReason<span style="color: #333333;">))</span>
<span style="color: #333333;">}</span>
<span style="color: #333333;">}</span>
<span style="color: #008800; font-weight: bold;">object</span> <span style="color: #bb0066; font-weight: bold;">Withdrawal</span> <span style="color: #333333;">{</span>
<span style="color: #008800; font-weight: bold;">def</span> apply<span style="color: #333333;">(</span>withdrawalService<span style="color: #008800; font-weight: bold;">:</span> <span style="color: #333399; font-weight: bold;">WithdrawalService</span><span style="color: #333333;">)</span> <span style="color: #008800; font-weight: bold;">=</span> <span style="color: #008800; font-weight: bold;">new</span> <span style="color: #bb0066; font-weight: bold;">Withdrawal</span><span style="color: #333333;">(</span>withdrawalService<span style="color: #333333;">)</span>
<span style="color: #333333;">}</span>
</pre>
</td></tr>
</tbody></table>
</div>
<div>
<br /></div>
<div>
<h2>
Agile Link</h2>
</div>
<div>
With the ISP we gain <b><i>Orthogonality</i></b>. For that concept I mean the following meanings<br />
<blockquote class="tr_bq">
<b><i>statistically independent</i></b></blockquote>
or<br />
<blockquote class="tr_bq">
<b><i>non-overlapping, uncorrelated, or independent objects of some kind</i></b></blockquote>
<br />
In other words, we get components with none or little relation. If one must change the other(s) remain untouched. This minimizes the impact of changes.<br />
<br />
Orthogonality can be applied to architectural layers such as IO, Persistence, Transactions, Logging, etc.; or to behaviors like the sample project presented here. The last version has a clear separation of Use Cases. We could implement all those behaviors in a single component but that will make the code harder to maintain.<br />
<br />
With such a reduced amount of use cases is difficult to see the need for this (over)engineering, but try to imagine the following:<br />
<br />
You are working in an online retailing product's back-end API. It's the fifth year since the API initial version, and you have about 500 different use cases, each one with some pretty complicated scenarios such as:<br />
<ul>
<li>Checkout with mixed payment methods: Coupons + Prepaid Card + Credit Card + PayPal, etc.</li>
<li>Manage upper bounds for customers by category to protect then from errors or malicious actions</li>
<li>Single purchase with multiple items with arbitrary groups allowing for shipment to different addresses</li>
<li>Manufacturers promotions by random distribution for customers matching certain profiles</li>
<li>...</li>
</ul>
<br />
How many times you think you would expend each time you need to add a new feature or change an existing one if all these cases are implemented into a single component, or distributed within a small group of components?<br />
<br />
<h3>
Series links</h3>
Previous, <a href="http://tales-of-agile-adoption.blogspot.com/2016/01/solid-principles-lsp-3-of-4.html" target="_blank">SOLID Principles: LSP (3 of 4)</a><br />
Next: none, this is the last one.</div>
Anonymoushttp://www.blogger.com/profile/12292838726080618300noreply@blogger.com0tag:blogger.com,1999:blog-8113723708012951738.post-84889801738764680582016-01-06T07:13:00.000-04:002016-05-28T22:20:24.139-04:00SOLID Principles: LSP (3 of 4)If you missed the previous post from this series check it out <a href="http://tales-of-agile-adoption.blogspot.com/2016/01/solid-principles-ocp-2-of-4.html" target="_blank">SOLID Principles: OCP (2 of 4)</a>.<br />
<h2>
Liskov substitution principle: LSP</h2>
<div>
This principle states that:<br />
<blockquote class="tr_bq">
"objects in a program should be replaceable with instances of their sub-types without altering the correctness of that program."</blockquote>
This introduces us to the concept of Substitutability.<br />
<blockquote class="tr_bq">
<b><i>Substitutability</i></b> is a principle in object-oriented programming. It states that, in a computer program, <i>if S is a sub-type of T, then objects of type T may be replaced with objects of type S (i.e., objects of type S may substitute objects of type T)</i> <b><i>without altering any of the desirable properties of that program (correctness, task performed, etc.).</i></b> </blockquote>
Put it simple: If you say you are a Duck be a one <b><i>but fully</i></b>. LSP differs from Duck typing <a href="http://tales-of-agile-adoption.blogspot.com/2016/01/solid-principles-lsp-3-of-4.html#ref_00" rel="nofollow">(0)</a> in that the former is more restrictive than the later. Duck typing says that for an object to be used in a particular context it must have a certain list of methods and properties, leaving out the details about what happens when you use those methods and properties (the object's internals). So how restrictive are the LSP sub-typing rules? here is a summary of the rules:<br />
<ul>
<li><b>Requirements on signatures</b></li>
<ul>
<li><i>Contravariance </i><a href="http://tales-of-agile-adoption.blogspot.com/2016/01/solid-principles-lsp-3-of-4.html#ref_01" rel="nofollow">(1)</a> of method arguments in the sub-type.</li>
<li><i>Covariance </i><a href="http://tales-of-agile-adoption.blogspot.com/2016/01/solid-principles-lsp-3-of-4.html#ref_01" rel="nofollow">(1)</a> of return types in the sub-type.</li>
<li><i>No new exceptions</i> should be thrown by methods of the sub-type, except where those exceptions are themselves sub-types of exceptions thrown by the methods of the super-type.</li>
</ul>
<li><b>Behavioral conditions</b></li>
<ul>
<li><i>Preconditions <a href="http://tales-of-agile-adoption.blogspot.com/2016/01/solid-principles-lsp-3-of-4.html#ref_02" rel="nofollow">(2)</a></i> cannot be strengthened in a sub-type.</li>
<li><i>Postconditions <a href="http://tales-of-agile-adoption.blogspot.com/2016/01/solid-principles-lsp-3-of-4.html#ref_02" rel="nofollow">(2)</a></i> cannot be weakened in a sub-type.</li>
<li><i>Invariants <a href="http://tales-of-agile-adoption.blogspot.com/2016/01/solid-principles-lsp-3-of-4.html#ref_02" rel="nofollow">(2)</a></i> of the super-type must be preserved in a sub-type.</li>
<li><i>History constraint</i> (the "history rule"): sub-types must not allow state changes that are impossible for its super-type, this is possible because sub-types may include new methods that can alter its state in ways not defined by the parent type. So the history that you get after calling a certain methods sequence must be the same for the super-type and the sub-type.</li>
</ul>
</ul>
<h3>
<b>Principle requirements explained (top-down):</b></h3>
<b><i>Contravariance of method arguments: </i></b><br />
If your father accepts <span style="font-family: "courier new" , "courier" , monospace;">Animal</span>s, you must accept also <span style="font-family: "courier new" , "courier" , monospace;">Animal</span>s, not just <span style="font-family: "courier new" , "courier" , monospace;">Cat</span>s.<br />
<br />
<b><i>Covariance of return types in the sub-type:</i></b><br />
If your father returns <span style="font-family: "courier new" , "courier" , monospace;">Animal</span>s, you are safe to only return <span style="font-family: "courier new" , "courier" , monospace;">Cat</span>s, because all <span style="font-family: "courier new" , "courier" , monospace;">Cat</span>s are also <span style="font-family: "courier new" , "courier" , monospace;">Animal</span>s.<br />
<br />
<b><i>No new exceptions:</i></b><br />
If your father throws an <span style="font-family: "courier new" , "courier" , monospace;">AnimalException</span> you are free to throw <span style="font-family: "courier new" , "courier" , monospace;">AnimalTooLargeException</span> but not a <span style="font-family: "courier new" , "courier" , monospace;">ChairException</span>.<br />
<br />
<b><i>Preconditions cannot be strengthened in a sub-type:</i></b><br />
Imagine that you have a <span style="font-family: "courier new" , "courier" , monospace;">VeterinaryClinic</span> with an operation called <span style="font-family: "courier new" , "courier" , monospace;">sacrifice(pet: Animal)</span>, with a contract saying that for an animal to be sacrificed it must have a deadly disease (<span style="font-family: "courier new" , "courier" , monospace;">hasADeadlyDisease</span> property returning <span style="font-family: "courier new" , "courier" , monospace;">true</span>).<br />
<br />
Later you derived a <span style="font-family: "courier new" , "courier" , monospace;">VainVeterinaryClinic</span> with a new rule: you only sacrifice pretty and deadly ill animals. If they are ugly and have a deadly illness you let then suffer. Now this sub class has a more restrictive precondition (contract) in order to sacrifice animals. Where your code expect a Vet Clinic instance and you pass the Vain one you could receive an exception when trying to sacrifice an ugly deadly ill animal.<br />
<br />
<b><i>Postconditions cannot be weakened in a sub-type:</i></b><br />
Continuing with this cruel example, if you have a post-condition for the <span style="font-family: "courier new" , "courier" , monospace;">sacrifice(pet: Animal)</span> method indicating that after the method completes the animal must be dead (<span style="font-family: "courier new" , "courier" , monospace;">isAlive</span> returning <span style="font-family: "courier new" , "courier" , monospace;">false</span>), then a sub-type of the Vet Clinic class can not alter this behavior leaving animals alive after calling the sacrifice operation. This will be a more permissive (weak) contract than the one defined by the super-type.<br />
<br />
<b><i>Invariants of the super-type must be preserved in a sub-type:</i></b><br />
If <span style="font-family: "courier new" , "courier" , monospace;">Animal</span> class defines the <span style="font-family: "courier new" , "courier" , monospace;">name</span> property as immutable, then <span style="font-family: "courier new" , "courier" , monospace;">Cat</span>s can not be renamed. For <span style="font-family: "courier new" , "courier" , monospace;">Animal</span> instances the <span style="font-family: "courier new" , "courier" , monospace;">name</span> is an invariant through the life-time of each object. So for <span style="font-family: "courier new" , "courier" , monospace;">Cat</span>s it must be also true.<br />
<br />
<b><i>History constraint:</i></b><br />
Imagine an animal cage with two operations <span style="font-family: "courier new" , "courier" , monospace;">enter(a: Animal)</span> and <span style="font-family: "courier new" , "courier" , monospace;">takeOut(): Animal</span>; the case also have a read-only property called <span style="font-family: "courier new" , "courier" , monospace;">isEmpty: boolean</span>. If you look back a sequence on calls to these methods (the history of an instance), you can easily predict the final value of <span style="font-family: "courier new" , "courier" , monospace;">isEmpty</span>.<br />
<ul>
<li><span style="font-family: "courier new" , "courier" , monospace;">enter(a)</span> => <span style="font-family: "courier new" , "courier" , monospace;">takeOut()</span> => <span style="font-family: "courier new" , "courier" , monospace;">enter(a</span>): <span style="font-family: "courier new" , "courier" , monospace;">isEmpty</span> is <span style="font-family: "courier new" , "courier" , monospace;">false</span></li>
<li><span style="font-family: "courier new" , "courier" , monospace;">enter(a)</span> => <span style="font-family: "courier new" , "courier" , monospace;">takeOut()</span> => <span style="font-family: "courier new" , "courier" , monospace;">enter(a)</span> => <span style="font-family: "courier new" , "courier" , monospace;">takeOut()</span>: <span style="font-family: "courier new" , "courier" , monospace;">isEmpty</span> is <span style="font-family: "courier new" , "courier" , monospace;">true</span></li>
</ul>
<br />
Then if you derive a <span style="font-family: "courier new" , "courier" , monospace;">CatCage</span> from <span style="font-family: "courier new" , "courier" , monospace;">AnimalCage</span> the former must ensure that the same relation (on the later) holds true. You cannot have a <span style="font-family: "courier new" , "courier" , monospace;">CatCage</span> saying that is empty after an <span style="font-family: "courier new" , "courier" , monospace;">enter(a: Animal)</span> call.<br />
<br />
These rules are better explained using an strongly typed language such as Java and C#, you can check out the following test classes and their associated class under test: <span style="font-family: "courier new" , "courier" , monospace;"><a href="https://github.com/lsolano/blog.solid.demo/blob/master/java/src/test/java/com/malpeza/solid/lsp/NonGenericPetCageTests.java" target="_blank">NonGenericPetCageTests.java</a></span>, and <span style="font-family: "courier new" , "courier" , monospace;"><a href="https://github.com/lsolano/blog.solid.demo/blob/master/java/src/test/java/com/malpeza/solid/lsp/GenericPetCageTests.java" target="_blank">GenericPetCageTests.java</a></span> (on the java sub-directory).<br />
<br /></div>
<div style="background: #AAA; border-width: .1em .1em .1em .2em; border: solid gray; max-height: 250px; overflow: auto; padding: .2em .6em; width: auto;">
<h3>
Side note: Who is Barbara Liskov?</h3>
<table>
<tbody>
<tr>
<td><h4>
Very, very short Bio</h4>
Barbara Liskov (born November 7, 1939 as Barbara Jane Huberman) is an American computer scientist who is an institute professor at the Massachusetts Institute of Technology (MIT) and Ford Professor of Engineering in its School of Engineering's electrical engineering and computer science department.
<br />
<br />
Among her achievements we found that, with Jeannette Wing, she developed a particular definition of sub-typing, commonly known as the Liskov substitution principle (LSP). For more information <a href="https://www.csail.mit.edu/user/971" target="_blank">check her bio at MIT web site.</a>
<br />
<br />
<h4>
Why I'm writing about her?</h4>
In our industry (software development), and in particular my country the <a href="http://www.godominicanrepublic.com/about-dr/" target="_blank">Dominican Republic</a>, we have a huge disparity between male and female personnel. I believe that this is holding us back because as with any aspect of the life, the diversity is good to avoid biases and narrow thinking.
</td>
</tr>
</tbody></table>
</div>
<div>
<br />
<h3>
Code sample</h3>
<blockquote class="tr_bq">
Code samples are on <a href="https://github.com/lsolano/blog.solid.demo" target="_blank">github repo lsolano/blog.solid.demo</a> </blockquote>
The code was written using JavaScript over Node.js v4.2.4. The sample API is about a logging library.We'll focus our attention to the Appenders cluster (family). The main components are:<br />
<ul>
<li>The API entry point called SOLIDLogs, from there get instances of loggers and appenders</li>
<li>The Logger, with very simple implementation: supports only debug() and error() operations.</li>
<li>The Appender interface (contract) and all implementations: Console, REST, DB, etc. Each appender is responsible for sending the messages from logger to its destination based on some configuration</li>
</ul>
<div>
All Level information was left out to keep the API as simple as possible. We are assuming that the level is ALL so always debug and error messages are sent to appenders.</div>
<div>
<br /></div>
<div>
Here is the diagram of the API on its first (dirty) version:<br />
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjOMruznLD5JNlVrzKvlrG6puB4Anzy_P0dxsoajeO0petxMhiBOat5oKgJ3D8qAR9-ZqJVHmpah-ru6oq0L4nZxx0EKJzjHtcaaBBDIumj-3avUp5RnAZ0_7o5IrjldTXAB77qHp8BQHg/s1600/Dirty_SOLIDLogs_classes.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img alt="Dirty logging API" border="0" height="400" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjOMruznLD5JNlVrzKvlrG6puB4Anzy_P0dxsoajeO0petxMhiBOat5oKgJ3D8qAR9-ZqJVHmpah-ru6oq0L4nZxx0EKJzjHtcaaBBDIumj-3avUp5RnAZ0_7o5IrjldTXAB77qHp8BQHg/s400/Dirty_SOLIDLogs_classes.png" title="Dirty logging API" width="396" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;"><span style="font-size: 12.8px;">Dirty logging API</span></td></tr>
</tbody></table>
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
</div>
<div>
This is the first version of the Appeder Base (<span style="font-family: "courier new" , "courier" , monospace;">BlackHoleAppender</span>), and its derivatives <span style="font-family: "courier new" , "courier" , monospace;">ConsoleAppender</span> and <span style="font-family: "courier new" , "courier" , monospace;">MySQLAppender</span>.</div>
<div>
<b><i><br /></i></b>
<b><i>BlackHoleAppender (aka AppenderBase)</i></b></div>
<div style="background: #ffffff; border-width: .1em .1em .1em .8em; border: solid gray; max-height: 250px; overflow: auto; padding: .2em .6em; width: auto;">
<table><tbody>
<tr><td><pre style="line-height: 125%; margin: 0;"> 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18</pre>
</td><td><pre style="line-height: 125%; margin: 0;"><span style="color: #008800; font-weight: bold;">function</span> BlackHoleAppender(args) {
<span style="color: #008800; font-weight: bold;">this</span>.name <span style="color: #333333;">=</span> (args.name <span style="color: #333333;">||</span> <span style="background-color: #fff0f0;">'defaultAppender'</span>);
};
BlackHoleAppender.prototype.normalizeMessage <span style="color: #333333;">=</span> <span style="color: #008800; font-weight: bold;">function</span>(message, category) {
<span style="color: #008800; font-weight: bold;">return</span> message;
}
BlackHoleAppender.prototype.append <span style="color: #333333;">=</span> <span style="color: #008800; font-weight: bold;">function</span>(message, category) {
<span style="color: #008800; font-weight: bold;">var</span> finalMessage <span style="color: #333333;">=</span> <span style="color: #008800; font-weight: bold;">this</span>.normalizeMessage(message, category);
<span style="color: #008800; font-weight: bold;">this</span>.write(finalMessage, category);
};
BlackHoleAppender.prototype.write <span style="color: #333333;">=</span> <span style="color: #008800; font-weight: bold;">function</span>(finalMessage, category) {
<span style="color: #888888;">/* To be implemented by sub-classes */</span>
};
module.exports <span style="color: #333333;">=</span> BlackHoleAppender;
</pre>
</td></tr>
</tbody></table>
</div>
<div>
<br />
<b><i>ConsoleAppender</i></b></div>
<div style="background: #ffffff; border-width: .1em .1em .1em .8em; border: solid gray; max-height: 250px; overflow: auto; padding: .2em .6em; width: auto;">
<table><tbody>
<tr><td><pre style="line-height: 125%; margin: 0;"> 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34</pre>
</td><td><pre style="line-height: 125%; margin: 0;"><span style="color: #008800; font-weight: bold;">const</span> maxMessageLength <span style="color: #333333;">=</span> <span style="color: #007020;">Math</span>.pow(<span style="color: #0000dd; font-weight: bold;">2</span>, <span style="color: #0000dd; font-weight: bold;">30</span>);
<span style="color: #008800; font-weight: bold;">var</span> AppenderBase <span style="color: #333333;">=</span> require(<span style="background-color: #fff0f0;">'./BlackHoleAppender.js'</span>);
<span style="color: #008800; font-weight: bold;">function</span> ConsoleAppender(cons, maxLength) {
<span style="color: #008800; font-weight: bold;">this</span>.console <span style="color: #333333;">=</span> (cons <span style="color: #333333;">||</span> console);
<span style="color: #008800; font-weight: bold;">this</span>.maxLength <span style="color: #333333;">=</span> maxLength <span style="color: #333333;">||</span> <span style="color: #0000dd; font-weight: bold;">0</span>;
<span style="color: #008800; font-weight: bold;">var</span> finalArgs <span style="color: #333333;">=</span> [<span style="background-color: #fff0f0;">'ConsoleAppender'</span>];
<span style="color: #007020;">Array</span>.prototype.forEach.call(arguments, <span style="color: #008800; font-weight: bold;">function</span>(arg) {
finalArgs.push(arg);
});
AppenderBase.apply(<span style="color: #008800; font-weight: bold;">this</span>, <span style="color: #007020;">Array</span>.prototype.slice.call(finalArgs));
}
ConsoleAppender.prototype <span style="color: #333333;">=</span> <span style="color: #008800; font-weight: bold;">new</span> AppenderBase(<span style="background-color: #fff0f0;">'ConsoleAppender'</span>);
ConsoleAppender.prototype.write <span style="color: #333333;">=</span> <span style="color: #008800; font-weight: bold;">function</span>(finalMessage, category) {
<span style="color: #008800; font-weight: bold;">switch</span> (category) {
<span style="color: #008800; font-weight: bold;">case</span> <span style="background-color: #fff0f0;">"Error"</span><span style="color: #333333;">:</span>
<span style="color: #008800; font-weight: bold;">this</span>.console.error(finalMessage);
<span style="color: #008800; font-weight: bold;">break</span>;
<span style="color: #008800; font-weight: bold;">default</span><span style="color: #333333;">:</span>
<span style="color: #008800; font-weight: bold;">this</span>.console.debug(finalMessage);
}
};
ConsoleAppender.prototype.normalizeMessage <span style="color: #333333;">=</span> <span style="color: #008800; font-weight: bold;">function</span>(message, category) {
<span style="color: #008800; font-weight: bold;">var</span> msg <span style="color: #333333;">=</span> (message <span style="color: #333333;">||</span> <span style="background-color: #fff0f0;">''</span>);
<span style="color: #008800; font-weight: bold;">var</span> allowedLength <span style="color: #333333;">=</span> (<span style="color: #008800; font-weight: bold;">this</span>.maxLength <span style="color: #333333;">||</span> maxMessageLength);
msg <span style="color: #333333;">=</span> msg.length <span style="color: #333333;">></span> allowedLength<span style="color: #333333;">?</span> msg.substring(<span style="color: #0000dd; font-weight: bold;">0</span>, allowedLength) <span style="color: #333333;">:</span> msg;
<span style="color: #008800; font-weight: bold;">return</span> msg;
}
module.exports <span style="color: #333333;">=</span> ConsoleAppender;
</pre>
</td></tr>
</tbody></table>
</div>
<div>
<br />
<b><i>MySQLAppender</i></b></div>
<div style="background: #ffffff; border-width: .1em .1em .1em .8em; border: solid gray; max-height: 250px; overflow: auto; padding: .2em .6em; width: auto;">
<table><tbody>
<tr><td><pre style="line-height: 125%; margin: 0;"> 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34</pre>
</td><td><pre style="line-height: 125%; margin: 0;"><span style="color: #008800; font-weight: bold;">const</span> maxMessageLength <span style="color: #333333;">=</span> <span style="color: #007020;">Math</span>.pow(<span style="color: #0000dd; font-weight: bold;">2</span>, <span style="color: #0000dd; font-weight: bold;">14</span>);
<span style="color: #008800; font-weight: bold;">var</span> AppenderBase <span style="color: #333333;">=</span> require(<span style="background-color: #fff0f0;">'./BlackHoleAppender.js'</span>);
<span style="color: #008800; font-weight: bold;">function</span> MySQLAppender(rdbmsRepository, maxLength) {
<span style="color: #008800; font-weight: bold;">this</span>.repository <span style="color: #333333;">=</span> rdbmsRepository;
<span style="color: #008800; font-weight: bold;">this</span>.maxLength <span style="color: #333333;">=</span> maxLength <span style="color: #333333;">||</span> <span style="color: #0000dd; font-weight: bold;">0</span>;
<span style="color: #008800; font-weight: bold;">var</span> finalArgs <span style="color: #333333;">=</span> [<span style="background-color: #fff0f0;">'MySQLAppender'</span>];
<span style="color: #007020;">Array</span>.prototype.forEach.call(arguments, <span style="color: #008800; font-weight: bold;">function</span>(arg) {
finalArgs.push(arg);
});
AppenderBase.apply(<span style="color: #008800; font-weight: bold;">this</span>, <span style="color: #007020;">Array</span>.prototype.slice.call(finalArgs));
}
MySQLAppender.prototype <span style="color: #333333;">=</span> <span style="color: #008800; font-weight: bold;">new</span> AppenderBase(<span style="background-color: #fff0f0;">'MySQLAppender'</span>);
MySQLAppender.prototype.write <span style="color: #333333;">=</span> <span style="color: #008800; font-weight: bold;">function</span>(finalMessage, category) {
<span style="color: #008800; font-weight: bold;">switch</span> (category) {
<span style="color: #008800; font-weight: bold;">case</span> <span style="background-color: #fff0f0;">"Error"</span><span style="color: #333333;">:</span>
<span style="color: #008800; font-weight: bold;">this</span>.repository.persist( { text<span style="color: #333333;">:</span> finalMessage, category<span style="color: #333333;">:</span> category });
<span style="color: #008800; font-weight: bold;">break</span>;
<span style="color: #008800; font-weight: bold;">default</span><span style="color: #333333;">:</span>
<span style="color: #008800; font-weight: bold;">this</span>.repository.persist( { text<span style="color: #333333;">:</span> finalMessage, category<span style="color: #333333;">:</span> <span style="background-color: #fff0f0;">"Debug"</span> });
}
};
MySQLAppender.prototype.normalizeMessage <span style="color: #333333;">=</span> <span style="color: #008800; font-weight: bold;">function</span>(message, category) {
<span style="color: #008800; font-weight: bold;">var</span> msg <span style="color: #333333;">=</span> (message <span style="color: #333333;">||</span> <span style="background-color: #fff0f0;">''</span>);
<span style="color: #008800; font-weight: bold;">var</span> allowedLength <span style="color: #333333;">=</span> (<span style="color: #008800; font-weight: bold;">this</span>.maxLength <span style="color: #333333;">||</span> maxMessageLength);
msg <span style="color: #333333;">=</span> msg.length <span style="color: #333333;">></span> allowedLength<span style="color: #333333;">?</span> msg.substring(<span style="color: #0000dd; font-weight: bold;">0</span>, allowedLength) <span style="color: #333333;">:</span> msg;
<span style="color: #008800; font-weight: bold;">return</span> msg;
}
module.exports <span style="color: #333333;">=</span> MySQLAppender;
</pre>
</td></tr>
</tbody></table>
</div>
<div>
<br />
To see how the API is used take a look to the following files: <span style="font-family: "courier new" , "courier" , monospace;">/js/test/dirtyTest.js</span> and <span style="font-family: "courier new" , "courier" , monospace;">/js/test/cleanTest.js</span>.<br />
<br /></div>
<div>
<h3>
What is wrong with this code: LSP?</h3>
Here we have one base class and two derivatives. The base does nothing with the passed message on the normalization step, it just returns the same thing. So its contract is "allow all messages".<br />
<br />
In contrast, Console and MySQL appenders have a limit on the message length. So they indeed are tightening their base-type's contract . That means that when an Appender is expected, and we pass the Console or MySQL version parts of the message could me silently truncated. This is a direct violation to the LS principle. Sub-types of the base appender must accept all the same input range managed by the base-type.</div>
<div>
<h2>
<br />Cleaning the code</h2>
</div>
<h3>
Honoring the LSP</h3>
<div>
By the time of this writing (2016) we have the following limitations in the length of an string when targeting the following platforms / products:</div>
<div>
<ul>
<li>UTF-8 is a "variable-length" encoding raging from 1 to 4 bytes per character, it can encode all UNICODE characters, so we must assume that UTF-8 will be used to store the message sent to the appenders.</li>
<li>The worst case scenario with UTF-8 is that all characters in a string use 4 bytes so we must divide the total bytes capacity of the storage media by 4 to know the safe possible maximum length.</li>
<li>JavaScript implementations can handle from 2^20 to 2^32 bytes per string. If we divide 2^32 by 4 we get 2^30, so for the <span style="font-family: "courier new" , "courier" , monospace;">ConsoleAppender</span> the max allowed message length will be 2^30.</li>
<li>MySQL (5.x) has a limit for string (varchar) columns of 2^16, again divided by 4 yields 2^14</li>
<li>SQL-Server has a 2^30 bytes limit, divided by 4 gives us 2^28</li>
</ul>
<div>
With that information, and knowing that in order to honor the LSP the sub-types of <span style="font-family: "courier new" , "courier" , monospace;">BlackHoleAppender</span> must allow at least the same message size as the super-type, we must force the base appender to handle the minimum possible message size, that is 2^14 from the MySQL implementation.</div>
</div>
<div>
<br /></div>
<div>
In order to do that we should "declare" the fact that know the appenders handle an explicit message max size. Also we must decide what to do when the message is longer than expected. To solve this we'll introduce the max length limit as the property <span style="font-family: "courier new" , "courier" , monospace;">maxLength</span>, and the behavior when exceeded as an enumeration with only two possible values: Truncate (default), and Ignore.</div>
<br />
As an invariant no sub-type of BlackHoleAppender should limit messages to a shorter length than its parent, in order to comply with the LSP. All these changes are captured in the following diagram:<br />
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiV_QUmj8K4PxCIgBfD2a7fgWyJ4BD8ZiB4_UqA1XttmnQ0X82dU0oWF-d0FqMis8Q9Gkq_d5ilQpxudGaLd7EO_huFKUf5Yb5PwM_6fENokmv8bRKK8RACG2Sjo6mryqZCil8sFJaq8vI/s1600/Clean_SOLIDLogs_classes.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img alt="Clean logging API" border="0" height="435" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiV_QUmj8K4PxCIgBfD2a7fgWyJ4BD8ZiB4_UqA1XttmnQ0X82dU0oWF-d0FqMis8Q9Gkq_d5ilQpxudGaLd7EO_huFKUf5Yb5PwM_6fENokmv8bRKK8RACG2Sjo6mryqZCil8sFJaq8vI/s640/Clean_SOLIDLogs_classes.png" title="Clean logging API" width="640" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">Clean logging API</td></tr>
</tbody></table>
The orange components (and notes), have all the relevant changes. Now lets see the base and console appeders:<br />
<br />
<b><i>BlackHoleAppender (cleaned):</i></b>
<!-- HTML generated using hilite.me --><br />
<div style="background: #ffffff; border-width: .1em .1em .1em .8em; border: solid gray; max-height: 250px; overflow: auto; padding: .2em .6em; width: auto;">
<table><tbody>
<tr><td><pre style="line-height: 125%; margin: 0;"> 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45</pre>
</td><td><pre style="line-height: 125%; margin: 0;"><span style="color: #008800; font-weight: bold;">var</span> msgHandling <span style="color: #333333;">=</span> require(<span style="background-color: #fff0f0;">'../messageHandling'</span>);
<span style="color: #008800; font-weight: bold;">function</span> BlackHoleAppender(name, config) {
<span style="color: #008800; font-weight: bold;">this</span>.name <span style="color: #333333;">=</span> (name <span style="color: #333333;">||</span> <span style="background-color: #fff0f0;">'blackHole'</span>);
<span style="color: #008800; font-weight: bold;">this</span>.maxLength <span style="color: #333333;">=</span> (<span style="color: #333333;">!!</span>config.baseMaxLength<span style="color: #333333;">?</span> config.baseMaxLength <span style="color: #333333;">:</span> <span style="color: #0000dd; font-weight: bold;">0</span>);
<span style="color: #008800; font-weight: bold;">this</span>._messageHandling <span style="color: #333333;">=</span> msgHandling.truncate;
};
<span style="color: #007020;">Object</span>.defineProperty(BlackHoleAppender.prototype, <span style="background-color: #fff0f0;">'messageHandling'</span>, {
get<span style="color: #333333;">:</span> <span style="color: #008800; font-weight: bold;">function</span>() {
<span style="color: #008800; font-weight: bold;">return</span> <span style="color: #008800; font-weight: bold;">this</span>._messageHandling;
},
set<span style="color: #333333;">:</span> <span style="color: #008800; font-weight: bold;">function</span>(messageHandling) {
<span style="color: #008800; font-weight: bold;">return</span> <span style="color: #008800; font-weight: bold;">this</span>._messageHandling <span style="color: #333333;">=</span> messageHandling;
}
});
BlackHoleAppender.prototype.normalizeMessage <span style="color: #333333;">=</span> <span style="color: #008800; font-weight: bold;">function</span>(message, category) {
<span style="color: #008800; font-weight: bold;">var</span> msg <span style="color: #333333;">=</span> (message <span style="color: #333333;">||</span> <span style="background-color: #fff0f0;">''</span>);
<span style="color: #008800; font-weight: bold;">if</span> (msg.length <span style="color: #333333;">></span> <span style="color: #008800; font-weight: bold;">this</span>.maxLength) {
<span style="color: #008800; font-weight: bold;">if</span> (<span style="color: #008800; font-weight: bold;">this</span>.messageHandling <span style="color: #333333;">===</span> msgHandling.truncate) {
msg <span style="color: #333333;">=</span> msg.substring(<span style="color: #0000dd; font-weight: bold;">0</span>, <span style="color: #008800; font-weight: bold;">this</span>.maxLength);
} <span style="color: #008800; font-weight: bold;">else</span> {
msg <span style="color: #333333;">=</span> <span style="color: #008800; font-weight: bold;">null</span>;
}
}
<span style="color: #008800; font-weight: bold;">return</span> msg;
}
BlackHoleAppender.prototype.append <span style="color: #333333;">=</span> <span style="color: #008800; font-weight: bold;">function</span>(message, category) {
<span style="color: #008800; font-weight: bold;">var</span> finalMessage <span style="color: #333333;">=</span> <span style="color: #008800; font-weight: bold;">this</span>.normalizeMessage(message, category);
<span style="color: #008800; font-weight: bold;">if</span> (<span style="color: #333333;">!!</span>finalMessage) {
<span style="color: #008800; font-weight: bold;">this</span>.write(finalMessage, category);
}
};
BlackHoleAppender.prototype.write <span style="color: #333333;">=</span> <span style="color: #008800; font-weight: bold;">function</span>(finalMessage, category) {
<span style="color: #888888;">/* To be implemented by sub-classes */</span>
};
module.exports <span style="color: #333333;">=</span> BlackHoleAppender;
</pre>
</td></tr>
</tbody></table>
</div>
<br />
<b><i>ConsoleAppender (cleaned):</i></b>
<!-- HTML generated using hilite.me --><br />
<div style="background: #ffffff; border-width: .1em .1em .1em .8em; border: solid gray; max-height: 250px; overflow: auto; padding: .2em .6em; width: auto;">
<table><tbody>
<tr><td><pre style="line-height: 125%; margin: 0;"> 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27</pre>
</td><td><pre style="line-height: 125%; margin: 0;"><span style="color: #008800; font-weight: bold;">var</span> AppenderBase <span style="color: #333333;">=</span> require(<span style="background-color: #fff0f0;">'./BlackHoleAppender.js'</span>);
<span style="color: #008800; font-weight: bold;">function</span> ConsoleAppender(cons, config) {
<span style="color: #008800; font-weight: bold;">var</span> finalArgs <span style="color: #333333;">=</span> [<span style="background-color: #fff0f0;">'console'</span>, config];
<span style="color: #007020;">Array</span>.prototype.forEach.call(arguments, <span style="color: #008800; font-weight: bold;">function</span>(arg) {
finalArgs.push(arg);
});
AppenderBase.apply(<span style="color: #008800; font-weight: bold;">this</span>, <span style="color: #007020;">Array</span>.prototype.slice.call(finalArgs, <span style="color: #0000dd; font-weight: bold;">2</span>));
<span style="color: #008800; font-weight: bold;">this</span>.maxLength <span style="color: #333333;">=</span> <span style="color: #007020;">Math</span>.max(config.consoleMaxLength, <span style="color: #008800; font-weight: bold;">this</span>.maxLength);
<span style="color: #008800; font-weight: bold;">this</span>.console <span style="color: #333333;">=</span> (cons <span style="color: #333333;">||</span> console);
}
ConsoleAppender.prototype <span style="color: #333333;">=</span> <span style="color: #008800; font-weight: bold;">new</span> AppenderBase(<span style="background-color: #fff0f0;">'console'</span>, {});
ConsoleAppender.prototype.write <span style="color: #333333;">=</span> <span style="color: #008800; font-weight: bold;">function</span>(finalMessage, category) {
<span style="color: #008800; font-weight: bold;">switch</span> (category) {
<span style="color: #008800; font-weight: bold;">case</span> <span style="background-color: #fff0f0;">"Error"</span><span style="color: #333333;">:</span>
<span style="color: #008800; font-weight: bold;">this</span>.console.error(finalMessage);
<span style="color: #008800; font-weight: bold;">break</span>;
<span style="color: #008800; font-weight: bold;">default</span><span style="color: #333333;">:</span>
<span style="color: #008800; font-weight: bold;">this</span>.console.debug(finalMessage);
}
};
module.exports <span style="color: #333333;">=</span> ConsoleAppender;
</pre>
</td></tr>
</tbody></table>
</div>
<br />
<b><i>API usage example (for real usage see mocha tests):</i></b>
<!-- HTML generated using hilite.me --><br />
<div style="background: #ffffff; border-width: .1em .1em .1em .8em; border: solid gray; max-height: 250px; overflow: auto; padding: .2em .6em; width: auto;">
<table><tbody>
<tr><td><pre style="line-height: 125%; margin: 0;"> 1
2
3
4
5
6
7
8
9
10
11
12
13
14</pre>
</td><td><pre style="line-height: 125%; margin: 0;"><span style="color: #888888;">/* Optional: Appenders configuration override */</span>
<span style="color: #008800; font-weight: bold;">var</span> configOverride <span style="color: #333333;">=</span> <span style="color: #008800; font-weight: bold;">null</span>,
<span style="color: #888888;">/* Boundary interface: How to "talk" with mySQL */</span>
repository <span style="color: #333333;">=</span> <span style="color: #008800; font-weight: bold;">new</span> DBMSXYZRepo(),
<span style="color: #888888;">/* The logger */</span>
logger <span style="color: #333333;">=</span> SOLIDLogs.getLogger(),
<span style="color: #888888;">/* Some appender */</span>
appender <span style="color: #333333;">=</span> SOLIDLogs.getMySQLAppender(repository, configOverride);
appender.messageHandling <span style="color: #333333;">=</span> msgHandling.ignore; <span style="color: #888888;">/* default is msgHandling.truncate */</span>
logger.addAppender(appender);
logger.debug(<span style="background-color: #fff0f0;">'Hello World!'</span>);
logger.error(<span style="background-color: #fff0f0;">'The World Is On Fire!!!'</span>);
</pre>
</td></tr>
</tbody></table>
</div>
<h2>
<br />Agile Link</h2>
With the LS principle we gain <b><i>predictability</i></b>. I like the following meaning found in the <a href="http://www.oxforddictionaries.com/definition/english/predictability" target="_blank">Oxford dictionary</a>:<br />
<blockquote class="tr_bq">
<b><i>The fact of always behaving or occurring in the way expected.</i></b></blockquote>
<br />
Simply put with LSP we avoid surprises (aka WTFs). We avoid wasting time chasing bugs from bad-behaving components. If we are designing some framework we can create tests to be run by people making extensions or sub-types of our base types, also for people implementing our contracts (pure abstract, interfaces, or just words on paper).<br />
<br />
With components designed like this, we are able to improve our estimates for change requests. Our velocity does not bounce dramatically and we get a sense of confidence both internal (the team) and external (stakeholders). This benefits help to build a Long Term Team, reduce stress level and staff turnover rate.<br />
<h3>
<br />Series links</h3>
Previous, <a href="http://tales-of-agile-adoption.blogspot.com/2016/01/solid-principles-ocp-2-of-4.html" target="_blank">SOLID Principles: OCP (2 of 4)</a><br />
Next, <a href="http://tales-of-agile-adoption.blogspot.com/2016/01/solid-principles-isp-4-of-4.html" target="_blank">SOLID Principles: ISP (4 of 4)</a><br />
<a name='more'></a><br />
<hr />
<div id="ref_00">
<b>(0)</b> <a href="https://en.wikipedia.org/wiki/Duck_typing" target="_blank">Duck typing</a> </div>
<div id="ref_01">
<b>(1)</b> <a href="https://en.wikipedia.org/wiki/Covariance_and_contravariance_(computer_science)" target="_blank">Covariance and contravariance</a></div>
<div id="ref_02">
<b>(2)</b> <a href="https://www.eiffel.com/values/design-by-contract/introduction/" target="_blank">Similar to Design by contract (eiffel language)</a></div>
</div>
Anonymoushttp://www.blogger.com/profile/12292838726080618300noreply@blogger.com0tag:blogger.com,1999:blog-8113723708012951738.post-5099529395832631682016-01-03T08:35:00.000-04:002016-05-28T22:20:14.874-04:00SOLID Principles: OCP (2 of 4)If you missed the previous post from this series check it out <a href="http://tales-of-agile-adoption.blogspot.com/2015/12/solid-principles-srp-and-dip-1-of-4.html" target="_blank">SOLID Principles: SRP and DIP (1 of 4)</a>.<br />
<br />
<h2>
Open Closed Principle</h2>
<div>
The OC principle states that<br />
<blockquote class="tr_bq">
"software entities (classes, modules, functions, etc.) should be open for extension, but closed for modification"</blockquote>
lets examine the meaning of <i>extension</i> and <i>modification</i>:<br />
<ul>
<li><b><i>Extension</i></b> means that the current functionality could be, relatively easy, enriched. </li>
<li><b><i>Modification</i></b> means the most insulting of the changes we could made to a component "to touch its source code". This is what we must try hard not to do.</li>
</ul>
<br />
<h3>
Code sample</h3>
<blockquote class="tr_bq">
Code samples are on <a href="https://github.com/lsolano/blog.solid.demo" target="_blank">github repo lsolano/blog.solid.demo</a></blockquote>
This sample is built using C# and the .NET Framework 4.5. It is a "Social Network Hub", imagine you as a very busy / lazy person and because of that you don't want (or have the time to), be constantly checking all different social networks to see your friends updates. You want a single place to look for Facebook, Twitter, Instagram, etc., updates. You start by devising a software component called <span style="font-family: "courier new" , "courier" , monospace;">SocialNetworksHub</span> that will check all your sources and will present the information in a consolidated way.<br />
<br />
To keep the model simple, suppose we are only interested on the following data elements for each entry: text (no videos, images, audio, etc.), tags (labels, hash-tags, etc.), publication date, source, and author. The "normal" behavior for the component is to have a pulling interval for social networks without a push API, and to listen for push notifications from the ones with that support.<br />
<br />
The hub has some helper components, they know how to "talk" with specific social networks APIs and convert that data to our internal model. Those components are called "collectors" with two kinds: Pull (on demand), and Push / Callback. The later are listeners for social networks supporting push notifications. All entries are sorted by date, the most recent ones first. Finally the hub support a predefined "filtering" capacity: it filters entries with "bad words".<br />
<br />
Here is the "dirty" version of this component:<br />
<div style="background: #ffffff; border-width: .1em .1em .1em .8em; border: solid gray; height: 350px; overflow: auto; padding: .2em .6em; width: auto;">
<table><tbody>
<tr><td><pre style="line-height: 125%; margin: 0;"> 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40</pre>
</td><td><pre style="line-height: 125%; margin: 0;"><span style="color: #008800; font-weight: bold;">public</span> <span style="color: #008800; font-weight: bold;">class</span> <span style="color: #bb0066; font-weight: bold;">DirtySocialNetworksHub</span> : SocialNetworksHub
{
<span style="color: #008800; font-weight: bold;">private</span> <span style="color: #008800; font-weight: bold;">readonly</span> IList<SocialNetworkPullCollector> collectors;
<span style="color: #008800; font-weight: bold;">private</span> <span style="color: #008800; font-weight: bold;">readonly</span> <span style="color: #333399; font-weight: bold;">bool</span> removeEntriesWithBadWords;
<span style="color: #008800; font-weight: bold;">private</span> <span style="color: #008800; font-weight: bold;">readonly</span> IEnumerable<String> badWords
= (<span style="color: #008800; font-weight: bold;">new</span> List<String> { <span style="background-color: #fff0f0;">"nestedLoops"</span>, <span style="background-color: #fff0f0;">"deadCode"</span>, <span style="background-color: #fff0f0;">"copy-n-paste"</span> })
.Select(word => word.ToLowerInvariant()).ToList();
<span style="color: #008800; font-weight: bold;">public</span> <span style="color: #0066bb; font-weight: bold;">DirtySocialNetworksHub</span>()
: <span style="color: #008800; font-weight: bold;">this</span>(<span style="color: #008800; font-weight: bold;">false</span>)
{
}
<span style="color: #008800; font-weight: bold;">public</span> <span style="color: #0066bb; font-weight: bold;">DirtySocialNetworksHub</span>(<span style="color: #333399; font-weight: bold;">bool</span> removeEntriesWithBadWords)
{
<span style="color: #008800; font-weight: bold;">this</span>.collectors = <span style="color: #008800; font-weight: bold;">new</span> List<SocialNetworkPullCollector>();
<span style="color: #008800; font-weight: bold;">this</span>.removeEntriesWithBadWords = removeEntriesWithBadWords;
}
<span style="color: #008800; font-weight: bold;">public</span> <span style="color: #008800; font-weight: bold;">void</span> <span style="color: #0066bb; font-weight: bold;">AddCollector</span>(SocialNetworkPullCollector collector)
{
<span style="color: #008800; font-weight: bold;">this</span>.collectors.Add(collector);
}
<span style="color: #008800; font-weight: bold;">public</span> IEnumerable<Entry> GetEntriesSince(DateTime since)
{
<span style="color: #333399; font-weight: bold;">var</span> entries = <span style="color: #008800; font-weight: bold;">this</span>.collectors.SelectMany(collector => collector.Collect(since));
<span style="color: #008800; font-weight: bold;">if</span> (<span style="color: #008800; font-weight: bold;">this</span>.removeEntriesWithBadWords) {
<span style="color: #008800; font-weight: bold;">return</span> entries.Where(entry =>
!<span style="color: #008800; font-weight: bold;">this</span>.badWords.Any(badWord => entry.Text.ToLowerInvariant().Contains(badWord))
&& (!entry.Tags.Any() || entry.Tags.Select(tag => tag.ToLowerInvariant())
.Where(tag => <span style="color: #008800; font-weight: bold;">this</span>.badWords.Any(badWord => tag.Contains(badWord))).Count() == <span style="color: #6600ee; font-weight: bold;">0</span>))
.OrderBy(entry => entry.Date).Reverse();
}
<span style="color: #008800; font-weight: bold;">return</span> entries.OrderBy(entry => entry.Date).Reverse();
}
}
</pre>
</td></tr>
</tbody></table>
</div>
<br />
<br />
This is an overview of all components, the class above is an implementation of the orange contract (interface):<br />
<div class="separator" style="clear: both; text-align: center;">
</div>
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEixAVEGCA3EZqEmD9AmD_fAWYIdXyPvuZwcteIztnm3vHxMFqC7BuN8V0emAf1yH1cRnEoT-nXy23EIQC0wACXwJR_G1H67OUHyc84pB46K9Y7AacTmZDm5pCBIG2CBx2GD-nljoNVvzvA/s1600/Dirty_Hub_Classes.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img alt="First class layout" border="0" height="364" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEixAVEGCA3EZqEmD9AmD_fAWYIdXyPvuZwcteIztnm3vHxMFqC7BuN8V0emAf1yH1cRnEoT-nXy23EIQC0wACXwJR_G1H67OUHyc84pB46K9Y7AacTmZDm5pCBIG2CBx2GD-nljoNVvzvA/s640/Dirty_Hub_Classes.png" title="First class layout" width="640" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">First class layout</td></tr>
</tbody></table>
<br />
<h3>
What is wrong with this code: OCP?</h3>
If you look closer to the <span style="font-family: "courier new" , "courier" , monospace;">GetEntriesSince(...)</span> method you'll see how the "filtering" feature was implemented:<br />
<ul>
<li>First, the component has a flag (given at construction time) to indicate if it must filter or not</li>
<li>Second, the filter is implemented as a hard-coded piece of code inside the <span style="font-family: "courier new" , "courier" , monospace;">if</span> statement using <span style="font-family: "courier new" , "courier" , monospace;">Linq</span> filters</li>
<li>Third, the "bad words" collection is hard coded inside the class</li>
</ul>
<div>
<br />
Now imagine what would happen in each of the following scenarios:</div>
<div>
<ol>
<li>From time to time the client request a change in the "bad words" list, new words are banned, then phrases, also abbreviations as WTF</li>
<li>One day a requirement arrives asking to filter entries by their extension, so only entries with up to certain characters limit will be considered</li>
<li>Another change arrives asking for a "little" tweak on the extension filter to allow for a length range, not just an upper bound</li>
<li>Then a regulation force us to implement a parental control feature with complex filter depending on the audience</li>
<li>Finally, your users request a new feature a "Mood Filter", they want you to implement a "flexible" filter that can be parameterized with allowed and forbidden moods. For example you can allow only "happy" entries, also you can eliminate entries by "bad" topics such as Politics, Dogs, or Celebrity's Gossip. This crazy request is backed up by some <a href="https://en.wikipedia.org/wiki/Neuro-linguistic_programming" target="_blank">NLP (Neuro-linguistic programming)</a> Guru, and will be implemented using a third party <a href="https://en.wikipedia.org/wiki/Sentiment_analysis" target="_blank">Sentiment analysis</a> API.</li>
<li>...</li>
</ol>
<div>
If we were to change the <span style="font-family: "courier new" , "courier" , monospace;">GetEntriesSince(...)</span> method for every request affecting the "filtering" capacity our hub will get touched a lot. It can easily get to 2,000+ lines in a couple of months. So we need to kill that monster before it grows.</div>
</div>
<div>
<br /></div>
<h2>
Cleaning the code</h2>
<h3>
Honoring the OCP</h3>
<div>
The required fix is quite simple: we just need to implement the same strategy used for the collectors. </div>
<div>
<ul>
<li>We extract the filter functionality into a contract, </li>
<li>Then, implement the bad words filtering feature a the first realization of that contract, </li>
<li>Finally, allow the hub to work without filters by just returning the raw collection of entries when no filters added</li>
</ul>
<div>
This way we leave out the basic algorithm from the possible constant change generated by the volatile "filter" functionality. </div>
</div>
<div>
<br /></div>
<div>
The components diagrams now looks like this:</div>
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhwxwYXDXhFXYyyOmZ8wwiMbASTHuNV1xLwNulqhKApkvutsI4i62CaorqZ09O27nLjbBDzC3vWpBcdGhmom-snjm3cdvAtU3DJuRCSQI5fzhHYdeOejGudG1cLWhP7EWV8ub_HIIqReec/s1600/Clean_Hub_Classes.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img alt="Second class layout" border="0" height="336" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhwxwYXDXhFXYyyOmZ8wwiMbASTHuNV1xLwNulqhKApkvutsI4i62CaorqZ09O27nLjbBDzC3vWpBcdGhmom-snjm3cdvAtU3DJuRCSQI5fzhHYdeOejGudG1cLWhP7EWV8ub_HIIqReec/s640/Clean_Hub_Classes.png" title="Second class layout" width="640" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;"><span style="font-size: 12.8px;">Second class layout</span></td></tr>
</tbody></table>
<div>
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
</div>
<div class="separator" style="clear: both; text-align: center;">
</div>
<div class="separator" style="clear: both; text-align: center;">
</div>
<div>
Here are the relevant changes:</div>
<div>
<ul>
<li>The filter functionality was extracted to the <span style="font-family: "courier new" , "courier" , monospace;">EntriesFilter</span> component, just as the collection with the Collectors family. </li>
<li>Collectors are now required to add a unique hash to each collected entry including the a source part, some like this: <span style="font-family: "courier new" , "courier" , monospace;">'facebook-bc7702b7-9f83-49b0-8245-f11c72de4b04'</span>, the UID could be provided by the underlying API, or just generated on the fly by the collector.</li>
<li>Each filter component must accept a collection of entries and return a collection of hashes for the filter-out ones, or empty if none.</li>
</ul>
<div>
The first two code samples below are the new, clean, implementation of our hub, and the extracted out "bad words" filter:</div>
<div>
<b><i><br /></i></b>
<b><i>Clean hub:</i></b></div>
<div>
<div style="background: #ffffff; border-width: .1em .1em .1em .8em; border: solid gray; height: 350px; overflow: auto; padding: .2em .6em; width: auto;">
<table><tbody>
<tr><td><pre style="line-height: 125%; margin: 0;"> 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46</pre>
</td><td><pre style="line-height: 125%; margin: 0;"><span style="color: #008800; font-weight: bold;">public</span> <span style="color: #008800; font-weight: bold;">class</span> <span style="color: #bb0066; font-weight: bold;">CleanSocialNetworksHub</span> : SocialNetworksHub
{
<span style="color: #008800; font-weight: bold;">private</span> <span style="color: #008800; font-weight: bold;">readonly</span> IList<SocialNetworkPullCollector> collectors;
<span style="color: #008800; font-weight: bold;">private</span> <span style="color: #008800; font-weight: bold;">readonly</span> IList<EntriesFilter> filters;
<span style="color: #008800; font-weight: bold;">public</span> <span style="color: #0066bb; font-weight: bold;">CleanSocialNetworksHub</span>()
{
<span style="color: #008800; font-weight: bold;">this</span>.collectors = <span style="color: #008800; font-weight: bold;">new</span> List<SocialNetworkPullCollector>();
<span style="color: #008800; font-weight: bold;">this</span>.filters = <span style="color: #008800; font-weight: bold;">new</span> List<EntriesFilter>();
}
<span style="color: #008800; font-weight: bold;">public</span> <span style="color: #008800; font-weight: bold;">void</span> <span style="color: #0066bb; font-weight: bold;">AddCollector</span>(SocialNetworkPullCollector collector)
{
<span style="color: #008800; font-weight: bold;">this</span>.collectors.Add(collector);
}
<span style="color: #008800; font-weight: bold;">public</span> <span style="color: #008800; font-weight: bold;">void</span> <span style="color: #0066bb; font-weight: bold;">AddFilter</span>(EntriesFilter filter)
{
<span style="color: #008800; font-weight: bold;">this</span>.filters.Add(filter);
}
<span style="color: #008800; font-weight: bold;">public</span> IEnumerable<Entry> GetEntriesSince(DateTime since)
{
<span style="color: #333399; font-weight: bold;">var</span> entries = <span style="color: #008800; font-weight: bold;">this</span>.collectors.SelectMany(collector => collector.Collect(since));
<span style="color: #008800; font-weight: bold;">return</span> <span style="color: #0066bb; font-weight: bold;">FilterEntries</span>(entries).OrderBy(entry => entry.Date).Reverse();
}
<span style="color: #008800; font-weight: bold;">private</span> IEnumerable<Entry> FilterEntries(IEnumerable<Entry> entries)
{
<span style="color: #333399; font-weight: bold;">var</span> filterOutHashes = <span style="color: #008800; font-weight: bold;">new</span> ConcurrentBag<String>();
Parallel.ForEach(<span style="color: #008800; font-weight: bold;">this</span>.filters, (filter) =>
{
IEnumerable<String> invalidEntriesHashes = filter.Filter(entries);
<span style="color: #008800; font-weight: bold;">foreach</span> (<span style="color: #333399; font-weight: bold;">var</span> hash <span style="color: #008800; font-weight: bold;">in</span> invalidEntriesHashes)
{
filterOutHashes.Add(hash);
}
});
<span style="color: #333399; font-weight: bold;">var</span> finalExclusions = filterOutHashes.Distinct().ToArray();
<span style="color: #008800; font-weight: bold;">return</span> entries.Where(entry => !finalExclusions.Contains(entry.Hash));
}
}
</pre>
</td></tr>
</tbody></table>
</div>
<br /></div>
<div>
<b><i>Bad words filter:</i></b></div>
<div style="background: #ffffff; border-width: .1em .1em .1em .8em; border: solid gray; height: 350px; overflow: auto; padding: .2em .6em; width: auto;">
<table><tbody>
<tr><td><pre style="line-height: 125%; margin: 0;"> 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41</pre>
</td><td><pre style="line-height: 125%; margin: 0;"><span style="color: #008800; font-weight: bold;">public</span> <span style="color: #008800; font-weight: bold;">sealed</span> <span style="color: #008800; font-weight: bold;">class</span> <span style="color: #bb0066; font-weight: bold;">BadWordsFilter</span> : EntriesFilter
{
<span style="color: #008800; font-weight: bold;">private</span> <span style="color: #008800; font-weight: bold;">readonly</span> ISet<String> badWords = <span style="color: #008800; font-weight: bold;">new</span> HashSet<String>();
<span style="color: #008800; font-weight: bold;">public</span> <span style="color: #0066bb; font-weight: bold;">BadWordsFilter</span>(IEnumerable<String> badWords)
{
<span style="color: #333399; font-weight: bold;">var</span> words = badWords ?? <span style="color: #008800; font-weight: bold;">new</span> List<String>();
<span style="color: #333399; font-weight: bold;">var</span> normalizedWords = words.Where(word => !String.IsNullOrWhiteSpace(word))
.Select(word => word.ToLowerInvariant().Trim());
<span style="color: #008800; font-weight: bold;">foreach</span> (<span style="color: #333399; font-weight: bold;">var</span> word <span style="color: #008800; font-weight: bold;">in</span> normalizedWords)
{
<span style="color: #008800; font-weight: bold;">this</span>.badWords.Add(word);
}
}
<span style="color: #008800; font-weight: bold;">public</span> IEnumerable<<span style="color: #333399; font-weight: bold;">string</span>> Filter(IEnumerable<Entry> entries)
{
<span style="color: #008800; font-weight: bold;">foreach</span> (<span style="color: #333399; font-weight: bold;">var</span> entry <span style="color: #008800; font-weight: bold;">in</span> entries.Where(entry => IsBadEntry(entry)))
{
<span style="color: #008800; font-weight: bold;">yield</span> <span style="color: #008800; font-weight: bold;">return</span> entry.Hash;
}
<span style="color: #008800; font-weight: bold;">yield</span> <span style="color: #008800; font-weight: bold;">break</span>;
}
<span style="color: #008800; font-weight: bold;">private</span> <span style="color: #333399; font-weight: bold;">bool</span> <span style="color: #0066bb; font-weight: bold;">IsBadEntry</span>(Entry entry)
{
<span style="color: #008800; font-weight: bold;">if</span> (<span style="color: #008800; font-weight: bold;">this</span>.badWords.Any(badWord => entry.Text.ToLowerInvariant().Contains(badWord)))
{
<span style="color: #008800; font-weight: bold;">return</span> <span style="color: #008800; font-weight: bold;">true</span>;
}
<span style="color: #333399; font-weight: bold;">var</span> lowerTags = entry.Tags.Select(tag => tag.ToLowerInvariant());
<span style="color: #008800; font-weight: bold;">if</span> (lowerTags.Any(tag => <span style="color: #008800; font-weight: bold;">this</span>.badWords.Any(badWord => tag.Contains(badWord))))
{
<span style="color: #008800; font-weight: bold;">return</span> <span style="color: #008800; font-weight: bold;">true</span>;
}
<span style="color: #008800; font-weight: bold;">return</span> <span style="color: #008800; font-weight: bold;">false</span>;
}
}
</pre>
</td></tr>
</tbody></table>
</div>
<div>
<br />
The usage of the clean hub will be something like this (see tests for real examples):<br />
<div style="background: #ffffff; border-width: .1em .1em .1em .8em; border: solid gray; overflow: auto; padding: .2em .6em; width: auto;">
<table><tbody>
<tr><td><pre style="line-height: 125%; margin: 0;"> 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17</pre>
</td><td><pre style="line-height: 125%; margin: 0;"><span style="color: #0000cc;">[Test]</span>
<span style="color: #008800; font-weight: bold;">public</span> <span style="color: #008800; font-weight: bold;">void</span> <span style="color: #0066bb; font-weight: bold;">TestSomething</span>()
{
<span style="color: #888888;">/* Test data: Fake entries */</span>
IEnumerable<Entry> entries = ...;
<span style="color: #888888;">/* Dummy collector (boundary interface) */</span>
SocialNetworkPullCollector returnAllCollector = <span style="color: #008800; font-weight: bold;">new</span> ReturnAllPullCollector(entries);
<span style="color: #888888;">/* Filter: real implementation */</span>
EntriesFilter filter = <span style="color: #008800; font-weight: bold;">new</span> BadWordsFilter(<span style="background-color: #fff0f0;">"nestedLoops,deadCode,copy-n-paste"</span>.Split(<span style="color: #0044dd;">','</span>));
<span style="color: #888888;">/* Hub instantiation and configuration */</span>
SocialNetworksHub hub = <span style="color: #008800; font-weight: bold;">new</span> CleanSocialNetworksHub();
hub.AddCollector(returnAllCollector);
hub.AddFilter(filter);
}
</pre>
</td></tr>
</tbody></table>
</div>
<br /></div>
<div>
<b>Going further:</b></div>
</div>
<div>
If you look to the final version of the method GetEntriesSince(...), you see just two lines of code, one that collect all entries and another that does the filtering and sorting. If we start to receive crazy sorting requirements like: by social network then by date, or by author ranking, then by social network, and then by date, etc.; then we must apply a similar solution and extract out the "sorting" responsibility to a new family of components. If you like just <a href="https://github.com/lsolano/blog.solid.demo" target="_blank">fork the github repository</a> and do that.<br />
<h2>
<br />
Agile Link</h2>
Again, I'll elaborate the code link to agile thinking using the Agile Principles from the manifesto.<br />
<blockquote class="tr_bq">
<b><i>The best architectures, requirements, and designs emerge from self-organizing teams.</i></b></blockquote>
The clean implementation is an example of <b><i>"emergent design"</i></b>. The initial requirement has a clear insight about the "collection" mechanisms so from day one we devise a flexible solution for this responsibility. After our imaginary first release, we start to see more an more incoming changes to the "filter" responsibility, so by that time we evolve our simple solution to a more maintainable one. We are also honoring the KISS principle that says<br />
<blockquote class="tr_bq">
<i>Keep it simple, stupid.</i></blockquote>
<h3>
Series links</h3>
<ul>
<li>Previous, <a href="http://tales-of-agile-adoption.blogspot.com/2015/12/solid-principles-srp-and-dip-1-of-4.html" target="_blank">SOLID Principles: SRP and DIP (1 of 4)</a></li>
<li>Next, <a href="http://tales-of-agile-adoption.blogspot.com/2016/01/solid-principles-lsp-3-of-4.html" target="_blank">SOLID Principles: LSP (3 of 4)</a> </li>
</ul>
</div>
<div>
<br /></div>
<div>
<br /></div>
</div>
Anonymoushttp://www.blogger.com/profile/12292838726080618300noreply@blogger.com0tag:blogger.com,1999:blog-8113723708012951738.post-12631620854017052952015-12-30T09:28:00.000-04:002016-05-28T22:19:47.633-04:00SOLID Principles: SRP and DIP (1 of 4)In this series I'll explain five of the core O.O. design principles. Each entry will have an <b><i>Agile Link</i></b> section describing how the explained principle(s) relates to Agile thinking.<br />
<h2>
Single responsibility principle (SRP)</h2>
<div>
The SRP states that elements (classes and methods), should have only one reason to change. They must be focused on a single task, anything related to that task must be extracted as services / helpers and need to be placed inside other components, called dependencies.<br />
<br />
This post will cover another core principle:<br />
<h2>
Dependency inversion principle (DIP)</h2>
Simply put, this principle says that both high and low level components should depend on abstractions (contracts), not on details.<br />
<br />
<h3>
Code sample</h3>
<blockquote class="tr_bq">
Code samples are on <a href="https://github.com/lsolano/blog.solid.demo" target="_blank">github repo lsolano/blog.solid.demo</a></blockquote>
This code sample (java SE 1.8), is a fake "ClientsReportBuilder" component, the ideal responsibility for this guy is to build a "Clients Report" pulling the data from underlying persistence mechanism and finally formatting it using one of the following (output formats): XML, JSON, or CSV. Code comments are omitted to keep it as short as possible.<br />
<br />
This is the initial (dirty) version, the behavior is defined by the contract <span style="font-family: "courier new" , "courier" , monospace;">ClientsReportBuilder</span>, and implemented by <span style="font-family: "courier new" , "courier" , monospace;">DirtyClientsReportBuilder</span>. This version of the method <span style="font-family: "courier new" , "courier" , monospace;">buildNewClientsReports</span> has around 40 lines of code (LOC). It has a very straitforward logic:<br />
<ul>
<li>First, it does some validations for method's parameters.</li>
<li>Second, it instantiates a known version of the repository <span style="font-family: "courier new" , "courier" , monospace;">ClientsRepository</span> (<span style="font-family: "courier new" , "courier" , monospace;">InMemoryClientsRepository</span>), and uses it to get all clients with sign-on date within the given date range.</li>
<li>Third, it examines the <span style="font-family: "courier new" , "courier" , monospace;">format</span> parameter and for each possible value builds the resulting string to return. Also if the format is not supported it throws and exception.</li>
</ul>
</div>
<div>
<!-- HTML generated using hilite.me -->
<br />
<div style="background: #ffffff; border-width: .1em .1em .1em .8em; border: solid gray; height: 400px; overflow: auto; padding: .2em .6em; width: auto;">
<table><tbody>
<tr><td><pre style="line-height: 125%; margin: 0;"> 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46</pre>
</td><td><pre style="line-height: 125%; margin: 0;"><span style="color: #008800; font-weight: bold;">import</span> <span style="color: #0e84b5; font-weight: bold;">java.util.Date</span><span style="color: #333333;">;</span>
<span style="color: #008800; font-weight: bold;">import</span> <span style="color: #0e84b5; font-weight: bold;">java.util.stream.Stream</span><span style="color: #333333;">;</span>
<span style="color: #008800; font-weight: bold;">public</span> <span style="color: #008800; font-weight: bold;">class</span> <span style="color: #bb0066; font-weight: bold;">DirtyClientsReportBuilder</span> <span style="color: #008800; font-weight: bold;">implements</span> ClientsReportBuilder <span style="color: #333333;">{</span>
<span style="color: #555555; font-weight: bold;">@Override</span>
<span style="color: #008800; font-weight: bold;">public</span> String <span style="color: #0066bb; font-weight: bold;">buildNewClientsReport</span><span style="color: #333333;">(</span><span style="color: #008800; font-weight: bold;">final</span> Date from<span style="color: #333333;">,</span> <span style="color: #008800; font-weight: bold;">final</span> Date to<span style="color: #333333;">,</span> <span style="color: #008800; font-weight: bold;">final</span> OutputFormat format<span style="color: #333333;">)</span> <span style="color: #333333;">{</span>
<span style="color: #008800; font-weight: bold;">if</span> <span style="color: #333333;">(</span>from <span style="color: #333333;">==</span> <span style="color: #008800; font-weight: bold;">null</span> <span style="color: #333333;">||</span> to <span style="color: #333333;">==</span> <span style="color: #008800; font-weight: bold;">null</span> <span style="color: #333333;">||</span> format <span style="color: #333333;">==</span> <span style="color: #008800; font-weight: bold;">null</span><span style="color: #333333;">)</span> <span style="color: #333333;">{</span>
<span style="color: #008800; font-weight: bold;">throw</span> <span style="color: #008800; font-weight: bold;">new</span> <span style="color: #0066bb; font-weight: bold;">IllegalArgumentException</span><span style="color: #333333;">(</span><span style="background-color: #fff0f0;">"Arguments can not be null."</span><span style="color: #333333;">);</span>
<span style="color: #333333;">}</span>
<span style="color: #008800; font-weight: bold;">if</span> <span style="color: #333333;">(</span>from<span style="color: #333333;">.</span><span style="color: #0000cc;">compareTo</span><span style="color: #333333;">(</span>to<span style="color: #333333;">)</span> <span style="color: #333333;">></span> <span style="color: #0000dd; font-weight: bold;">0</span><span style="color: #333333;">)</span> <span style="color: #333333;">{</span>
<span style="color: #008800; font-weight: bold;">throw</span> <span style="color: #008800; font-weight: bold;">new</span> <span style="color: #0066bb; font-weight: bold;">IllegalArgumentException</span><span style="color: #333333;">(</span>String<span style="color: #333333;">.</span><span style="color: #0000cc;">format</span><span style="color: #333333;">(</span><span style="background-color: #fff0f0;">"Invalid date range [%s, %s]."</span><span style="color: #333333;">,</span> from<span style="color: #333333;">,</span> to<span style="color: #333333;">));</span>
<span style="color: #333333;">}</span>
<span style="color: #008800; font-weight: bold;">final</span> ClientsRepository clientsRepo <span style="color: #333333;">=</span> <span style="color: #008800; font-weight: bold;">new</span> InMemoryClientsRepository<span style="color: #333333;">();</span>
<span style="color: #008800; font-weight: bold;">final</span> Stream<span style="color: #333333;"><</span>Client<span style="color: #333333;">></span> clients <span style="color: #333333;">=</span> clientsRepo<span style="color: #333333;">.</span><span style="color: #0000cc;">getBySignOnDate</span><span style="color: #333333;">(</span>from<span style="color: #333333;">,</span> to<span style="color: #333333;">);</span>
<span style="color: #008800; font-weight: bold;">final</span> StringBuffer sb <span style="color: #333333;">=</span> <span style="color: #008800; font-weight: bold;">new</span> StringBuffer<span style="color: #333333;">();</span>
<span style="color: #008800; font-weight: bold;">switch</span> <span style="color: #333333;">(</span>format<span style="color: #333333;">)</span> <span style="color: #333333;">{</span>
<span style="color: #008800; font-weight: bold;">case</span> <span style="color: #997700; font-weight: bold;">XML:</span>
sb<span style="color: #333333;">.</span><span style="color: #0000cc;">append</span><span style="color: #333333;">(</span><span style="background-color: #fff0f0;">"<report>"</span><span style="color: #333333;">);</span>
clients<span style="color: #333333;">.</span><span style="color: #0000cc;">parallel</span><span style="color: #333333;">()</span>
<span style="color: #333333;">.</span><span style="color: #0000cc;">forEach</span><span style="color: #333333;">(</span>client <span style="color: #333333;">-></span> sb<span style="color: #333333;">.</span><span style="color: #0000cc;">append</span><span style="color: #333333;">(</span><span style="background-color: #fff0f0;">"<client><name>"</span><span style="color: #333333;">).</span><span style="color: #0000cc;">append</span><span style="color: #333333;">(</span>client<span style="color: #333333;">.</span><span style="color: #0000cc;">getName</span><span style="color: #333333;">()).</span><span style="color: #0000cc;">append</span><span style="color: #333333;">(</span><span style="background-color: #fff0f0;">"</name></client>"</span><span style="color: #333333;">));</span>
sb<span style="color: #333333;">.</span><span style="color: #0000cc;">append</span><span style="color: #333333;">(</span><span style="background-color: #fff0f0;">"</report>"</span><span style="color: #333333;">);</span>
<span style="color: #008800; font-weight: bold;">break</span><span style="color: #333333;">;</span>
<span style="color: #008800; font-weight: bold;">case</span> <span style="color: #997700; font-weight: bold;">JSON:</span>
sb<span style="color: #333333;">.</span><span style="color: #0000cc;">append</span><span style="color: #333333;">(</span><span style="color: #0044dd;">'['</span><span style="color: #333333;">);</span>
clients<span style="color: #333333;">.</span><span style="color: #0000cc;">parallel</span><span style="color: #333333;">().</span><span style="color: #0000cc;">forEach</span><span style="color: #333333;">(</span>client <span style="color: #333333;">-></span> sb<span style="color: #333333;">.</span><span style="color: #0000cc;">append</span><span style="color: #333333;">(</span><span style="background-color: #fff0f0;">"{ \"name\": \""</span><span style="color: #333333;">).</span><span style="color: #0000cc;">append</span><span style="color: #333333;">(</span>client<span style="color: #333333;">.</span><span style="color: #0000cc;">getName</span><span style="color: #333333;">()).</span><span style="color: #0000cc;">append</span><span style="color: #333333;">(</span><span style="background-color: #fff0f0;">"\" },"</span><span style="color: #333333;">));</span>
sb<span style="color: #333333;">.</span><span style="color: #0000cc;">deleteCharAt</span><span style="color: #333333;">(</span>sb<span style="color: #333333;">.</span><span style="color: #0000cc;">length</span><span style="color: #333333;">()</span> <span style="color: #333333;">-</span> <span style="color: #0000dd; font-weight: bold;">1</span><span style="color: #333333;">);</span>
sb<span style="color: #333333;">.</span><span style="color: #0000cc;">append</span><span style="color: #333333;">(</span><span style="color: #0044dd;">']'</span><span style="color: #333333;">);</span>
<span style="color: #008800; font-weight: bold;">break</span><span style="color: #333333;">;</span>
<span style="color: #008800; font-weight: bold;">case</span> <span style="color: #997700; font-weight: bold;">CSV:</span>
sb<span style="color: #333333;">.</span><span style="color: #0000cc;">append</span><span style="color: #333333;">(</span>String<span style="color: #333333;">.</span><span style="color: #0000cc;">format</span><span style="color: #333333;">(</span><span style="background-color: #fff0f0;">"email,name%n"</span><span style="color: #333333;">));</span>
clients<span style="color: #333333;">.</span><span style="color: #0000cc;">parallel</span><span style="color: #333333;">().</span><span style="color: #0000cc;">forEach</span><span style="color: #333333;">(</span>client <span style="color: #333333;">-></span> sb<span style="color: #333333;">.</span><span style="color: #0000cc;">append</span><span style="color: #333333;">(</span>client<span style="color: #333333;">.</span><span style="color: #0000cc;">getEmail</span><span style="color: #333333;">()).</span><span style="color: #0000cc;">append</span><span style="color: #333333;">(</span><span style="background-color: #fff0f0;">","</span><span style="color: #333333;">).</span><span style="color: #0000cc;">append</span><span style="color: #333333;">(</span>client<span style="color: #333333;">.</span><span style="color: #0000cc;">getName</span><span style="color: #333333;">()));</span>
<span style="color: #008800; font-weight: bold;">break</span><span style="color: #333333;">;</span>
<span style="color: #008800; font-weight: bold;">default</span><span style="color: #333333;">:</span>
<span style="color: #008800; font-weight: bold;">throw</span> <span style="color: #008800; font-weight: bold;">new</span> <span style="color: #0066bb; font-weight: bold;">IllegalArgumentException</span><span style="color: #333333;">(</span>String<span style="color: #333333;">.</span><span style="color: #0000cc;">format</span><span style="color: #333333;">(</span><span style="background-color: #fff0f0;">"Format not supported '%s'."</span><span style="color: #333333;">,</span> format<span style="color: #333333;">));</span>
<span style="color: #333333;">}</span>
<span style="color: #008800; font-weight: bold;">return</span> sb<span style="color: #333333;">.</span><span style="color: #0000cc;">toString</span><span style="color: #333333;">();</span>
<span style="color: #333333;">}</span>
<span style="color: #333333;">}</span>
</pre>
</td></tr>
</tbody></table>
</div>
<br />
<h3>
What is wrong with this code: SRP?</h3>
<ol>
<li>At the class level: this class is supposed to "build report(s)" but is doing a little more: it knows to much about the repository used, and also knows about how to handle all output formats. This means that:</li>
<ol>
<li>If a new format is added, this class must change</li>
<li>If a different implementation of the repository (flat file, RDB, No-SQL DB, ...), is used this class must change</li>
</ol>
<li>At the method level: this method is supposed to build the report using helper entities within its class or as outside services. We can count up to 3 responsibilities here:</li>
<ol>
<li>The parameters validation logic,</li>
<li>Pulling out clients from repository, and</li>
<li>Building the report using the proper format</li>
</ol>
</ol>
<div>
In order to fix these violations we must split as much as possible all things done by the dirty class.</div>
<h3>
</h3>
<h3>
What is wrong with this code: DIP?</h3>
<div>
<ol>
<li>This class depends on the ClientsRepository but actually has to much information about it. It knows about the implementation details.</li>
<li>Conceptually, it must depend on a "formatter" component, actually spread inside the switch statement.</li>
</ol>
<div>
To fix the violations to the DI principle we must extract these two dependencies and define contracts (abstractions) so both high and low level components can interact knowing as little as possible about each other. Just to be clear, in this example the high level component is the ClientsReportBuilder and the low level ones are the repository and the (not yet created) formatter. </div>
</div>
<div>
<br /></div>
<h2>
Cleaning the code</h2>
<div>
<h3>
Honoring SRP</h3>
At the class level the helper responsibilities where extracted:<br />
<ul>
<li>A dependency to the repository contract was introduced to the, new and only, constructor</li>
<li>A dependency to builder / factory function for the <i>formatter</i> component, which will take the Client's collection (stream) and return the final string with the proper format.</li>
</ul>
<div>
At the method level, the following changes were made:</div>
<div>
<ul>
<li>The parameters validation logic was extracted into a private method</li>
<li>The formatter was extracted to a helper factory function using the Optional pattern. If the format is invalid (not managed yet), the Option will be empty</li>
<li>The method was reduced from around 40 lines to just 12 lines of code.</li>
</ul>
</div>
</div>
<div>
<div style="background: #ffffff; border-width: .1em .1em .1em .8em; border: solid gray; overflow: auto; padding: .2em .6em; width: auto;">
<table><tbody>
<tr><td><pre style="line-height: 125%; margin: 0;"> 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42</pre>
</td><td><pre style="line-height: 125%; margin: 0;"><span style="color: #008800; font-weight: bold;">import</span> <span style="color: #0e84b5; font-weight: bold;">java.util.Date</span><span style="color: #333333;">;</span>
<span style="color: #008800; font-weight: bold;">import</span> <span style="color: #0e84b5; font-weight: bold;">java.util.Optional</span><span style="color: #333333;">;</span>
<span style="color: #008800; font-weight: bold;">import</span> <span style="color: #0e84b5; font-weight: bold;">java.util.function.Function</span><span style="color: #333333;">;</span>
<span style="color: #008800; font-weight: bold;">import</span> <span style="color: #0e84b5; font-weight: bold;">java.util.stream.Stream</span><span style="color: #333333;">;</span>
<span style="color: #008800; font-weight: bold;">public</span> <span style="color: #008800; font-weight: bold;">class</span> <span style="color: #bb0066; font-weight: bold;">CleanClientsReportBuilder</span> <span style="color: #008800; font-weight: bold;">implements</span> ClientsReportBuilder <span style="color: #333333;">{</span>
<span style="color: #008800; font-weight: bold;">private</span> <span style="color: #008800; font-weight: bold;">final</span> Function<span style="color: #333333;"><</span>OutputFormat<span style="color: #333333;">,</span> Optional<span style="color: #333333;"><</span>Function<span style="color: #333333;"><</span>Stream<span style="color: #333333;"><</span>Client<span style="color: #333333;">>,</span> String<span style="color: #333333;">>>></span> formattersFactory<span style="color: #333333;">;</span>
<span style="color: #008800; font-weight: bold;">private</span> <span style="color: #008800; font-weight: bold;">final</span> ClientsRepository clientsRepo<span style="color: #333333;">;</span>
<span style="color: #008800; font-weight: bold;">public</span> <span style="color: #0066bb; font-weight: bold;">CleanClientsReportBuilder</span><span style="color: #333333;">(</span>
<span style="color: #008800; font-weight: bold;">final</span> Function<span style="color: #333333;"><</span>OutputFormat<span style="color: #333333;">,</span> Optional<span style="color: #333333;"><</span>Function<span style="color: #333333;"><</span>Stream<span style="color: #333333;"><</span>Client<span style="color: #333333;">>,</span> String<span style="color: #333333;">>>></span> formattersFactory<span style="color: #333333;">,</span>
<span style="color: #008800; font-weight: bold;">final</span> ClientsRepository clientsRepo<span style="color: #333333;">)</span> <span style="color: #333333;">{</span>
<span style="color: #008800; font-weight: bold;">this</span><span style="color: #333333;">.</span><span style="color: #0000cc;">formattersFactory</span> <span style="color: #333333;">=</span> formattersFactory<span style="color: #333333;">;</span>
<span style="color: #008800; font-weight: bold;">this</span><span style="color: #333333;">.</span><span style="color: #0000cc;">clientsRepo</span> <span style="color: #333333;">=</span> clientsRepo<span style="color: #333333;">;</span>
<span style="color: #333333;">}</span>
<span style="color: #555555; font-weight: bold;">@Override</span>
<span style="color: #008800; font-weight: bold;">public</span> String <span style="color: #0066bb; font-weight: bold;">buildNewClientsReport</span><span style="color: #333333;">(</span><span style="color: #008800; font-weight: bold;">final</span> Date from<span style="color: #333333;">,</span> <span style="color: #008800; font-weight: bold;">final</span> Date to<span style="color: #333333;">,</span> <span style="color: #008800; font-weight: bold;">final</span> OutputFormat format<span style="color: #333333;">)</span> <span style="color: #333333;">{</span>
validateReportParameters<span style="color: #333333;">(</span>from<span style="color: #333333;">,</span> to<span style="color: #333333;">,</span> format<span style="color: #333333;">);</span>
<span style="color: #008800; font-weight: bold;">final</span> Stream<span style="color: #333333;"><</span>Client<span style="color: #333333;">></span> clients <span style="color: #333333;">=</span> clientsRepo<span style="color: #333333;">.</span><span style="color: #0000cc;">getBySignOnDate</span><span style="color: #333333;">(</span>from<span style="color: #333333;">,</span> to<span style="color: #333333;">);</span>
<span style="color: #008800; font-weight: bold;">final</span> Optional<span style="color: #333333;"><</span>Function<span style="color: #333333;"><</span>Stream<span style="color: #333333;"><</span>Client<span style="color: #333333;">>,</span> String<span style="color: #333333;">>></span> formatter <span style="color: #333333;">=</span> <span style="color: #008800; font-weight: bold;">this</span><span style="color: #333333;">.</span><span style="color: #0000cc;">formattersFactory</span><span style="color: #333333;">.</span><span style="color: #0000cc;">apply</span><span style="color: #333333;">(</span>format<span style="color: #333333;">);</span>
<span style="color: #008800; font-weight: bold;">if</span> <span style="color: #333333;">(</span>formatter<span style="color: #333333;">.</span><span style="color: #0000cc;">isPresent</span><span style="color: #333333;">())</span> <span style="color: #333333;">{</span>
<span style="color: #008800; font-weight: bold;">return</span> formatter<span style="color: #333333;">.</span><span style="color: #0000cc;">get</span><span style="color: #333333;">().</span><span style="color: #0000cc;">apply</span><span style="color: #333333;">(</span>clients<span style="color: #333333;">);</span>
<span style="color: #333333;">}</span>
<span style="color: #008800; font-weight: bold;">throw</span> <span style="color: #008800; font-weight: bold;">new</span> <span style="color: #0066bb; font-weight: bold;">IllegalArgumentException</span><span style="color: #333333;">(</span>String<span style="color: #333333;">.</span><span style="color: #0000cc;">format</span><span style="color: #333333;">(</span><span style="background-color: #fff0f0;">"Format not supported '%s'."</span><span style="color: #333333;">,</span> format<span style="color: #333333;">));</span>
<span style="color: #333333;">}</span>
<span style="color: #008800; font-weight: bold;">private</span> <span style="color: #333399; font-weight: bold;">void</span> <span style="color: #0066bb; font-weight: bold;">validateReportParameters</span><span style="color: #333333;">(</span><span style="color: #008800; font-weight: bold;">final</span> Date from<span style="color: #333333;">,</span> <span style="color: #008800; font-weight: bold;">final</span> Date to<span style="color: #333333;">,</span> <span style="color: #008800; font-weight: bold;">final</span> OutputFormat format<span style="color: #333333;">)</span> <span style="color: #333333;">{</span>
<span style="color: #008800; font-weight: bold;">if</span> <span style="color: #333333;">(</span>from <span style="color: #333333;">==</span> <span style="color: #008800; font-weight: bold;">null</span> <span style="color: #333333;">||</span> to <span style="color: #333333;">==</span> <span style="color: #008800; font-weight: bold;">null</span> <span style="color: #333333;">||</span> format <span style="color: #333333;">==</span> <span style="color: #008800; font-weight: bold;">null</span><span style="color: #333333;">)</span> <span style="color: #333333;">{</span>
<span style="color: #008800; font-weight: bold;">throw</span> <span style="color: #008800; font-weight: bold;">new</span> <span style="color: #0066bb; font-weight: bold;">IllegalArgumentException</span><span style="color: #333333;">(</span><span style="background-color: #fff0f0;">"Arguments can not be null."</span><span style="color: #333333;">);</span>
<span style="color: #333333;">}</span>
<span style="color: #008800; font-weight: bold;">if</span> <span style="color: #333333;">(</span>from<span style="color: #333333;">.</span><span style="color: #0000cc;">compareTo</span><span style="color: #333333;">(</span>to<span style="color: #333333;">)</span> <span style="color: #333333;">></span> <span style="color: #0000dd; font-weight: bold;">0</span><span style="color: #333333;">)</span> <span style="color: #333333;">{</span>
<span style="color: #008800; font-weight: bold;">throw</span> <span style="color: #008800; font-weight: bold;">new</span> <span style="color: #0066bb; font-weight: bold;">IllegalArgumentException</span><span style="color: #333333;">(</span>String<span style="color: #333333;">.</span><span style="color: #0000cc;">format</span><span style="color: #333333;">(</span><span style="background-color: #fff0f0;">"Invalid date range [%s, %s]."</span><span style="color: #333333;">,</span> from<span style="color: #333333;">,</span> to<span style="color: #333333;">));</span>
<span style="color: #333333;">}</span>
<span style="color: #333333;">}</span>
<span style="color: #333333;">}</span>
</pre>
</td></tr>
</tbody></table>
</div>
<br /></div>
<div>
<h3>
Honoring the DIP</h3>
</div>
<div>
To use this version of the component we need to do the following (<a href="https://github.com/lsolano/blog.solid.demo/tree/master/java/src/test/java/com/malpeza/solid/srp_dip" target="_blank">see tests on GitHub repository</a>).<br />
<!-- HTML generated using hilite.me --><br />
<div style="background: #ffffff; border-width: .1em .1em .1em .8em; border: solid gray; overflow: auto; padding: .2em .6em; width: auto;">
<table><tbody>
<tr><td><pre style="line-height: 125%; margin: 0;">1
2
3</pre>
</td><td><pre style="line-height: 125%; margin: 0;"><span style="color: #008800; font-weight: bold;">final</span> ClientsReportBuilder clientReportBuilder <span style="color: #333333;">=</span>
<span style="color: #008800; font-weight: bold;">new</span> <span style="color: #0066bb; font-weight: bold;">CleanClientsReportBuilder</span><span style="color: #333333;">(</span>ClientsReportFormatter<span style="color: #333333;">.</span><span style="color: #0000cc;">buildFormattersFactory</span><span style="color: #333333;">(),</span>
<span style="color: #008800; font-weight: bold;">new</span> <span style="color: #0066bb; font-weight: bold;">InMemoryClientsRepository</span><span style="color: #333333;">());</span>
</pre>
</td></tr>
</tbody></table>
</div>
</div>
<br />
Basically, we set both dependencies using the constructor's parameters. With a good IOC tool you just inject those into the component. Here both dependencies were extracted and supplied, achieving the following goals:<br />
<br />
<ul>
<li>The report builder component knows nothing about the implementation of the repository. It only knows about the contract (using a java interface).</li>
<li>The report builder component knows nothing about the formatter components family. If only requires a factory function that will give Nothing or an actual formatter function.</li>
</ul>
<br />
<br />
<h2>
Agile Link</h2>
I'll elaborate the code link to agile thinking using the <a href="http://agilemanifesto.org/principles.html" target="_blank">Agile Principles from the manifesto</a>.<br />
<div>
<blockquote class="tr_bq">
<b><i>Welcome changing requirements, even late in development. Agile processes harness change for the customer's competitive advantage.</i></b></blockquote>
With the final implementation is easy to add a new output format. Also we can change the repository implementation without impacting the report builder. Adding / fixing the validation logic is easy because is encapsulated within a single, short method.<br />
<br />
<blockquote class="tr_bq">
<b><i>Agile processes promote sustainable development. ... [We] should be able to maintain a constant pace indefinitely.</i></b></blockquote>
With a clean code base we avoid the "maintenance hell". We avoid working extra hours and burning the team in the process. Remember this is job, we must not die like heroes in the process, if that what you want join the army :)<br />
<br />
<blockquote class="tr_bq">
<b><i>Continuous attention to technical excellence and good design enhances agility.</i></b></blockquote>
"Excellence" is a relative term, but code's final version is more elegant than the first. Surely, someone in the future can improve the code even further but is our job to let the code as clean and simple as our current knowledge level allows.<br />
<br />
<h3>
Next on this series</h3>
<a href="http://tales-of-agile-adoption.blogspot.com/2016/01/solid-principles-ocp-2-of-4.html" target="_blank">SOLID Principles: Open/closed principle (OCP)</a> </div>
</div>
Anonymoushttp://www.blogger.com/profile/12292838726080618300noreply@blogger.com2tag:blogger.com,1999:blog-8113723708012951738.post-1567258087636899032015-12-24T11:32:00.000-04:002016-05-28T22:19:34.785-04:00Reflections on Clean Code: Team's Performance<div dir="ltr">
<h2 style="text-align: center;">
<span style="font-size: large;">XP-agra for flaccid Scrum teams (Doctor's Choice)</span></h2>
</div>
<div dir="ltr">
<br /></div>
<div dir="ltr">
Keep reading if you find yourself or your team in one of the following situations:</div>
<div dir="ltr">
<ol>
<li>You no longer have confidence in your estimates (time, effort, risks)</li>
<li>You have 'owners' for certain software components</li>
<li>Your regression test takes more than half a day</li>
<li>A very high rate of bugs (defects) are discovered in production by your users</li>
<li>In order to find the piece of code to change or the place to add a few new lines you need to spend hours digging the code base</li>
<li>Sometimes you touch Component A and the change affects Components B to Z, and you discover that on late test cycles or live in production</li>
<li>With every iteration you feel that the time to perform minor changes is growing exponentially</li>
<li>Everybody fears the release date, and stay alert the next week or two expecting the next bomb coming from production</li>
<li>Your team is doing Scrum (or so you believe)</li>
</ol>
</div>
<div dir="ltr">
<br /></div>
<div dir="ltr">
If any of the described situations is happening to you be advised: <b style="font-style: italic;">your team is suffering from the disease called "Flaccid Scrum" </b><b><i>(FlaccidScrum)</i></b>. This illness causes your performance to, gradually, decrease until you reach the zero productivity (velocity) point. By that time the only possible solution is to dump the code base (put the product in the trashcan), and start over with a greenfield project.</div>
<div dir="ltr">
<br /></div>
<div dir="ltr">
But, fear no more, you can be cured with a simple solution: just take XP-agra the Doctor's Choice for flaccid scrum implementations. You need to start with solid engineering practices as proposed by eXtreme Programming.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgtBxz-Cr43U_tct258BZaWyEHc3UpokOgkMBgWNNJ8i9rMFxqeBG-rj2kAR6JbPunWEKi6rmByk67Fux7L-zZBs9Uu2Nig9lh6_Pjfc7k6I6VgeCsoTQZoJCV7-yuv8I5SzGNL3ajpqVs/s1600/svgexpanded.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="417" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgtBxz-Cr43U_tct258BZaWyEHc3UpokOgkMBgWNNJ8i9rMFxqeBG-rj2kAR6JbPunWEKi6rmByk67Fux7L-zZBs9Uu2Nig9lh6_Pjfc7k6I6VgeCsoTQZoJCV7-yuv8I5SzGNL3ajpqVs/s640/svgexpanded.png" width="640" /></a></div>
<br /></div>
<div dir="ltr">
The basic problem is that a flaccid scrum team is constantly neglecting the need for internal quality (not just functional quality) in the code base. A team with such a problem is compromising <b><i>(1)</i></b> the quality vertex from the following triangle:</div>
<div dir="ltr">
<br /></div>
<div dir="ltr">
<h3>
Solid Scrum (with XP) mindset</h3>
</div>
<div dir="ltr">
Let's examine each vertex, in the context of "normal" Agile team:</div>
<div dir="ltr">
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjseXpvRRssamUtv9gaxeOQnu7DiHQVpVlg_w5fLkRw7FSjzoOnbVmoWWI2Nnc2OHbOvlWSeB1RkxKzok44kUonTa4aCYGlDVdUAM8pf3frDs5B_xO-sz_4ozNa3EnbJf-1c6TDq8bnw2I/s1600/Good_Agile_Triangle.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="266" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjseXpvRRssamUtv9gaxeOQnu7DiHQVpVlg_w5fLkRw7FSjzoOnbVmoWWI2Nnc2OHbOvlWSeB1RkxKzok44kUonTa4aCYGlDVdUAM8pf3frDs5B_xO-sz_4ozNa3EnbJf-1c6TDq8bnw2I/s320/Good_Agile_Triangle.png" width="320" /></a></div>
<ul>
<li>The time one is the easiest, it is fixed by one of the core concepts of agile methodologies "Time Boxing"</li>
<li>The scope vertex must be flexible in order have really time boxed iterations, and</li>
<li>The quality vertex must be fixed in order to maintain a sustainable velocity (performance) by the team.</li>
</ul>
<div>
<br /></div>
</div>
<div dir="ltr">
<h3>
Flaccid Scrum mindset </h3>
</div>
<div dir="ltr">
This is the mindset, respecting each vertex, for a "flaccid" Scrum team:</div>
<div dir="ltr">
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjTssx_mvbPeQ9bHzs91zxB2I-dIgiychFGN6g-9fK1Fh6OwAa_d6HkEJemDomp0G0RJNINv1kGyA3bmmzjUM826Z5AkXdkh6dL-4RiWN_NFpTlmmUIlO9MF6Ll101EKi_0AqE9Xywy3lI/s1600/Bad_Agile_Triangle.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="279" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjTssx_mvbPeQ9bHzs91zxB2I-dIgiychFGN6g-9fK1Fh6OwAa_d6HkEJemDomp0G0RJNINv1kGyA3bmmzjUM826Z5AkXdkh6dL-4RiWN_NFpTlmmUIlO9MF6Ll101EKi_0AqE9Xywy3lI/s320/Bad_Agile_Triangle.png" width="320" /></a></div>
<ul>
<li>The time one remains fixed (time boxed)</li>
<li>The scope vertex is fixed giving a false sense of commitment and "performance" to the Product Owner and the customer, and</li>
<li>The quality vertex, by necessity, becomes flexible in order to allocate all committed scope inside the time boxed iteration.</li>
</ul>
<br />
<ul>
</ul>
</div>
<div dir="ltr">
<h3>
The Jenga Tower</h3>
</div>
<div dir="ltr">
By compromising the internal quality the team is shooting himself in the foot because the performance will be gradually degraded. A poor quality code base is difficult to maintain, a headache for the team and for the customers. It becomes very fragile, with each change a new crack arise. With each crack a quick patch is added. After a few iterations the code base has too many patches and becomes extremely hard to touch without breaking it: this is the final stage of a Jenga Tower before collapsing. Something like this: </div>
<div dir="ltr">
<blockquote class="tr_bq">
"Each block removed is then balanced on top of the tower, <i><b>creating a progressively taller but less stable structure.</b></i>" (<a href="https://en.wikipedia.org/wiki/Jenga" target="_blank">https://en.wikipedia.org/wiki/Jenga</a>)</blockquote>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhVJ_syV3-s-PqhGrHMjaV-E6b_y5_NarbDoWuv54HzkBVH5acoGkdf_5A9k_ggBSdsIGypqySHXhpf3QymfNg0RQ9ScAxVCquERTS58OWqdTIx-_3j_fz7J7bYDLGUeHuhN-Qf3tCz1bI/s1600/jenga.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="400" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhVJ_syV3-s-PqhGrHMjaV-E6b_y5_NarbDoWuv54HzkBVH5acoGkdf_5A9k_ggBSdsIGypqySHXhpf3QymfNg0RQ9ScAxVCquERTS58OWqdTIx-_3j_fz7J7bYDLGUeHuhN-Qf3tCz1bI/s400/jenga.jpg" width="332" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<br />
<h3>
Practical steps towards solving the problem</h3>
Just to be crystal clear, XP is not a pill, we really can just "take it" and the problem will be gone. In order to solve the underlying quality problem we need to take small, but solid actions. Here I'm only listing the suggested steps but details on each one will be left for upcoming posts:<br />
<ul>
<li>First, we need to build awareness around the issue for all stakeholders:</li>
<ul>
<li>Your team (complete): developers, testers, leaders, ...</li>
<li>Your product owner</li>
<li>Your customers: both inside and outside the organization</li>
<li>Capital investors / business owners</li>
</ul>
<li>Second, improve the knowledge level of the people actually doing the work, because they need to change their bad habits and may require some sort of education / coaching / etc.</li>
<li>Finally, devise a plan covering short, mid, and large term actions for team to undertake. </li>
<ul>
<li>One of the first steps of this plan is to measure the current situation</li>
<li>Then, you need to define the KPIs that will be observed as process and quality improvement indicators</li>
<li>Pick the smallest steps possible, because you don't want to completely stop the team and you need each new practice to be assimilated by the team shifting the mindset a little bit each time. </li>
</ul>
</ul>
<a name='more'></a><hr />
<i style="font-weight: bold;">(FlaccidScrum)</i> The first time I saw the term was in a Martin Fowler's posts</div>
<blockquote style="border: none; margin: 0 0 0 40px; padding: 0px;">
<div dir="ltr">
<br />
<br />
<li><a href="http://martinfowler.com/bliki/FlaccidScrum.html" target="_blank">FlaccidScrum (2009)</a></li>
</div>
</blockquote>
<blockquote style="border: none; margin: 0 0 0 40px; padding: 0px;">
<div dir="ltr">
<br />
<br />
<li><a href="http://martinfowler.com/snips/201401291515.html" target="_blank">Five years of Flaccid Scrum (2014)</a></li>
</div>
</blockquote>
<br />
<div dir="ltr">
<b><i>(1)</i></b> <b>Compromising </b>is used in the following sense: "a change that makes something worse and that is not done for a good reason". See <a href="http://www.merriam-webster.com/dictionary/compromise" target="_blank">merriam-webster.com</a></div>
Anonymoushttp://www.blogger.com/profile/12292838726080618300noreply@blogger.com0tag:blogger.com,1999:blog-8113723708012951738.post-36871717746844878092015-12-14T02:21:00.000-04:002016-05-28T22:19:09.336-04:00Reflections on Clean Code: Estimates<div class="WordSection1">
<h1>
Reflections on Clean Code: Estimates</h1>
Day one of your iteration, your team is doing the planning
game (planning poker, ideal hours, etc.) and everyone is reflecting about the
effort needed to work a given requirement. We could have two scenarios:<br />
<br />
<h3>
<span style="font-size: large;">
One: With a Clean Code Base</span></h3>
<table cellpadding="0" cellspacing="0" class="tr-caption-container" style="float: left; margin-right: 1em; text-align: left;"><tbody>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhGE7gjrmNm1FbSfz0ThUag5yJNatHAJFMf6C6oH6VnEkNErJ53yZFRWP3o0CcVQAjNcDISU87GMGlE-kqByeYwFcSBHQ9KGLk87gKlzpoJSA7iJimEFmAlbtDgw_1iPsMakVqEVySfVME/s1600/Clean_Code.PNG" imageanchor="1" style="clear: left; margin-bottom: 1em; margin-left: auto; margin-right: auto;"><img alt="Clean code estimates" border="0" height="360" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhGE7gjrmNm1FbSfz0ThUag5yJNatHAJFMf6C6oH6VnEkNErJ53yZFRWP3o0CcVQAjNcDISU87GMGlE-kqByeYwFcSBHQ9KGLk87gKlzpoJSA7iJimEFmAlbtDgw_1iPsMakVqEVySfVME/s640/Clean_Code.PNG" title="Clean code estimates" width="640" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;"><i>Clean Code estimates</i></td></tr>
</tbody></table>
<br />
<div class="separator" style="clear: both; text-align: center;">
</div>
<br />
<br />
<h3>
<span style="font-size: large;">
Two: With a Bad (dirty) Code Base</span></h3>
<table cellpadding="0" cellspacing="0" class="tr-caption-container" style="float: left; margin-right: 1em; text-align: left;"><tbody>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgrDnIjA0rNHr9TnFbEOdQxrXCoA06yTW8C29qh69Sr_cLgsuiV7jevtJfHUP4jxmicqjfGmAzukSwZTvVoaT1GE4pzfins4F0I1LeriD5nd4UX4Flj8g1ZvcFudc2SO73VMcyRkdNJwfE/s1600/Bad_Code.PNG" imageanchor="1" style="clear: left; margin-bottom: 1em; margin-left: auto; margin-right: auto;"><img alt="Bad Code estimates" border="0" height="360" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgrDnIjA0rNHr9TnFbEOdQxrXCoA06yTW8C29qh69Sr_cLgsuiV7jevtJfHUP4jxmicqjfGmAzukSwZTvVoaT1GE4pzfins4F0I1LeriD5nd4UX4Flj8g1ZvcFudc2SO73VMcyRkdNJwfE/s640/Bad_Code.PNG" title="Bad Code estimates" width="640" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;"><i>Bad Code estimates</i></td></tr>
</tbody></table>
<br />
<div class="separator" style="clear: both; text-align: center;">
</div>
<br />
Imaging your code base as a tool’s repository, those tools
are used to solve problems. Your job is to use the proper tool for each task,
but you need to do that as quickly as possible. Now think what would happen if
any time you enter the shop you find a mess of tools?<br />
<br />
In order to do your job, first you need to find all required
tools, you reach for the hammer, but find a screwdriver, then you find the
drill on the level’s bucket, … (you fell me?)<br />
<br />
After finding all required tools you start working on the
piece of furniture, but you find that the last carpenter use nails where you expected
screws. Also, he had use glue where fine nails where more appropriated. The
hammer has grease on the handle and slips. The drill heads are out of order …<br />
<br />
By the end of the day you are done with the piece, but you
realize that building it from scratch will take half the time.<br />
<br />
<h2>
</h2>
<h2>
Too much bla, bla, bla: What should we do about this?</h2>
<h3>
Put each piece / tool inside the proper drawer:</h3>
First, imagine your code base as a cabinet with many
drawers, each one with a label. Depending on your design decisions labels will
have words like (persistence, core logic, controllers, views, domain, tests,
etc.); but no matter how your team decided to organize the code, each element
must be inside the proper drawer.<br />
<br />
You must put components where they belong in order in accordance
to the team’s guidelines for the given application.<br />
<h3>
</h3>
<h3>
</h3>
<h3>
</h3>
<div>
<br /></div>
<h3>
Leave pieces as clean as possible:</h3>
Now imagine a single file as the drill and its heads. Any time
you use change heads you need to leave the set in proper order. Also, you
should clean and grease moving parts regularly in order to extend the tool’s
live and improve performance. <br />
You must keep your components (files, classes, methods,
etc.) as clean as possible both on the inside (implementation) and on the
outside (public interface / contract).<br />
<h3>
</h3>
<h3>
</h3>
<h3>
</h3>
<div>
<br /></div>
<h3>
Include the “cleaning” process in all your estimates:</h3>
Let me change the analogy for a moment: imaging what would
happen if your preferred restaurant only estimates the cost of serving the dish
to your table and cleaning up after you leave. But they “forget” to consider
cost of dish-washing, kitchen cleaning cost and time, bathrooms cleaning time,
etc. <br />
<br />
So, the next time you’ll get there to eat your favorite
dinner, they need to spend one hour just to start working on it because all
elements were dirty and out of order. So you get served with one-hour delay. As
they do all this in such a hurry, you find that the fork is dirty and the
napkins have stains all over…<br />
<br />
The same happens with software developers only estimating
the “change” / “implementation” time, and not considering the time needed to
leave the solution as clean as they found it. Also they forgot the time to add
/ change existing documentation to reflect the changes. They do not consider
the time for proper testing. Simply, they are leaving the shop dirty and tools
out of order. When they need to “serve” another client they found the same
problems as the lazy restaurant’s employees.</div>
Anonymoushttp://www.blogger.com/profile/12292838726080618300noreply@blogger.com0tag:blogger.com,1999:blog-8113723708012951738.post-14277903783369054652015-05-30T01:01:00.000-04:002016-05-28T22:18:46.928-04:00Boundary Test: JSON De-serialization with Json.NETYes, this blog is about agile software development, so why are you posting about a JSON serialization API for the .NET framework?<br />
<br />
If you do not associate the concept Boundary Test to Agile Software Development, please refer to<br />
<blockquote class="tr_bq">
Robert C. Martin (a.k.a Uncle Bob) - <a href="http://www.amazon.com/Clean-Code-Handbook-Software-Craftsmanship-ebook/dp/B001GSTOAM/ref=tmm_kin_title_0" target="_blank">Clean Code: A Handbook of Agile Software Craftsmanship</a> / Chapter 8: Boundaries</blockquote>
<br />
Now, let go to the subject ...<br />
<br />
<h2>
The Problem</h2>
While de-serializing some POCOs using Json.NET one property, a collection, remains empty but the input JSON has the corresponding array to fill it.<br />
<br />
The property was a list of integers (<span style="font-family: "courier new" , "courier" , monospace;">List<int></int></span>), with some tricks on the accessors (get and set). For some reason related to Windows Communication Foundation (WCF) serialization mechanism that property was converted from <span style="font-family: "courier new" , "courier" , monospace;">ISet<int></int></span> to <span style="font-family: "courier new" , "courier" , monospace;">List<int></int></span>. Conceptually that POCO must not support duplicated elements within that collection but the ISet interface was causing me some issues with WCF. So I dropped it and fall back to the more 'safe' one <span style="font-family: "courier new" , "courier" , monospace;">IList / List</span>.<br />
<br />
The actual implementation was something like this:<br />
<pre style="background-color: white; border: 1px solid Gray; margin: 0em; max-height: 200px; overflow-x: scroll; overflow-y: scroll;"><code style="color: black; font-family: Consolas,"Courier New",Courier,Monospace; font-size: 10pt;">[DataContract]
<span style="color: blue;">public</span> <span style="color: blue;">class</span> DummyPoco
{
<span style="color: blue;">private</span> ISet<<span style="color: blue;">int</span>> internalSet01;
<span style="color: blue;">public</span> DummyPoco()
{
internalSet01 = <span style="color: blue;">new</span> HashSet<<span style="color: blue;">int</span>>();
}
[DataMember]
[JsonProperty(<span style="color: #a31515;">"fakeList01"</span>)]
<span style="color: blue;">public</span> List<<span style="color: blue;">int</span>> FakeList01
{
<span style="color: blue;">get</span>
{
<span style="color: blue;">return</span> <span style="color: blue;">this</span>.internalSet01.ToList();
}
<span style="color: blue;">set</span>
{
<span style="color: blue;">var</span> safeList = (value ?? <span style="color: blue;">new</span> List<<span style="color: blue;">int</span>>());
<span style="color: blue;">this</span>.internalSet01 = <span style="color: blue;">new</span> HashSet<<span style="color: blue;">int</span>>(safeList);
}
}
[DataMember]
[JsonProperty(<span style="color: #a31515;">"realList"</span>)]
<span style="color: blue;">public</span> List<<span style="color: blue;">int</span>> RealList { <span style="color: blue;">get</span>; <span style="color: blue;">set</span>; }
}</code></pre>
<br />
I tested my code using a classic NUnit test, without worrying about JSON serialization issues. After all tests were done (green), I took the next step expose my, carefully tested, API as a WCF REST end point. There I met reality.<br />
<br />
Any time the client (single page application) sends to the REST end point the resource to be de-serialized as my POCO that property (FakeList01) was empty.<br />
<br />
Other collections (like RealList) with simple property constructors have no problem. Clearly something with my 'Fake' list (internal) set was causing the problem.<br />
<br />
<span style="font-family: "courier new" , "courier" , monospace;"><i>{ myFakeList: [ 1, 1, 2, 2 ], myRealList: [ 1, 1, 2, 2, 3, 3 ] }</i></span> de-serializes as<br />
<blockquote class="tr_bq">
poco.FakeList01.Count /* 0 */;<br />
poco.RealList.Count /* 6 */;</blockquote>
I didn't want to use a simple property and be forced to deal with duplicated data in other points of the application.<br />
<br />
<h2>
The Solution</h2>
Reading some post in <a href="http://stackoverflow.com/search?q=ObjectCreationHandling" target="_blank">StackOverflow</a> and the <a href="http://www.newtonsoft.com/json/help/html/Introduction.htm" target="_blank">Json.NET API documentation</a>, I found the following parameter for the <span style="font-family: "courier new" , "courier" , monospace;">JsonProperty</span> annotation: <span style="font-family: "courier new" , "courier" , monospace;">ObjectCreationHandling</span>. <span style="font-family: "courier new" , "courier" , monospace;">ObjectCreationHandling</span> parameter accepts values from an homonym enumeration . That enum has three possible values <span style="font-family: "courier new" , "courier" , monospace;">Auto</span>, <span style="font-family: "courier new" , "courier" , monospace;">Reuse</span>, and <span style="font-family: "courier new" , "courier" , monospace;">Replace</span>. The default is Auto.<br />
<br />
<b><span style="font-family: "courier new" , "courier" , monospace;">ObjectCreationHandling.Auto</span> means</b><br />
<ul>
<li>If the property being set is null (known by calling the getter), then create a new instance and assign it (by calling the setter). <i><u>Doing a 'replace' (of the property's reference).</u></i></li>
<li>If the property being set is not null (also known by calling the getter), then keep this reference and and use its properties to set all values. For collection types, keep that instance and call Add to store elements. Doing a 'reuse' (of the property's reference).</li>
</ul>
<br />
<b><span style="font-family: "courier new" , "courier" , monospace;">ObjectCreationHandling.Replace</span> means</b><br />
<ul>
<li>"Always ignore the actual property value and override it with a new instance".</li>
</ul>
<br />
Because my property's getter was returning a 'detached' list (<span style="font-family: "courier new" , "courier" , monospace;">internalSet01.ToList()</span>), Json.NET was using that 'detached' list to add elements found in JSON input. And ignoring the setter. Clearly the solution was to change the Auto value for that parameter.<br />
<br />
<pre style="background-color: white; border: 1px solid Gray; margin: 0em; max-height: 200px; overflow-x: scroll; overflow-y: scroll;"><code style="color: black; font-family: Consolas,"Courier New",Courier,Monospace; font-size: 10pt;">[DataMember]
[JsonProperty(<span style="color: #a31515;">"fakeList01"</span>, ObjectCreationHandling = ObjectCreationHandling.Replace)]
<span style="color: blue;">public</span> List<<span style="color: blue;">int</span>> FakeList01 { ... }
}</code></pre>
<br />
After doing that, I remembered the <b><i>"Boundary Test"</i></b> concept explained by Uncle Bob in his book "Clean Code".<br />
<br />
The "missing test" for this bug was a Boundary Test, one that validates the usage of this JSON serialization library and ensures that a properly annotated class could be used without problems, no matter the actual implementation of the property's accessors.<br />
<br />
With that test in place, I could test if changes in the Json.NET project will break my assumptions about JSON serialization and de-serialization of weird properties like the one described.<br />
<br />
Also I added a 'negative test' by creating a similar property but leaving the <span style="font-family: "courier new" , "courier" , monospace;">ObjectCreationHandling</span> attribute with its default value (<span style="font-family: "courier new" , "courier" , monospace;">Auto</span>).<br />
<br />
<pre style="background-color: white; border: 1px solid Gray; margin: 0em; max-height: 200px; overflow-x: scroll; overflow-y: scroll;"><code style="color: black; font-family: Consolas,"Courier New",Courier,Monospace; font-size: 10pt;">[DataMember]
[JsonProperty(<span style="color: #a31515;">"fakeList02"</span>)]
<span style="color: blue;">public</span> List<<span style="color: blue;">int</span>> FakeList02
{
<span style="color: blue;">get</span>
{
<span style="color: blue;">return</span> <span style="color: blue;">this</span>.internalSet02.ToList();
}
<span style="color: blue;">set</span>
{
<span style="color: blue;">var</span> safeList = (value ?? <span style="color: blue;">new</span> List<<span style="color: blue;">int</span>>());
<span style="color: blue;">this</span>.internalSet02 = <span style="color: blue;">new</span> HashSet<<span style="color: blue;">int</span>>(safeList);
}
}</code></pre>
<br />
<h3>
Notes</h3>
These technique is not considered as 'third-party library testing'. Json.NET has a vast amount of functionalities that I'm not testing. I'm only testing the part of the framework actively used.<br />
<br />
<br />
<h2>
References</h2>
<br />
<ul>
<li><b>.NEt Project: </b>on <a href="https://github.com/lsolano/json_deserialization_boundary_test" target="_blank">Github</a> ( <a href="https://github.com/lsolano/json_deserialization_boundary_test">https://github.com/lsolano/json_deserialization_boundary_test</a> ) </li>
</ul>
<br />
<br />
<ul>
<li><b>Json.NET:</b> <span style="font-family: "courier new" , "courier" , monospace;">Newtonsoft.Json.dll, v6.0.0.0</span></li>
<ul>
<li>Sources: Download it from NuGet or <a href="http://www.newtonsoft.com/json">http://www.newtonsoft.com/json</a></li>
</ul>
</ul>
<br />
<br />
<ul>
<li><b>NUnit:</b> <span style="font-family: "courier new" , "courier" , monospace;">nunit.framework.dll, v2.6.4.14350</span></li>
<ul>
<li>Sources: Download it from NuGet or <a href="http://www.nunit.org/">http://www.nunit.org/</a></li>
</ul>
</ul>
Anonymoushttp://www.blogger.com/profile/12292838726080618300noreply@blogger.com0Santo Domingo, Dominican Republic18.431084839996853 -69.95441436767578118.400958339996851 -69.99475486767578 18.461211339996854 -69.914073867675782tag:blogger.com,1999:blog-8113723708012951738.post-76643894894080042842012-11-19T08:00:00.000-04:002016-05-28T22:18:33.076-04:00Phrase of the Software Craftsman 009<br />
<div style="text-align: center;">
<span style="font-size: large;">"Bad code tries to do too much it has muddle intent and ambiguity of purpose."</span></div>
<div style="text-align: center;">
<span style="font-size: large;"><a href="https://sites.google.com/site/unclebobconsultingllc/books" rel="nofollow" target="_blank">-Robert C. Martin (Clean Code)</a></span></div>
Anonymoushttp://www.blogger.com/profile/12292838726080618300noreply@blogger.com0