Thursday, November 29, 2012

Continuous Inspection



How can you ensure the quality of your code continuously?
Some measures comes to my mind are as follows:
  • Your bug rate
  • compliance of coding rules
  •   complexity
  • duplications
  • comments
  • coupling and cohesion level
  • code coverage
  • automated acceptance test
  •  performance &stress test

Using continuous inspection tools like Sonar you run pre-defined rules and if not enough for you, plus your custom rules against your source files. Then it collects violations of the rules, quality metrics and then lists them on the dashboard historically. Measuring these while time goes on you actually measure your team’s experience as well.  These results also give you a chance to focus on the risky components and may suggest some action plans to solve them. 
Some rules’ priority should be higher than others for your project. You can change rules threshold as blocker, critical, major, minor, info etc whenever you want.
Here is a screen shot from my test project:

                                                                                                 Figure-1
Here you can assign a violation to someone via the assing button, or you can ignore it by marking False-positive, or you can take action by selecting a plan you've defined. If you use Jira issue tracking system then you can make it viewable to jira by using a sonar jira plugin as well. One of the most important thing, you can    make rules active or inactive anytime you want and you can also change severity of them.

Figure-2


Wednesday, November 14, 2012

Eclipse editor for liquibase database change management



             To use eclipse magic auto-complete feature for liquibase change log file editing i defined a xtext grammer and generated a plugin. [ Xtext, an open-source framework for development of programming langauges and domain-specific languages.]

You will see below my xtext grammer for liquibase which just defines some part of its language and also a template of this language to suggest keywords and phrases smartly when using auto complete feature of the Eclipse environment:

Grammer Part:

grammar org.xtext.example.mydsl.Liquibase with org.eclipse.xtext.common.Terminals
generate LiquibaseEditor "http://www.xtext.org/example/mydsl/LiquibaseEditor"
Model:
      (xlists+=Xlist)*;
Xlist:
   '<?xml version="1.0" encoding="UTF-8"?>'
   '<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog"'
      'xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"'
      'xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog'
      'http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-2.0.xsd">'(include+=INCLUDEFILE)*(changeset+=CHANGESET)*'</databaseChangeLog>';
CHANGESET:'<changeSet' 'id='id=STRING 'author='author=STRING(ra=RUNALWAYS)?(roc=RUNONCHANGE)?'>'(pre+=PRECONDITION)?(comment=COMMENT)?((sql+=SQL)|(createProcedure+=CREATEPROCEDURE)|(rb+=ROOLBACK))*'</changeSet>';
 
SQL returns MSQL:
 a=MSQL
;
terminal MSQL:'<sql>'->'</sql>';
MSQLs:'<sql>'=>'</sql>';
INCLUDEFILE:'<include file='fileLocation=STRING'/>';
//SQLFILE:'<sqlFile path='fileLocation=STRING'/>';
RUNALWAYS:'runAlways='ra=BOOLEAN;
RUNONCHANGE:'runOnChange='roc=BOOLEAN;
ROOLBACK returns MROOLBACK:mr=MROOLBACK;
terminal MROOLBACK:'<roolback>'->'</roolback>';
ENDDELIMITER:'endDelimiter='ed=STRING;
STRIPCOMMENTS:'stripComments='sc=BOOLEAN;
SPLITSTATEMENTS:'splitStatements='sps=BOOLEAN;
PRECONDITION:'<preConditions'prect=PRECONDITIONTYPE'>'(sqlCheck+=SQLCHECK)'</preConditions>';
SQLCHECK returns MSQLCHECK:
 b=MSQLCHECK
;
//SQLCHECK:'<sqlCheck expectedResult='EXPECTEDRESULT'>'(sqlStatement+=STRING)'</sqlCheck>';
 
terminal MSQLCHECK:'<sqlCheck expectedResult='STRING'>'->'</sqlCheck>';
//ANDLOGICALEXP:(ab=ENDBTAG)((s+=SQLCHECK)|(ole+=ORLOGICALEXP)|(ale+=ANDLOGICALEXP))*(ae=ENDETAG);
//ORLOGICALEXP:(ob=ORBTAG)((s+=SQLCHECK)|(ole+=ORLOGICALEXP)|(ale+=ANDLOGICALEXP))*(oe=ORETAG);
//ANDLOGIC:'<and>''</and>';
//ORLOGIC:'<or>''</or>';
//ENDBTAG:'<and>';
//ENDETAG:'</and>';
//ORBTAG:'<or>';
//ORETAG:'</or>';
 
