├── .gitignore ├── README.md ├── pom.xml └── src └── main └── java ├── conditionals ├── consolidatedconditional │ ├── bad │ │ └── Main.java │ └── good │ │ └── Main.java ├── consolidateduplicate │ ├── bad │ │ └── Main.java │ └── good │ │ └── Main.java └── polymorphism │ ├── bad │ └── Product.java │ └── good │ ├── BasicProduct.java │ ├── Main.java │ ├── PremiumProduct.java │ └── Product.java ├── data ├── magicnumbers │ └── bad │ │ └── Main.java └── replacearray │ └── bad │ └── Main.java ├── methods ├── extractmethod │ └── bad │ │ └── Main.java ├── extractvariable │ └── bad │ │ ├── Main.java │ │ └── Order.java ├── inlinemethod │ └── bad │ │ └── Main.java ├── inlinetemp │ └── bad │ │ ├── Main.java │ │ └── Order.java ├── removeassign │ └── bad │ │ ├── Main.java │ │ └── Order.java ├── replacemethod │ └── bad │ │ └── Product.java └── replacetemp │ └── bad │ └── Product.java └── objects ├── extractclass └── bad │ └── Person.java └── inlineclass └── bad ├── Direction.java └── Person.java /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | ### Eclipse ### 3 | .metadata 4 | bin/ 5 | tmp/ 6 | *.tmp 7 | *.bak 8 | *.swp 9 | *~.nib 10 | local.properties 11 | .settings/ 12 | .loadpath 13 | .recommenders 14 | 15 | # External tool builders 16 | .externalToolBuilders/ 17 | 18 | # Locally stored "Eclipse launch configurations" 19 | *.launch 20 | 21 | # PyDev specific (Python IDE for Eclipse) 22 | *.pydevproject 23 | 24 | # CDT-specific (C/C++ Development Tooling) 25 | .cproject 26 | 27 | # CDT- autotools 28 | .autotools 29 | 30 | # Java annotation processor (APT) 31 | .factorypath 32 | 33 | # PDT-specific (PHP Development Tools) 34 | .buildpath 35 | 36 | # sbteclipse plugin 37 | .target 38 | 39 | # Tern plugin 40 | .tern-project 41 | 42 | # TeXlipse plugin 43 | .texlipse 44 | 45 | # STS (Spring Tool Suite) 46 | .springBeans 47 | 48 | # Code Recommenders 49 | .recommenders/ 50 | 51 | # Annotation Processing 52 | .apt_generated/ 53 | .apt_generated_test/ 54 | 55 | # Scala IDE specific (Scala & Java development for Eclipse) 56 | .cache-main 57 | .scala_dependencies 58 | .worksheet 59 | 60 | # Uncomment this line if you wish to ignore the project description file. 61 | # Typically, this file would be tracked if it contains build/dependency configurations: 62 | #.project 63 | 64 | ### Eclipse Patch ### 65 | # Spring Boot Tooling 66 | .sts4-cache/ 67 | 68 | ### Intellij+all ### 69 | # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider 70 | # Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 71 | 72 | # User-specific stuff 73 | .idea 74 | .idea/**/workspace.xml 75 | .idea/**/tasks.xml 76 | .idea/**/usage.statistics.xml 77 | .idea/**/dictionaries 78 | .idea/**/shelf 79 | 80 | # AWS User-specific 81 | .idea/**/aws.xml 82 | 83 | # Generated files 84 | .idea/**/contentModel.xml 85 | 86 | # Sensitive or high-churn files 87 | .idea/**/dataSources/ 88 | .idea/**/dataSources.ids 89 | .idea/**/dataSources.local.xml 90 | .idea/**/sqlDataSources.xml 91 | .idea/**/dynamic.xml 92 | .idea/**/uiDesigner.xml 93 | .idea/**/dbnavigator.xml 94 | 95 | # Gradle 96 | .idea/**/gradle.xml 97 | .idea/**/libraries 98 | 99 | # Gradle and Maven with auto-import 100 | # When using Gradle or Maven with auto-import, you should exclude module files, 101 | # since they will be recreated, and may cause churn. Uncomment if using 102 | # auto-import. 103 | # .idea/artifacts 104 | # .idea/compiler.xml 105 | # .idea/jarRepositories.xml 106 | # .idea/modules.xml 107 | # .idea/*.iml 108 | # .idea/modules 109 | *.iml 110 | 111 | # *.ipr 112 | 113 | # CMake 114 | cmake-build-*/ 115 | 116 | # Mongo Explorer plugin 117 | .idea/**/mongoSettings.xml 118 | 119 | # File-based project format 120 | *.iws 121 | 122 | # IntelliJ 123 | out/ 124 | 125 | # mpeltonen/sbt-idea plugin 126 | .idea_modules/ 127 | 128 | # JIRA plugin 129 | atlassian-ide-plugin.xml 130 | 131 | # Cursive Clojure plugin 132 | .idea/replstate.xml 133 | 134 | # SonarLint plugin 135 | .idea/sonarlint/ 136 | 137 | # Crashlytics plugin (for Android Studio and IntelliJ) 138 | com_crashlytics_export_strings.xml 139 | crashlytics.properties 140 | crashlytics-build.properties 141 | fabric.properties 142 | 143 | # Editor-based Rest Client 144 | .idea/httpRequests 145 | 146 | # Android studio 3.1+ serialized cache file 147 | .idea/caches/build_file_checksums.ser 148 | 149 | ### Intellij+all Patch ### 150 | # Ignore everything but code style settings and run configurations 151 | # that are supposed to be shared within teams. 152 | 153 | .idea/* 154 | 155 | !.idea/codeStyles 156 | !.idea/runConfigurations 157 | 158 | ### Java ### 159 | # Compiled class file 160 | *.class 161 | 162 | # Log file 163 | *.log 164 | 165 | # BlueJ files 166 | *.ctxt 167 | 168 | # Mobile Tools for Java (J2ME) 169 | .mtj.tmp/ 170 | 171 | # Package Files # 172 | *.jar 173 | *.war 174 | *.nar 175 | *.ear 176 | *.zip 177 | *.tar.gz 178 | *.rar 179 | 180 | # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml 181 | hs_err_pid* 182 | replay_pid* 183 | 184 | ### Maven ### 185 | target/ 186 | pom.xml.tag 187 | pom.xml.releaseBackup 188 | pom.xml.versionsBackup 189 | pom.xml.next 190 | release.properties 191 | dependency-reduced-pom.xml 192 | buildNumber.properties 193 | .mvn/timing.properties 194 | # https://github.com/takari/maven-wrapper#usage-without-binary-jar 195 | .mvn/wrapper/maven-wrapper.jar 196 | 197 | # Eclipse m2e generated files 198 | # Eclipse Core 199 | .project 200 | # JDT-specific (Eclipse Java Development Tools) 201 | .classpath 202 | 203 | ### VisualStudioCode ### 204 | .vscode/* 205 | !.vscode/settings.json 206 | !.vscode/tasks.json 207 | !.vscode/launch.json 208 | !.vscode/extensions.json 209 | !.vscode/*.code-snippets 210 | 211 | # Local History for Visual Studio Code 212 | .history/ 213 | 214 | # Built Visual Studio Code Extensions 215 | *.vsix 216 | 217 | ### VisualStudioCode Patch ### 218 | # Ignore all local history of files 219 | .history 220 | .ionide 221 | 222 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Clean code en Java 2 | 3 | ## 1. Código limpio 4 | 5 | ### Qué es el código limpio 6 | 7 | Cada lenguaje y paradigma de programación tiene su conjunto de matices, buenas prácticas, convenciones. EJ: 8 | 9 | * Java: camelCase 10 | * Python: snake_case 11 | 12 | > El código limpio puede resumirse como un código que cualquier desarrollador puede leer y modificar fácilmente. 13 | 14 | Referentes: Martin Fowler y Robert C Martin 15 | 16 | Cualquiera puede escribir código que un ordenador pueda entender, la clave es que otras personas puedan entenderlo. 17 | 18 | * Lenguaje de bajo nivel 19 | * Lenguaje ensamblador 20 | * Lenguaje de alto nivel 21 | * Primera generación 22 | * Segunda generación 23 | * .... 24 | 25 | El código fuente será compilado/interpretado para un procesador concreto. 26 | 27 | Java: 28 | 29 | * Lenguaje de programación: Java SE 30 | * JVM 31 | * Biblioteca estándar (API) 32 | * Java EE (Jakarta EE): javax a jakarta 33 | 34 | Características: 35 | 36 | * Enfocado: debe escribirse para resolver un problema específico y nada más. 37 | * Simple. Evitar complejidad 38 | * Testable: el código debe ser intuitivo y fácil de probar 39 | 40 | Ciclo de vida del software: 41 | * Análisis de requisitos (ERS) 42 | * Diseño: Arquitectura (alto nivel) y bajo nivel (UML) 43 | * Desarrollo 44 | * Testing: QA, TDD, BDD 45 | * Despliegue: devOps, devSecOps (AWS, GCP, DO, Azure) 46 | * Mantenimiento: monitorización 47 | 48 | Paradigmas: 49 | 50 | * Estructurada 51 | * POO 52 | * Funcional 53 | * Reactiva 54 | 55 | ### Por qué queremos el código limpio 56 | Problema **deuda técnica** y complejidad: el código acumula defectos, demasiada complejidad, desarrollos que no se han implementado de buena manera. Se forma un efecto de bola de nieve que se acumula y puede hacer que un proyecto de software, al cabo de 5 años sea insostenible económicamente. 57 | 58 | Herramientas para medir deuda técnica y complejidad: 59 | 60 | * Empresa: SonarSource 61 | * Plugin IntelliJ IDEA: Sonarlint 62 | * Plataforma: SonarQube 63 | * SaaS: SonarCloud 64 | 65 | Ventajas: 66 | 67 | * Mejor mantenimiento: corrección de fallos, evolución, nuevas mejoras, todo más fácil. 68 | * Solución de problemas más rápida 69 | * Comprensión más rápida: cualquier desarrollador nuevo en el proyecto se adapta antes. 70 | 71 | ### Regla BoyScout 72 | 73 | > Deja el código más limpio de lo que lo encontraste. 74 | 75 | Basta con introducir un pequeño arreglo cada vez que tocamos un código. Desde mejorar los identificadores hasta refactorizar una función. 76 | 77 | El concepto de calidad debe ser común para todo el equipo, todo el equipo debe estar alineado en base a unas mismas prácticas. 78 | 79 | ## 2. Nombrado 80 | 81 | * Utilizar nombres que revelen la intención 82 | * Evitar desinformación 83 | * hacer distinciones significativas 84 | * Utilizar nombres pronunciables 85 | * Utilizar nombres que se puedan buscar 86 | * Evitar el mapeo mental 87 | * Elegir nombre de Clase 88 | * Elección nombre de método 89 | * Claridad, cuidado con eufemismos: kill(), abort() 90 | * Una palabra con concepto 91 | * Contexto significativo 92 | 93 | ### 2.1. Nombres que revelen intención 94 | 95 | Mal: 96 | ```java 97 | int d; // elapsed time in days 98 | ``` 99 | 100 | Bien: 101 | ```java 102 | int elapsedTimeInDays; 103 | int elapsedDays; 104 | int fileAgeInDays; 105 | ``` 106 | 107 | 108 | 109 | Mal: 110 | ```java 111 | // get active employees 112 | public List getElements(){ 113 | List list1 = new ArrayList<>(); 114 | for( int[] x: theList ) 115 | if(x[0] == 1) 116 | list1.add(x); 117 | return list1; 118 | } 119 | ``` 120 | 121 | Bien: 122 | ```java 123 | public List getActiveEmployees(){ 124 | List activeEmployees = new ArrayList<>(); 125 | for(Employee employee: employees ) 126 | if(employee.isActive()) 127 | activeEmployees.add(employee); 128 | return activeEmployees; 129 | } 130 | ``` 131 | 132 | ### 2.2. Evitar desinformación 133 | Evitar dejar pistas falsas que creen confusión con respecto a los datos que estamos manejando. 134 | 135 | Si tenemos una variable ``account``, que en realidad es una lista entonces nos está creando la confusión de pensar que es una sola cuenta cuando en realidad es una lista. O al revés, una variables ``accounts`` cuando en realidad no es una estructura de datos. 136 | 137 | ### 2.3. Distinciones significativas 138 | 139 | No utilizar el mismo nombre para referirse a cosas diferentes en el mismo ámbito. Evitar elegir nombres de forma arbitraria: 140 | 141 | * ``Product``, ``ProductInfo``, ``ProductData`` 142 | * ``Customer``, ``CustomerObject`` 143 | * ``customer``, ``customerInfo`` 144 | * ``money``, ``moneyAmount`` 145 | * ``message``, ``theMessage`` 146 | 147 | Mal: 148 | 149 | ```java 150 | public static void copyChars(char[] a1, char[] a2){ 151 | for (int i = 0; i < a1.length; i++) 152 | a2[i] = a1[i]; 153 | } 154 | ``` 155 | 156 | Bien: 157 | 158 | ```java 159 | public static void copyChars(char[] source, char[] destination){ 160 | for (int i = 0; i < source.length; i++) 161 | destination[i] = source[i]; 162 | } 163 | ``` 164 | 165 | ### 2.4. Utilizar nombres pronunciables 166 | 167 | Mal: 168 | 169 | ```java 170 | class DtaRcrd102{ 171 | LocalDateTime genymdhms; 172 | LocalDateTime modymdhms; 173 | } 174 | ``` 175 | 176 | Bien: 177 | 178 | ```java 179 | class Customer{ 180 | LocalDateTime generationTimestamp; 181 | LocalDateTime modificationTimestamp; 182 | } 183 | ``` 184 | 185 | ### 2.5. Búsqueda de nombres 186 | 187 | 188 | Mal: 189 | 190 | ```java 191 | for (int j = 0; j < 34; j++){ 192 | s += (t[j]*4) / 5; 193 | } 194 | ``` 195 | 196 | Bien: 197 | 198 | ```java 199 | public static final int WORK_DAYS_PER_WEEK = 5; 200 | 201 | int idealTasksPerDay = 4; 202 | int sum = 0; 203 | 204 | for (int j = 0; j < tasks.length; j++){ 205 | int realTaskDays = tasks[j].estimate * idealTasksPerDay; 206 | int realTaskWeek = realTaskDays / WORK_DAYS_PER_WEEK; 207 | sum += realTaskWeek; 208 | } 209 | 210 | ``` 211 | 212 | ### 2.6. Notación Húngara 213 | 214 | HN proporciona una forma de prefijar el nombre de una variable con su tipo de dato. Esto se utilizaba más en los lenguajes de bajo nivel. 215 | 216 | No se usa hoy en día en los lenguajes de alto nivel, especialmente java que es un lenguaje fuertemente tipado. 217 | 218 | ```java 219 | // Notación húngara: [scope] + type + name + [qualifier] 220 | 221 | bFinished = false; 222 | strHexDigits = "0123456789ABCDEF"; 223 | ``` 224 | 225 | ### 2.7. Prefijos 226 | 227 | Mal: 228 | 229 | ```java 230 | public class Part{ 231 | private String m_dsc; // textual description 232 | } 233 | ``` 234 | 235 | Bien: 236 | 237 | ```java 238 | public class Part{ 239 | private String description; 240 | } 241 | ``` 242 | 243 | ### 2.8. Interfaces e implementaciones 244 | 245 | Mal: `IShapeFactory`, `ShapeFactory` 246 | 247 | Bien: `ShapeFactory`, `ShapeFactoryImp` o `ShapeFactoryImpl` 248 | 249 | ### 2.9. Asignación mental 250 | 251 | En el contexto tradicional de los bucles ``for`` se suelen utilizar las letras ``i``, ``j``, ``k``, ``l``. 252 | 253 | Pero en otros contextos no es buena idea utilizar variables de una sola letra que impliquen un proceso mental extra de tener que saber o mapear mentalmente a qué concepto equivale cada cosa. 254 | 255 | ### 2.10. Nombrado de clases y métodos 256 | 257 | Los métodos deberían ser verbos: ``postPayment()``, ``deletePage()``, ``save()``. 258 | 259 | Los métodos para acceder o cambiar debería ser: ``get``, ``set``, ``is``. 260 | 261 | En lugar de sobrecargar constructores es mejor usar: 262 | 263 | * Factorías que describan los argumentos 264 | * Patrón Builder 265 | 266 | ```java 267 | Complex point = new Complex(23.0); 268 | Complex point = new Complex(23.0, 50.9, 6.0, 77, true, "text"); 269 | 270 | // Uso de Factories 271 | Complex point = Complex.fromRealNumber(23.0); 272 | ``` 273 | 274 | ### 2.11. Claridad, cuidado con eufemismos: kill(), abort() 275 | 276 | ``` 277 | kill() 278 | abort() 279 | stop() 280 | delete() 281 | ``` 282 | 283 | ### 2.12. Una palabra por concepto 284 | 285 | Ser consistente a la hora de nombrar, no utilizar distintas palabras para lo mismo de manera arbitraria: 286 | 287 | * get(), fetch(), retrieve(), find(), read(): Si todos hacen lo mismo en diferentes clases, lo mejor es nombrarlos igual en todas las clases. 288 | * CustomerController, EmployeeController. Evitar utilizar palabras distintas cuando en realidad es lo mismo: CustomerController, EmployeeManager, AccountDriver 289 | * Spring REST: CustomerRestController, EmployeeRestController 290 | * Spring MVC: CustomerController, EmployeeController 291 | 292 | ## 3. Funciones 293 | 294 | ### 3.1. Funciones pequeñas 295 | 296 | 2,3,4 líneas de código por función está bien. En general, cuantas menos líneas tenga mejor. 297 | 298 | ### 3.2. Bloques e indentación 299 | Indentación es la sangría que aplicamos al código que está contenido en una estructura: if, else, switch, for, while. 300 | 301 | Cada bloque debería tener una o dos líneas como mucho. 302 | 303 | ### 3.3. Una sola funcionalidad por función 304 | 305 | Mal 306 | 307 | ```java 308 | public void emailClients(List clients){ 309 | for(Client client: clients){ 310 | Client clientDB = repository.findOne(client.getId()); 311 | if(clientDB.isActive()) 312 | email(client); 313 | } 314 | } 315 | 316 | ``` 317 | 318 | Bien: 319 | 320 | ```java 321 | public void emailClients(List clients){ 322 | for(Client client: clients){ 323 | if(isActive(client.getId())) 324 | email(client); 325 | } 326 | } 327 | 328 | private boolean isActive(Long customerId){ 329 | Client clientDB = repository.findById(customerId); 330 | return clientDB.isActive(); 331 | } 332 | 333 | ``` 334 | 335 | 336 | ### 3.4. No mezclar niveles de abstracción 337 | 338 | * Nivel abstracción alto: ``getHtml();`` 339 | * Nivel de abstracción intermedio: ``String pagePathName = PathParser.render(pagePath);`` 340 | * Nivel de abstracción bajo: ``.append("\n")`` 341 | 342 | ### 3.5. Lectura descendente 343 | 344 | > De alto nivel a bajo nivel. 345 | 346 | El código se lee como una narración descendente. 347 | 348 | Cada función vaya seguida de las del siguiente nivel de abstracción, de modo que podamos leer el programa descendiendo un nivel de abstracción cada vez. 349 | 350 | Es decir, no mezclar en el orden las funciones de alto nivel con las de bajo ni intercalarlas. 351 | 352 | ### 3.6. Instrucciones switch 353 | 354 | * Técnica de refactoring del polimorfismo. 355 | * Mejoras de expresiones switch incorporadas en las últimas versiones de java 14 y 17. 356 | 357 | ### 3.7. Nombres descriptivos 358 | 359 | ```java 360 | 361 | // mal 362 | addToDate(date, 1) 363 | 364 | // bien 365 | addMonthToDate(1, date) 366 | 367 | ``` 368 | 369 | ### 3.8. Argumentos 370 | 371 | * cero (niládicas) 372 | * uno (monádico) 373 | * dos (diádico) 374 | * tres (triádico) 375 | * más de tres (poliádico) 376 | 377 | El número ideal de argumentos es cero. Los argumentos dificultan el testing. 378 | 379 | ### 3.9. Evitar flags 380 | 381 | ```java 382 | 383 | // mal 384 | render(false); 385 | 386 | // bien 387 | // funcion para true 388 | renderForSuite(); 389 | 390 | // funcion para false 391 | renderForSingleTest(); 392 | 393 | ``` 394 | 395 | ### 3.10. Funciones diádicas 396 | 397 | Se debería evitar tener que revisar el javadoc/signatura para enterarnos de qué argumentos y en qué orden debemos pasarlos. 398 | 399 | ```java 400 | 401 | assertEquals(expected, actual) 402 | 403 | assertExpectedActualEquals(expected, actual) 404 | ``` 405 | 406 | ### 3.11. Objetos y listas de argumentos 407 | 408 | ``` 409 | Circle makeCircle(double x, double y, double radius) 410 | 411 | Circle makeCircle(Point point, double radius) 412 | ``` 413 | 414 | 415 | ### 3.12. Verbos y palabras clave 416 | 417 | ```java 418 | // tratar de combinar verbo/sustantivo 419 | write(String name) 420 | write("Alan") 421 | ``` 422 | 423 | ### 3.13. Evitar efectos secundarios 424 | 425 | Función que comprueba unas credenciales. 426 | 427 | Un efecto secundario sería si esa misma función inicia una sesión en la que cargue las credenciales cuando son correctas. 428 | 429 | Ejemplos de efectos secundarios: 430 | 431 | * llamadas en red 432 | * IO con archivos 433 | * Bases de datos 434 | * Interactuar con otros sistemas 435 | 436 | Tratar de desglosar las funcionalidades que no tienen efectos secundarios de las que sí con el fin de evitar confusiones. Por ejemplo llamar dos veces a una función checkPassword podría sobreescribir los datos de la sesión. 437 | 438 | ## 4. Comentarios 439 | 440 | ### Malos comentarios 441 | 442 | * Comentarios confusos 443 | * Comentarios redundantes 444 | * Comentarios obligatorios (javadoc con muchos o excesivos parámetros) 445 | * Javadoc en código que no es público 446 | * Comentarios de seguimiento de cambios con fechas etc: Se usa control de versiones como por ejemplo Git. 447 | * Comentarios ruido: un comentario indicando cuál es el constructor por defecto 448 | * Comentarios autogenerados por el IDE y que no aportan realmente información 449 | * Código comentado 450 | * Comentarios HTML 451 | * Comentarios muy largos 452 | * Información sin contexto o no evidente: por ejemplo un comentario que dice que agregues 200 bytes a algo 453 | * Información no local: añadir información de aspectos que no pueden ser controlados por dicha función. 454 | 455 | ### Buenos 456 | 457 | * Comentarios legales / copyright 458 | * Comentarios informativos pero breves que muestre determinada importancia o agregue información relevante 459 | * Comentarios que expliquen la intencionalidad del código 460 | * Clarificación: aclarar una expresión regular 461 | * Comentarios TODO: siempre y cuando se quiten una vez se haya terminado el desarrollo 462 | * Amplificar o destacar la importancia de un proceso 463 | * Javadocs en APIs públicas 464 | * Advertencia de consecuencias: por ejemplo avisar de que la ejecución de un determinado método puede consumir mucho tiempo. 465 | 466 | ## 5. Formateo 467 | 468 | ### Formato vertical: 469 | 470 | * Cuantas menos líneas en cada archivo de código fuente mejor. 471 | * Ideal: menos de 200 líneas. Combinar esta técnica junto con el Principio de una sola responsabilidad. 472 | * Metáfora del periódico: arriba del todo lo de más alto nivel y a medida que descendemos está lo de más bajo nivel. 473 | * distancia vertical: 474 | * Si tenemos una función que llama a otra función entonces interesa que estén próximas 475 | * Los conceptos que sean afine o relacionados deberían estar más próximos verticalmente. Ejemplo: Métodos de la interfaz List, los que están relacionados están más próximos 476 | * densidad vertical 477 | * facilitar la respiración entre sentencias 478 | * se pueden poner seguidas aquellas sentencias que estén relacionadas o conformen un todo mientras que aquellas que no estén tan relacionadas se pueden separar 479 | 480 | ### Formato horizontal: 481 | 482 | * La regla principal es no tener que hacer scroll horizontal 483 | * Tamaño ideal de 120 caracteres (IDEs ya lo controlan) 484 | * Apertura horizontal y densidad: poner espacios entre operadores y variables 485 | * En los argumentos de los métodos no es necesario dejar espacios entre los paréntesis 486 | * Respetar la indentación 487 | * IntelliJ IDEA: 488 | * Formatear el código con: Ctrl + Shift + L 489 | * Se pueden exportar/importar las configuraciones en File > Manage IDE Settings > Export 490 | 491 | 492 | ## 6. Objetos y estructuras de datos 493 | 494 | * No exponer los detalles de implementación 495 | * Abstracción: interfaces, clases abstractas 496 | * Encapsulación: modificadores ``public``, ``private``, ``protected`` 497 | * Métodos ``get()`` y ``set()`` 498 | * Bajo acoplamiento 499 | 500 | Asimetría de objetos y estructuras de datos: 501 | 502 | * Las **estructuras de datos** exponen sus datos y no tienen funciones significativas que restrinjan los detalles de esos datos. 503 | * **Objetos** esconden sus datos detrás de abstracciones y exponen funciones/métodos que operan sobre esos datos. 504 | * Ejemplo: Clase ``Customer`` tiene un atributo ``age`` solo dejamos modificarla a través de un método en el que controlamos que sea mayor de edad y que esté en un rango que tenga sentido (18 a 100 años). 505 | 506 | Aplicar la Ley de Demeter (LOD): 507 | * Directiva del principio de **menor conocimiento** promueve modularidad, separación de responsabilidades, evita el código Espagueti. 508 | * Funciones: un método no debe invocar métodos en objetos que son devueltos por cualquier de las funciones permitidas. Ejemplo: 509 | 510 | ```java 511 | 512 | // mal 513 | context.getOptions().getScrathDir().getAbsolutePath().getURI() 514 | 515 | // bien 516 | context.createScrathDirPathURI() 517 | 518 | ``` 519 | 520 | En el caso de estar trabajando con APIs cerradas que no podemos modificar se podría plantear usar un patrón de diseño Adapter. 521 | 522 | * Data Access Object (DAO): patrón de diseño empleado para abstraer las operaciones de base de datos (CRUD: Create Retrieve Update Delete). 523 | * Data Transfer Object (DTO): es un POJO (Plain Old Java Object), es decir, una clase normal y corriente con getters y setter que sirve únicamente para llevar información. Ejemplo: se usan para interactuar con otros sistemas software externos, serializar-deserializar de un formato a java y viceversa. 524 | * https://stackoverflow.com/questions/1612334/difference-between-dto-vo-pojo-javabeans 525 | * Record: son nuevos tipos en Java que permiten evitar tener que escribir boilerplate el uso de getter, setter, toString, etc. La idea es realizar lo que hace Lombok pero de forma nativa: https://docs.oracle.com/en/java/javase/16/language/records.html 526 | 527 | ## 7. Manejo de errores 528 | 529 | * Usar excepciones en lugar de códigos de error 530 | * Escribir try-catch de entrada a la hora de desarrollar un código que puede ocasionar excepciones. 531 | * checked vs. unchecked: las excepciones comprobadas (checked) dan lugar a tener que cambiar la signatura en todos los métodos asociados, es decir, quien ha invocado a la función que lanza la excepción. Recomendación: unchecked. 532 | * Casuística en la que desde una función de alto nivel/intermedio nos puede interesar gestionar todas las excepciones lanzadas por funciones de bajo nivel siempre y cuando estén relacionadas. 533 | * Si son totalmente independientes y no están relacionadas puede interesar más tratarlas con try catch en la propia función. 534 | * El trato de las excepciones lanzadas se podría gestionar con AOP. 535 | * Retorno de valores: 536 | * No devolver ``null``, o lanzar una excepción o usar ``Optional``. 537 | * El principal problema de devolver null o trabajar con null es: 538 | * Ensucia el código teniendo que añadir las típicas comprobaciones de null-checks 539 | * Es propenso a bugs y errores: ``NullPointerException`` 540 | * Pasar valores: 541 | * No pasar ``null`` como parámetro. Se suele aplicar programación defensiva y lanzar una excepción de tipo ``IllegalArgumentException``. 542 | * A nivel de catch: tratar de capturar siempre excepciones concretas en lugar de ``Exception`` 543 | * CUIDADO: los niveles de error cuando usamos loggers porque podemos saturar las alertas al equipo de desarrollo si ponemos como error algo que en realidad sería de tipo INFO o WARNING. 544 | * Dentro de los catch solemos utilizar una herramienta de logging (ejemplo log4j) para registrar los errores ya sea en archivos o en sistemas externos como por ejemplo [Elastic Stack](https://www.elastic.co/es/elastic-stack/). 545 | 546 | ## 8. Límites 547 | 548 | Límites entre nuestro código y las APIs que utilizamos. 549 | 550 | * Código de **terceras partes**: ``java.util.Map``. 551 | * Crear una clase que represente una estructura de datos, por ejemplo la clase ``Sensors`` que tenga dentro un Mapa y permita realizar operaciones con el mismo sin necesidad de tener que conocer sus métodos desde fuera de Sensors. 552 | * Patrón Iterator 553 | * Patrón Adapter 554 | * **Learning test**: crear un test donde se pruebe la librería o dependencia antes de utilizarla en nuestros desarrollos. El test luego servirá para probar que todo funciona si el día de mañana se decide actualizar la versión de la librería. 555 | * Uso de **mocks** cuando necesitamos utilizar un código que todavía no ha sido desarrollado. 556 | 557 | ### log4j 558 | 559 | 4j: para java. 560 | 561 | Lo normal es que se utilice **log4j** a través de **slf4j** que actuaría como un Factory que permite obtener objetos de log. 562 | 563 | 564 | 565 | ## 9. Organización de clases 566 | 567 | 568 | Orden de una clase: 569 | 570 | 1. Variables 571 | 1. Constantes públicas/privadas 572 | 2. Variables estáticas (static) privadas 573 | 3. Variables privadas de instancia 574 | 2. Funciones públicas 575 | 3. Funciones privadas 576 | 577 | 578 | * Respetar el orden de las clases 579 | * Encapsulación: modificadores private/protected 580 | * Principio SRP: clases pequeñas y de una sola responsabilidad 581 | * Alta cohesión: una clase en la que cada variable es utilizada por cada método tiene una cohesión máxima. Cuando la cohesión es alta, significa que los métodos y las variables de la clase son codependientes y forman un todo lógico. 582 | * Buscamos bajo acoplamiento y alta cohesión 583 | * Romper clases grandes en clases más pequeñas 584 | * Romper funciones en funciones más pequeñas 585 | * Organización para el cambio: principio de Open/Closed, separar todo en clases más pequeñas en vez de una clase grande de manera que los nuevos se añaden por medio de nuevas clases y la estructura lo permite. 586 | 587 | 588 | ## 10. Sistemas 589 | 590 | * Separación de conceptos: 591 | * No vincularse con clases concretas: no usar concreciones o implementaciones directamente. 592 | * Utilizar abstracción: inyección de dependencias (DI) (IoC). No crear nosotros directamente los objetos, los crea e inyecta un mecanismo de dependencias. 593 | * Usar patrón Factory para la construcción de objetos 594 | * Java Proxies: utilizar las APIs de Java Proxy y Reflection da lugar a código complejo y la recomendación es utilizar un framework de AOP. 595 | * Desarrollo escalado: implementar solo las historias de esta iteración o de este momento en lugar de programar cosas que no hacen falta todavía "por si acaso". 596 | * Uso de Domain Specific Language (DSL): es interesante crear lenguajes específicos de dominio con el objetivo de representar el conocimiento del equipo experto en una materia. Ejemplo de DSL: lenguaje SQL, queries de Spring Data JPA, sintaxis JHipster para la generación de entities. 597 | 598 | ### AOP 599 | 600 | Programación Orientada Objetos (POO) tiene ciertas desventajas: 601 | 602 | * Dispersión y duplicado del código: una misma responsabilidad se repite a lo largo de diferentes componentes del código: **seguridad, logs, auditoría, transaccionalidad**. 603 | * Código Espagueti: acoplamiento entre diferentes responsabilidades 604 | 605 | Solución: 606 | 607 | Programación Orientada a Aspectos (AOP): es un paradigma que intenta formalizar y representar aquellos elementos que son transversales a todo el sistema. 608 | 609 | Elementos de AOP: 610 | 611 | * Aspectos (aspect) 612 | * Consejos (advice) 613 | * punto de corte (pointcut) 614 | * Interceptadores (interceptors) 615 | 616 | Implementación: 617 | 618 | * Spring AOP: implementación simple de AOP a través de Spring IoC para resolver los problemas más comunes. 619 | * AspectJ: la tecnología AOP original que ofrece una solución AOP completa. 620 | 621 | 622 | 623 | ## 11. Diseños emergentes 624 | 625 | 4 reglas: 626 | 627 | 1. Todos los tests deben pasar, tener éxito, cumplirse todos los asserts programados 628 | 2. No debe haber código duplicado 629 | 3. Se debe expresar la intención por medio del nombrado 630 | 4. Minimizar el uso de clases y métodos 631 | 632 | ## 12. Concurrencia 633 | 634 | ### Conceptos 635 | Concurrencia: es simplemente ejecutar varias tareas en paralelo entre sí para aprovechar mejor los recursos computacionales. En los lenguajes de programación como Java, los encargados de proporcionar la concurrencia son los hilos. 636 | 637 | Hilo: un hilo es un proceso ligero con su propia pila de llamadas. Sin embargo, un hilo tiene el privilegio de acceder a los datos compartidos de otros hilos que se ejecutan bajo el mismo proceso. Dentro de una aplicación Java, podemos utilizar muchos hilos para lograr un procesamiento paralelo o concurrencia. 638 | 639 | Es mucho más fácil escribir código que se ejecuta en un solo hilo que escribir programas concurrentes. 640 | 641 | ### Por qué queremos concurrencia 642 | 643 | La concurrencia es una estrategia de desacoplamiento porque nos ayuda a segmentar qué es lo que se hace del cuándo se hace. En aplicaciones de un solo hilo (single-threated) el qué y el cuando están acoplados. 644 | 645 | Desacoplar el qué del cuando permite mejorar el rendimiento y la estructura de los programas, pero es difícil de diseñar e implementar. 646 | 647 | 648 | ### Mitos y conceptos erróneos 649 | 650 | - La concurrencia siempre mejora el rendimiento 651 | - El diseño no cambia cuando se escriben programas concurrentes 652 | - Entender los problemas de concurrencia no es importante cuando se trabaja con un contenedor como el contenedor Web o EJB 653 | 654 | Cuidado: 655 | 656 | * La concurrencia incurre en cierta sobrecarga (escribir código adicional) 657 | * La concurrencia correcta es compleja 658 | * Los errores de concurrencia son difíciles de repetir 659 | * La concurrencia a menudo requiere un cambio fundamental en la estrategia de diseño 660 | 661 | ¿Qué hace que la concurrencia sea tan difícil? A diferencia de las aplicaciones de un solo hilo, la concurrencia permite múltiples vías de procesamiento que pueden conducir a resultados diferentes. 662 | 663 | 664 | ### Principios para la concurrencia: 665 | 666 | * SRP 667 | * Limitar el alcance de los datos usando encapsulación y evitando compartición de los datos 668 | * Usar copias de los datos 669 | * Hilos independientes que eviten compartir datos con otros hilos 670 | * Conocer la librería que se use: por ejemplo framework Collections de Java tiene colecciones concurrentes 671 | * Modelos de ejecución: 672 | * Bound resources 673 | * mutual exclusion 674 | * starvation 675 | * deadlock 676 | * livelock 677 | * Esquema producer-consumer 678 | * Esquema readers-writers 679 | * Problema de la cena entre filósofos 680 | * Mantener secciones synchronized lo más pequeñas posibles 681 | * Escribir código de terminación de hilos es complicado 682 | * Escribir test que permitan comprobar el código que use hilos 683 | * Aquellos fallos intermitentes y extraños podrían venir derivados de problemas en el uso de hilos 684 | * Parametrizar el código que usa hilos, dejarlo tuneable 685 | 686 | 687 | ### Concurrencia en Java 688 | 689 | java.lang.Thread 690 | 691 | java.lang.Runnable 692 | 693 | Explorar la API _java.util.concurrent_ 694 | 695 | La librería rxjava proporciona programación reactiva que facilita el uso de concurrencia. 696 | 697 | 698 | ### Posibles fuentes de problemas 699 | 700 | * Errores de interferencia de hilos 701 | * Errores de consistencia de memoria 702 | 703 | ### Implementación 704 | 705 | * Procesos 706 | * Hilos 707 | * Clase Thread 708 | * Crear Runnable 709 | * Thread.sleep 710 | * Interrumpir: t.interrupt() y Thread.interrupted() 711 | * t.join() permite a un hilo esperar a que otro acabe 712 | * Palabras reservadas en Java: ``synchronized`` y ``volatile``. 713 | * Fallos de sincronización: 714 | * Thread interference: describe cómo se introducen los errores cuando varios hilos acceden a datos compartidos. 715 | * memory consistency: describe los errores que resultan de las vistas inconsistentes de la memoria compartida. 716 | * synchronized methods: describe un sencillo lenguaje que puede prevenir eficazmente la interferencia de hilos y los errores de consistencia de memoria. 717 | * implicit locks: describe un lenguaje de sincronización más general, y describe cómo la sincronización se basa en bloqueos implícitos. 718 | * atomic access: habla de la idea general de operaciones que no pueden ser interferidas por otros hilos. 719 | * **deadlock**: El bloqueo describe una situación en la que dos o más hilos están bloqueados para siempre, esperando el uno al otro. 720 | * **Starvation**: La inanición describe una situación en la que un hilo no puede acceder regularmente a los recursos compartidos y no puede progresar. Esto ocurre cuando los recursos compartidos dejan de estar disponibles durante largos periodos por hilos "codiciosos". 721 | * **livelock**: A menudo, un hilo actúa en respuesta a la acción de otro hilo. Si la acción del otro hilo es también una respuesta a la acción de otro hilo, entonces puede producirse un bloqueo. Al igual que en el caso del bloqueo, los hilos bloqueados no pueden seguir avanzando. Sin embargo, los hilos no están bloqueados - simplemente están demasiado ocupados respondiendo el uno al otro para reanudar el trabajo. 722 | 723 | 724 | ## 13. SOLID 725 | 726 | Principios orientados a objetos con el fin de que el código sea más mantenibles. Tienen su origen gracias a Robert Martins (Uncle Bob) y son promovidos 727 | 728 | SOLID es un acrónimo mnemotécnico acuñado por Michael Feathers y que se basa en los cinco principios que establece para escribir software comprensible y mantenible: 729 | 730 | * **Principio de responsabilidad única (SRP)**: Cada interfaz, clase o método que definamos debe tener un objetivo claramente definido. En esencia, lo ideal es que haga una cosa y la haga bien. Esto lleva a que los métodos y las clases sean más pequeños y que se puedan probar. 731 | * **Principio de apertura-cierre (OCP)**: El código que escribimos debería estar idealmente abierto a la extensión pero cerrado a la modificación. Lo que esto significa es que una clase debe ser escrita de manera que no haya necesidad de modificarla. Sin embargo, debería permitir cambios a través de la herencia o la composición. 732 | * **Principio de sustitución de Liskov (LSP)**: Este principio establece que cada subclase o clase derivada debe ser sustituible por su clase madre o base. Esto ayuda a reducir el acoplamiento en el código base y, por tanto, a mejorar la reutilización. 733 | * **Principio de segregación de interfaces (ISP)**: Implementar una interfaz es una forma de proporcionar un comportamiento específico a nuestra clase. Sin embargo, una clase no debe implementar métodos que no necesita. Esto nos obliga a definir interfaces más pequeñas y centradas. 734 | * **Principio de inversión de la dependencia (DIP)**: Según este principio, las clases sólo deben depender de las abstracciones y no de sus implementaciones concretas. Esto significa efectivamente que una clase no debería ser responsable de crear instancias para sus dependencias. En su lugar, dichas dependencias deben ser inyectadas en la clase. 735 | 736 | ## 14. Arquitectura limpia 737 | 738 | 739 | ### 1. Diseño y arquitectura 740 | Diseño y arquitectura son lo mismo, con matices. 741 | 742 | El **diseño** se asocia comúnmente con bajo nivel de detalle mientras que la arquitectura hace referencia a estructuras a alto nivel de detalle pero ambas son parte del mismo todo. 743 | 744 | El objetivo de la **arquitectura** es minimizar los recursos humanos requeridos para construir y mantener el sistema requerido. 745 | 746 | **¿Motivo?** El principal enemigo del buen diseño es el exceso de confianza de los desarrolladores que quieren terminar los desarrollos demasiado rápido. El problema viene al pensar que se puede limpiar el código más adelante pero finalmente nunca se arregla y la deuda técnica se acumula y la complejidad crece exponencialmente. Es por esta razón que deben plantearse las buenas prácticas desde el principio. 747 | 748 | ### Por qué arquitectura limpia 749 | 750 | 751 | El centro de tu aplicación no es la base de datos. Tampoco es uno o varios de los frameworks que puedas estar utilizando. El centro de tu aplicación son los casos de uso de tu aplicación - Unclebob (fuente) 752 | 753 | La arquitectura limpia nos ayuda a resolver, o al menos a mitigar, estos problemas comunes de la arquitectura: 754 | 755 | * Las decisiones se toman demasiado pronto, a menudo al principio del proyecto, cuando menos sabemos del problema que tenemos que resolver 756 | * Es difícil cambiar, así que cuando descubrimos nuevos requisitos tenemos que decidir si queremos introducirlos o pasar por un costoso y doloroso rediseño. Todos sabemos cuál suele ganar. Las mejores arquitecturas son las que nos permiten aplazar el compromiso con una solución concreta y nos permiten cambiar de opinión 757 | * Se centra en los frameworks. Los marcos son herramientas que se utilizan, no arquitecturas a las que hay que ajustarse. Los marcos a menudo requieren compromisos de tu parte, pero no se comprometen contigo. Pueden evolucionar en diferentes direcciones, y entonces estarás atascado siguiendo sus reglas y peculiaridades 758 | * Se centra en la base de datos. A menudo pensamos primero en la base de datos y luego creamos un sistema CRUD a su alrededor. Acabamos utilizando los objetos de la base de datos en todas partes y tratamos todo en términos de tablas, filas y columnas 759 | * Nos centramos en los aspectos técnicos y cuando nos preguntan por nuestra arquitectura decimos cosas como "son servlets corriendo en tomcat con una db de oracle usando spring" 760 | * Es difícil encontrar las cosas lo que hace que cada cambio sea más largo y doloroso 761 | * La lógica de negocio está repartida por todas partes, dispersa en muchas capas, por lo que al comprobar cómo funciona algo nuestra única opción es depurar todo el código base. Peor aún, a menudo está duplicada en múltiples lugares 762 | * Fuerza/Anima a realizar pruebas lentas y pesadas. A menudo nuestra única opción para las pruebas es pasar por la GUI, ya sea porque la GUI tiene mucha lógica, o porque la arquitectura no nos permite hacer otra cosa. Esto hace que las pruebas sean lentas de ejecutar, pesadas y frágiles. El resultado es que la gente no los ejecuta y la compilación se rompe a menudo 763 | * Despliegues poco frecuentes porque es difícil hacer cambios sin romper las funcionalidades existentes. La gente recurre a ramas de características de larga duración que sólo se integran al final y dan lugar a grandes lanzamientos, en lugar de pequeños incrementos 764 | 765 | La arquitectura limpia nos proporciona todos estos beneficios: 766 | 767 | * Estrategia de pruebas efectiva que sigue la pirámide de pruebas y nos da una construcción rápida y fiable 768 | * Los frameworks están aislados en módulos individuales para que cuando (no si) cambiamos de opinión sólo tengamos que cambiar un lugar, sin que el resto de la aplicación se entere 769 | * Independiente de la base de datos, que se trata como cualquier otro proveedor de datos. Nuestra aplicación tiene casos de uso reales en lugar de ser un sistema CRUD 770 | * Arquitectura chillona, es decir, grita su uso previsto. Cuando miras la estructura del paquete te haces una idea de lo que hace la aplicación en lugar de ver los detalles técnicos 771 | * Toda la lógica de negocio está en un caso de uso, por lo que es fácil de encontrar y no está duplicada en ningún otro lugar 772 | * Es difícil hacer algo incorrecto porque los módulos imponen dependencias de compilación. Si intentas usar algo que no debes, la aplicación no compila 773 | * Siempre estamos listos para desplegar dejando el cableado del objeto para el final o utilizando banderas de características, por lo que obtenemos todos los beneficios de la integración continua (sin necesidad de ramas de características) 774 | * Enjambre de historias para que diferentes parejas puedan trabajar fácilmente en la misma historia al mismo tiempo para completarla más rápidamente 775 | * Un buen monolito con casos de uso claros que puedes dividir en microservicios más adelante, una vez que hayas aprendido más sobre ellos 776 | 777 | Por supuesto, tiene un coste: 778 | 779 | * La percepción de la duplicación de código. Las entidades pueden ser representadas de manera diferente cuando se utilizan en la lógica de negocio, cuando se trata de la base de datos y cuando se presentan en un formato JSON. Puedes sentir que estás duplicando código, pero en realidad estás favoreciendo el desacoplamiento sobre el DRY 780 | * Necesitas una lógica de negocio interesante para "justificar" la estructura. Si todo lo que haces en tu caso de uso es un método de una línea para leer o guardar desde una base de datos, entonces tal vez puedas salirte con la tuya con algo más simple 781 | 782 | 783 | ### Arquitectura limpia 784 | 785 | 4 aspectos del desarrollo de software: 786 | 787 | * Desarrollo 788 | * despliegue 789 | * operaciones 790 | * mantenimiento 791 | 792 | La arquitectura debe mantener esos 4 aspectos lo más sencillos posibles para poder crear software realmente útil. Un arquitecto dejará para el final siempre los detalles y se centrará en esos 4 aspectos a alto nivel primero. 793 | 794 | Dejar cuantas más opciones abiertas mejor. 795 | 796 | 797 | ### Características de arquitectura limpia 798 | 799 | - Independiente de los marcos de trabajo. La arquitectura no depende de la existencia de alguna biblioteca de software cargada de características. Esto le permite utilizar dichos marcos como herramientas, en lugar de obligarle a encajar su sistema en sus limitadas restricciones. 800 | - Comprobable. Las reglas de negocio pueden probarse sin la interfaz de usuario, la base de datos, el servidor web o cualquier otro elemento externo. 801 | - Independiente de la interfaz de usuario. La interfaz de usuario puede cambiar fácilmente, sin cambiar el resto del sistema. Una interfaz de usuario web puede ser sustituida por una interfaz de usuario de consola, por ejemplo, sin cambiar las reglas de negocio. 802 | - Independiente de la base de datos. Puedes cambiar Oracle o SQL Server por Mongo, BigTable, CouchDB o cualquier otra cosa. Sus reglas de negocio no están ligadas a la base de datos. 803 | - Independientes de cualquier organismo externo. De hecho, tus reglas de negocio no saben nada de las interfaces con el mundo exterior. 804 | 805 | 806 | ### partes de arquitectura limpia 807 | 808 | * Entidades 809 | * Casos de uso 810 | * Adaptadores de interfaces 811 | * Frameworks y drivers 812 | 813 | 814 | ### Cohesión y acoplamiento 815 | 816 | Cohesión: 817 | 818 | - REP: Principio de Equivalencia de Reutilización/Liberación 819 | - CCP: El principio de cierre común 820 | - CRP: El principio de reutilización común 821 | 822 | Acoplamiento: 823 | 824 | * SDP: Principio de dependencias estables 825 | * SAP: principio de abstracciones estables. 826 | 827 | 828 | Acoplamiento: 829 | * Dependencias acíclicas 830 | * Diseño top-down 831 | * Dependencias estables 832 | * Métricas para la gestión de dependencias 833 | 834 | ### Política y nivel 835 | Un software es un conjunto de políticas. 836 | 837 | El nivel de una política es la distancia de las entradas y salidas. 838 | 839 | Cuanto más lejos esté, mayor será su nivel. Las políticas de alto nivel tienden a cambiar con menos frecuencia que las de bajo nivel. 840 | 841 | Separar esas políticas y hacer que las dependencias apunten hacia las de alto nivel reduce el impacto del cambio. 842 | 843 | ### Reglas del negocio 844 | 845 | Las reglas de negocio son la razón de ser de un sistema de software. Son el núcleo de la funcionalidad. Llevan el código que hace, o ahorra, dinero. Son las joyas de la familia. 846 | 847 | Las reglas de negocio deben permanecer claras, sin ser manchadas por preocupaciones más básicas como la interfaz de usuario o la base de datos utilizada. Idealmente, el código que representa las reglas de negocio debería ser el corazón del sistema, con preocupaciones menores conectadas a ellas. Las reglas de negocio deberían ser el código más independiente y reutilizable del sistema. 848 | 849 | Son las: 850 | 851 | * Entidades 852 | * Casos de uso 853 | 854 | ### Límites y su anatomía 855 | 856 | La arquitectura de un sistema está compuesta por un conjunto de componentes software y los límites que los separan. 857 | * **Cruce de límites**: una función de un límite llama a otra función que está en otro límite pasando datos. La clave es controlar esos límites para que si uno cambia no haya que recompilar el otro. 858 | * **Arquitectura monolítica**: no tiene límites físicos estrictos, todo está en un mismo desplegable. No obstante define sus límites haciendo uso de polimorfismo. 859 | * Componentes desplegables: en el caso de java están los jar y war. 860 | * Hilos: no son límites arquitecturales, tan solo una forma de organizar y programar el orden de ejecución. 861 | * Procesos locales 862 | * Servicios: representan los límites más fuertes 863 | 864 | Conclusión: 865 | 866 | La mayoría de los sistemas, salvo los monolíticos, utilizan más de una estrategia de límites. Un sistema que hace uso de los límites de los servicios también puede tener algunos límites de los procesos locales. 867 | 868 | De hecho, un servicio es a menudo sólo una fachada para un conjunto de procesos locales que interactúan. Un servicio, o un proceso local, será casi con toda seguridad un monolito compuesto por componentes de código fuente o un conjunto de componentes de despliegue vinculados dinámicamente. 869 | 870 | Los límites de un sistema suelen ser una mezcla de comunicaciones locales y otras que se preocupan por la latencia. 871 | 872 | 873 | ### Límites parciales y capas 874 | 875 | YAGNI: “You Aren’t Going to Need It.” 876 | 877 | 3 formas de implementar un límite parcial: 878 | 879 | Un límite completo puede ser caro: interfaces de límite, estructuras de datos de entrada y salida, y difícil de mantener. Un diseño puramente anticipatorio puede violar YAGNI "no lo vas a necesitar", en cuyo caso los arquitectos a veces proponen un límite parcial, en el que todos los componentes pueden estar en su lugar pero sentados en un sistema monolítico, o una inversión de dependencia (interfaz) está en su lugar, o como un patrón de fachada donde incluso una inversión de dependencia no se aplica. 880 | 881 | 882 | 883 | ### Servicios pequeños y grandes 884 | 885 | ¿Son los servicios siempre importantes desde el punto de vista arquitectónico? 886 | 887 | No necesariamente: la arquitectura del sistema está definida por los límites que separan la política de alto nivel de los detalles de bajo nivel. Los servicios en sí mismos son una forma, y son arquitectónicamente significativos cuando representan límites arquitectónicos. 888 | 889 | ¿Ofrecen un mejor desacoplamiento? 890 | 891 | No necesariamente. Todavía pueden estar acoplados por los recursos compartidos en la red, o los datos que comparten. Por ejemplo, al igual que ocurre con los cambios en la firma de las funciones, la incorporación de un nuevo campo en una serie de microservicios requiere cambios en el esquema del servicio. 892 | 893 | ¿Ofrecen desarrollo y despliegue independientes? 894 | 895 | Es cierto hasta cierto punto, pero a menudo vemos que las operaciones siguen necesitando coordinación. "La arquitectura no se define por los mecanismos físicos por los que los elementos se comunican y ejecutan". 896 | 897 | Preocupaciones transversales: un sistema construido con descomposición funcional es muy vulnerable a las nuevas características que atraviesan todos los comportamientos funcionales, sean o no SOA. 898 | 899 | En resumen, por muy útiles que sean, las SOA no son la panacea, y para tener en cuenta los cambios transversales, puede ser necesario diseñar las partes internas de un servicio (o un componente funcional) teniendo en cuenta la Regla de Dependencia, y permitir implementaciones concretas enchufables. 900 | 901 | * **Monolítica** 902 | * **SOA** (Service Oriented Architecture): 903 | * es un tipo de arquitectura de software, la cual se basa en la integración de aplicaciones mediante servicios. Sobre estos servicios se construyen: composiciones, BPM, proxys e incluso APIs. 904 | * Descomponer la lógica de negocio de una organización (o partes de ella) en pequeñas unidades de funcionalidad. Estas pequeñas unidades son los **servicios**. Con esto conseguimos romper con el concepto de aplicaciones «silo», donde se creaba una aplicación para resolver una necesidad de negocio concreta, otra para resolver otra, etc… Lo que tendremos será una **plataforma transversal** formada por un **inventario de servicios** (o varios) de forma que no solventaremos las necesidades cambiantes del negocio creando nuevas aplicaciones sino **combinando diferentes servicios** (y creando nuevos servicios cuando corresponda) 905 | * Normalmente usan SOAP (web services): **SOAP (S**imple **O**bject **A**ccess **P**rotocol), es un protocolo que nos permitirá realizar servicios web sin estado, a través de TCP y con un formato XML. 906 | * **Microservicios**: se consideran una evolución de SOA y son más a grano fino e independientes entre sí. 907 | * Normalmente usan REST (servicios RESTful): **RE**presentational **S**tate **T**ransfer es una definición de arquitectura basadas en el protocolo HTTP usando habitualmente JSON. 908 | * GraphQL 909 | 910 | 911 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | 7 | org.example 8 | java-clean-code 9 | 1.0-SNAPSHOT 10 | 11 | 12 | 18 13 | 18 14 | 15 | 16 | -------------------------------------------------------------------------------- /src/main/java/conditionals/consolidatedconditional/bad/Main.java: -------------------------------------------------------------------------------- 1 | package conditionals.consolidatedconditional.bad; 2 | 3 | public class Main { 4 | 5 | private double extraSalary; 6 | private int seniority; 7 | private int education; 8 | private int incidents; 9 | private boolean certification; 10 | 11 | double calculateExtraSalary(){ 12 | double result = 0; 13 | if (seniority<1){ 14 | return 0; 15 | } 16 | if (education<1){ 17 | return 0; 18 | } 19 | if(incidents > 10){ 20 | return 0; 21 | } 22 | if (!certification){ 23 | return 0; 24 | } 25 | 26 | // Calculate extra salary: 27 | // ... 28 | return result; 29 | 30 | } 31 | 32 | } 33 | -------------------------------------------------------------------------------- /src/main/java/conditionals/consolidatedconditional/good/Main.java: -------------------------------------------------------------------------------- 1 | package conditionals.consolidatedconditional.good; 2 | 3 | public class Main { 4 | 5 | public static final double EXTRA_SALARY = 0.10; 6 | private double extraSalary; 7 | private int seniority; 8 | private int education; 9 | private int incidents; 10 | private boolean certification; 11 | 12 | double calculateExtraSalary(){ 13 | double result = 0; 14 | 15 | if (isEligibleExtraSalary()) 16 | return result + result * EXTRA_SALARY; 17 | 18 | return result; 19 | 20 | } 21 | 22 | private boolean isEligibleExtraSalary() { 23 | 24 | boolean category = seniority > 1 || education > 1; 25 | boolean experience = incidents < 10 || !certification; 26 | return category || experience; 27 | } 28 | 29 | } 30 | -------------------------------------------------------------------------------- /src/main/java/conditionals/consolidateduplicate/bad/Main.java: -------------------------------------------------------------------------------- 1 | package conditionals.consolidateduplicate.bad; 2 | 3 | public class Main { 4 | 5 | private double extraSalary; 6 | private int seniority; 7 | private int education; 8 | private int incidents; 9 | private boolean certification; 10 | 11 | double calculateExtraSalary(){ 12 | double result = 0; 13 | if(isEligibleExtraSalary()){ 14 | result = 500; 15 | sendMessage(); // metodo que se repite en la condicion 16 | }else{ 17 | result = 0; 18 | sendMessage(); // metodo que se repite en la condicion 19 | } 20 | return result; 21 | 22 | } 23 | 24 | private void sendMessage() { 25 | // send email 26 | // connect smtp 27 | System.out.println("Sending message"); 28 | } 29 | 30 | private boolean isEligibleExtraSalary() { 31 | boolean firstLevel = seniority<1 || education<1; 32 | boolean secondLevel = incidents > 10 || !certification; 33 | 34 | return firstLevel || secondLevel; 35 | } 36 | 37 | } 38 | -------------------------------------------------------------------------------- /src/main/java/conditionals/consolidateduplicate/good/Main.java: -------------------------------------------------------------------------------- 1 | package conditionals.consolidateduplicate.good; 2 | 3 | public class Main { 4 | 5 | private double extraSalary; 6 | private int seniority; 7 | private int education; 8 | private int incidents; 9 | private boolean certification; 10 | 11 | double calculateExtraSalary(){ 12 | double result = 0; 13 | 14 | result = isEligibleExtraSalary() ? 500 : 0; 15 | 16 | sendMessage(); // metodo que se repite en la condicion 17 | 18 | return result; 19 | 20 | } 21 | 22 | private void sendMessage() { 23 | // send email 24 | // connect smtp 25 | System.out.println("Sending message"); 26 | } 27 | 28 | private boolean isEligibleExtraSalary() { 29 | boolean firstLevel = seniority<1 || education<1; 30 | boolean secondLevel = incidents > 10 || !certification; 31 | 32 | return firstLevel || secondLevel; 33 | } 34 | 35 | } 36 | -------------------------------------------------------------------------------- /src/main/java/conditionals/polymorphism/bad/Product.java: -------------------------------------------------------------------------------- 1 | package conditionals.polymorphism.bad; 2 | 3 | public class Product { 4 | 5 | private static final Double COMMISSION = 0.10; 6 | private static final Double SHIPPING = 5.99; 7 | 8 | private String name; 9 | private String type; 10 | private Double price; 11 | 12 | double calculatePrice(){ 13 | 14 | switch(this.type){ 15 | case "SIMPLE": 16 | return this.price + SHIPPING; 17 | case "MEDIUM": 18 | return calculateMedium(); 19 | case "PREMIUM": 20 | return this.price + price * COMMISSION; 21 | default: 22 | return this.price; 23 | } 24 | } 25 | 26 | private double calculateMedium() { 27 | return this.price + price * COMMISSION + SHIPPING; 28 | } 29 | 30 | 31 | } 32 | -------------------------------------------------------------------------------- /src/main/java/conditionals/polymorphism/good/BasicProduct.java: -------------------------------------------------------------------------------- 1 | package conditionals.polymorphism.good; 2 | 3 | public class BasicProduct extends Product { 4 | 5 | @Override 6 | double calculatePrice() { 7 | return this.getPrice() + SHIPPING; 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/main/java/conditionals/polymorphism/good/Main.java: -------------------------------------------------------------------------------- 1 | package conditionals.polymorphism.good; 2 | 3 | public class Main { 4 | 5 | public static void main(String[] args) { 6 | 7 | Product product = new BasicProduct(); 8 | product.calculatePrice(); 9 | 10 | Product product2 = new PremiumProduct(); 11 | product2.calculatePrice(); 12 | } 13 | 14 | static double calculatePrice(Product product){ 15 | 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/main/java/conditionals/polymorphism/good/PremiumProduct.java: -------------------------------------------------------------------------------- 1 | package conditionals.polymorphism.good; 2 | 3 | public class PremiumProduct extends Product { 4 | 5 | @Override 6 | double calculatePrice() { 7 | return this.getPrice() + SHIPPING + COMMISSION; 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/main/java/conditionals/polymorphism/good/Product.java: -------------------------------------------------------------------------------- 1 | package conditionals.polymorphism.good; 2 | 3 | public abstract class Product { 4 | 5 | protected static final Double COMMISSION = 0.10; 6 | protected static final Double SHIPPING = 5.99; 7 | 8 | private String name; 9 | private Double price; 10 | 11 | abstract double calculatePrice(); 12 | 13 | public String getName() { 14 | return name; 15 | } 16 | 17 | public void setName(String name) { 18 | this.name = name; 19 | } 20 | 21 | public Double getPrice() { 22 | return price; 23 | } 24 | 25 | public void setPrice(Double price) { 26 | this.price = price; 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/main/java/data/magicnumbers/bad/Main.java: -------------------------------------------------------------------------------- 1 | package data.magicnumbers.bad; 2 | 3 | public class Main { 4 | 5 | public static void main(String[] args) { 6 | double price = 129.99; 7 | 8 | double discountPrice = calculateDiscount(price); 9 | double shippingPrice = calculateShipping(price); 10 | } 11 | 12 | private static double calculateShipping(double price) { 13 | return price < 100 ? 4.99 : 0; // hard coded 14 | 15 | } 16 | 17 | private static double calculateDiscount(double price) { 18 | return price * 0.1; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/main/java/data/replacearray/bad/Main.java: -------------------------------------------------------------------------------- 1 | package data.replacearray.bad; 2 | 3 | public class Main { 4 | 5 | public static void main(String[] args) { 6 | String[] row = new String[4]; 7 | row[0] = "Chair"; 8 | row[1] = "49.99"; 9 | row[2] = "Black"; 10 | row[3] = "5"; 11 | 12 | double finalPrice = Double.parseDouble(row[1]) * Double.parseDouble(row[3]); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/main/java/methods/extractmethod/bad/Main.java: -------------------------------------------------------------------------------- 1 | package methods.extractmethod.bad; 2 | 3 | public class Main { 4 | 5 | void printHTML(){ 6 | 7 | printHead(); 8 | printBody(); 9 | System.out.println("This is the footer"); 10 | System.out.println("script"); 11 | System.out.println("copyright"); 12 | System.out.println(""); 13 | 14 | } 15 | 16 | private void printBody() { 17 | } 18 | 19 | private void printHead() { 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/main/java/methods/extractvariable/bad/Main.java: -------------------------------------------------------------------------------- 1 | package methods.extractvariable.bad; 2 | 3 | public class Main { 4 | 5 | void printProductPrice(Order order){ 6 | Double totalPrice = order.getPrice() * order.getQuantity() - order.getOffer() + order.getShipping() * 2; 7 | 8 | System.out.println(totalPrice); 9 | } 10 | 11 | } 12 | -------------------------------------------------------------------------------- /src/main/java/methods/extractvariable/bad/Order.java: -------------------------------------------------------------------------------- 1 | package methods.extractvariable.bad; 2 | 3 | public class Order { 4 | 5 | private Double price; 6 | private Integer quantity; 7 | private Double offer; 8 | private Double shipping; 9 | 10 | public Double getPrice() { 11 | return price; 12 | } 13 | public Integer getQuantity() { 14 | return quantity; 15 | } 16 | public Double getOffer() { 17 | return offer; 18 | } 19 | public void setPrice(Double price) { 20 | this.price = price; 21 | } 22 | public void setQuantity(Integer quantity) { 23 | this.quantity = quantity; 24 | } 25 | public void setOffer(Double offer) { 26 | this.offer = offer; 27 | } 28 | public Double getShipping() { 29 | return shipping; 30 | } 31 | public void setShipping(Double shipping) { 32 | this.shipping = shipping; 33 | } 34 | 35 | 36 | 37 | } 38 | -------------------------------------------------------------------------------- /src/main/java/methods/inlinemethod/bad/Main.java: -------------------------------------------------------------------------------- 1 | package methods.inlinemethod.bad; 2 | 3 | public class Main { 4 | 5 | private double interest = 5d; 6 | 7 | double getRateInterest(){ 8 | return getAdjustedInterest() ? 2 : 1; 9 | } 10 | 11 | private boolean getAdjustedInterest() { 12 | return interest > 5; 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/main/java/methods/inlinetemp/bad/Main.java: -------------------------------------------------------------------------------- 1 | package methods.inlinetemp.bad; 2 | 3 | public class Main { 4 | 5 | /* 6 | * Calcular si debería tener descuento sí o no 7 | */ 8 | boolean calculateDiscount(Order order){ 9 | double discount = order.getPrice(); 10 | return discount > 200; 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /src/main/java/methods/inlinetemp/bad/Order.java: -------------------------------------------------------------------------------- 1 | package methods.inlinetemp.bad; 2 | 3 | public class Order { 4 | 5 | private Double price; 6 | private Double quantity; 7 | private Double offer; 8 | private Double shipping; 9 | 10 | public Double getPrice() { 11 | return price; 12 | } 13 | public Double getQuantity() { 14 | return quantity; 15 | } 16 | public Double getOffer() { 17 | return offer; 18 | } 19 | public void setPrice(Double price) { 20 | this.price = price; 21 | } 22 | public void setQuantity(Double quantity) { 23 | this.quantity = quantity; 24 | } 25 | public void setOffer(Double offer) { 26 | this.offer = offer; 27 | } 28 | public Double getShipping() { 29 | return shipping; 30 | } 31 | public void setShipping(Double shipping) { 32 | this.shipping = shipping; 33 | } 34 | 35 | 36 | 37 | } 38 | -------------------------------------------------------------------------------- /src/main/java/methods/removeassign/bad/Main.java: -------------------------------------------------------------------------------- 1 | package methods.removeassign.bad; 2 | 3 | public class Main { 4 | 5 | 6 | double calculateDiscount(Order order, double totalPrice){ 7 | if (order.getPrice() > 100) 8 | totalPrice += order.getPrice() * order.getOffer(); // sobreescribe totalPrice 9 | return totalPrice; 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/main/java/methods/removeassign/bad/Order.java: -------------------------------------------------------------------------------- 1 | package methods.removeassign.bad; 2 | 3 | public class Order { 4 | 5 | private Double price; 6 | private Double quantity; 7 | private Double offer; 8 | private Double shipping; 9 | 10 | public Double getPrice() { 11 | return price; 12 | } 13 | public Double getQuantity() { 14 | return quantity; 15 | } 16 | public Double getOffer() { 17 | return offer; 18 | } 19 | public void setPrice(Double price) { 20 | this.price = price; 21 | } 22 | public void setQuantity(Double quantity) { 23 | this.quantity = quantity; 24 | } 25 | public void setOffer(Double offer) { 26 | this.offer = offer; 27 | } 28 | public Double getShipping() { 29 | return shipping; 30 | } 31 | public void setShipping(Double shipping) { 32 | this.shipping = shipping; 33 | } 34 | 35 | 36 | 37 | } 38 | -------------------------------------------------------------------------------- /src/main/java/methods/replacemethod/bad/Product.java: -------------------------------------------------------------------------------- 1 | package methods.replacemethod.bad; 2 | 3 | public class Product { 4 | 5 | double price; 6 | int quantity; 7 | double discount; 8 | double shipping; 9 | 10 | // constructores 11 | 12 | // metodos 13 | 14 | // tostring 15 | 16 | public double calculatePrice(){ 17 | double result = 0; 18 | double priceQuantity = this.price * this.quantity; 19 | double priceDiscount = this.price * this.discount; 20 | double priceShipping = shipping * 0.50; 21 | 22 | // ....... 23 | 24 | // ...... 25 | return result; 26 | } 27 | 28 | // getter y setter 29 | public double getPrice() { 30 | return price; 31 | } 32 | public int getQuantity() { 33 | return quantity; 34 | } 35 | public double getDiscount() { 36 | return discount; 37 | } 38 | public double getShipping() { 39 | return shipping; 40 | } 41 | public void setPrice(double price) { 42 | this.price = price; 43 | } 44 | public void setQuantity(int quantity) { 45 | this.quantity = quantity; 46 | } 47 | public void setDiscount(double discount) { 48 | this.discount = discount; 49 | } 50 | public void setShipping(double shipping) { 51 | this.shipping = shipping; 52 | } 53 | 54 | } 55 | -------------------------------------------------------------------------------- /src/main/java/methods/replacetemp/bad/Product.java: -------------------------------------------------------------------------------- 1 | package methods.replacetemp.bad; 2 | 3 | public class Product { 4 | 5 | private double price; 6 | private int quantity; 7 | 8 | void printProductPrice(){ 9 | // .... 10 | 11 | // ... 12 | double quantityPrice = this.price * this.quantity * 2.0; 13 | if (quantityPrice > 100){ 14 | 15 | }else{ 16 | 17 | } 18 | // .... 19 | } 20 | 21 | } 22 | -------------------------------------------------------------------------------- /src/main/java/objects/extractclass/bad/Person.java: -------------------------------------------------------------------------------- 1 | package objects.extractclass.bad; 2 | 3 | public class Person { 4 | 5 | private Long id; 6 | private String firstName; 7 | private String lastName; 8 | private Integer age; 9 | // address 10 | private String street; 11 | private String postalCode; 12 | private String city; 13 | private String country; 14 | private String door; 15 | 16 | 17 | } 18 | -------------------------------------------------------------------------------- /src/main/java/objects/inlineclass/bad/Direction.java: -------------------------------------------------------------------------------- 1 | package objects.inlineclass.bad; 2 | 3 | public class Direction { 4 | 5 | private String postalCode; 6 | 7 | } 8 | -------------------------------------------------------------------------------- /src/main/java/objects/inlineclass/bad/Person.java: -------------------------------------------------------------------------------- 1 | package objects.inlineclass.bad; 2 | 3 | public class Person { 4 | 5 | private Long id; 6 | private String firstName; 7 | private String lastName; 8 | private Integer age; 9 | } 10 | --------------------------------------------------------------------------------