-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathatom.xml
594 lines (456 loc) · 56.9 KB
/
atom.xml
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
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
<title><![CDATA[Marcelo Alexandre]]></title>
<link href="http://www.marcelobalexandre.com/atom.xml" rel="self"/>
<link href="http://www.marcelobalexandre.com/"/>
<updated>2014-10-27T19:56:45-02:00</updated>
<id>http://www.marcelobalexandre.com/</id>
<author>
<name><![CDATA[Marcelo Alexandre]]></name>
</author>
<generator uri="http://octopress.org/">Octopress</generator>
<entry>
<title type="html"><![CDATA[Manutenção De Schema De Banco De Dados Com Migrations Em .NET]]></title>
<link href="http://www.marcelobalexandre.com/blog/2014/10/27/manutencao-de-schema-de-banco-de-dados-com-migrations-em-net/"/>
<updated>2014-10-27T19:55:00-02:00</updated>
<id>http://www.marcelobalexandre.com/blog/2014/10/27/manutencao-de-schema-de-banco-de-dados-com-migrations-em-net</id>
<content type="html"><![CDATA[<p>A manutenção de schema de banco de dados é algo importante e delicado em qualquer projeto de desenvolvimento de software. Quando o assunto é banco de dados, todos os desenvolvedores do time precisam estar na mesma página para que possamos realizar mudanças rápidas e com o mínimo de propensão a falhas possível. Com o intuito de atingirmos esses objetivos é importante que o schema do banco de dados esteja protegido pelo nosso controle de versão, e que de preferência, faça parte do processo de Integração Contínua do projeto.</p>
<p>Normalmente o processo de atualização e manutenção de schema de banco de dados é realizado de maneira manual através da criação de scripts SQL e/ou utilização de softwares que geram estes scripts a partir da comparação de dois bancos de dados. Apesar deste processo funcionar em muitos projetos existentes, ele exige muita intervenção manual, o que pode acabar atrasando o lançamento de uma nova versão do sistema e prejudicando os processos de Integração Contínua do projeto.</p>
<p>Uma maneira interessante de abordar a manutenção de schema de banco de dados é através da utilização de migrations. Neste post irei explanar um pouco sobre migrations e demonstrar uma abordagem de como utilizá-las em projetos .NET através de um ótimo framework, o <a href="https://github.com/schambers/fluentmigrator" target="_blank">FluentMigrator</a></p>
<!--more-->
<h1>O Básico Sobre Migrations</h1>
<p>As migrations surgiram como uma alternativa as alterações de banco de dados através da escrita de SQL, bem como uma maneira de evoluir o schema de banco de dados de uma forma gradativa, maneira essa muito válida quando se adota metodologias ágeis. As migrations normalmente são escritas em uma linguagem de programação mais simples para descrever as mudanças no banco de dados, o que normalmente facilita a escrita e a leitura das mesmas.</p>
<p>Esse conceito de migrations foi popularizado pela comunidade <a href="http://rubyonrails.org/" target="_blank">Ruby on Rails</a> que o aplica através das <a href="http://guides.rubyonrails.org/migrations.html" target="_blank">Active Record Migrations</a>, de onde o FluentMigrator buscou inspiração.</p>
<h2>Implementando o FluentMigrator</h2>
<p>A abordagem que irei demonstrar neste post é a que tenho utilizado e recomendado atualmente, mas ela é apenas uma das possíveis maneiras de utilização do FluentMigrator, fique a vontade para implementar da maneira que achar mais interessante para os seus projetos.</p>
<p>Para auxiliar este post eu desenvolvi um pequeno projeto de exemplo que pode ser encontrado em <a href="https://github.com/marcelobalexandre/fluentmigrator-poc" target="_blank">github.com/marcelobalexandre/fluentmigrator-poc</a>.</p>
<p>Como é possível verificar na imagem abaixo eu organizei a estrutura do projeto de exemplo da seguinte maneira:</p>
<ul>
<li><strong>Scripts</strong>: nesta pasta são mantidos os scripts SQL, nesse caso temos o de criação do banco de dados e um script de criação de tabelas antes da implementação do FluentMigrator.</li>
<li><strong>MyProject.Data.Migrations</strong>: neste projeto temos as migrations organizadas em pastas com o número da versão do projeto a que se referem e o MyProjectMigrator que é responsável por executar as migrações.</li>
<li><strong>MyProjectMigratorRunner</strong>: este projeto é um Console Application que utiliza o MyProjectMigrator para executar as migrações.</li>
</ul>
<p><img src="http://www.marcelobalexandre.com/images/manutencao-de-schema-de-banco-de-dados-com-migrations-em-net/solution-explorer.png"></p>
<p>Minha recomendação é criar um projeto separado que conterá as migrations e o nosso Migrator, que no projeto de exemplo chamei de MyProject.Data.Migrations. Basta criar uma Class Library e instalar o Fluent Migrator e o Fluent Migrator Runner utilizando o NuGet.</p>
<h2>Criando um Migrator Runner</h2>
<p>Para executarmos as migrations podemos utilizar o Command Line Runner (executável do próprio FluentMigrator), o MSBuild, o Rake, ou outros. Eu particularmente prefiro criar um Runner próprio para o projeto, que neste caso chamei de MyProjectMigrator.</p>
<p>Como é possível observar no código abaixo, o MyProjectMigrator é bastante simples e fácil de usar, basta invocar o método <code>Migrate</code> passando como parâmetros a ação que deseja realizar (Up ou Down), a string de conexão com o banco de dados e o MigratorEnvironment. O MigratorEnvironment é um Enumerable que criei para que você possa executar ações diferentes nas migrations dependendo do ambiente, muito útil para por exemplo, criar dados fakes (seeds) no ambiente de desenvolvimento e realizar ações exclusivas para os testes unitários. É importante observar que neste exemplo o MyProjectMigrator espera uma string de conexão para o SQL Server 2012, se o seu caso é diferente basta alterá-lo.</p>
<figure class='code'><figcaption><span>MyProjectMigrator.cs</span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
<span class='line-number'>15</span>
<span class='line-number'>16</span>
<span class='line-number'>17</span>
<span class='line-number'>18</span>
<span class='line-number'>19</span>
<span class='line-number'>20</span>
<span class='line-number'>21</span>
<span class='line-number'>22</span>
<span class='line-number'>23</span>
<span class='line-number'>24</span>
<span class='line-number'>25</span>
<span class='line-number'>26</span>
<span class='line-number'>27</span>
<span class='line-number'>28</span>
<span class='line-number'>29</span>
<span class='line-number'>30</span>
<span class='line-number'>31</span>
<span class='line-number'>32</span>
<span class='line-number'>33</span>
<span class='line-number'>34</span>
<span class='line-number'>35</span>
<span class='line-number'>36</span>
<span class='line-number'>37</span>
<span class='line-number'>38</span>
<span class='line-number'>39</span>
<span class='line-number'>40</span>
<span class='line-number'>41</span>
<span class='line-number'>42</span>
<span class='line-number'>43</span>
<span class='line-number'>44</span>
<span class='line-number'>45</span>
<span class='line-number'>46</span>
<span class='line-number'>47</span>
<span class='line-number'>48</span>
<span class='line-number'>49</span>
<span class='line-number'>50</span>
<span class='line-number'>51</span>
<span class='line-number'>52</span>
</pre></td><td class='code'><pre><code class='c#'><span class='line'><span class="k">using</span> <span class="nn">FluentMigrator</span><span class="p">;</span>
</span><span class='line'><span class="k">using</span> <span class="nn">FluentMigrator.Runner</span><span class="p">;</span>
</span><span class='line'><span class="k">using</span> <span class="nn">FluentMigrator.Runner.Announcers</span><span class="p">;</span>
</span><span class='line'><span class="k">using</span> <span class="nn">FluentMigrator.Runner.Initialization</span><span class="p">;</span>
</span><span class='line'><span class="k">using</span> <span class="nn">FluentMigrator.Runner.Processors.SqlServer</span><span class="p">;</span>
</span><span class='line'><span class="k">using</span> <span class="nn">System</span><span class="p">;</span>
</span><span class='line'><span class="k">using</span> <span class="nn">System.Reflection</span><span class="p">;</span>
</span><span class='line'>
</span><span class='line'><span class="k">namespace</span> <span class="nn">MyProject.Data.Migrations</span>
</span><span class='line'><span class="p">{</span>
</span><span class='line'> <span class="k">public</span> <span class="k">enum</span> <span class="n">MigratorEnvironment</span>
</span><span class='line'> <span class="p">{</span>
</span><span class='line'> <span class="n">Development</span><span class="p">,</span>
</span><span class='line'> <span class="n">Test</span><span class="p">,</span>
</span><span class='line'> <span class="n">Production</span>
</span><span class='line'> <span class="p">}</span>
</span><span class='line'>
</span><span class='line'> <span class="k">public</span> <span class="k">static</span> <span class="k">class</span> <span class="nc">MyProjectMigrator</span>
</span><span class='line'> <span class="p">{</span>
</span><span class='line'> <span class="k">private</span> <span class="k">class</span> <span class="nc">MigrationOptions</span> <span class="p">:</span> <span class="n">IMigrationProcessorOptions</span>
</span><span class='line'> <span class="p">{</span>
</span><span class='line'> <span class="k">public</span> <span class="kt">bool</span> <span class="n">PreviewOnly</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="k">set</span><span class="p">;</span> <span class="p">}</span>
</span><span class='line'>
</span><span class='line'> <span class="k">public</span> <span class="kt">int</span> <span class="n">Timeout</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="k">set</span><span class="p">;</span> <span class="p">}</span>
</span><span class='line'>
</span><span class='line'> <span class="k">public</span> <span class="kt">string</span> <span class="n">ProviderSwitches</span>
</span><span class='line'> <span class="p">{</span>
</span><span class='line'> <span class="k">get</span> <span class="p">{</span> <span class="k">throw</span> <span class="k">new</span> <span class="n">NotImplementedException</span><span class="p">();</span> <span class="p">}</span>
</span><span class='line'> <span class="p">}</span>
</span><span class='line'> <span class="p">}</span>
</span><span class='line'>
</span><span class='line'> <span class="k">public</span> <span class="k">static</span> <span class="k">void</span> <span class="nf">Migrate</span><span class="p">(</span><span class="n">Action</span><span class="p"><</span><span class="n">IMigrationRunner</span><span class="p">></span> <span class="n">migrationRunnerAction</span><span class="p">,</span>
</span><span class='line'> <span class="kt">string</span> <span class="n">connectionString</span><span class="p">,</span>
</span><span class='line'> <span class="n">MigratorEnvironment</span> <span class="n">migratorEnvironment</span><span class="p">)</span>
</span><span class='line'> <span class="p">{</span>
</span><span class='line'> <span class="n">Assembly</span> <span class="n">assembly</span> <span class="p">=</span> <span class="n">Assembly</span><span class="p">.</span><span class="n">GetExecutingAssembly</span><span class="p">();</span>
</span><span class='line'>
</span><span class='line'> <span class="kt">var</span> <span class="n">textWriterAnnouncer</span> <span class="p">=</span> <span class="k">new</span> <span class="n">TextWriterAnnouncer</span><span class="p">(</span><span class="n">write</span> <span class="p">=></span> <span class="n">Console</span><span class="p">.</span><span class="n">WriteLine</span><span class="p">(</span><span class="n">write</span><span class="p">));</span>
</span><span class='line'> <span class="kt">var</span> <span class="n">runnerContext</span> <span class="p">=</span> <span class="k">new</span> <span class="n">RunnerContext</span><span class="p">(</span><span class="n">textWriterAnnouncer</span><span class="p">);</span>
</span><span class='line'> <span class="n">runnerContext</span><span class="p">.</span><span class="n">ApplicationContext</span> <span class="p">=</span> <span class="n">migratorEnvironment</span><span class="p">;</span>
</span><span class='line'>
</span><span class='line'> <span class="kt">var</span> <span class="n">migrationOptions</span> <span class="p">=</span> <span class="k">new</span> <span class="n">MigrationOptions</span> <span class="p">{</span> <span class="n">PreviewOnly</span> <span class="p">=</span> <span class="k">false</span><span class="p">,</span> <span class="n">Timeout</span> <span class="p">=</span> <span class="m">0</span> <span class="p">};</span>
</span><span class='line'> <span class="kt">var</span> <span class="n">processorFactory</span> <span class="p">=</span> <span class="k">new</span> <span class="n">SqlServer2012ProcessorFactory</span><span class="p">();</span>
</span><span class='line'> <span class="kt">var</span> <span class="n">processor</span> <span class="p">=</span> <span class="n">processorFactory</span><span class="p">.</span><span class="n">Create</span><span class="p">(</span><span class="n">connectionString</span><span class="p">,</span>
</span><span class='line'> <span class="n">textWriterAnnouncer</span><span class="p">,</span>
</span><span class='line'> <span class="n">migrationOptions</span><span class="p">);</span>
</span><span class='line'>
</span><span class='line'> <span class="kt">var</span> <span class="n">migrationRunner</span> <span class="p">=</span> <span class="k">new</span> <span class="n">MigrationRunner</span><span class="p">(</span><span class="n">assembly</span><span class="p">,</span> <span class="n">runnerContext</span><span class="p">,</span> <span class="n">processor</span><span class="p">);</span>
</span><span class='line'> <span class="n">migrationRunnerAction</span><span class="p">(</span><span class="n">migrationRunner</span><span class="p">);</span>
</span><span class='line'> <span class="p">}</span>
</span><span class='line'> <span class="p">}</span>
</span><span class='line'><span class="p">}</span>
</span></code></pre></td></tr></table></div></figure>
<h2>Criando as Migrations</h2>
<p>Recomendo a leitura da <a href="https://github.com/schambers/fluentmigrator/wiki/Migration" target="_blank">documentação oficial</a> sobre a criação de migrations que é bem direta e de fácil entendimento, mas basicamente para criamos uma migration é preciso criar uma nova classe que derive da classe abstrata <code>Migration</code> e implemente dois métodos, o <code>Up</code> e o <code>Down</code>. Além disso você devera adicionar o atributo Migration que aceita valores Int64, esse atributo será utilizado para identificar a migration, é baseado nesse atributo que o FluentMigrator vai saber se já rodou ou não a migration.</p>
<p>A classe abstrata <code>Migration</code> nos fornece diversos métodos para manipulação de banco de dados, o que nos permite criar tabelas, criar colunas, renomear colunas, inserir dados, executar um script SQL, dentre outras tarefas. Para conhecer mais e entender melhor esses métodos recomendo a leitura da <a href="https://github.com/schambers/fluentmigrator/wiki/Fluent-Interface" target="_blank">documentação oficial</a> sobre Fluent Interface.</p>
<p>Algo para se ter em mente na hora de criar uma migration é que não devemos agrupar muitas alterações no banco de dados em apenas uma migration, se você precisa criar duas tabelas novas por exemplo, faça isso em duas migrations separadas e não em apenas uma. Outra boa prática é em relação aos nomes das migration, adote um padrão claro para que todo o time entenda de maneira fácil o que determinada migration irá fazer apenas olhando o nome da mesma, se sua migration irá criar uma tabela Clients por exemplo, uma boa opção seria CreateClientsTable. Outra dica é utilizar o padrão YYYYMMDDHHMM no atributo identificador da migration, dessa maneira conseguimos saber rapidamente quando foi desenvolvida e diminuímos o risco de dois desenvolvedores criarem uma migration com o mesmo identificador.</p>
<p>Criei alguns exemplos de como uso e organizo migrations no projeto de exemplo, mas lembre-se que mais importante que usar esse ou aquele padrão, é utilizar algum e fazer com que o time todo o siga.</p>
<figure class='code'><figcaption><span>01 - RunBaselineScript.cs</span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
<span class='line-number'>15</span>
<span class='line-number'>16</span>
<span class='line-number'>17</span>
<span class='line-number'>18</span>
<span class='line-number'>19</span>
</pre></td><td class='code'><pre><code class='c#'><span class='line'><span class="k">using</span> <span class="nn">FluentMigrator</span><span class="p">;</span>
</span><span class='line'><span class="k">using</span> <span class="nn">System</span><span class="p">;</span>
</span><span class='line'><span class="k">using</span> <span class="nn">System.IO</span><span class="p">;</span>
</span><span class='line'>
</span><span class='line'><span class="k">namespace</span> <span class="nn">MyProject.Data.Migrations._1._0._0._0</span>
</span><span class='line'><span class="p">{</span>
</span><span class='line'><span class="na"> [Migration(01)]</span>
</span><span class='line'> <span class="k">public</span> <span class="k">class</span> <span class="nc">RunBaselineScript</span> <span class="p">:</span> <span class="n">Migration</span>
</span><span class='line'> <span class="p">{</span>
</span><span class='line'> <span class="k">public</span> <span class="k">override</span> <span class="k">void</span> <span class="nf">Up</span><span class="p">()</span>
</span><span class='line'> <span class="p">{</span>
</span><span class='line'> <span class="n">Execute</span><span class="p">.</span><span class="n">Script</span><span class="p">(</span><span class="n">Path</span><span class="p">.</span><span class="n">Combine</span><span class="p">(</span><span class="n">Environment</span><span class="p">.</span><span class="n">CurrentDirectory</span><span class="p">,</span> <span class="s">@"Scripts\02 - BaselineScript.sql"</span><span class="p">));</span>
</span><span class='line'> <span class="p">}</span>
</span><span class='line'>
</span><span class='line'> <span class="k">public</span> <span class="k">override</span> <span class="k">void</span> <span class="nf">Down</span><span class="p">()</span>
</span><span class='line'> <span class="p">{</span>
</span><span class='line'> <span class="p">}</span>
</span><span class='line'> <span class="p">}</span>
</span><span class='line'><span class="p">}</span>
</span></code></pre></td></tr></table></div></figure>
<figure class='code'><figcaption><span>201410192200 - CreateTestTable.cs</span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
<span class='line-number'>15</span>
<span class='line-number'>16</span>
<span class='line-number'>17</span>
<span class='line-number'>18</span>
<span class='line-number'>19</span>
</pre></td><td class='code'><pre><code class='c#'><span class='line'><span class="k">using</span> <span class="nn">FluentMigrator</span><span class="p">;</span>
</span><span class='line'>
</span><span class='line'><span class="k">namespace</span> <span class="nn">MyProject.Data.Migrations._1._0._1._0</span>
</span><span class='line'><span class="p">{</span>
</span><span class='line'><span class="na"> [Migration(201410192200)]</span>
</span><span class='line'> <span class="k">public</span> <span class="k">class</span> <span class="nc">CreateTestTable</span> <span class="p">:</span> <span class="n">Migration</span>
</span><span class='line'> <span class="p">{</span>
</span><span class='line'> <span class="k">public</span> <span class="k">override</span> <span class="k">void</span> <span class="nf">Up</span><span class="p">()</span>
</span><span class='line'> <span class="p">{</span>
</span><span class='line'> <span class="n">Create</span><span class="p">.</span><span class="n">Table</span><span class="p">(</span><span class="s">"Test"</span><span class="p">)</span>
</span><span class='line'> <span class="p">.</span><span class="n">WithColumn</span><span class="p">(</span><span class="s">"Id"</span><span class="p">).</span><span class="n">AsGuid</span><span class="p">().</span><span class="n">NotNullable</span><span class="p">().</span><span class="n">PrimaryKey</span><span class="p">();</span>
</span><span class='line'> <span class="p">}</span>
</span><span class='line'>
</span><span class='line'> <span class="k">public</span> <span class="k">override</span> <span class="k">void</span> <span class="nf">Down</span><span class="p">()</span>
</span><span class='line'> <span class="p">{</span>
</span><span class='line'> <span class="n">Delete</span><span class="p">.</span><span class="n">Table</span><span class="p">(</span><span class="s">"Test"</span><span class="p">);</span>
</span><span class='line'> <span class="p">}</span>
</span><span class='line'> <span class="p">}</span>
</span><span class='line'><span class="p">}</span>
</span></code></pre></td></tr></table></div></figure>
<figure class='code'><figcaption><span>201410192210 - AddColumnTestToTableTest.cs</span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
<span class='line-number'>15</span>
<span class='line-number'>16</span>
<span class='line-number'>17</span>
<span class='line-number'>18</span>
<span class='line-number'>19</span>
</pre></td><td class='code'><pre><code class='c#'><span class='line'><span class="k">using</span> <span class="nn">FluentMigrator</span><span class="p">;</span>
</span><span class='line'>
</span><span class='line'><span class="k">namespace</span> <span class="nn">MyProject.Data.Migrations._1._0._1._0</span>
</span><span class='line'><span class="p">{</span>
</span><span class='line'><span class="na"> [Migration(201410192210)]</span>
</span><span class='line'> <span class="k">public</span> <span class="k">class</span> <span class="nc">AddColumnTestToTableTest</span> <span class="p">:</span> <span class="n">Migration</span>
</span><span class='line'> <span class="p">{</span>
</span><span class='line'> <span class="k">public</span> <span class="k">override</span> <span class="k">void</span> <span class="nf">Up</span><span class="p">()</span>
</span><span class='line'> <span class="p">{</span>
</span><span class='line'> <span class="n">Alter</span><span class="p">.</span><span class="n">Table</span><span class="p">(</span><span class="s">"Test"</span><span class="p">)</span>
</span><span class='line'> <span class="p">.</span><span class="n">AddColumn</span><span class="p">(</span><span class="s">"Test"</span><span class="p">).</span><span class="n">AsString</span><span class="p">(</span><span class="m">255</span><span class="p">).</span><span class="n">NotNullable</span><span class="p">();</span>
</span><span class='line'> <span class="p">}</span>
</span><span class='line'>
</span><span class='line'> <span class="k">public</span> <span class="k">override</span> <span class="k">void</span> <span class="nf">Down</span><span class="p">()</span>
</span><span class='line'> <span class="p">{</span>
</span><span class='line'> <span class="n">Delete</span><span class="p">.</span><span class="n">Column</span><span class="p">(</span><span class="s">"Test"</span><span class="p">).</span><span class="n">FromTable</span><span class="p">(</span><span class="s">"Test"</span><span class="p">);</span>
</span><span class='line'> <span class="p">}</span>
</span><span class='line'> <span class="p">}</span>
</span><span class='line'><span class="p">}</span>
</span></code></pre></td></tr></table></div></figure>
<figure class='code'><figcaption><span>201410192215 - CreateTestTableSeedData.cs</span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
<span class='line-number'>15</span>
<span class='line-number'>16</span>
<span class='line-number'>17</span>
<span class='line-number'>18</span>
<span class='line-number'>19</span>
<span class='line-number'>20</span>
<span class='line-number'>21</span>
<span class='line-number'>22</span>
<span class='line-number'>23</span>
<span class='line-number'>24</span>
<span class='line-number'>25</span>
</pre></td><td class='code'><pre><code class='c#'><span class='line'><span class="k">using</span> <span class="nn">FluentMigrator</span><span class="p">;</span>
</span><span class='line'><span class="k">using</span> <span class="nn">System</span><span class="p">;</span>
</span><span class='line'>
</span><span class='line'><span class="k">namespace</span> <span class="nn">MyProject.Data.Migrations._1._0._1._0</span>
</span><span class='line'><span class="p">{</span>
</span><span class='line'><span class="na"> [Migration(201410192215)]</span>
</span><span class='line'> <span class="k">public</span> <span class="k">class</span> <span class="nc">CreateTestTableSeedData</span> <span class="p">:</span> <span class="n">Migration</span>
</span><span class='line'> <span class="p">{</span>
</span><span class='line'> <span class="k">public</span> <span class="k">override</span> <span class="k">void</span> <span class="nf">Up</span><span class="p">()</span>
</span><span class='line'> <span class="p">{</span>
</span><span class='line'> <span class="k">if</span> <span class="p">((</span><span class="n">MigratorEnvironment</span><span class="p">)</span><span class="k">this</span><span class="p">.</span><span class="n">ApplicationContext</span> <span class="p">==</span> <span class="n">MigratorEnvironment</span><span class="p">.</span><span class="n">Development</span><span class="p">)</span>
</span><span class='line'> <span class="p">{</span>
</span><span class='line'> <span class="n">Insert</span><span class="p">.</span><span class="n">IntoTable</span><span class="p">(</span><span class="s">"Test"</span><span class="p">).</span><span class="n">Row</span><span class="p">(</span><span class="k">new</span> <span class="p">{</span> <span class="n">Id</span> <span class="p">=</span> <span class="n">Guid</span><span class="p">.</span><span class="n">NewGuid</span><span class="p">(),</span> <span class="n">Test</span> <span class="p">=</span> <span class="s">"Test 01"</span> <span class="p">});</span>
</span><span class='line'> <span class="n">Insert</span><span class="p">.</span><span class="n">IntoTable</span><span class="p">(</span><span class="s">"Test"</span><span class="p">).</span><span class="n">Row</span><span class="p">(</span><span class="k">new</span> <span class="p">{</span> <span class="n">Id</span> <span class="p">=</span> <span class="n">Guid</span><span class="p">.</span><span class="n">NewGuid</span><span class="p">(),</span> <span class="n">Test</span> <span class="p">=</span> <span class="s">"Test 02"</span> <span class="p">});</span>
</span><span class='line'> <span class="n">Insert</span><span class="p">.</span><span class="n">IntoTable</span><span class="p">(</span><span class="s">"Test"</span><span class="p">).</span><span class="n">Row</span><span class="p">(</span><span class="k">new</span> <span class="p">{</span> <span class="n">Id</span> <span class="p">=</span> <span class="n">Guid</span><span class="p">.</span><span class="n">NewGuid</span><span class="p">(),</span> <span class="n">Test</span> <span class="p">=</span> <span class="s">"Test 03"</span> <span class="p">});</span>
</span><span class='line'> <span class="n">Insert</span><span class="p">.</span><span class="n">IntoTable</span><span class="p">(</span><span class="s">"Test"</span><span class="p">).</span><span class="n">Row</span><span class="p">(</span><span class="k">new</span> <span class="p">{</span> <span class="n">Id</span> <span class="p">=</span> <span class="n">Guid</span><span class="p">.</span><span class="n">NewGuid</span><span class="p">(),</span> <span class="n">Test</span> <span class="p">=</span> <span class="s">"Test 04"</span> <span class="p">});</span>
</span><span class='line'> <span class="n">Insert</span><span class="p">.</span><span class="n">IntoTable</span><span class="p">(</span><span class="s">"Test"</span><span class="p">).</span><span class="n">Row</span><span class="p">(</span><span class="k">new</span> <span class="p">{</span> <span class="n">Id</span> <span class="p">=</span> <span class="n">Guid</span><span class="p">.</span><span class="n">NewGuid</span><span class="p">(),</span> <span class="n">Test</span> <span class="p">=</span> <span class="s">"Test 05"</span> <span class="p">});</span>
</span><span class='line'> <span class="p">}</span>
</span><span class='line'> <span class="p">}</span>
</span><span class='line'>
</span><span class='line'> <span class="k">public</span> <span class="k">override</span> <span class="k">void</span> <span class="nf">Down</span><span class="p">()</span>
</span><span class='line'> <span class="p">{</span>
</span><span class='line'> <span class="p">}</span>
</span><span class='line'> <span class="p">}</span>
</span><span class='line'><span class="p">}</span>
</span></code></pre></td></tr></table></div></figure>
<h2>Executando as Migrations</h2>
<p>Como visto anteriormente eu criei um Migrator Runner próprio chamado MyProjectMigrator, ele pode ser utilizado para rodar as migrations nos seus projetos de teste, em uma Console Application (como é o caso do projeto de exemplo) ou em um aplicativo com uma interface gráfica amigável. Como é possível observar no projeto de exemplo a utilização do MyProjectMigrator é bastante simples e pode ser customizada, mas se preferir outras maneiras de rodar as migrations, dê uma conferida na d<a href="https://github.com/schambers/fluentmigrator/wiki/Migration-Runners" target="_blank">documentação oficial</a> sobre Migration Runners.</p>
<p>Após a execução das migrations, como pode ser verificado nas imagens abaixo, o FluentMigrator irá criar uma tabela <code>VersionInfo</code> no seu banco de dados onde salvará a identificação das migrations que foram executadas, com a data e hora da execução das mesmas bem como sua descrição, que nada mais é do que o nome das classes.</p>
<p><img src="http://www.marcelobalexandre.com/images/manutencao-de-schema-de-banco-de-dados-com-migrations-em-net/database.png"></p>
<p><img src="http://www.marcelobalexandre.com/images/manutencao-de-schema-de-banco-de-dados-com-migrations-em-net/version-info.png"></p>
<h1>Conclusão</h1>
<p>O que gosto nesta abordagem é a facilidade que qualquer desenvolvedor têm de realizar uma alteração no banco de dados, bem como compreender o que determinada migration, criada por outro desenvolvedor, irá realizar. A maneira que o FluentMigrator controla quais migrations foram executadas pelo número identificador, traz mais segurança na hora de atualizar o banco de dados de um cliente, e tudo isso permite que o processo de Integração Contínua funcione de maneira adequada. Ao invés de termos a necessidade de alguém executar algum software que gere um script de alteração de banco de dados, de maneira manual, a cada nova versão do sistema, basta fazer com que um Gerenciador ou Atualizar de Banco de Dados do projeto seja compilado com a versão correta do projeto que contêm as migrations.</p>
<p>Apesar de minha preferência pela utilização de migrations, é importante que você estude e adote a estratégia mais importante para o seu projeto. Se sua opção for utilizar migrations, não fique preso na maneira que eu utilizo, adapte para que funcione melhor para o seu projeto. Enfim, o que gostaria de passar neste post era isso, por favor deixe seu comentário com críticas, dúvidas ou sugestões.</p>
]]></content>
</entry>
<entry>
<title type="html"><![CDATA[Dicas Sobre Integração Contínua Com .NET E Jenkins]]></title>
<link href="http://www.marcelobalexandre.com/blog/2014/09/07/dicas-sobre-integracao-continua-com-net-e-jenkins/"/>
<updated>2014-09-07T16:10:00-03:00</updated>
<id>http://www.marcelobalexandre.com/blog/2014/09/07/dicas-sobre-integracao-continua-com-net-e-jenkins</id>
<content type="html"><![CDATA[<p>No momento em que escrevo este post estou trabalhando em uma aplicação desktop para Windows desenvolvida na plataforma .NET. Com a primeira versão que será entregue para os usuários finais quase pronta, nossa equipe sentiu necessidade de colocar em prática o processo de Integração Contínua. Para atingir tal objetivo precisaríamos configurar uma ferramenta que nos auxiliasse a automatizar esse processo, e para isso escolhemos um servidor de Integração Contínua chamado <a href="http://jenkins-ci.org/" target="_blank">Jenkins</a>.</p>
<p>Não tenho a intenção de me aprofundar muito nos processos relacionados a Integração Contínua neste post, a ideia é documentar algumas dicas que encontrei durante a configuração do Jenkins para o nosso cenário atual. Espero que possa ser útil para mais pessoas, boa leitura. ;)</p>
<!--more-->
<h1>WTF is Continuous Integration?</h1>
<p>Basicamente, Integração Contínua ou Continuous Integration (CI) é uma prática de desenvolvimento de software considerada por muitos um dos pilares das metodologias ágeis. Ela permite que a equipe encontre e elimine problemas rapidamente, agilizando os processos de build e delivery, melhorando as respostas à falhas e aumentando a qualidade do software.</p>
<p>De maneira simplificada, um processo de integração continua deve monitorar as mudanças de código no seu repositório de controle de versão e realizar os passos necessários para gerar um executável entregável para o cliente. O que normalmente consiste em compilar a aplicação em modo Release, rodar os testes e gerar o executável.</p>
<p>Apesar de no nosso caso termos implementado um processo de Integração Contínua automatizado em um estágio um pouco mais avançado do ciclo de vida do projeto, é muito recomendável adotar essa prática já no início do desenvolvimento, obtendo assim os benefícios da Integração Contínua o mais rápido possível.</p>
<h1>The Jenkins</h1>
<p>O Jenkins é um servidor de Integração Contínua open source, multiplataforma e que pode ser utilizado para automatizar os processos de build e delivery de muitas linguagens, como C#, Ruby, PHP, Java, dentre outras. Um dos pontos principais do Jenkins são os seus inúmeros plugins, que estendem suas funcionalidades e podem ser desenvolvidos por qualquer um. Além disso, seu processo de instalação e configuração é relativamente simples.</p>
<h1>Qual processo queríamos automatizar?</h1>
<p>Como citado anteriormente, estou trabalhando em uma aplicação desktop para Windows desenvolvida na plataforma .NET, o processo de integração que precisávamos automatizar consistia basicamente nos seguintes passos:</p>
<ol>
<li>Rebuild da aplicação em Release.</li>
<li>Execução do processo de Code Analysis.</li>
<li>Execução dos testes unitários.</li>
<li>Criação dos setups.</li>
</ol>
<h1>Preparação do ambiente</h1>
<p>A instalação do Jenkins no Windows é bem simples, basta baixar o instalador no <a href="http://jenkins-ci.org/" target="_blank">site oficial</a>, executar o mesmo e seguir o passo a passo. Ao final do processo o Jenkins estará instalado como um serviço e será executado automaticamente na inicialização do Windows. Para verificar se tudo ocorreu corretamente acesse o endereço <a href="http://localhost:8080/" target="_blank">localhost:8080</a> e veja se o Jenkins está rodando.</p>
<p>Uma dica importante para evitar dores de cabeça é forçar o serviço do Jenkins a ser executado com um usuário administrador do Windows ao invés de Local System que é o padrão. No meu caso específico o Inno Setup não funcionou corretamente como Local System, para evitar esse tipo de problema execute os seguintes passos:</p>
<ol>
<li>Abra o <strong>Services</strong> do Windows.</li>
<li>Abra as propriedades do serviço do <strong>Jenkins</strong>.</li>
<li>Clique na aba <strong>Log On</strong>.</li>
<li>Marque a opção <strong>This account</strong>.</li>
<li>Selecione um usuário administrador e digite a senha.</li>
<li>Clique em <strong>OK</strong> e reinicie o serviço.</li>
</ol>
<p><img src="http://www.marcelobalexandre.com/images/dicas-sobre-integracao-continua-com-net-e-jenkins/jenkins-service.png"></p>
<p>Além do Jenkins você precisará que todos os softwares necessários para seus processos estejam instalados, como por exemplo o MSBuild, o NUnit, o Inno Setup, etc. Como esses softwares são normalmente executados pelo Jenkins através do Command Prompt do Windows é interessante adicioná-los as variáveis de ambiente para que não seja necessário passar o caminho completo do executável, para isso siga os seguintes passos:</p>
<ol>
<li>Abra o <strong>System Properties</strong> do Windows.</li>
<li>Clique na aba <strong>Advanced</strong>.</li>
<li>Clique no botão <strong>Environment Variables</strong>.</li>
<li>Em <strong>System Variables</strong> selecione a variável <strong>Path</strong>.</li>
<li>Clique em <strong>Edit</strong> e ao final da linha adicione os caminhos dos diretórios dos executáveis separados por ponto e vírgula.</li>
</ol>
<p><img src="http://www.marcelobalexandre.com/images/dicas-sobre-integracao-continua-com-net-e-jenkins/environment-variables.png"></p>
<h1>Estendendo o Jenkins</h1>
<p>Antes de criarmos nosso primeiro job podemos instalar alguns plugins interessantes, para isso acesse o endereço <a href="http://localhost:8080/pluginManager/" target="_blank">localhost:8080/pluginManager</a> do Jenkins, esta página é bem simples e intuitiva, para instalar novos plugins vá para a aba <strong>Available</strong>, para removê-los vá para a aba <strong>Installed</strong> e para atualizá-los vá para a aba <strong>Updates</strong>.</p>
<p><img src="http://www.marcelobalexandre.com/images/dicas-sobre-integracao-continua-com-net-e-jenkins/jenkins-manage-plugins.png"></p>
<p>Logo abaixo segue uma lista de alguns dos plugins que achei interessante e que utilizamos para esse nosso projeto. Existem centenas de outros plugins, fique a vontade para procurar novos.</p>
<ul>
<li><strong>BitBucket Plugin</strong> - Permite acessar um repositório no BitBucket e configurar para um job) ser iniciado quando um Push for realizado no repositório.</li>
<li><strong>MSBuild</strong> - Permite realizar o build de projects e solutions do Visual Studio.</li>
<li><strong>NUnit</strong> - Permite que o Jenkins utilize os relatórios gerados pelo NUnit.</li>
<li><strong>Disk Usage Plugin</strong> - Exibe estatísticas sobre o uso do disco.</li>
<li><strong>Timestamper</strong> - Adiciona o horário antes de cada linha do console do Jenkins, bastante útil para medir o tempo de realização de cada tarefa.</li>
<li><strong>Google Cloud Messaging Notification Plugin</strong> - Envia notificações para smartphones Android.</li>
<li><strong>Safe Restart Plugin</strong> - Permite realizar o restart do Jenkins de maneira segura.</li>
</ul>
<h1>Segurança</h1>
<p>Uma dica que considero importante, principalmente se você vai permitir acesso externo ao seu servidor Jenkins, é desativar a funcionalidade de Sign up e controlar as permissões dos usuários, para isso siga os seguintes passos:</p>
<ol>
<li>Acesse o endereço <a href="http://localhost:8080/configureSecurity/" target="_blank">localhost:8080/configureSecurity</a>.</li>
<li>Marque a opção <strong>Enable security</strong>.</li>
<li>Em <strong>Security Realm</strong> selecione a opção <strong>Jenkins’ own user database</strong> e desmarque a opção <strong>Allow users to sign up</strong>.</li>
<li>Em <strong>Authorization</strong> selecione a opção <strong>Matrix-based security</strong>, adicione os usuários e marque as opções que deseja que o usuário tenha permissão.</li>
</ol>
<p><img src="http://www.marcelobalexandre.com/images/dicas-sobre-integracao-continua-com-net-e-jenkins/jenkins-security.png"></p>
<p>Como desativamos a permissão de Sign up você precisará criar as contas dos usuários, para isso acesse o endereço <a href="http://localhost:8080/securityRealm/" target="_blank">localhost:8080/securityRealm</a>. Um detalhe importante aqui é que o <strong>Username</strong> deve ser o mesmo que foi adicionado no passo anterior para que as permissões funcionem corretamente.</p>
<h1>Configurações</h1>
<p>As configurações do Jenkins podem ser acessadas através do endereço <a href="http://localhost:8080/configure/" target="_blank">localhost:8080/configure</a>, dentre outras coisas, aqui você pode configurar o servidor SMTP de envio de e-mail, o local onde seu Git está instalado (que normalmente é reconhecido automaticamente), as configurações para o Google Cloud Messaging Notification, etc.</p>
<h1>Criando seu primeiro job</h1>
<p>Para criar um novo job no Jenkins, acesse o endereço <a href="http://localhost:8080/newJob" target="_blank">localhost:8080/newJob</a>, digite um nome para o job, marque a opção <strong>Freestyle project</strong> e clique em <strong>OK</strong>. Você será levado para a página de configuração do seu job recém criado, está página é muito importante pois é aqui que devemos configurar tudo que o nosso job irá realizar.</p>
<h2>Custom workspace</h2>
<p>A primeira dica aqui é alterar o workspace onde o job será realizado, por padrão ele fica dentro do diretório onde o Jenkins foi instalado, que normalmente é em <code>C:\Program Files (x86)\Jenkins</code>, o que pode desencadear alguns erros relacionados a permissão de escrita se algum dos softwares utilizados pelo seu job tentar criar algum arquivo em disco. Para alterar a workspace clique no botão <strong>Advanced</strong> em <strong>Advanced Project Options</strong>, marque a opção <strong>Use custom workspace</strong> e informe o caminho do diretório, por exemplo: <code>C:\CI\my-job\workspace</code>.</p>
<h2>Git e BitBucket</h2>
<p>Caso tenha instalado o plugin do BitBucket (e consequentemente o do Git), em <strong>Source Code Managment</strong> selecione a opção <strong>Git</strong> e configure seu repositório, sua branch e suas credenciais de acesso. Um dica importante aqui é alterar o timeout de clone e fetch do Git, o padrão é de apenas 10 minutos, o que pode não ser suficiente dependendo do tamanho do seu repositório e da velocidade de sua conexão. Até descobrir isso perdi alguns minutos, para você não passar por isso também, clique no botão <strong>Add</strong>, escolha a opção <strong>Advanced Clone Behaviors</strong> e informe um tempo que ache razoável para o timeout.</p>
<p>Com o plugin do BitBucket você pode configurar para que seu job ser iniciado assim que um push no repositório seja feito, para isso marque a opção <strong>Build when change is pushed to BitBucket</strong>. Para essa opção funcionar você precisará adicionar um Hook de POST apontando para <a href="http://seu-ip-publico:8080/bitbucket-hook/" target="_blank">seu-ip-publico:8080/bitbucket-hook</a> nas configurações do seu repositório no BitBucket.</p>
<h2>MSBuild</h2>
<p>Para configurar o build do seu projeto no MSBuild clique em <strong>Add build step</strong> e na opção <strong>Build a Visual Studio project or solution using MSBuild</strong>. Em <strong>MSBuild Build File</strong> informe o caminho da solution no workspace do job, por exemplo: <code>C:\CI\my-job\workspace\MyProject.sln</code>. Em <strong>Command Line Arguments</strong> você deverá informar os parâmetros do seu build, por exemplo: <code>/t:Rebuild /p:Configuration="Release" /p:Platform=x86 /p:DevEnvDir="C:\Program Files (x86)\Microsoft Visual Studio 12.0\Common7\IDE"</code>. O parâmetro <code>DevEnvDir</code> é importante, ele é utilizado para algumas coisas durante o processo de build, como por exemplo na execução do Code Analisys. Clicando em <strong>Advanced</strong> você também pode marcar a opção <strong>If warning set the build to Unstable</strong>.</p>
<h2>NUnit</h2>
<p>Os testes do NUnit serão executados através do Console, para configurá-lo clique em <strong>Add build step</strong> e na opção <strong>Execute Windows batch command</strong>, no campo <strong>Command</strong> você deverá informar o nome do executável do NUnit (ou o caminho completo caso não o tenha adicionado nas variáveis de ambiente do Windows), o caminho do teste no workspace e o nome do arquivo XML onde será salvo o relatório com os resultados dos testes. Por exemplo: <code>"nunit-console-x86.exe" "MyTest\bin\x86\Release\MyTest.dll" /xml=MyTest.dll-nunit-result.xml</code>.</p>
<p>Para que o Jenkins exiba os resultados dos testes clique em <strong>Add post-build action</strong> e na opção <strong>Publish NUnit test result report</strong> e em <strong>Test report XMLs</strong> e informe <code>*nunit-result.xml</code>.</p>
<h2>Inno Setup</h2>
<p>Para gerar os executáveis utilizando o Inno Setup clique novamente em <strong>Add build step</strong> e na opção <strong>Execute Windows batch command</strong>, no campo <strong>Command</strong> informe o nome do executável do Inno Setup (ou o caminho completo caso não o tenha adicionado nas variáveis de ambiente do Windows) e o caminho do seu script no workspace. Por exemplo: <code>"Compil32.exe" /cc "setup.iss"</code>.</p>
<h1>Finalizando</h1>
<p>Como comentei no início do post, não pretendia me aprofundar nos conceitos relacionados a Integração Contínua e sim compartilhar algumas dicas que acredito serem úteis. A intenção também não era ser nenhuma receita de bolo, adapte o que for necessário para a realidade do seu projeto, o Jenkins é uma ferramenta muito poderosa, explore seus recursos.</p>
<p>Espero que tenha gostado do post, por favor deixe críticas, dúvidas ou sugestões nos comentários.</p>
]]></content>
</entry>
<entry>
<title type="html"><![CDATA[Como Um Tomate Pode Melhorar Sua Produtividade?]]></title>
<link href="http://www.marcelobalexandre.com/blog/2014/02/16/como-um-tomate-pode-melhorar-sua-produtividade/"/>
<updated>2014-02-16T23:45:00-03:00</updated>
<id>http://www.marcelobalexandre.com/blog/2014/02/16/como-um-tomate-pode-melhorar-sua-produtividade</id>
<content type="html"><![CDATA[<p>Como programador algumas das minhas preocupações estão relacionadas a produtividade e a eficiência. Em certos momentos eu me pergunto: como posso fazer mais em menos tempo e com a melhor qualidade possível? Em busca de uma resposta para essa pergunta me deparei com uma técnica que venho tentando aplicar no meu dia a dia, e gostaria de compartilhar minhas opiniões sobre ela com vocês.</p>
<!--more-->
<h1>O tomate “mágico”</h1>
<p>Na década de 80 um estudante italiano chamado Francesco Cirillo estava tendo alguns problemas no tempo em que passava com os livros em sua universidade. Mas o que talvez nem mesmo ele imaginasse era que um utensilio doméstico poderia mudar isso. Olhando para um timer de cozinha em formato de tomate ele teve uma ideia e resolveu colocá-la a prova durante seus estudos.</p>
<p>Essa ideia acabou se tornando uma técnica de gerenciamento de tempo bastante conhecida hoje como <a href="http://pomodorotechnique.com/" target="_blank">Pomodoro Technique</a> ou apenas Pomodoro, que consiste em alguns hábitos simples que prometem melhorar sua produtividade.</p>
<h1>Mantenha uma lista de tarefas</h1>
<p>Um dos hábitos incentivados pelo Pomodoro é o de manter uma lista de tarefas organizada por prioridade. O “truque” da lista de tarefas é que ela libera “processamento” do seu cérebro para melhor realizar as tarefas, ao invés de ficar tentando memorizar tudo que você precisa fazer.</p>
<p>A técnica recomenda que você use as ferramentas mais simples possíveis para manter sua lista, ou seja, papel e caneta. Mas eu particularmente gosto de utilizar um software chamado <a href="https://www.wunderlist.com/en/" target="_blank">Wunderlist</a>. Fique a vontade para utilizar a ferramenta que funcione melhor para você.</p>
<h1>Trabalhando duro mas sem sobrecarga</h1>
<p>Outro hábito que a técnica tenta melhorar está relacionado a não nos sobrecarregarmos. Nosso cérebro normalmente perde eficiência ao realizar uma mesma tarefa por longos períodos de tempo. Quem nunca teve um aha moment quando fez uma pausa para ir ao banheiro após um longo período tentando resolver um problema? Seu cérebro só precisava de uma pausa para achar a melhor solução. Para evitar essa sobrecarga o Pomodoro incentiva o gerenciamento do tempo de maneira que você alterne entre trabalhar duro em uma tarefa e relaxar o cérebro antes de exigi-lo novamente.</p>
<p>Você deve utilizar alguma ferramenta para marcar o tempo, novamente a técnica recomenda usar algo simples como um timer de cozinha em formato de tomate por exemplo (ok, não precisa ser em formato de tomate). Mas você pode utilizar algum software para isso, eu tenho utilizado o <a href="http://www.moosti.com/" target="_blank">Moosti</a> em minhas sessões.</p>
<p>Depois de escolhida a ferramenta, pegue uma tarefa da sua lista, marque 25 minutos no seu timer e trabalhe apenas nela (sem interrupções) durante esse tempo, quando chegar ao fim do Pomodoro marque a tarefa como concluída caso a tenha terminado, não se preocupe caso não tenha terminado em apenas um Pomodoro, você pode continuar a tarefa no próximo, mas tente dividir tarefas grandes em tarefas menores na próxima vez que for organizar sua lista.</p>
<p>Depois de trabalhar duro é hora de descansar seu cérebro, marque 5 minutos no timer e relaxe, você está livre para fazer qualquer coisa não relacionada a sua tarefa nesse tempo. Ao completar uma sessão de 4 Pomodoros de 25 minutos você pode tirar uma folga maior de 15 minutos antes de começar uma nova sessão.</p>
<h1>Só produtividade é pouco, eu quero mais</h1>
<p>Se você não ficou satisfeito apenas com a promessa de melhor produtividade e eficiência que o Pomodoro pode te beneficiar, saiba que como bônus você ainda pode ser tornar mais saudável.</p>
<p>Como? Basta que ao invés de ficar sentando acessando seu Facebook nos intervalos dos seus Pomodoros, você levante um pouco, vá até a cozinha pegar um café, faça algum alongamento, ficar sentando é uma dar piores posições para o ser humano. Acredite, não é da nossa natureza passar o dia sentado em frente a um computador.</p>
<p>Outro beneficio que o Pomodoro pode te trazer é o da satisfação e do bem estar consigo mesmo. A cada tarefa que você consegue finalizar o cérebro libera endorfina, produzindo uma sensação de calma e alegria em nosso corpo.</p>
<h1>That’s it</h1>
<p>A técnica possui algumas outras “regras”, se você se interessou pode encontrar mais informações no site e no livro oficial do <a href="http://pomodorotechnique.com/" target="_blank">Pomodoro Technique</a>. Os pontos que abordei são os mais importantes para mim e acredito que você não precise seguir tudo que está no livro oficial ao pé da letra, adapte a técnica para um jeito que vá funcionar para você, se você acha que consegue se manter focado por mais que 25 minutos, aumente o tempo dos seus Pomodoros, não fique preso a regras em um livro.</p>
<p>Experimente, talvez essa técnica não sirva para você, mas o ato de experimentar algo novo pode ser o suficiente para descobrir algo sobre você que te ajude melhorar.</p>
<p>Espero que este post possa ser útil de alguma maneira para vocês, fiquem a vontade para comentar sobre o post e sobre suas experiências com a técnica.</p>
]]></content>
</entry>
<entry>
<title type="html"><![CDATA[But, Why? What Do I Have to Say?]]></title>
<link href="http://www.marcelobalexandre.com/blog/2014/02/01/but-why-what-do-i-have-to-say/"/>
<updated>2014-02-01T15:00:00-02:00</updated>
<id>http://www.marcelobalexandre.com/blog/2014/02/01/but-why-what-do-i-have-to-say</id>
<content type="html"><![CDATA[<p>Escrever um blog é algo que penso em fazer há algum tempo, mas sempre me preocupei em não ter algo para escrever ou não ter tempo para mantê-lo, e a ideia acabou sempre ficando em segundo plano.</p>
<p>Mas essa ideia voltou a tomar forma ao ler o post <a href="http://chadfowler.com/blog/2014/01/21/on-having-something-to-say/" target="_blank">On Having Something to Say</a> escrito por <a href="https://twitter.com/chadfowler" target="_blank">Chad Fowler</a> em seu blog. Nele, Chad Fowler comenta sobre seus receios ao ser convidado para falar/escrever sobre suas experiências como programador (como na primeira vez em que foi convidado para palestrar em um evento ou quando foi convidado a escrever um livro sobre Ruby On Rails). Ocasiões em que ele se perguntava, “But, why? What do I have to say? I’m still learning, after all”.</p>
<!--more-->
<p>Mesmo com suas dúvidas ele não deixou de aproveitar essas oportunidades para aprender e aperfeiçoar-se. E foi justamente este ponto que me motivou a colocar a ideia do blog em prática e aproveitar essa “oportunidade” para aprender e me aperfeiçoar.</p>
<p>Acredito que o compartilhamento de experiências (mesmo as experiências “erradas”) é uma ferramenta incrível para aprendermos coisas novas e/ou fixarmos o que já aprendemos. E como bônus podemos ajudar outras pessoas que estejam dispostas a aprender com nossas experiências.</p>
<p>Apesar de gostar de ler (principalmente sobre tecnologia e outros assuntos nerds) sempre tive dificuldades para escrever, e essa é uma das skills que espero melhorar através desse blog. Pois como tudo na vida, é a prática que nos leva à excelência.</p>
<p>Ainda não tenho muitas experiências profissionais como programador, mas espero poder compartilhar o que já sei e o que irei aprender através desse blog. Também não sei exatamente quais assuntos irei abordar ou com que frequência conseguirei atualiza-lo, mas gostaria que vocês aproveitassem o conteúdo que irei escrever e me dessem um feedback com suas opiniões.</p>
<p>Obrigado a vocês que leram até aqui, espero que voltem mais vezes! :)</p>
]]></content>
</entry>
</feed>