PRECONDITIONTYPE:(u=ONUPDATE)|(f=ONFAIL)|(e=ONERROR)|(fm=ONFAILMESSAGE)|(em=ONERRORMESSAGE);
ONUPDATE:'onUpdate='((o='"RUN"')|(o='"FAIL"')|(o='"IGNORE"'));
ONFAIL:'onFail='onFailAttribute=ONFAILERRORTYPEATTRIBUTE;
ONERROR:'onError='onFailAttribute=ONFAILERRORTYPEATTRIBUTE;
ONFAILERRORTYPEATTRIBUTE:(a='"HALT"')|(a='"CONTINUE"')|(a='"MARK_RAN"')|(a='"WARN"');
ONFAILMESSAGE:'onFailMessage='message=STRING;
ONERRORMESSAGE:'onErrorMessage='essage=STRING;
COMMENT:'<comment>'comment=STRING'</comment>';//Comments should go after preCondition. If they are before then liquibase usually gives error.
DROPTABLE:'<dropTable tableName="'tableName=STRING'/>';
 
//~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-
//CREATEPROCEDURE:'<createProcedure>'createProcedure=STRING'</createProcedure>';
CREATEPROCEDURE returns MCREATEPROCEDURE:
 b=MCREATEPROCEDURE;
 
terminal MCREATEPROCEDURE:'<createProcedure>'->'</createProcedure>';
/*MERGECOLUMNS:'<mergeColumns tableName="'tableName=STRING
 'column1Name='column1Name=STRING
 'joinString='joinString=STRING
 'column2Name'column2Name=STRING
 'finalColumnName'finalColumnName=STRING
 'finalColumnType'finalColumnType=STRING
;*/
//ADDCOLUMN:'<addColumn tableName='tableName=STRING'>'column=COLUMN'</addColumn>';
//COLUMN:'<column name='columnName=STRING'type='type=STRING'/>';
//Types
BOOLEAN:(t='"true"')|(f='"false"');
//terminal ID:'~~~';
//terminal STRING:!('') (INT |WS | ID)* ;
//terminal mystr:
//(ANY_OTHER | STRING)*;

Template Part:
i exported this file from my eclipse to use it just import from eclipse Preferences>>LiquibaseEditor>>Templates


<?xml version="1.0" encoding="UTF-8" standalone="no" ?> 
- <templates>
  <template autoinsert="true" context="org.xtext.example.mydsl.LiquibaseEditor.kw_author=" deleted="false" description="" enabled="true" name="author">author="${user}"</template> 
  <template autoinsert="true" context="org.xtext.example.mydsl.LiquibaseEditor.kw_author=" deleted="false" description="" enabled="true" name="author">author="ozayd"</template> 
  <template autoinsert="true" context="org.xtext.example.mydsl.LiquibaseEditor.CHANGESET" deleted="false" description="" enabled="true" name="changeSet"><changeSet id="BLK-x-${date}-${time}" author="ozayd"> ${cursor} </changeSet></template> 
  <template autoinsert="true" context="org.xtext.example.mydsl.LiquibaseEditor.CREATEPROCEDURE" deleted="false" description="" enabled="true" name="CREATEPROCEDURE"><createProcedure> ${cursor} </createProcedure></template> 
  <template autoinsert="true" context="org.xtext.example.mydsl.LiquibaseEditor.CREATEPROCEDURE" deleted="false" description="" enabled="true" name="CREATEPROCEDURE"><createProcedure> ${cursor} </createProcedure></template> 
  <template autoinsert="true" context="org.xtext.example.mydsl.LiquibaseEditor.Xlist" deleted="false" description="" enabled="true" name="databaseChangeLog"><?xml version="1.0" encoding="UTF-8"?> <databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-2.0.xsd"> ${cursor} </databaseChangeLog></template> 
