112
State of Apache Wicket

The State of Wicket

Embed Size (px)

DESCRIPTION

The current state of the Apache Wicket framework in 2014 as presented at the DEVdev meetup held in Deventer, the Netherlands. - A critique of ThoughtWorks' Technology Review 2014 where they slam JSF (jay) as a concept (nay) - A look back at 10 years of Wicket - A review of the current Wicket versions - An outlook and roadmap for Wicket 7 and Wicket 8 The DEVdev (Deventer Developers) is a new meetup for any developer in the eastern part of the Netherlands (the right side of the IJssel river). This presentation was delivered at the first meetup, and was kindly sponsored by Topicus B.V.

Citation preview

Page 1: The State of Wicket

State of Apache Wicket

Page 2: The State of Wicket

DEVELOPERSENTERDEV

powered by Topicus

presented at:

Page 3: The State of Wicket

topicus

sponsored by

Page 4: The State of Wicket
Page 5: The State of Wicket

“We continue to see teams run into trouble using JSF -- JavaServer Faces -- and are recommending you avoid this technology.”

–ThoughtWorks Technology Radar January 2014

Wicket Developers Rejoice! !Our archenemy has been denounced!!!

Or is there more to this story?

Page 6: The State of Wicket

“We continue to see teams run into trouble using JSF -- JavaServer Faces -- and are recommending you avoid this technology. Teams seem to choose JSF because it is a J2EE standard without really evaluating whether the programming model suits them. We think JSF is flawed because it tries to abstract away HTML, CSS and HTTP, exactly the reverse of what modern web frameworks do. JSF, like ASP.NET webforms, attempts to create statefulness on top of the stateless protocol HTTP and ends up causing a whole host of problems involving shared server-side state. We are aware of the improvements in JSF 2.0, but think the model is fundamentally broken. We recommend teams use simple frameworks and embrace and understand web technologies including HTTP, HTML and CSS.”–ThoughtWorks Technology Radar January 2014

The full quote from ThoughtWorks

Technology Radar. The good bits are

on the next slide...

Page 7: The State of Wicket

“We continue to see teams run into trouble using JSF and are recommending you avoid this technology. We think JSF is flawed because it tries to abstract away HTML, CSS and HTTP. JSF, like ASP.NET webforms, attempts to create statefulness on top of the stateless protocol HTTP. We think the model is fundamentally broken.”

–ThoughtWorks Technology Radar January 2014

This is not a critique of JSF in particular but (server side) component frameworks. The grunt of the critique is that JSF attempts to create state fullness on top of the stateless protocol–which is precisely what JSF, .Net, Wicket and Tapestry are doing.

Page 8: The State of Wicket

“We recommend teams use simple frameworks and embrace and understand web technologies

including HTTP, HTML and CSS.”

I don’t agree with this assessment:!

server side, state managing frameworks were

created to provide a solution for problems

that are difficult to solve with “simple frameworks”. !

Going back to 2004 is not the solution!

–ThoughtWorks Technology Radar January 2014

Page 9: The State of Wicket

A typical screen in one of our 1000+ page multi-tenant SaaS applications.!Would a“simple framework” make it possible to maintain 3 of these 1M lines of code applications with just 30 developers?

Page 10: The State of Wicket

10 years of Apache Wicket

Page 11: The State of Wicket

2004

Page 13: The State of Wicket

2004

The Server Side

Page 14: The State of Wicket

2004

The Server SideThe original Wicket website. We have seen several different stylings over the years...

Page 15: The State of Wicket

20052004

codehaus.org

The Server Side

Page 16: The State of Wicket

20052004

codehaus.org

The Server Side

The first Wicket meetup in 2005 in Deventer at the Topicus offices.

Page 17: The State of Wicket

20052004

codehaus.org

The Server Side

Page 18: The State of Wicket

20052004

codehaus.org

The Server Side

The web framework shoot-out at JavaOne 2005. Now that was fun!

JSF Tapestry

Struts 2 (originally Webwork)

Wicket Shale

Page 19: The State of Wicket

codehaus.org

2004

The Server Side JavaOne

2005

Page 20: The State of Wicket

codehaus.org

2004

The Server Side JavaOne

1.0

2005

Page 21: The State of Wicket

codehaus.org

2004

The Server Side JavaOne

1.0

1.1

2005

