tag:blogger.com,1999:blog-31021225360152593172024-03-13T04:58:13.472-07:00People and CodeAnonymoushttp://www.blogger.com/profile/05338804644878097635noreply@blogger.comBlogger4125tag:blogger.com,1999:blog-3102122536015259317.post-12541397022909001362016-12-04T21:14:00.000-08:002017-10-24T17:38:28.885-07:00Getting 'Domain' back in DDD<div dir="ltr" style="text-align: left;" trbidi="on">
<div style="font-family: "Helvetica Neue", Arial, sans; font-size: 16px; text-align: left;">
I was first introduced to Domain Engineering through Jim Coplien's book on 'Multi paradigm design in C++'. It was around early 2000s, when Object Oriented Programming was considered synonym for professional and good programming. I was C++ developer then, and a fan of C++ STL. There was nothing OO about STL, a library I liked was at the time. Around the same time Aspect Oriented Programming was becoming popular with frameworks like AspectJ and later Spring support for Aspect oriented programming. There was nothing Object Oriented about this as well.</div>
<div style="font-family: "Helvetica Neue", Arial, sans; font-size: 16px;">
So, I thought, there must be some fundamental design thinking, more fundamental than Object Orientation which needed to be used for design.<br />
I found Jim Coplien's book on Multiparadigm Design, and was fascinated by that. The concepts of Commonality and Variability, and mapping them to solution domain based on the the programming language or tool we use was perfect. It allowed me to broaden my design thinking.</div>
<div style="font-family: "Helvetica Neue", Arial, sans; font-size: 16px;">
<br />
<span style="color: #99cc00;"><span style="font-size: 24px;">Domain Engineering</span></span><br />
The concept of domain engineering is thinking in terms of domains, instead of applications. Wikipedia has a nice description of this <a href="https://en.wikipedia.org/wiki/Domain_engineering">https://en.wikipedia.org/wiki/Domain_engineering</a>. I am using following diagram from Wikipedia for quick reference.<br />
<img src="https://upload.wikimedia.org/wikipedia/commons/thumb/f/f2/Domain_Engineering_vs_Application_Engineering.svg/330px-Domain_Engineering_vs_Application_Engineering.svg.png" style="height: auto;" /><br />
The idea is to think and model about generic domains/sub domains instead of thinking in terms of specific application requirements.<br />
So, if we are working on building web applications, techniques for implementing representations can be a domain in itself. Implementations can vary to use different libraries like freemarker, velocity or stringtemplate. Designing for allowing various different templating mechanisms gives lot more flexibility. </div>
<div style="font-family: "Helvetica Neue", Arial, sans; font-size: 16px;">
If we are communicating across services. Communication methods can be domain in itself. Keeping design flexible to use different communication methods helps.</div>
<div style="font-family: "Helvetica Neue", Arial, sans; font-size: 16px;">
At a business domain level, if we are building a core banking system, finding commonalities/variabilities across concepts like Account help leveraging the same implementation to use across multiple banks in multiple countries. Getting these domain concepts implemented right with correctly identified commonalities and variations help reusing the components across multiple implementations.</div>
<div style="font-family: "Helvetica Neue", Arial, sans; font-size: 16px;">
<span style="color: #99cc00; font-size: 18px;"><br /></span></div>
<div style="font-family: "Helvetica Neue", Arial, sans; font-size: 16px;">
<span style="color: #99cc00; font-size: 18px;">DDD, the problems.</span></div>
<div style="font-family: "Helvetica Neue", Arial, sans; font-size: 16px;">
<br /></div>
<div style="font-family: "Helvetica Neue", Arial, sans; font-size: 16px;">
Domain Driven Design is the term popularized by book by Eric Evans with the same title, 'Domain Driven Design'. The first few chapters of the book are very appealing. The concept of 'Ubiquitous Language' is great. Reflecting domain model in code using the ubiquitous language of the domain was a good advice I follow in my code. It maps well to my understanding of domain engineering as well.</div>
<div style="font-family: "Helvetica Neue", Arial, sans; font-size: 16px;">
<br /></div>
<div style="font-family: "Helvetica Neue", Arial, sans; font-size: 16px;">
There are some issues with technical implementation patterns though. Entities, Value Objects, Modules, Aggregates are all good guidance. But a lot of these findings come iteratively. Its good to know these, particularly in the context of Ubiquitous Language and keeping Domain concepts separate from User interface or persistence mechanisms. But there are more things in domain, than just Entities, Value Objects, Repositories and Services. But the problem is not really this. The conceptual problems start when DDD gets discussed in the context of MicroServices, which most people today talk about.<br />
<br />
<span style="color: #99cc00;"><span style="font-size: 18px;">Microservices and DDD.</span></span><br />
<span style="font-size: 18px;"><span style="color: #99cc00;"><br /></span></span>In last few years, since the dawn of Microservices Architecture,there is a surge in discussions about Domain Driven Design.<br />
The discussion resolves primarily about Bounded Contexts, Aggregates and Eventual Consistency.<br />
Most DDD discussions mapping it to Microservices world keep on using DDD technical design patterns like Aggregates, Aggregate Roots, Entities, Value Objects and so on.<br />
Splitting application into multiple services is the decision is not only dependent on domain/subdomain split. Following can be major drivers for system partitioning.</div>
<div style="font-family: "Helvetica Neue", Arial, sans; font-size: 16px;">
<br /></div>
<span style="font-family: "helvetica neue" , "arial" , "sans";"> 1. Autonomy of teams working on different features</span><br />
<span style="font-family: "helvetica neue" , "arial" , "sans";"> 2. Different rate of change of parts of the system.</span><br />
<span style="font-family: "helvetica neue" , "arial" , "sans";"> 3. Non functional aspects, particularly scalability</span><br />
<span style="font-family: "helvetica neue" , "arial" , "sans";"><br /></span>
<span style="font-family: "helvetica neue" , "arial" , "sans";">That domains and subdomains provide a good guidance for splitting is just one aspect. e.g. Its generally better to not split domain across teams. If you are developing for travel domain, shopping and booking can be sub domains. Its OK to split teams and so software components for these two sub domains. Splitting teams working on single subdomain across architectural units might not be a good idea. But then if the architectural units can evolve independently like Android Mobile UI, Web UI, IOS UI, and core services, each can be a separate team working on independent code base.</span><br />
<span style="font-family: "helvetica neue" , "arial" , "sans";"><br /></span>
<span style="font-family: "helvetica neue" , "arial" , "sans";">So based on my observations and experience , the difficulties people find in DDD is mostly because of these implementation patterns which do not necessarily map to 'Domain' concepts.</span><br />
<span style="font-family: "helvetica neue" , "arial" , "sans";">In fact I see a danger where developers on the team all talking in terms of these technical implementation patterns like Bounded Context, Aggregate, Entities, Value Objects etc.. which is neither domain specific nor ubiquitous and might confuse domain experts.</span><br />
<br />
<span style="font-family: "helvetica neue" , "arial" , "sans";"> </span><br />
<br />
<br />
<br />
<div style="font-family: gotham, helvetica, arial, sans-serif; font-size: 14px;">
</div>
</div>
Anonymoushttp://www.blogger.com/profile/05338804644878097635noreply@blogger.com1tag:blogger.com,1999:blog-3102122536015259317.post-13144731731666644172016-02-11T02:36:00.001-08:002016-02-11T03:08:09.152-08:00Using DbDeploy in large globally distributed project<div dir="ltr" style="text-align: left;" trbidi="on">
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Recently we successfully implemented DBDeploy for managing database migrations in a large globally distributed project. It was a huge program with more than 200 developers working in separate teams, globally distributed in seven locations.</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">The database management was done manually. For every release developers used to prepare release notes, listing all the sql scripts which should be executed for that release.</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">It was chaotic to manage correct list of sqls to be executed. Worst yet, given an environment and db schema, no one ever knew which sql scripts are run on that schema to take it to current state. This process was definitely not scalable and was one of the biggest bottleneck in making successful releases.</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span class="Apple-tab-span" style="white-space: pre;"> </span></span><span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">To fix this situation, we decided to introduce DBDeploy for database change management. DBDeploy is a well known database change management tool, which is built around various ideas discussed in the book ‘</span><a href="http://www.amazon.com/Refactoring-Databases-Evolutionary-paperback-Addison-Wesley/dp/0321774515" style="text-decoration: none;"><span style="background-color: transparent; color: #1155cc; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: underline; vertical-align: baseline; white-space: pre-wrap;">Refactoring Databases</span></a><span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">’. Several tools like flyway and liquibase are available now, but we chose DBDeploy because it was easier to introduce (doesn’t need you to write XML like liquibase) and also had a feature to just output consolidated sql file from migrations, instead of executing all the migrations directly against database. This was crucial because DBAs were very keen to review all the changes going into database for every release.</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">DBDeploy kind of tools is a common practice now, and many people know about standard patterns and practices to use these tools, But when you have several teams working on a same codebase and distributed globally, there are some unique set of challenges you face. Based on our learnings in last few months, following are some of the things which are crucial to successfully implement DBDeploy in large distributed teams, making changes to same database.</span></div>
<b id="docs-internal-guid-55610a5d-cfe3-7cea-b383-1960d058a3a8" style="font-weight: normal;"><br /></b>
<br />
<ol style="margin-bottom: 0pt; margin-top: 0pt;">
<li dir="ltr" style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 700; list-style-type: decimal; text-decoration: none; vertical-align: baseline;"><div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 700; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Use Timestamp as a change number</span></div>
</li>
</ol>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-left: 36pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">DbDeploy expects each migration to be named with unique change number. Generally a simple integer is used. But when you have globally distributed teams, it’s impossible to use simple integer. When you have several developers distributed across locations, its very hard to know what next integer to use for your script. If the last script in version control system is say 001_create_customer_table.sql, and you add your script as 002_create_address_table.sql, there is high chance that someone has already checked in a script with id 002. Using Timestamp in the format yyyyMMddHHmmss_<scriptname>.sql solves that problem. There is less likelihood for the timestamp with millisecond granularity to collide.</span></div>
<b style="font-weight: normal;"><br /></b>
<br />
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> 2. </span><span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 700; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Write a build task to generate migration scripts with correct timestamp.</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-left: 36pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Even if you expect everyone to know and follow rules to create correctly named migrations, people make mistakes. Unless there is a quick and easy way to generate timestamps for migrations, most developers will copy paste one of the existing scripts and change one digit in the timestamp value. So make sure you write a gradle or ant task to generate database migration files with correct timestamp format.</span></div>
<b style="font-weight: normal;"><br /></b>
<br />
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-left: 36pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">The gradle task we wrote is as following</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-left: 36pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #383838; font-size: 14px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: "courier new" , "courier" , monospace;">def askTicket() {</span></span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-left: 72pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #383838; font-size: 14px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: "courier new" , "courier" , monospace;">def console = System.console()</span></span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-left: 72pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #383838; font-size: 14px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: "courier new" , "courier" , monospace;">def ticket</span></span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-left: 72pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #383838; font-size: 14px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: "courier new" , "courier" , monospace;">for (;;){</span></span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-left: 72pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #383838; font-size: 14px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: "courier new" , "courier" , monospace;">if (console) {</span></span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-left: 72pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #383838; font-size: 14px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: "courier new" , "courier" , monospace;">ticket = console.readLine('\n> Please enter your story or jira reference (e.g: DT-002): ')</span></span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-left: 72pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #383838; font-size: 14px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: "courier new" , "courier" , monospace;">} else {</span></span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-left: 72pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #383838; font-size: 14px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: "courier new" , "courier" , monospace;">logger.error "Cannot get console."</span></span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-left: 72pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #383838; font-size: 14px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: "courier new" , "courier" , monospace;">}</span></span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-left: 72pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #383838; font-size: 14px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: "courier new" , "courier" , monospace;">if (ticket ==~ /([A-Za-z])+\-[0-9]+/){</span></span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-left: 72pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #383838; font-size: 14px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: "courier new" , "courier" , monospace;">break</span></span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-left: 72pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #383838; font-size: 14px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: "courier new" , "courier" , monospace;">}</span></span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-left: 72pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #383838; font-size: 14px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: "courier new" , "courier" , monospace;">}</span></span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-left: 72pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #383838; font-size: 14px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: "courier new" , "courier" , monospace;">return ticket</span></span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-left: 36pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #383838; font-size: 14px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: "courier new" , "courier" , monospace;">}</span></span></div>
<b style="font-weight: normal;"><span style="font-family: "courier new" , "courier" , monospace;"><br /></span></b>
<br />
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-left: 36pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #383838; font-size: 14px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: "courier new" , "courier" , monospace;">def timestampExists(timestamp, location) {</span></span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-left: 36pt; margin-top: 0pt; text-indent: 36pt;">
<span style="background-color: transparent; color: #383838; font-size: 14px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: "courier new" , "courier" , monospace;">return false</span></span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-left: 36pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #383838; font-size: 14px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: "courier new" , "courier" , monospace;">}</span></span></div>
<b style="font-weight: normal;"><span style="font-family: "courier new" , "courier" , monospace;"><br /></span></b>
<br />
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-left: 36pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #383838; font-size: 14px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: "courier new" , "courier" , monospace;">task newMigration {</span></span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-left: 36pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #383838; font-size: 14px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: "courier new" , "courier" , monospace;"> doLast {</span></span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-left: 72pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #383838; font-size: 14px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: "courier new" , "courier" , monospace;">def sql_path = "../../db/migrations"</span></span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-left: 72pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #383838; font-size: 14px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: "courier new" , "courier" , monospace;">def ticket = askTicket()</span></span></div>
<b style="font-weight: normal;"><span style="font-family: "courier new" , "courier" , monospace;"><br /></span></b>
<br />
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-left: 72pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #383838; font-size: 14px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: "courier new" , "courier" , monospace;">def timestamp = new Date().format('yyyyMMddHHmmss', TimeZone.getTimeZone('GMT'))</span></span></div>
<b style="font-weight: normal;"><span style="font-family: "courier new" , "courier" , monospace;"><br /></span></b>
<br />
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-left: 72pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #383838; font-size: 14px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: "courier new" , "courier" , monospace;">def newMigrationFile = "${sql_path}/${timestamp}-${ticket}.sql"</span></span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-left: 72pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #383838; font-size: 14px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: "courier new" , "courier" , monospace;">println ">> ${newMigrationFile}"</span></span></div>
<b style="font-weight: normal;"><span style="font-family: "courier new" , "courier" , monospace;"><br /></span></b>
<br />
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-left: 72pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #383838; font-size: 14px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: "courier new" , "courier" , monospace;">File configFile = file(new File("${newMigrationFile}"))</span></span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-left: 72pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #383838; font-size: 14px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: "courier new" , "courier" , monospace;">configFile.write("-- migration for '${ticket}' at '${timestamp}'")</span></span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt; text-indent: 36pt;">
<span style="background-color: transparent; color: #383838; font-size: 14px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: "courier new" , "courier" , monospace;"> }</span></span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-left: 36pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #383838; font-size: 14px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: "courier new" , "courier" , monospace;">}</span></span></div>
<b style="font-weight: normal;"><br /></b>
<br />
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> 3. </span><span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 700; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Have a CI build just for running DBDeploy migrations.</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-left: 36pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">It is very useful to have CI build just for running db migrations against a separate CI database. Having a separate build helps because, typically db migrations run very quickly and do not depend on any other build pipeline.</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-left: 36pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">On large monolithic projects, you typically tend to have long running build, which make it harder to get quick feedback (within seconds) of committing wrong migration.</span></div>
<b style="font-weight: normal;"><br /></b>
<br />
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> 4. </span><span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 700; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Add Validations for migrations.</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-left: 36pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Often, it's not enough to have conventions and expect people to follow it. It helps when we have build that breaks when conventions are not followed. Simplest one to violate is the naming of scripts. There is no guarantee that every developer will use the build script you have to generate correctly named scripts. There will be scripts which have wrong timestamp value.</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-left: 36pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">With timestamps, it's important to have in the form yyyyMMddHhmmss. One more or less digit and the order of execution will change. </span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-left: 36pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">There are other useful validations like DDL and DMLs should be in a separate file. There should generally be no ‘drop table’ statement. </span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-left: 36pt; margin-top: 0pt; text-indent: 36pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">We modified DBDeploy to allow adding these kind of validations before executing migrations. It was extremely helpful, to have these validations break the CI build.</span></div>
<b style="font-weight: normal;"><br /></b>
<br />
<h2 dir="ltr" style="line-height: 1.38; margin-bottom: 6pt; margin-top: 18pt; text-indent: 36pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 21.333333333333332px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Intercepting Filter in DBDeploy</span><span style="background-color: transparent; color: black; font-family: "arial"; font-size: 21.333333333333332px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span class="Apple-tab-span" style="white-space: pre;"> </span></span></h2>
<b style="font-weight: normal;"><br /></b>
<br />
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-left: 36pt; margin-top: 0pt; text-indent: 36pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">In DBDeploy we added a generic intercepting filter which executes before applying all the new migrations. This allowed us to plugin required functionality in DBDeploy. Executing validations or generating report from all the new migrations was easy to add then. Here is how you can specify intercepting filter in DBDeploy now.</span></div>
<b style="font-weight: normal;"><span style="font-family: "courier new" , "courier" , monospace;"><br /></span></b>
<br />
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-left: 72pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #383838; font-size: 14px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: "courier new" , "courier" , monospace;">def dbDeploy = new com.dbdeploy.DbDeploy(driver: "${driver}",</span></span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-left: 72pt; margin-top: 0pt; text-indent: 36pt;">
<span style="background-color: transparent; color: #383838; font-size: 14px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: "courier new" , "courier" , monospace;">url: "${jdbcUrl}",</span></span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-left: 72pt; margin-top: 0pt; text-indent: 36pt;">
<span style="background-color: transparent; color: #383838; font-size: 14px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: "courier new" , "courier" , monospace;">userid: "${jdbcUsername}",</span></span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-left: 72pt; margin-top: 0pt; text-indent: 36pt;">
<span style="background-color: transparent; color: #383838; font-size: 14px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: "courier new" , "courier" , monospace;">password: "${jdbcPassword}",</span></span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-left: 72pt; margin-top: 0pt; text-indent: 36pt;">
<span style="background-color: transparent; color: #383838; font-size: 14px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: "courier new" , "courier" , monospace;">scriptdirectory: new File("${migrations}"),</span></span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-left: 72pt; margin-top: 0pt; text-indent: 36pt;">
<span style="background-color: transparent; color: #383838; font-size: 14px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: "courier new" , "courier" , monospace;">dbms: "ora",</span></span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-left: 72pt; margin-top: 0pt; text-indent: 36pt;">
<span style="background-color: transparent; color: #383838; font-size: 14px; font-style: normal; font-variant: normal; font-weight: 700; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: "courier new" , "courier" , monospace;">changeScriptFilter: changeScriptValidatingFilfer,</span></span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-left: 72pt; margin-top: 0pt; text-indent: 36pt;">
<span style="background-color: transparent; color: #383838; font-size: 14px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: "courier new" , "courier" , monospace;">undoOutputfile: new File("${migrationsPath}/undo_last_change.sql"))</span></span></div>
<b style="font-weight: normal;"><span style="font-family: "courier new" , "courier" , monospace;"><br /></span></b>
<br />
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-left: 72pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #383838; font-size: 14px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: "courier new" , "courier" , monospace;">dbDeploy.go()</span></span></div>
<b style="font-weight: normal;"><br /></b>
<br />
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #383838; font-family: "arial"; font-size: 14px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span class="Apple-tab-span" style="white-space: pre;"> </span></span><span style="background-color: transparent; color: #383838; font-family: "arial"; font-size: 14px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">ChangeScriptFilter which has a generic interface </span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #383838; font-family: "arial"; font-size: 14px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span class="Apple-tab-span" style="white-space: pre;"> </span></span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-left: 36pt; margin-top: 0pt; text-indent: 36pt;">
<span style="background-color: transparent; color: #383838; font-size: 14px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: "courier new" , "courier" , monospace;">public interface ChangeScriptFilter {</span></span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-left: 72pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #383838; font-size: 14px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: "courier new" , "courier" , monospace;"> void process(List<ChangeScript> changeScripts);</span></span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-left: 36pt; margin-top: 0pt; text-indent: 36pt;">
<span style="background-color: transparent; color: #383838; font-size: 14px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: "courier new" , "courier" , monospace;">}</span></span></div>
<b style="font-weight: normal;"><br /></b>
<br />
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt; text-indent: 36pt;">
<span style="background-color: transparent; color: #383838; font-family: "arial"; font-size: 14px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">You can then implement ChangeScriptFilter as part of your build. Gradle makes it really easy to write groovy script to implement this filter and add this to part of the build. Adding Validations is just one usage of this filter.</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt; text-indent: 36pt;">
<span style="background-color: transparent; color: #383838; font-family: "arial"; font-size: 14px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span class="Apple-tab-span" style="white-space: pre;"> </span></span></div>
<b style="font-weight: normal;"><span style="font-family: "courier new" , "courier" , monospace;"><br /></span></b>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt; text-indent: 36pt;">
<span style="background-color: transparent; color: #383838; font-size: 14px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: "courier new" , "courier" , monospace;">public class ChangeScriptValidatingFilfer implements ChangeScriptFilter {</span></span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-left: 36pt; margin-top: 0pt; text-indent: 36pt;">
<span style="background-color: transparent; color: #383838; font-size: 14px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: "courier new" , "courier" , monospace;">public void process(List<ChangeScript> scripts) {</span></span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-left: 36pt; margin-top: 0pt; text-indent: 36pt;">
<span style="background-color: transparent; color: #383838; font-size: 14px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: "courier new" , "courier" , monospace;">for(ChangeScript script:scripts) {</span></span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-left: 72pt; margin-top: 0pt; text-indent: 36pt;">
<span style="background-color: transparent; color: #383838; font-size: 14px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: "courier new" , "courier" , monospace;">applyValidations(script);</span></span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-left: 36pt; margin-top: 0pt; text-indent: 36pt;">
<span style="background-color: transparent; color: #383838; font-size: 14px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: "courier new" , "courier" , monospace;">}</span></span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt; text-indent: 36pt;">
<span style="background-color: transparent; color: #383838; font-size: 14px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: "courier new" , "courier" , monospace;">}</span></span></div>
<b style="font-weight: normal;"><span style="font-family: "courier new" , "courier" , monospace;"><br /></span></b>
<br />
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt; text-indent: 36pt;">
<span style="background-color: transparent; color: #383838; font-size: 14px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: "courier new" , "courier" , monospace;">Validations can be written something like this</span></span></div>
<b style="font-weight: normal;"><span style="font-family: "courier new" , "courier" , monospace;"><br /></span></b>
<br />
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt; text-indent: 36pt;">
<span style="background-color: transparent; color: #383838; font-size: 14px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: "courier new" , "courier" , monospace;">public class DMLAndDDLSeparationValidator implements ChangeScriptValidator {</span></span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-left: 36pt; margin-top: 0pt; text-indent: 36pt;">
<span style="background-color: transparent; color: #383838; font-size: 14px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: "courier new" , "courier" , monospace;">public boolean validate(com.dbdeploy.scripts.ChangeScript changeScript) {</span></span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-left: 36pt; margin-top: 0pt; text-indent: 36pt;">
<span style="background-color: transparent; color: #383838; font-size: 14px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: "courier new" , "courier" , monospace;">String content = changeScript.getContent().toLowerCase();</span></span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-left: 72pt; margin-top: 0pt; text-indent: 36pt;">
<span style="background-color: transparent; color: #383838; font-size: 14px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: "courier new" , "courier" , monospace;">if (hasDDL(content) && hasDML(content)) {</span></span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-left: 144pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #383838; font-size: 14px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: "courier new" , "courier" , monospace;">throw new com.dbdeploy.exceptions.ChangeScriptValidationFailedException(changeScript + " has create or alter table and insert/update. Please put DML and DDL in separate scripts");</span></span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-left: 108pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #383838; font-size: 14px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: "courier new" , "courier" , monospace;">}</span></span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-left: 72pt; margin-top: 0pt; text-indent: 36pt;">
<span style="background-color: transparent; color: #383838; font-size: 14px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: "courier new" , "courier" , monospace;">return true;</span></span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-left: 36pt; margin-top: 0pt; text-indent: 36pt;">
<span style="background-color: transparent; color: #383838; font-size: 14px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: "courier new" , "courier" , monospace;">}</span></span></div>
<b style="font-weight: normal;"><span style="font-family: "courier new" , "courier" , monospace;"><br /></span></b>
<br />
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-left: 36pt; margin-top: 0pt; text-indent: 36pt;">
<span style="background-color: transparent; color: #383838; font-size: 14px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: "courier new" , "courier" , monospace;">private boolean hasDML(String content) {</span></span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-left: 36pt; margin-top: 0pt; text-indent: 36pt;">
<span style="background-color: transparent; color: #383838; font-size: 14px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: "courier new" , "courier" , monospace;">return content.contains("insert into ") || content.contains("update ");</span></span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-left: 36pt; margin-top: 0pt; text-indent: 36pt;">
<span style="background-color: transparent; color: #383838; font-size: 14px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: "courier new" , "courier" , monospace;">}</span></span></div>
<b style="font-weight: normal;"><span style="font-family: "courier new" , "courier" , monospace;"><br /></span></b>
<br />
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-left: 36pt; margin-top: 0pt; text-indent: 36pt;">
<span style="background-color: transparent; color: #383838; font-size: 14px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: "courier new" , "courier" , monospace;">private boolean hasDDL(String content) {</span></span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-left: 36pt; margin-top: 0pt; text-indent: 36pt;">
<span style="background-color: transparent; color: #383838; font-size: 14px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: "courier new" , "courier" , monospace;">return content.contains("create table ") || content.contains("alter table ");</span></span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-left: 36pt; margin-top: 0pt; text-indent: 36pt;">
<span style="background-color: transparent; color: #383838; font-size: 14px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: "courier new" , "courier" , monospace;">}</span></span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt; text-indent: 36pt;">
<span style="background-color: transparent; color: #383838; font-size: 14px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: "courier new" , "courier" , monospace;">}</span></span></div>
<b style="font-weight: normal;"><br /></b>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> 5. </span><span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 700; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Have a dryRun task which DBAs can run before executing dbdeploy against production database.</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span class="Apple-tab-span" style="white-space: pre;"> </span></span><span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">It helped having a dryRun task which shows all the changes which will be applied when migrations are run. DBDeploy already has a feature which allows you have to specify ‘outputFile’ and then it consolidates all the migrations to be applied to given schema in that file.</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">It helped us to write some scripts to analyse newly applied migrations and generate a report to show what all tables are affected and if there are inserts or alters or updates in those tables.</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Some of the tables are sensitive and DBAs like to if the current deployment might affect those tables in any way.</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span class="Apple-tab-span" style="white-space: pre;"> </span></span><span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">DryRun task was also added with a custom intercepting filter to analyse all the newly executing scripts. Here is a snapshot of script analyser.</span></div>
<b style="font-weight: normal;"><span style="font-family: "courier new" , "courier" , monospace;"><br /></span></b>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #383838; font-size: 14px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: "courier new" , "courier" , monospace;">class ChangeScriptAnalyzer implements ChangeScriptFilter {</span></span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-left: 36pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #383838; font-size: 14px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: "courier new" , "courier" , monospace;">def inserts = [:]</span></span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-left: 36pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #383838; font-size: 14px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: "courier new" , "courier" , monospace;">def updates = [:]</span></span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-left: 36pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #383838; font-size: 14px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: "courier new" , "courier" , monospace;">def creates = [:]</span></span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-left: 36pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #383838; font-size: 14px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: "courier new" , "courier" , monospace;">def alters = [:]</span></span></div>
<b style="font-weight: normal;"><span style="font-family: "courier new" , "courier" , monospace;"><br /></span></b>
<br />
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-left: 36pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #383838; font-size: 14px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: "courier new" , "courier" , monospace;">void process(List<ChangeScript> scripts) {</span></span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-left: 36pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #383838; font-size: 14px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: "courier new" , "courier" , monospace;">scripts.each { script -></span></span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-left: 36pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #383838; font-size: 14px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: "courier new" , "courier" , monospace;">def tableAnalyzer = new util.TableAnalyzer(sqls: script.content.readLines())</span></span></div>
<b style="font-weight: normal;"><span style="font-family: "courier new" , "courier" , monospace;"><br /></span></b>
<br />
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-left: 36pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #383838; font-size: 14px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: "courier new" , "courier" , monospace;">putInMap(inserts, tableAnalyzer.getTablesWithInserts(), script)</span></span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-left: 36pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #383838; font-size: 14px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: "courier new" , "courier" , monospace;">putInMap(updates, tableAnalyzer.getUpdatedTables(), script)</span></span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-left: 36pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #383838; font-size: 14px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: "courier new" , "courier" , monospace;">putInMap(creates, tableAnalyzer.getNewlyCreatedTables(), script)</span></span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-left: 36pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #383838; font-size: 14px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: "courier new" , "courier" , monospace;">putInMap(alters, tableAnalyzer.getAlteredTables(), script)</span></span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-left: 36pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #383838; font-size: 14px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: "courier new" , "courier" , monospace;">}</span></span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #383838; font-size: 14px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: "courier new" , "courier" , monospace;">}</span></span></div>
<b style="font-weight: normal;"><span style="font-family: "courier new" , "courier" , monospace;"><br /></span></b>
<br />
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #383838; font-size: 14px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: "courier new" , "courier" , monospace;">Which then could be used to print reports as following.</span></span></div>
<b style="font-weight: normal;"><span style="font-family: "courier new" , "courier" , monospace;"><br /></span></b>
<br />
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #383838; font-size: 14px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: "courier new" , "courier" , monospace;">Data is inserted in following tables (38)</span></span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #383838; font-size: 14px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: "courier new" , "courier" , monospace;">JOB_MASTER</span></span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-left: 36pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #383838; font-size: 14px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: "courier new" , "courier" , monospace;">20151130061549-JIRA-122072.sql</span></span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-left: 36pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #383838; font-size: 14px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: "courier new" , "courier" , monospace;">20151216233622-JIRA-120792.sql</span></span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-left: 36pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #383838; font-size: 14px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: "courier new" , "courier" , monospace;">20160112210928-JIRA-120792.sql</span></span></div>
<b style="font-weight: normal;"><span style="font-family: "courier new" , "courier" , monospace;"><br /></span></b>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #383838; font-size: 14px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: "courier new" , "courier" , monospace;">JOB_CATEGORY</span></span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-left: 36pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #383838; font-size: 14px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: "courier new" , "courier" , monospace;">20151130061549-JIRA-122072.sql</span></span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-left: 36pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #383838; font-size: 14px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: "courier new" , "courier" , monospace;">20151216233622-JIRA-120792.sql</span></span></div>
<b style="font-weight: normal;"><span style="font-family: "courier new" , "courier" , monospace;"><br /></span></b>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #383838; font-size: 14px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: "courier new" , "courier" , monospace;">CONFIGURATIONS_MASTER</span></span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-left: 36pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #383838; font-size: 14px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: "courier new" , "courier" , monospace;">20151209080100-JIRA-126407.sql</span></span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-left: 36pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #383838; font-size: 14px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: "courier new" , "courier" , monospace;">20151209165500-JIRA-125508.sql</span></span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-left: 36pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #383838; font-size: 14px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: "courier new" , "courier" , monospace;">20151213045000-JIRA-122529.sql</span></span></div>
<b style="font-weight: normal;"><span style="font-family: "courier new" , "courier" , monospace;"><br /></span></b>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #383838; font-size: 14px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: "courier new" , "courier" , monospace;">Data is updated in following tables (21)</span></span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #383838; font-size: 14px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: "courier new" , "courier" , monospace;">CONFIGURATION_MASTER</span></span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt; text-indent: 36pt;">
<span style="background-color: transparent; color: #383838; font-size: 14px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: "courier new" , "courier" , monospace;">20151209165500-JIRA-125508.sql</span></span></div>
<b style="font-weight: normal;"><span style="font-family: "courier new" , "courier" , monospace;"><br /></span></b>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #383838; font-size: 14px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: "courier new" , "courier" , monospace;">WEBSERVICE_CFG</span></span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-left: 36pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #383838; font-size: 14px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: "courier new" , "courier" , monospace;">20151209165500-JIRA-125508.sql</span></span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-left: 36pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #383838; font-size: 14px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: "courier new" , "courier" , monospace;">20160105202700-JIRA-60012.sql</span></span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #383838; font-size: 14px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: "courier new" , "courier" , monospace;">Following tables are newly created (13)</span></span></div>
<b style="font-weight: normal;"><span style="font-family: "courier new" , "courier" , monospace;"><br /></span></b>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #383838; font-size: 14px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: "courier new" , "courier" , monospace;">CUSTOMER_ADDRESS</span></span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt; text-indent: 36pt;">
<span style="background-color: transparent; color: #383838; font-size: 14px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: "courier new" , "courier" , monospace;">20151210070136-JIRA-127509.sql</span></span></div>
<b style="font-weight: normal;"><span style="font-family: "courier new" , "courier" , monospace;"><br /></span></b>
<br />
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #383838; font-size: 14px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: "courier new" , "courier" , monospace;">Following tables are altered (6)</span></span></div>
<b style="font-weight: normal;"><span style="font-family: "courier new" , "courier" , monospace;"><br /></span></b>
<br />
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #383838; font-size: 14px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: "courier new" , "courier" , monospace;">CUSTOMER</span></span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-left: 36pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #383838; font-size: 14px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: "courier new" , "courier" , monospace;">20151209091755-JIRA-124737.sql</span></span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-left: 36pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #383838; font-size: 14px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: "courier new" , "courier" , monospace;">20151210070136-JIRA-127509.sql</span></span></div>
<b style="font-weight: normal;"><span style="font-family: "courier new" , "courier" , monospace;"><br /></span></b>
<br />
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #383838; font-size: 14px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: "courier new" , "courier" , monospace;">CONTENT_MASTER</span></span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-left: 36pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #383838; font-size: 14px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: "courier new" , "courier" , monospace;">20151209180600-JIRA-126977.sql</span></span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-left: 36pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #383838; font-size: 14px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: "courier new" , "courier" , monospace;">20151215183001-JIRA-127777.sql</span></span></div>
<b style="font-weight: normal;"><br /></b>
<br />
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">This helped the DBAs to identify if there is any sensitive table which is modified by current deployment and to have a closer look at migration which is modifying that table.</span></div>
<b style="font-weight: normal;"><br /></b>
<br />
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">6. </span><span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 700; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Stored procedures are not Migrations.</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Do not put stored procedures in migrations. Stored procedures are compiled in database and all the procedures can be applied for every deployment. Adding a migration for every change in stored procedure, makes it extremely hard to track version history of that procedure.</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">So manage stored procedures as database source outside of migrations. Apply all procedures to database for every deployment. Have a the deployment script fail if there are compilation errors in stored procedures.</span></div>
<b style="font-weight: normal;"><br /></b>
<br />
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">7. </span><span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 700; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Get consolidated list of all exceptions in the end.</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">This one is controversial, but it greatly helped us in initial days.</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">DBDeploy fails on the first sql exception it gets while executing migrations. When you have globally distributed teams, managing their own databases, and especially with developers not used to automation and dbdeploy, they tend to manually execute migration scripts to fix issues.</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">This creates problem for deployments then, because dbdeploy execution fails with errors like Unique Constraint or Table already exists etc..</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Imagine a deployment which is executing 100 migrations, and 10 of those migrations fail. If dbDeploy fails for each migration, its extremely painful to fix issue, and rerun dbdeploy.</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Instead, if you get all the errors (of type table already exists etc…) at the end of run, it's lot easier to go through all the errors at once and then either make manual entries in changelog table or reach out to developers who wrote those migrations to understand why they are failing.</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt; text-indent: 36pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">This is not something that you will need in a typical project and might not be the right thing to do as well. But this helped us a lot. For getting all the errors in the end for specific error codes, we could specify it as following</span></div>
<b style="font-weight: normal;"><br /></b>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt; text-indent: 36pt;">
<span style="background-color: transparent; color: #383838; font-size: 14px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: "courier new" , "courier" , monospace;">def dbDeploy = new com.dbdeploy.DbDeploy(driver: "${driver}",</span></span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-left: 36pt; margin-top: 0pt; text-indent: 36pt;">
<span style="background-color: transparent; color: #383838; font-size: 14px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: "courier new" , "courier" , monospace;">url: "${jdbcUrl}",</span></span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-left: 36pt; margin-top: 0pt; text-indent: 36pt;">
<span style="background-color: transparent; color: #383838; font-size: 14px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: "courier new" , "courier" , monospace;">userid: "${jdbcUsername}",</span></span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-left: 36pt; margin-top: 0pt; text-indent: 36pt;">
<span style="background-color: transparent; color: #383838; font-size: 14px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: "courier new" , "courier" , monospace;">password: "${jdbcPassword}",</span></span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-left: 36pt; margin-top: 0pt; text-indent: 36pt;">
<span style="background-color: transparent; color: #383838; font-size: 14px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: "courier new" , "courier" , monospace;">scriptdirectory: new File("${migrationPath}"),</span></span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-left: 36pt; margin-top: 0pt; text-indent: 36pt;">
<span style="background-color: transparent; color: #383838; font-size: 14px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: "courier new" , "courier" , monospace;">dbms: "ora",</span></span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-left: 36pt; margin-top: 0pt; text-indent: 36pt;">
<span style="background-color: transparent; color: #383838; font-size: 14px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: "courier new" , "courier" , monospace;">changeScriptFilter: validatorProvider,</span></span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-left: 36pt; margin-top: 0pt; text-indent: 36pt;">
<span style="background-color: transparent; color: #383838; font-size: 14px; font-style: normal; font-variant: normal; font-weight: 700; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: "courier new" , "courier" , monospace;">exceptionsToContinueExecutionOn: "ORA-00001,ORA-00955,ORA-01430,ORA-00957,ORA-01430",</span></span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-left: 36pt; margin-top: 0pt; text-indent: 36pt;">
<span style="background-color: transparent; color: #383838; font-size: 14px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: "courier new" , "courier" , monospace;">undoOutputfile: new File("${migrationsPath}/undo_last_change.sql"))</span></span></div>
<b style="font-weight: normal;"><span style="font-family: "courier new" , "courier" , monospace;"><br /></span></b>
<br />
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt; text-indent: 36pt;">
<span style="background-color: transparent; color: #383838; font-size: 14px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: "courier new" , "courier" , monospace;">dbDeploy.go()</span></span></div>
<b style="font-weight: normal;"><br /></b>
<br />
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #383838; font-family: "arial"; font-size: 14px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">This helped a lot in initial phase of roll out, when people were still running manual scripts and DBDeploy will give all the unique constraint or table already exists, kind errors at once in the end, instead of breaking for each error. </span></div>
<br />
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">The code with all the changes mentioned above is available at <a href="https://github.com/unmeshjoshi/dbdeploy">https://github.com/unmeshjoshi/dbdeploy</a></span></div>
</div>
Anonymoushttp://www.blogger.com/profile/05338804644878097635noreply@blogger.com0tag:blogger.com,1999:blog-3102122536015259317.post-42384528768730118462014-03-31T07:46:00.000-07:002014-11-12T02:44:40.531-08:00Microservices and Agility<div dir="ltr" style="text-align: left;" trbidi="on">
'Microservices' is a new buzz word our industry has found. The idea is that a system is built with a set of independently managed services. The idea is catching up as people are seeing more and more problems with the monolithic applications.<br />
<b><br /></b>
<br />
<ul style="text-align: left;">
<li><b>A bit of history..</b></li>
</ul>
Most enterprise applications today get developed in Java and JVM. Around early 2000, when J2EE / Java was still gaining popularity, distributed objects was the recommended way of developing enterprise applications. Books like J2EE design patterns pushed for that. People claimed that distributed objects were necessary for scaling.<br />
In practice though, people were experiencing difficulties with the way distributed objects were creating problems. It was considered 'developer's nightmare'.<br />
Rod Johnson, in his book 'Expert one - on -one J2EE development without EJB', claimed that POJO components with dependency injection was much better and lightweight approach to develop better applications. Monoliths are better for managing and can be scaled well as well.<br />
Monolithic web applications using spring / or similar DI frameworks was the way most of the web applications were developed. <br />
<br />
<ul style="text-align: left;">
<li><b>SOA</b></li>
</ul>
<br />
Came along, SOA, Service Oriented Architecture. The idea was to break the applications based on the different set of business capabilities and expose those as services, so that they can be consumed by outside clients. Unfortunately, SOA was quickly tied to SOAP and Enterprise Service Buses.<br />
In last four to five years though, REST and HTTP have been clearly established as a de facto standard for exposing services. This is the preferred 'light weight' approach.<br />
<br />
<br />
<ul style="text-align: left;">
<li><b>Partitioning .</b></li>
</ul>
Exposing services along the lines of business capabilities is just one aspect of partitioning the system. By System I mean a software system which enables an organization to run their business. There are complex relationships between software systems and an organization. The way organization is partitioned impacts the way software systems are partitioned and vice versa. Almost always, these decisions can not be taken by just business people or just software people. The whole point of Agile was to allow business people and software people to work together for that reason, as the quality of this relationship determines quality of software architecture. By Architecture I mean how the system is partitioned into modules or components. They should closely resemble the domain partitioning.<br />
<br />
<br />
<br />
<ul style="text-align: left;">
<li><b>Forces for partitioning the system (organization and architecture)</b></li>
</ul>
Following are the most common reasons for partitioning the system.<br />
<ul style="text-align: left;">
</ul>
<ol style="text-align: left;">
<li><b>Different rate of change of parts of the system. :-</b> There are parts of the system which change at different rate. For example on a flight booking website, insurance rules might change more frequently than say search options. In such scenario, it might be worth splitting system, so that insurance module can be changed and deployed indendently.</li>
<li><b>Autonomy of teams working on different features :- </b>Some times its worth splitting the system , so that different teams can work on different parts as independently as possible. This is one of the common reasons for splitting monoliths. (This is actually driven by Conway's Law which states that parts of the systems reflects the way teams are structured)</li>
<li><b>Independent domains :- </b>Complex systems almost always have several independent business units. These are reflected in various different domains which are reflected in software system. Eric Evans calls these as 'bounded contexts' in his DDD book. It always beneficial to split the system on domain boundaries and have different modules (and teams) take care of these domains.</li>
<li><b>Non functional aspects. :- </b>Different parts of the system can have different non functional requirements. Common requirements like scaling, availability, performance, security are some of the most important reasons for which system needs to be split into parts. Monoliths often suffer with the problems that the whole monolith needs to be scaled even when a part of the system needs scaling. For example, in flight booking website, flight search is generally very expensive in terms of resources. Its well worth to split the application so that search components can be managed and scaled independently. It also better if these components can naturally map to teams, which can manage this component life cycle independently. Key management parts of the API might need more secure storage, monitoring and network infrastructure than rest of the application. In that case, pulling key management as a separate service makes a lot of sense.</li>
</ol>
<div>
These four are the most common reasons to partition the system and organization. As we can easily see, the forces aren't just about the technical aspects, but in fact more about organizational aspects. This is the reason, we see Conway's Law mentioned almost always in any write up on micro services.</div>
Of course just Conway's Law is not enough to guide us on how an organization should be structured and how the code should map to teams.<br />
Jim Coplien's great book 'Organizational Patterns of Agile Software Development' has a pattern language called 'People and Code Pattern Language'. This language lists a set of patterns which are necessary for having successful partitioning of the system. Architect Controls the Product, Architect Also Implements, Architecture team, Stand Up Meeting are just to name the few.<br />
<br />
<br />
<ul style="text-align: left;">
<li><b>Microservices or MicroApplications?</b> </li>
</ul>
<br />
As we can clearly see, there is broader problem of splitting or partitioning the software system and organization at stake here. One of the important parts of these systems is UI, either Web UI or otherwise. If we literally focus just on 'services', we can very easily fall in a trap of having a 'monolithic' web UI using granular back end services. Considering 'verticals' including UI is essential when thinking of partitioning the systems. The term 'MicroServices' is probably misleading here. Its more about having 'Micro Applications'.<br />
<br />
<br />
<ul style="text-align: left;">
<li><b>Its about being Agile</b></li>
</ul>
<div>
So, its all about individuals (Business people, architects and developers) and how they decide to implement software and build teams which develop this software. That's what being Agile is all about.<br />
Mapping software artifacts to teams or people, and structuring them to make sure teams can work as effectively as possible is a very important aspect of software development. This is very commonly known as the 'Conway's Law'.<br />
Conway's Law was at the heart of what Agile was. It was always the case. </div>
<div>
So when we say we need 'microservices architecture' we are really saying 'how can we be more Agile by having people and software in sync with business goals'. </div>
<div>
Unfortunately, Agile is thought of in a very very narrow sense now a days. Its generally limited to CI, CD, TDD, iterations etc etc..</div>
<div>
Most of what we are talking about 'MicroServices', is really about 'Agile'. The meaning that was lost all these years, is getting rediscovered under a different name. </div>
<div>
<br /></div>
</div>
Anonymoushttp://www.blogger.com/profile/05338804644878097635noreply@blogger.com0tag:blogger.com,1999:blog-3102122536015259317.post-44077970341643689682012-10-06T07:30:00.001-07:002012-10-06T07:57:53.582-07:00A Case for Use Cases for Agile Software Development<div dir="ltr" style="text-align: left;" trbidi="on">
Most Agile methods today, use 'product backlog' to track requirements. A product backlog is an ordered list of deliverables. The most widely accepted form of listing these deliverables is User Story.<br />
What is a 'User Story'? Mike Cohn defines it as 'A simple description of a feature told from the perspective of the person who desires the new capability'<br />
<br />
An agile team is supposed to complete one or more user stories in an iteration.<br />
That puts another constraint on user stories. They should be small enough so that they can be estimated and worked upon by a team in two to four weeks. So a user story, is not just a 'feature that a end user wants', but also a 'unit of work' which can be estimated and used for planning.<br />
<br />
There is a tension between these two aspects. Agile teams, many times fall in trap when one is given more importance than the other. If 'User Value' is always asked for, the work items might become too big and there is a danger of it spanning multiple iterations. If small work items are created directly, there is a danger of losing big picture or 'context'.[2]. Experienced Agile teams generally create smaller stories and use techniques like 'Story Maps' to fill in the context. The larger stories which the smaller 'work item' stories map to are called 'Epics'.<br />
<br />
There is another aspect of 'User Story'. Its supposed to be a reminder to have conversation. Its not just a documented requirement. The understanding of what needs to be built is dependent on the quality of the conversation which developers have with business people. But how do you make sure that the discussions which actually produce these stories are guided correctly?<br />
'Agile' requirements gathering needs a framework to allow business people and developer to talk. For guiding these talks, the best approach is to discuss scenarios of end user interacting with the system.<br />
And thats what a 'Use Case' is! Every use case exists because it helps achieve some actor a goal. We start with high level user interactions with the system. For every action that the system performs, we dig more and try to figure out why we have this step? Who wants it? (who is the actor) Why? (What’s the goal?). After we break down a high level flow into more granular ‘goals’,we have a set of use cases.<br />
We first concentrate just on the happy path of the use case. A use case happy path is not more than 3 to 7 steps. Generally, lesser steps. its better.<br />
<br />
Lets take an example of use case for a flight booking system. At very high level, following is the summary of user actions. This is called as a 'Summary level' use case.<br />
<br />
<b>User goal - Book a flight.</b><br />
<div>
<ol style="text-align: left;">
<li>User<u> searches for a flight </u>specifying source, destination airports and travel dates.</li>
<li>Travel website displays flights matching user criteria</li>
<li>Travel website accepts traveler information and preferences to <u>build Itinerary</u></li>
<li>Travel website <u>stores traveler preferences</u> and presents payment options</li>
<li>User enters payment details</li>
<li>Travel website <u>processes payment</u> and <u>books flight</u></li>
</ol>
From this summary, we can come up with more detailed use cases.<br />
<br />
Lets detail out 'Search Flights' use case.<br />
<b><br /></b>
<b>User goal - User wants to get all possible flight options for travel</b><br />
<ol style="text-align: left;">
<li>User visits travel site.</li>
<li>Travel website presents fields to enter departure, arrival airports, date of travel and travel time.</li>
<li>User enters required information.</li>
<li>Travel website communicates with GDS and presents list of available flights.</li>
</ol>
Now, how to come up with Product backlog items? (Or User stories).<br />
The main driving factor for product backlog items is that they should be small enough to be worked upon in an iteration (2 weeks). Items like these help in release planning and also provide enough guidance for developers to work on.<br />
<div>
<div>
<br /></div>
<div>
A happy path scenario of a use case makes a good backlog item(read use story). Its extremely important to really really think about minimal happy path scenario. ‘Individual and Interactions’ help here.<br />
A minimal happy path scenario, makes a perfect backlog item.</div>
<div>
<br /></div>
<div>
Once we have happy paths, use cases naturally help thinking about deviations. </div>
<div>
Each deviation, then can become a good product backlog item. (User story).</div>
<div>
<br /></div>
<div>
So, following is the first cut backlog that we come up with</div>
</div>
<ol style="text-align: left;">
<li>Search Flights</li>
<li>Store traveler information</li>
<li>Process payment</li>
<li>Book flight with GDS.</li>
</ol>
<br />
<div>
<div>
<b>Brainstorming deviations.</b></div>
<div>
<b><br /></b></div>
<div>
Once we have basic happy path scenarios, for each use case we think of deviations.<br />
<b><br /></b>
<br />
<div style="text-align: left;">
<b>User goal - User wants to get all possible flight options for travel</b></div>
</div>
</div>
<div>
<div style="text-align: left;">
<b><br /></b></div>
<div style="text-align: left;">
<b>Main Success Scenario:</b></div>
</div>
<ol>
<li style="text-align: left;">User visits travel site.</li>
<li style="text-align: left;">Travel website presents fields to enter departure, arrival airports, date of travel and travel time.</li>
<li style="text-align: left;">User enters required information.</li>
<li style="text-align: left;">Travel website communicates with GDS and presents list of available flights.</li>
</ol>
<div style="text-align: left;">
<b>Deviations</b>:</div>
<div style="text-align: left;">
<br /></div>
<div style="text-align: left;">
3a1 User enters wrong origin or destination</div>
<div>
<div style="text-align: left;">
3a2 Travel website presents possible airport code options.</div>
</div>
<div>
<div style="text-align: left;">
</div>
</div>
<div>
<div style="text-align: left;">
4a1 No flights are available matching criteria</div>
</div>
<div>
<div style="text-align: left;">
4a2 Travel website presents appropriate message </div>
</div>
<div style="text-align: left;">
<br /></div>
These deviations are source of additional backlog items<br />
<br />
<b>An curious case where happy path scenario is too big a story for an iteration</b><br />
<br />
To start with we had a backlog item called ‘search flights’. Discussing the happy path with developers, we think that in one iteration, we can do the work to display required fields and find airport codes for airports that user has entered. Finding these airport codes requires us to integrate with a system which has all the airport data available.<br />
So we break down our first backlog item ‘Search Flights’ into two backlog items as follows.<br />
<div>
<div>
<ol style="text-align: left;">
<li>Accept flight search criteria and build search request. [Use Case step 2 and part of step 4, and deviation 4a]</li>
<li>Search flights with Sabre GDS. [Use case step 2]</li>
<li>Store traveler information</li>
<li>Process payment</li>
<li>Book flight with GDS.</li>
<li>Provide airport options to user.</li>
</ol>
</div>
</div>
<div>
We included step 4a, (no flights found case) in the first item as developers thought it will help them build a vertical slice through the system.<br />
<br /></div>
From the above example we see that the Use Cases provide a very good thinking and brainstorming framework for discussions between business people and developers. 'Agile' teams should not deny a lot of wisdom that's already available with Use Case community.<br />
<b><br /></b>
<b>References:</b><br />
<br />
Alistair Cockburn has a very nice presentation, which talks about how use cases can be used in Agile projects at <a href="http://alistair.cockburn.us/Agile+Use+Cases">http://alistair.cockburn.us/Agile+Use+Cases</a><br />
<div>
<br /></div>
Jim Coplien’s book ‘<a href="http://www.leansoftwarearchitecture.com/">Lean Architecture</a>’ has very good explanation of how Use Cases help in Agile and Lean development.<br />
<div>
<br /></div>
<div>
Martin Fowler has a nice paragraph discussing relationship between Use Cases and User Stories</div>
<a href="http://martinfowler.com/bliki/UseCasesAndStories.html">http://martinfowler.com/bliki/UseCasesAndStories.html</a><br />
<br />
Books 'Patterns of Effective Use Cases' and 'Writing Effective Use Cases' should be 'must read' for Agile BAs along with Mike Cohn's 'User Stories Applied'.</div>
</div>
Anonymoushttp://www.blogger.com/profile/05338804644878097635noreply@blogger.com0