<template autoinsert="true" context="org.xtext.example.mydsl.LiquibaseEditor.Xlist" deleted="false" description="" enabled="true" name="databaseChangeLog"><?xml version="1.0" encoding="UTF-8"?> <databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-2.0.xsd"> ${cursor} </databaseChangeLog></template>
<template autoinsert="true" context="org.xtext.example.mydsl.LiquibaseEditor.INCLUDEFILE" deleted="false" description="" enabled="true" name="includeFile"><include file="${cursor}"/></template>
<template autoinsert="true" context="org.xtext.example.mydsl.LiquibaseEditor.INCLUDEFILE" deleted="false" description="" enabled="true" name="includeFile"><include file="${cursor}"/></template>
<template autoinsert="true" context="org.xtext.example.mydsl.LiquibaseEditor.ROOLBACK" deleted="false" description="" enabled="true" name="ROOLBACK"><roolback> ${cursor} </roolback></template>
<template autoinsert="true" context="org.xtext.example.mydsl.LiquibaseEditor.ROOLBACK" deleted="false" description="" enabled="true" name="ROOLBACK"><roolback> ${cursor} </roolback></template>
<template autoinsert="true" context="org.xtext.example.mydsl.LiquibaseEditor.Xlist" deleted="false" description="" enabled="true" name="sql"><sql> ${cursor} </sql></template>
<template autoinsert="true" context="org.xtext.example.mydsl.LiquibaseEditor.Xlist" deleted="false" description="" enabled="true" name="sql"><sql> ${cursor} </sql></template>
<template autoinsert="true" context="org.xtext.example.mydsl.LiquibaseEditor.SQL" deleted="false" description="" enabled="true" name="SQL"><sql> ${cursor} </sql></template>
<template autoinsert="true" context="org.xtext.example.mydsl.LiquibaseEditor.SQL" deleted="false" description="" enabled="true" name="SQL"><sql> ${cursor} </sql></template>
<template autoinsert="true" context="org.xtext.example.mydsl.LiquibaseEditor.SQLCHECK" deleted="false" description="" enabled="true" name="sqlCheck"><sqlCheck expectedResult="${cursor}expectedResult">"sqlStatement"</sqlCheck></template>
<template autoinsert="true" context="org.xtext.example.mydsl.LiquibaseEditor.SQLCHECK" deleted="false" description="" enabled="true" name="sqlCheck"><sqlCheck expectedResult="${cursor}expectedResult">"sqlStatement"</sqlCheck></template>
</templates>



Continuous Database İntegration



        For most of us it is a new concept.  The  main idea behind the forest is to record database structural changes to a version control system (svn,git etc.)  at the same time code base versioning . With this way you keep the database structure corresponding to the code base. Thus there is no need to execute scripts in various enviroments manually.
 Liquibase is one of the best continuous database integration tool i may suggest. With this tool you write your database scripts in database change log files in human readable format by creating a changeSet.
And then run changeSets via ant, maven or command line the way shown below


<?xml version="1.0" encoding="UTF-8"?>
 
<databaseChangeLog
  xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog
         http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-2.0.xsd">
 
    <changeSet id="prj-issue-1111" author="ozay.duman">
        <sql>
            CREATE TABLE BOOK( book_id NUMBER PRIMARY KEY,book_name VARCHAR2(30),author_name VARCHAR2(40),book_isbn VARCHAR2(20) )
                    </sql>
   </changeSet>
 
</databaseChangeLog>



liquibase --driver=com.mysql.jdbc.Driver \
     --classpath=/path/to/classes \
     --changeLogFile=com/example/db.changelog.xml \
     --url="jdbc:mysql://localhost/example" \
     --username=user \
     --password=asdf \
     migrate

Magic happens, check your database you will see two tables databasechandelog and databasechandeloglock created. The databasechangelog table contains a list of all the statements that have been run against the database. The databasechangeloglock table is used to make sure two machines don't attempt to modify the database at the same time.

Another feature of Liquibase is database change documentation generation:

liqubase.sh --driver=oracle.jdbc.OracleDriver \
        --url=jdbc:oracle:thin:@test:1521:test \
        --username=user \
        --password=asdf \
        --changeLogFile=path/to/changelog.xml
    dbDoc \
        /docs/dbdoc
You can also use Liquibase as database integrity checkher. To do this, you should use sqlcheck inside preCondition tag as follows:

<databaseChangeLog>
<changeSet id="1" author="bob">
        <preConditions onFail="WARN">
            <sqlCheck expectedResult="0">select count(*) from MY_TABLE</sqlCheck>
        </preConditions>
    </changeSet>
</databaseChangeLog>

When expectedResult differs from the result of the sql statement it will warn you.

Tuesday, November 13, 2012

Continuous İntegration


They say a picture tells much more..from that truth i draw the big picture makes things clear


Continuous integration is a practise comes from Extreme Programming. In large projects  all developers makes their indiviual works but when it is time to integrate them it is a big problem. A lot more time has to be spend to solve integration problems. So each member of a team should make their commits frequently to a repository  this gives the team to re-use the common code early and recognise integration problems early.  An integration server such as hudson, jenkins etc. builds code, runs unit & integration test, inspects the quality of the code, deploys the build, updates the database to the same version of the code and runs Automated User Interface tests.Then developers look at the test results. QA manager  looks at Continuous Inpestion results. He/she opens issues on issue tracking system which continuous inspection rules marked as major or critical. Then the errors found in tests results are fixed and improvements are made for QA.  Finally a clean integrated work is ready for the production. You may read alot more about CI on Matin Fowler’ site.