Page 22: The State of Wicket

codehaus.org

2004

The Server Side JavaOne

1.0

1.1

2006

1.2

2005

Page 23: The State of Wicket

2007

Page 24: The State of Wicket

2007

Wicket joins !The Apache Software Foundation!

Page 25: The State of Wicket

2007

One of 3 Wicket meetups in

Amsterdam organised by Arjé

Cahn (Hippo CMS)

Page 26: The State of Wicket

2007

Page 27: The State of Wicket

2007

1.3

2008

Page 28: The State of Wicket

2007

1.3

2008

Page 29: The State of Wicket

2007

1.3

2008

Page 30: The State of Wicket

2007

1.3

2008 2009

1.4

Page 31: The State of Wicket

2007

1.3

2008 2009

1.4

2010

Page 32: The State of Wicket

2007

1.3

2008 2009

1.4

2010 2011

1.5

Page 33: The State of Wicket

2012 2013 2014

Page 34: The State of Wicket

2012

6.0

2013 2014

Page 35: The State of Wicket

2012

6.0

2013 2014

6.126.2

6.46.6

6.86.10

6.16.3

6.56.7

6.96.11

6.13

Page 36: The State of Wicket

State of Apache Wicket

Page 37: The State of Wicket
Page 38: The State of Wicket
Page 39: The State of Wicket

1. core

2. extensions

3. spring

4. datetime

5. auth-roles

Page 40: The State of Wicket

Mailinglist traffic

Page 41: The State of Wicket

Commit activity

Wicket in ActionWicket Cookbook

Page 42: The State of Wicket

Commit activity

Wicket in ActionWicket Cookbook

book writing has caused quite a dent

in our Wicket related activities:!

burn-out plays a major part.

Page 43: The State of Wicket

In a Nutshell, Wicket...

– Ohloh report for Wicket

Page 44: The State of Wicket

In a Nutshell, Wicket...

… has had 17,645 commits made by 52 contributors representing 314,959 lines of code

– Ohloh report for Wicket

Page 45: The State of Wicket

In a Nutshell, Wicket...

… has had 17,645 commits made by 52 contributors representing 314,959 lines of code

… is mostly written in Java witha well-commented source code

– Ohloh report for Wicket

Page 46: The State of Wicket

In a Nutshell, Wicket...

… has had 17,645 commits made by 52 contributors representing 314,959 lines of code

… is mostly written in Java witha well-commented source code

… has a well established, mature codebase maintained by a large development team with stable Y-O-Y commits

– Ohloh report for Wicket

Page 47: The State of Wicket

In a Nutshell, Wicket...

… has had 17,645 commits made by 52 contributors representing 314,959 lines of code

… is mostly written in Java witha well-commented source code

… has a well established, mature codebase maintained by a large development team with stable Y-O-Y commits

… took an estimated 83 years of effort (COCOMO model) starting with its first commit in September, 2004ending with its most recent commit 2 days ago– Ohloh report for Wicket

Page 48: The State of Wicket

Wicket 1.4

security fixes only

Page 49: The State of Wicket

Wicket 1.5

security fixes only

Page 50: The State of Wicket

Wicket 6continues to be released along

side Wicket 7, monthlies will

transform into bi-monthlies when

number of resolved tickets subsides.

Page 51: The State of Wicket

Java 6

Page 52: The State of Wicket

semantic versioning

Works wonderful for us. Only snag: JQuery updates.

Page 53: The State of Wicket

Monthly releases

also wonderful: no longer waiting for a long time for a fixed bug.

Page 54: The State of Wicket

Wicket 7

not much to say about Wicket 7: no major API changes.

Page 55: The State of Wicket

Java 7

Page 56: The State of Wicket

Servlet 3

Page 57: The State of Wicket

Minor API breaks

Page 58: The State of Wicket

Wicket 8Anything written here is just

speculation from my side. This is not set in stone, this is not how

we are going to implement things, or quite reasonably at all.

Page 59: The State of Wicket

Java 8

Page 60: The State of Wicket

PROJECT LAMBDA

“functional” programming in Java

Page 61: The State of Wicket

@FunctionalInterface public interface ILinkListener { void onLickClicked(); }

Page 62: The State of Wicket

ILinkListener l = new ILinkListener() { @Override public void onLinkClicked() { System.out.println("Klik"); } }

