-
Notifications
You must be signed in to change notification settings - Fork 0
/
index.html
411 lines (380 loc) · 22.1 KB
/
index.html
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
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Arquitectura de desarrollo en proyectos Drupal</title>
<meta name="description" content="Arquitectura de desarrollo en proyectos Drupal">
<meta name="author" content="Ramon Vilar">
<meta name="apple-mobile-web-app-capable" content="yes" />
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent" />
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no, minimal-ui">
<link rel="stylesheet" href="css/reveal.css">
<link rel="stylesheet" href="css/theme/black.css" id="theme">
<!-- Code syntax highlighting -->
<link rel="stylesheet" href="lib/css/zenburn.css">
<!-- Printing and PDF exports -->
<script>
var link = document.createElement( 'link' );
link.rel = 'stylesheet';
link.type = 'text/css';
link.href = window.location.search.match( /print-pdf/gi ) ? 'css/print/pdf.css' : 'css/print/paper.css';
document.getElementsByTagName( 'head' )[0].appendChild( link );
</script>
<!--[if lt IE 9]>
<script src="lib/js/html5shiv.js"></script>
<![endif]-->
</head>
<body>
<div class="reveal">
<!-- Any section element inside of this container is displayed as a slide -->
<div class="slides">
<section>
<h1>Arquitectura de desarrollo en proyectos Drupal</h1>
<h3>DrupalCamp Spain 2015</h3>
<p>
<small>Por <a href="https://www.drupal.org/u/rvilar">Ramon Vilar</a> / <a href="http://twitter.com/rvilar">@rvilar</a></small>
</p>
</section>
<section>
<h2>Sobre mi</h2>
<img src="images/ramon.jpg" style="width: 300px; float: left" alt="Me" />
<h3 style="text-transform: none; padding-top: 60px">Ramon Vilar</h3>
<p><a href="http://twitter.com/rvilar">@rvilar</a></p>
<p><a href="http://ymbra.com">http://ymbra.com</a></p>
<img src="images/logo.png" alt="Ymbra" style="width: 350px; background: #fff" />
</section>
<section>
<h2>Índice</h2>
<ol>
<li>El proceso de desarrollo ideal</li>
<li>Buenas prácticas iniciales</li>
<li>Flujos de desarrollo en las distintas fases de un proyecto</li>
<li>El desarrollo</li>
<li>El testing</li>
<li>Integración contínua y entornos</li>
<li>Otras buenas prácticas</li>
</ol>
</section>
<section>
<section>
<h2>El proceso de desarrollo ideal</h2>
</section>
<section>
<h2>As a developer, I would like...</h2>
<p>Cómo equipo de desarrollo, si hiciesemos una carta a los reyes, nos gustaría que se cumplieran una serie de requisitos:</p>
<ul>
<li>Código versionado</li>
<li>Despliegues automatizados</li>
<li>Pruebas automatizadas</li>
<li>Fácil de probar manualmente por quien sea</li>
<li>Que todo el equipo tenga conocimiento de todo el código</li>
<li>Fácilmente mantenible</li>
</ul>
<p>Y todo <em>de forma transparente a nosotros</em> XD</p>
</section>
<section>
<h2>Esto es una utopía?</h2>
<p>Puede parecerlo, pero no! Nosotros lo hacemos</p>
<p>Lo primero, y lo más importante de todo, es:</p>
<ul>
<li>Preparar al equipo para el cambio</li>
<li>Tener complicidad y ganas por parte de todos los implicados</li>
<li>No tener prisa en la adopción</li>
<li>Ir paso a paso</li>
</ul>
</section>
</section>
<section>
<section>
<h2>Buenas prácticas iniciales</h2>
</section>
<section>
<h2>Conocimientos necesarios para seguir</h2>
<ul>
<li>Conocemos y usamos Git</li>
<li>Conocemos y usamos Drush</li>
<li>Conocemos y usamos Features</li>
<li>y ...</li>
</ul>
</section>
<section>
<h2>Cuál es nuestra finalidad</h2>
<ul>
<li>Nuestra finalidad primera es que nuestro proyecto se pueda instalar de un entorno a otro sin requerir ninguna tarea manual</li>
<li>Esto implica trabajar siempre con código y tener todas y cada una de las funcionalidades en nuestro código (ya sea con features o de otras formas que veremos más tarde)</li>
</ul>
</section>
<section>
<h2>Estructura de directorios</h2>
<p>Seguimos una mínima estuctura para nuestros módulos y temas:</p>
<ul>
<li><code>/contrib</code></li>
<li><code>/custom</code></li>
</ul>
<p>Y tenemos nuestras features dentro de un directorio <code>/features</code>. Este también lo podemos estructurar a su vez:</p>
<ul>
<li><code>/content_types</code></li>
<li><code>/general</code></li>
<li><code>/entity_types</code></li>
</ul>
</section>
<section>
<h2>Encapsular el desarrollo</h2>
<ul>
<li>Debemos pensar en una forma de encapsular nuestro desarrollo y hacer fácil el flujo</li>
<li>Los perfiles de instalación son una herramienta Drupal nacida para ello</li>
<li>Instalar el proyecto es tan fácil como instalar el perfil</li>
<li>Más tarde veremos como estructurar nuestro desarrollo</li>
</ul>
</section>
<section>
<h2>Makefile</h2>
<ul>
<li>Nos permite tener una documentación rápida de los módulos, temas y librerías usadas</li>
<li>Nos permite identificar rápidamente las versiones que usamos y los patches aplicados</li>
<li>Nos evita tener código duplicado en nuestro repositoria</li>
<li>Y asegura a nuestro cliente que no hemos modificador ningún contrib "a saco"</li>
</ul>
</section>
</section>
<section>
<section>
<h2>Flujos de desarrollo en las distintas fases de un proyecto</h2>
</section>
<section>
<h2>Fases de un proyecto</h2>
<ul>
<li>Desarrollo sin intervención de agentes externos: flujo de instalación</li>
<li>Desarrollo mientras el cliente interactua con la aplicación: flujo de actualización</li>
</ul>
</section>
<section>
<h2>Flujo de instalación</h2>
<ul>
<li>Si sólo los desarrolladores estan trabajando en el proyecto, entonces podemos borrar y manipular la base de datos sin problemas</li>
<li>Para asegurarnos que toda la configuración está en código, debemos instalar nuestra aplicación a menudo</li>
<li>Desplegar nuestra aplicación en un nuevo entorno es algo tan sencillo cómo:</li>
</ul>
<p><code>drush si <profile></code></p>
</section>
<section>
<h2>Flujo de actualización</h2>
<ul>
<li>En cuanto el cliente empieza a añadir contenido al sitio, ya no podemos seguir con un flujo de instalación (machacaríamos la base de datos)</li>
<li>Debemos pasar a un flujo de actualización usando features como hasta ahora pero pasando a usar <code>hook_update_N()</code> cuando se requiera</li>
<li>Para hacer nuevos despliegues, hay que actualizarla, y por tanto hacer:</li>
</ul>
<p><code>drush updb -y</code></p>
<p><code>drush fra -y</code></p>
</section>
</section>
<section>
<section>
<h2>El desarrollo</h2>
</section>
<section>
<h2>Divide y vencerás</h2>
<ul>
<li>Trabajar con metodologías ágiles es un <em>win</em></li>
<li>Cómo desarrolladores, dividimos cada história de usuario en tareas</li>
<li>Durante el desarrollo, una tarea equivale a un commit (cuanto más unitario, más fácil de revisar)</li>
</ul>
</section>
<section>
<h2>Qué exportar y que no</h2>
<ul>
<li>Debemos ir con cuidado con aquello que exportamos</li>
<li>Sólo debemos exportar aquellas cosas que son própiamente configuración que no dependa del momento o del entorno (por eso nace State API en Drupal 8)</li>
<li>Especial cuidado con las variables: debemos ser conscientes de cuando usar <code>strongarm</code> o cuando hacer <code>variable_set</code> en nuestra función de instalación</li>
</ul>
</section>
<section>
<h2>Qué exportar</h2>
<ul>
<li>Campos</li>
<li>Tipos de contenido</li>
<li>Taxonomías</li>
<li>Menús</li>
<li>Vistas</li>
<li>Panels (siempre y cuando no puedan ser modificados por el editor)</li>
<li>Variables (sólo las de configuración)</li>
<li>...</li>
</ul>
</section>
<section>
<h2>Qué no exportar</h2>
<ul>
<li>Enlaces de menú</li>
<li>Roles</li>
<li>Permisos</li>
<li>Variables (aquellas que dependan del entorno o sean modificables por el editor)</li>
<li>Contenido (nodos, términos, etc.)</li>
</ul>
</section>
<section>
<h2>Cuidado al crear vistas</h2>
<ul>
<li>En D7, si creamos vistas con algunos filtros estos pasaran a depender de identificadores en vez de nombres máquina</li>
<li>Filtrar por término: se exporta el <code>tid</code>. Filtra mejor por nombre o por machine_name</li>
<li>Filtro o control de acceso por rol: se exporta el <code>rid</code>. Usar el nombre para el filtro o un permiso especial para el control de acceso</li>
</ul>
</section>
<section>
<h2>Roles y permisos</h2>
<ul>
<li>Si exportamos los permisos y más tarde, el cliente los modifica, pasaremos a tener nuestras features sobreescritas</li>
<li>Lo mejor es exportar los roles y luego crear los permisos en la función de instalación de nuestro perfil</li>
</ul>
</section>
<section>
<h2>Traducciones de cadenas</h2>
<ul>
<li>Debemos usar siempre cadenas en inglés</li>
<li>Usando la suite <code>i18n</code> podemos traducir y exportar fácilmente las traducciones</li>
<li>Tendremos un directorio <code>/translations</code> en nuestro perfil de instalación con las traducciones de las cadenas necesarias</li>
<li>Nuestro proceso de instalación importará todas las traducciones una vez instalados todos los módulos y features</li>
</ul>
</section>
</section>
<section>
<section>
<h2>El testing</h2>
</section>
<section>
<h2>Facilitar las pruebas</h2>
<ul>
<li>En un entorno ágil, cómo desarrolladores, debemos facilitar un entorno de pruebas a nuestro PO, que a su vez, deberá poder hacer demos a cliente</li>
<li>Si en nuestro flujo de desarrollo instalamos en cada despliegue, cómo podemos proveer de contenido de forma fácil para que se puedan hacer las pruebas?</li>
<li>Para ello nace <a href="https://github.com/Ymbra/migrate_default_content/">migrate_default_contet</a></li>
</ul>
</section>
<section>
<h2>migrate_default_contet</h2>
<ul>
<li>Módulo basado en Migrate para crear contenido de prueba</li>
<li>API sencilla para crear migraciones de nuevos tipos de contenido, términos, menús, etc.</li>
<li>Importar y eliminar este contenido por defecto es tan fácil como:</li>
</ul>
<p><code>drush mi --group=migrate_default_content</code></p>
<p><code>drush mr --group=migrate_default_content</code></p>
</section>
<section>
<h2>Contenido no por defecto</h2>
<ul>
<li>Por requisito de algunos proyectos hay contenido que debe proveerse con la aplicación</li>
<li>Ejemplos de ello pueden ser elementos de menú, términos, alguna página, etc.</li>
<li>La creación de estos contenidos debe estar programado en nuestra función de instalación del perfil</li>
</ul>
</section>
</section>
<section>
<section>
<h2>Integración contínua y entornos</h2>
</section>
<section>
<h2>Integración contínua</h2>
<ul>
<li>El equipo debe de trabajar de forma que no sepa que hay más entornos</li>
<li>Se debe montar un sistema transparente al equipo que haga el trabajo de integración y que sólo informe del resultado</li>
</ul>
</section>
<section>
<h2>Entornos</h2>
<dl>
<dt>Desarrollo</dt>
<dd>Este entorno se lanza a cada push al respositorio. Integra el código, pasa los tests e informa si todo ha ido bien</dd>
<dt>Test</dt>
<dd>Una vez aprobados los commits, y cada ciertas horas, se integra todo el código para que pueda ser probado por el PO</dd>
<dt>Stage</dt>
<dd>Este entorno es el accesible por el cliente. Se construye bajo demanda</dd>
</dl>
</section>
<section>
<h2>Herramientas</h2>
<dl>
<dt>Capistrano</dt>
<dd>Es el software que usamos para crear las tareas de despliegue basadas en su <a href="http://capistranorb.com/documentation/getting-started/flow/">flow</a>. Desarrollado en Ruby y muy fácil de usar</dd>
<dt>Jenkins</dt>
<dd>La usamos para lanzar las builds en los distintios entornos. Hace llamadas a capistrano e informa a nuestras herramientas del resultado</dd>
<dt>IRC</dt>
<dd>Sí IRC. Lo usamos para tener un canal todo el equipo y es dónde las builds lanzan los resultados al finalizar cada una de ellas. Muy útil para no perder el foco.</dd>
</dl>
</section>
<section>
<h2>Larga vida a las <em>builds</em></h2>
<ul>
<li>Cuando lanzamos nuestras tareas de construcción en cada entorno, podemos aprovechar para lanzar otras cosas</li>
<li>Nosotros aprovechamos para, por ejemplo, lanzar tests, sacar estadísticas sobre coding standards, revisar la calidad del código, etc.</li>
<li>Lo hace una máquina, así que aprovechad para darle trabajo</li>
<li>Pero no nos pasemos que una <em>build</em> larga puede llegar a ser un cuello de botella</li>
</ul>
</section>
</section>
<section>
<section>
<h2>Otras buenas prácticas</h2>
</section>
<section>
<h2>Trazabilidad</h2>
<ul>
<li>Desde una tarea debo tener enlazado el commit que la resuelve para futuras revisiones</li>
<li>Eso es fácil usando algunas herramientas, pero sobretodo, documentando bien</li>
<li>Por ejemplo, en nuestro mensaje de commit, debemos incluir el identificador de la tarea</li>
<li>Redmine y jenkins tienen plugins para integrarse entre sí y con nuestro repositorio y facilitar así la nevegación entre ellos</li>
</ul>
</section>
<section>
<h2>Revisión de código</h2>
<ul>
<li>Incluir revisión de código es una de las mejores prácticas que hemos añadido en estos últimos tiempos</li>
<li>Mejora la calidad del código, el control de errores,...</li>
<li>Pero sobretodo ayuda a mejorar como desarrollador y aprender mucho de todos</li>
<li>Y facilita la propiedad del código por parte de todo el equipo, no sólo por parte de la persona que lo desarrolla</li>
</ul>
</section>
<section>
<h2>Agile</h2>
<ul>
<li>Agile, agile y agile; no hay más</li>
<li>Aunque no se pueda usar agile con el cliente, usarlo internamente facilita mucho el trabajo con el equipo de desarrollo</li>
<li>Definir cada una de las funcionalidades, dividirlas, pero sobretodo discutirlas, hace que se entienda mucho más el proyecto y se puedan prevenir errores</li>
</ul>
</section>
</section>
<section>
<h2>Conclusiones</h2>
<ul>
<li>Interpretar esto como un recetario, no como una norma</li>
<li>Lo mejor es adoptar poco a poco</li>
<li>Empezar por cambiar la forma de desarrollo, luego empezar con revisión de código y dejar para el final las peleas con la integración contínua y los entornos</li>
</ul>
</section>
<section>
<h2>Dudas?</h2>
</section>
</div>
</div>
<script src="lib/js/head.min.js"></script>
<script src="js/reveal.js"></script>
<script>
// Full list of configuration options available at:
// https://github.com/hakimel/reveal.js#configuration
Reveal.initialize({
controls: true,
progress: true,
history: true,
center: true,
transition: 'slide', // none/fade/slide/convex/concave/zoom
// Optional reveal.js plugins
dependencies: [
{ src: 'lib/js/classList.js', condition: function() { return !document.body.classList; } },
{ src: 'plugin/markdown/marked.js', condition: function() { return !!document.querySelector( '[data-markdown]' ); } },
{ src: 'plugin/markdown/markdown.js', condition: function() { return !!document.querySelector( '[data-markdown]' ); } },
{ src: 'plugin/highlight/highlight.js', async: true, condition: function() { return !!document.querySelector( 'pre code' ); }, callback: function() { hljs.initHighlightingOnLoad(); } },
{ src: 'plugin/zoom-js/zoom.js', async: true },
{ src: 'plugin/notes/notes.js', async: true }
]
});
</script>
</body>
</html>