groovy vs boilerplate and ceremony code
TRANSCRIPT
JVM. quack() or Groovy vs Ceremony
…
Stas ShevchenkoJava Launch, 23/04/2013, Riga
Java Language comes with
• Design Patterns• Boilerplate• Overly Ceremony code
1. Patterns
…
Boilerplate
2. Boilerplate
- getter/setters- Lazy init factories- toString, hashCode, equals- Explicit Exception declaration/handling- Close for resources- synchronization
Ceremony: Code’s Worst Enemy
Code Today (Death Star)
CEREMONY
ESSENCE
Future: Paradigm, Languages, Frameworks
CEREMONY
ESSENCE
3. Ceremony to Essence code. Step 0
public ActionForward edit(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception { PersonForm personForm = (PersonForm) form; if (personForm.getId() != null) { PersonManager mgr = (PersonManager) getBean("personManager"); Person person = mgr.getPerson(personForm.getId()); personForm = (PersonForm) convert(person); updateFormBean(mapping, request, personForm); } return mapping.findForward("edit"); }
Step 1. Duck Typing
edit(mapping, form, request, response) throws Exception { personForm = form; if (personForm.getId() != null) { mgr = getBean("personManager"); person = mgr.getPerson(personForm.getId()); personForm = convert(person); updateFormBean(mapping, request, personForm); } return mapping.findForward("edit"); }
Step 2. duck typing, without local variable
edit(mapping, form, request, response) throws Exception { if (form.getId() != null) { mgr = getBean("personManager"); person = mgr.getPerson(form.getId()); form = convert(person); updateFormBean(mapping, request, form); } return mapping.findForward("edit"); }
Step 3. Implicit return, exceptions
edit(mapping, form, request, response) { if (form.getId() != null) { mgr = getBean("personManager"); person = mgr.getPerson(form.getId()); form = convert(person); updateFormBean(mapping, request, form); } mapping.findForward("edit"); }
Step 4. Don't add a manager layer to MVC (yet). KISS + YAGNI.
edit(mapping, form, request, response) { if (form.getId() != null) { person = Person.find(form.getId()); form = convert(person); updateFormBean(mapping, request, form); } mapping.findForward("edit"); }
Step 5. Conditionals make code expensive to test
edit(mapping, form, request, response) { person = Person.find(form.getId()); form = convert(person); updateFormBean(mapping, request, form); mapping.findForward("edit"); }
Step 6. All action methods have the same four arguments
edit() { person = Person.find(form.getId()); form = convert(person); updateFormBean(mapping, request, form); mapping.findForward("edit"); }
Step 7. Delegate object showing to form
edit() { person = Person.find(form.getId()); mapping.findForward("edit"); }
Step 8. Standard routing
edit() { person = Person.find(form.getId()); }
Or Rubydef edit @person = Person.find(params[:id]) end
Java Word
IoCAspectsLombok or Eclipse XtendCode generators -> Spring Roo
JVM Languages
ClojureScala
GroovyJRubyJython
Java Script
Clojure- Lisp – WTF?- By default Functional Programming only
Scala- Syntax WTF- Acclimatization period 6 to 12 months
JRuby- Ruby guys - gemns hell
Jython- Python syntax ((
Java Script (Rhino)- Is Java Script
Starting Groovy
1. Download the .zip file from http://groovy.codehaus.org and unzip it to local drive
2. Create the GROOVY_HOME environment variable and add $GROOVY_HOME/bin to you path
3. type groovy -version
Groovy Console
Primitives
3.times { println it }
assert (10 instanceof Integer)
println 4.4.class
String s = 10 as String;println s;
Groovy Beans
class Customer { Integer id def name Date dob}
def customer = new Customer(id:1, name:"Gromit", dob:new Date())
Collections – Lists, Ranges
def list = [5, 6, 7, 8]assert list[2] == 7assert list instanceof java.util.List
def range = 5..8assert range.size() == 4assert range[2] == 7assert range instanceof java.util.List
Collections - Map
def map = [name:"Gromit", likes:"cheese", id:1234]assert map["name"] == "Gromit"assert map['id'] == 1234assert map instanceof java.util.Map
Collections features
assert [1, 3, 5] == ['a', 'few', 'words']*.size()
def words = ['ant', 'buffalo', 'cat', 'dinosaur']assert words.findAll{ w -> w.size() > 4 } == ['buffalo', 'dinosaur']
def words = ['ant', 'buffalo', 'cat', 'dinosaur']assert words.collect{ it[0] } == ['a', 'b', 'c', 'd']
def sub = list[1, 3, 20..25, 33]assert sub == [101, 103, 120, 121, 122, 123, 124, 125, 133]
Duck typing
// Hey duckDuck myDuck = new Duck()myDuck.quack()
// Hey quackerdef duck = new Duck()myDuck.quack()
Duck typing 2
class Duck { def quack() {println("quack")}}
def action = "quack"def duck = new Duck()duck."${action}"()
Operators
a == b a.equals(b)a + b a.plus(b)a - b a.minus(b)a++ a.next()a << b a.leftShift(b)
def groovy = [”beer", ”rock&roll"]groovy << ”girls"
Closures
def squareClosure = { value -> value * value;}
assert (4 == squareClosure(2))
IO
def file = new File(sms.txt).eachLine{ println it }
file.write(”rewrite file”)
file.append(“add to file”)file << ”sexy style"
XML
def xml = new groovy.xml.MarkupBuilder()xml.goods(type:”current”){ good(“Beer”) good (“Rock&Roll”) good (“Girls”)}
XML
def goods = new XmlSlurper().parseText(…)def allGoods = records.nameassert 3 == allRecords.size()def allNodes = goods.depthFirst().collect{ it }def firstGood = goods.name[0]assert ’sms’ == firstGood .name()assert ‘Text’ == [email protected]()
DSL
This is a really cool topic, where the stars are began…
• A DSL allows expressions in a domain specific manner
• Method pointers make this easy:def list = []def insert = list.&addinsert ”beer"insert ”rock&roll"
Something to read
Groovy++Grails -> GORMGradle
At the end – NPE fighter in my team
infringementAction.setCustomsOffice( versionedReplyInf != null ? (versionedReplyInf.getReplyInf() != null ? (versionedReplyInf.getReplyInf().getInf() != null ? (versionedReplyInf.getReplyInf().getInf().getInf() != null ? (versionedReplyInf.getReplyInf().getInf().getInf().
getCustomsOffice() != null ? versionedReplyInf.getReplyInf().getInf().getInf().
getCustomsOffice() : null) : null) : null) : null) : null);
At the end on Groovy
Safe navigation operator “?.”
infringementAction.setCustomsOffice(versionedReplyInf?.getReplyInf()?.getInf()?.getInf()?.getCustomsOffice())