Page 63: The State of Wicket

ILinkListener l = () -> { System.out.println("Klik"); }

Page 64: The State of Wicket

ILinkListener l = new ILinkListener() { @Override public void onLinkClicked() { System.out.println("Klik"); } }

-of- !ILinkListener l = () -> { System.out.println("Klik"); }

Page 65: The State of Wicket

add(new Link<Void>("save") { @Override public void onClick() { dao.save(object); getSession().info("Saved."); setResponsePage(new OtherPage()) } });

Page 66: The State of Wicket

add(new Link<Void>("save") { @Override public void onClick() { dao.save(object); getSession().info("Saved."); setResponsePage(new OtherPage()) } });

Page 67: The State of Wicket

add(new Link<>("save").onClick(()-> { dao.save(object); getSession().info("Saved."); setResponsePage(new OtherPage()); });

Page 68: The State of Wicket

private void onSave() { dao.save(object); getSession().info("Saved."); setResponsePage(new OtherPage()) } !!!!!!

Page 69: The State of Wicket

private void onSave() { dao.save(object); getSession().info("Saved."); setResponsePage(new OtherPage()) } !!add(new Link<Void>("save") .onClick(this::onSave); !!

Page 70: The State of Wicket

A link with onclick, visibility and body

Page 71: The State of Wicket

add(new Link<Void>("like") { @Override public void onClick() { person.likedBy(me); } @Override public boolean isVisible() { return person.isNotLiked(); } }.setBody(new AbstractReadOnlyModel<String>() { @Override public String getObject() { StringBuilder sb = new StringBuilder("Like "); sb.append(person.getFirstName()); return sb.toString(); } }));

Page 72: The State of Wicket

add(new Link<Void>("like") { @Override public void onClick() { person.likedBy(me); } @Override public boolean isVisible() { return person.isNotLiked(); } }.setBody(new AbstractReadOnlyModel<String>() { @Override public String getObject() { StringBuilder sb = new StringBuilder("Like "); sb.append(person.getFirstName()); return sb.toString(); } }));

Page 73: The State of Wicket

add(new Link<Void>("like") { @Override public void onClick() { person.likedBy(me); } @Override public boolean isVisible() { return person.isNotLiked(); } }.setBody(new AbstractReadOnlyModel<String>() { @Override public String getObject() { StringBuilder sb = new StringBuilder("Like "); sb.append(person.getFirstName()); return sb.toString(); } }));

Page 74: The State of Wicket

add(new Link<Void>("like") { @Override public void onClick() { person.likedBy(me); } @Override public boolean isVisible() { return person.isNotLiked(); } }.setBody(new AbstractReadOnlyModel<String>() { @Override public String getObject() { StringBuilder sb = new StringBuilder("Like "); sb.append(person.getFirstName()); return sb.toString(); } }));

Page 75: The State of Wicket

add(new Link<Void>("like") { @Override public void onClick() { person.likedBy(me); } @Override public boolean isVisible() { return person.isNotLiked(); } }.setBody(new AbstractReadOnlyModel<String>() { @Override public String getObject() { StringBuilder sb = new StringBuilder("Like "); sb.append(person.getFirstName()); return sb.toString(); } }));

Page 76: The State of Wicket

add(new Link<Void>("like") { @Override public void onClick() { person.likedBy(me); } @Override public boolean isVisible() { return person.isNotLiked(); } }.setBody(new AbstractReadOnlyModel<String>() { @Override public String getObject() { StringBuilder sb = new StringBuilder("Like "); sb.append(person.getFirstName()); return sb.toString(); } }));

Page 77: The State of Wicket

add(new Link<Void>("like") { @Override public void onClick() { person.likedBy(me); } @Override public boolean isVisible() { return person.isNotLiked(); } }.setBody(new AbstractReadOnlyModel<String>() { @Override public String getObject() { StringBuilder sb = new StringBuilder("Like "); sb.append(person.getFirstName()); return sb.toString(); } }));

Page 78: The State of Wicket

A link with onclick, visibility and body

Page 79: The State of Wicket

add(new Link<>("like") .visible(() -> person.isNotLiked()) .onClick(() -> person.likedBy(me)) .body(() -> { StringBuilder sb = new StringBuilder("L sb.append(person.getFirstName()); return sb.toString(); }) );

Page 80: The State of Wicket

add(new Link<>("like") .visible(() -> person.isNotLiked()) .onClick(() -> person.likedBy(me)) .body(() -> { StringBuilder sb = new StringBuilder("L sb.append(person.getFirstName()); return sb.toString(); }) );

Page 81: The State of Wicket

add(new Link<>("like") .visible(() -> person.isNotLiked()) .onClick(() -> person.likedBy(me)) .body(() -> { StringBuilder sb = new StringBuilder("L sb.append(person.getFirstName()); return sb.toString(); }) );

Page 82: The State of Wicket

add(new Link<>("like") .visible(() -> person.isNotLiked()) .onClick(() -> person.likedBy(me)) .body(() -> { StringBuilder sb = new StringBuilder("L sb.append(person.getFirstName()); return sb.toString(); }) );

Page 83: The State of Wicket

add(new Link<>("like") .visible(() -> person.isNotLiked()) .onClick(() -> person.likedBy(me)) .body(() -> { StringBuilder sb = new StringBuilder("L sb.append(person.getFirstName()); return sb.toString(); }) );

Page 84: The State of Wicket

add(new Link<>("like") .visible(() -> person.isNotLiked()) .onClick(() -> person.likedBy(me)) .body(() -> { StringBuilder sb = new StringBuilder("L sb.append(person.getFirstName()); return sb.toString(); }) );

Page 85: The State of Wicket

Anon inner classes: 17 lines Java 8 lambdas: 9 lines

add(new Link<Void>("like") { @Override public void onClick() { person.likedBy(me); } @Override public boolean isVisible() { return person.isNotLiked(); } }.setBody(new AbstractReadOnlyModel<String>() { @Override public String getObject() { StringBuilder sb = new StringBuilder("Like "); sb.append(person.getFirstName()); return sb.toString(); } }));

add(new Link<>("like") .visible(() -> person.isNotLiked()) .onClick(() -> person.likedBy(me)) .body(() -> { StringBuilder sb = new StringBuilder("L sb.append(person.getFirstName()); return sb.toString(); }) ); !!!!!!!!

Page 86: The State of Wicket

nashorn

Page 87: The State of Wicket

JavaScript validation

Page 88: The State of Wicket

ScriptEngineManager m = new ScriptEngineManager(); !ScriptEngine nashorn = m.getEngineByName("nashorn"); !nashorn.put("age", validatable.getValue()); String js = "age >= 18"; !try { Object result = nashorn.eval(js); if(!((Boolean)result) { ValidationError e = new ValidationError(); validatable.error(e); } } catch(Exception e) { }

Page 89: The State of Wicket

ScriptEngineManager m = new ScriptEngineManager(); !ScriptEngine nashorn = m.getEngineByName("nashorn"); !nashorn.put("age", validatable.getValue()); String js = "age >= 18"; !try { Object result = nashorn.eval(js); if(!((Boolean)result) { ValidationError e = new ValidationError(); validatable.error(e); } } catch(Exception e) { }

Page 90: The State of Wicket

ScriptEngineManager m = new ScriptEngineManager(); !ScriptEngine nashorn = m.getEngineByName("nashorn"); !nashorn.put("age", validatable.getValue()); String js = "age >= 18"; !try { Object result = nashorn.eval(js); if(!((Boolean)result) { ValidationError e = new ValidationError(); validatable.error(e); } } catch(Exception e) { }

Page 91: The State of Wicket

ScriptEngineManager m = new ScriptEngineManager(); !ScriptEngine nashorn = m.getEngineByName("nashorn"); !nashorn.put("age", validatable.getValue()); String js = "age >= 18"; !try { Object result = nashorn.eval(js); if(!((Boolean)result) { ValidationError e = new ValidationError(); validatable.error(e); } } catch(Exception e) { }

Page 92: The State of Wicket

ScriptEngineManager m = new ScriptEngineManager(); !ScriptEngine nashorn = m.getEngineByName("nashorn"); !nashorn.put("age", validatable.getValue()); String js = "age >= 18"; !Object result = nashorn.eval(js); try { if(!((Boolean)result) { ValidationError e = new ValidationError(); validatable.error(e); } } catch(Exception e) { }

Page 93: The State of Wicket

ScriptEngineManager m = new ScriptEngineManager(); !ScriptEngine nashorn = m.getEngineByName("nashorn"); !nashorn.put("age", validatable.getValue()); String js = "age >= 18"; !Object result = nashorn.eval(js); if(!((Boolean)result) { ValidationError e = new ValidationError(); validatable.error(e); } try { } catch(Exception e) { }

Page 94: The State of Wicket

ScriptEngineManager m = new ScriptEngineManager(); !ScriptEngine nashorn = m.getEngineByName("nashorn"); !nashorn.put("age", validatable.getValue()); String js = "age >= 18"; !try { Object result = nashorn.eval(js); if(!((Boolean)result) { ValidationError e = new ValidationError(); validatable.error(e); } } catch (Exception e) { }

Page 95: The State of Wicket

ScriptEngineManager m = !ScriptEngine nashorn = m.getEngineByName(!nashorn.put(String js = !try Object result = nashorn.eval(js); ValidationError e = new ValidationError() validatable.error(e); } } }

This was only a proof-of-concept. This probably won’t ever fly due to business entities residing on

server, and difficult to share those in browser, including I18N

messages.

Page 96: The State of Wicket

java.timesupport for this will be for

converters, validations and possibly wicket-datetime

Page 97: The State of Wicket

RoadmapAnything written here is just

speculation from my side. This is not set in stone. Dates are mere

guidelines.

Page 98: The State of Wicket

Monthly releases

Page 99: The State of Wicket

6.14 6.15

7.0-M17.0-M2

7.0

6.18

feb mar may

2014

7.1

6.19

jun

Page 100: The State of Wicket

7.9 7.10

8.0-M18.0-M2

8.0

7.12

feb mar may

2015

8.1

7.13

jun

Page 101: The State of Wicket

git organization

Page 102: The State of Wicket

master wicket-1.0.x wicket-1.1.x wicket-1.2.x wicket-1.3.x wicket-1.4.x wicket-1.5.x wicket-6.x !

Current organisation of our repository: master is new development, rest

is maintenance.

Page 103: The State of Wicket

master wicket-1.0.x wicket-1.1.x wicket-1.2.x wicket-1.3.x wicket-1.4.x wicket-1.5.x wicket-6.x !

wicket 7.x!

Current organisation of our repository: master is new development, rest

is maintenance.

Page 104: The State of Wicket

master wicket-1.0.x wicket-1.1.x wicket-1.2.x wicket-1.3.x wicket-1.4.x wicket-1.5.x wicket-6.x wicket-7.x wicket-8.x

proposed layout: no more master, but just product branches.

Page 105: The State of Wicket

experimental modulesJay! Many experimental modules have been upgraded to core modules! beanvalidation, CDI-1.1, web sockets will be part of Wicket core from 6.14 and onwards.

Page 106: The State of Wicket

org.apache.wicket.experimental.wicket-6.x wicket-atmosphere wicket-bootstrap wicket-new-examples !org.apache.wicket.experimental.wicket-7.x wicket-atmosphere wicket-cdi-1.1

Remaining experimental modules

Page 107: The State of Wicket

org.apache.wicket.experimental.wicket-6.x wicket-atmosphere wicket-bootstrap wicket-new-examples !org.apache.wicket.experimental.wicket-7.x wicket-atmosphere wicket-cdi-1.1

No more bootstrap: bootstrap is

just a resource reference to

JavaScript and CSS. Write your

own (~10 lines of code) or use

L0rdn1kk0n’s bootstrap wicket component library.

new examples: no time to do anything useful with them.

Page 108: The State of Wicket

org.apache.wicket.experimental.wicket-6.x wicket-atmosphere !!org.apache.wicket.experimental.wicket-7.x wicket-atmosphere !

Wic

ket 6

.xW

icke

t 7.x

How to separate the same experimental modules in multiple

product lines?

Page 109: The State of Wicket

org.apache.wicket.experimental.wicket-6.x wicket-atmosphere !!org.apache.wicket.experimental.wicket-7.x wicket-atmosphere !

Wic

ket 6

.xW

icke

t 7.x

Make the groupId specific to the product line, keep code as similar as possible.

Page 110: The State of Wicket

The state of Apache Wicket:

Page 111: The State of Wicket

The state of Apache Wicket:

HEALTHY

Page 112: The State of Wicket

DEVELOPERS

ENTERDEVpowered by Topicus