Founded in 2010 by former Swedbank developers
Acquired Hansabank, a very innovative bank of 2000s
After 2008 closed many branches/ATMs
In Estonia, most banking business is online
Ural Reconstruction and Development Bank
GlobalFinance / Markswebb awards
produce simpler code
easier to customize
more reliable
you can fix it in case of urgent problems
Makes you write more code
Makes your app slow
Makes debugging hard
Makes sysadmin's life harder
If it breaks, it is broken
A platform for online banks
Private + Corporate + Mobile + Web site
Java 8 / Play Framework 1.3
Rails, Django inspired
We use newly-released v1.3
not 2.x, which is for Scala
Fresh, no bullshit, anti-enterprise
Writing few code that also works
Full-stack, quick start
Influenced our architecture a lot
"Hit refresh" workflow
(You can use springloaded in your own project)
Play 2 is much slower at that
Disadvantage: it recompiles code itself
Good/Bad: so-called "Magic", or enhancers
Tries to make Java a better language
Properties, less boilerplate
Config files with support for environments
db.url=jdbc:h2:mem
%prod.db.url=jdbc:oracle:thin:blahblah
Localization files (multilanguage support)
Own HTTP server (based on Netty)
play start
play stop
No even servlets :-)
Signed cookies
String-only up to 4kb
No server state
Deployment during working hours!
Better back button support
+ Flash
Async support
Inspired by Node.js
await(WS.url("http://blah").getAsync())
Returns request thread to the pool
Serves all static files asynchronously
But, hard to call DB stored procedures that way
For asynchronous stuff
And processing (e.g. deferred and recurrent payments)
new DeferredPaymentProcessor(payment).now();
or
@Every("5mn")
public class DeferredPaymentProcessor extends Job { ... }
Dependency management (using ivy)
Many 3rd-party ones (e.g. pdf, excel)
And we write our own (logging, testing, cms)
Most stuff can be customized/redefined
e.g. ModuleInheritingPlugin
Alive and open-source @github
MVC is much easier than single-page apps
If needed, write modular JS/AJAX
Less & Autoprefixer for CSS
.book {
padding-top: @defaultPadding + 10px;
.title {
font-weight: bold;
transform: scale(1.2);
}
}
ActiveRecord pattern on top of JPA/Hibernate
User user = User.find("byUsername").first();
user.lastLoginTime = now();
user.save();
save() must be explicit
Hibernate in JPA mode (no detached save)
@DynamicUpdate
Play evolutions are good
We use Liquibase (via plugin)
<changeSet id="123" author="Codeborne">
<addColumn table="users">
<column name="lastLoginAt" type="timestamp"/>
</addColumn>
</changeSet>
Supports almost any database
We share most (but not all) changesets between banks
Changesets must be backwards-compatible
Necessary evil
Abstraction layer between ibank and the backend(s)
ibank -> service -> banking system
MVC -> MVSC :-)
@Inject CardService cardService;
...
List<Card> cards = cardService.activeCards(customer);
class BankOne extends Module {
public void configure() {
bind(CardService.class).to(BankOneBackendCardService.class);
}
}
class Demo extends Module {
public void configure() {
bind(CardService.class).to(DemoCardService.class);
}
}
Services are non-abstract classes
Integrations, customizations
In every bank, there are plenty:
Core system (ABS)
Card/processing system
CRM
Forex
Customer support
Loyalty program
Partners
etc, etc, etc
More integrations - harder to be reliable
Parallel development is hard with non-agile devs
soapService.request("Cards").param("CustomerID", 123L).send();
No code generation!
No problems with SOAP 1.0, 1.1, 1.2 interoperation
dbService.query("get_customer", 123L);
Unfortunately, many of these (over)use XML
DOM and xpath are slow: custom SAX-based XML parser
new XMLParser((path, value) -> {
switch (path) {
case "messages/message": message = new Message(); break;
case "messages/message/@id": message.id = value; break;
case "messages/message/subject": message.subject = value; break;
}
}).parse(xml);
Template-based generation
${beneficiaryAccount}
${beneficiaryName}
${amount}
${currency}
You can even use it for more bizarre SOAP requests :-)
(Unit-)Test Driven Integration
Almost like TDD
Alternative inverse integration
(Bank implements our spec)
GET /customers/123
GET /customers/123/accounts
GET /customers/123/accounts/123123123123/transactions
Automated testing tool with warnings and errors
Hard to make changes in the spec
Caching via Guice interceptors
bindInterceptor(any(), annotatedWith(CacheFor.class), this);
Memcached
Prefetching jobs
Fault-protection
Health monitor
Temporary storage
Deferred executor jobs
Merge data from multiple sources
All in the name of UX
CSS first
Services
You can override any file in sub-module
You can write 100% custom code
No architectural restrictions
(besides discouraging of copy-paste)
Essential part of knowing that your code (still) works
Good: testing is part of Play
Bad: Rails-style "boot-up-everything" tests
Slow + Not great for TDD
1500 tests, 4-5 mins
Run all during every build
Optimizations + Parallel execution
Fast, preferred
Business logic and all special cases
Mockito helps
userService = mock(UserService.class, RETURNS_DEEP_STUBS);
when(userService.user("bob").getFullName()).thenReturn("John");
Slower, for "happy paths"
Selenide helps
$(By.name("username")).val("bob");
$(By.name("password")).val("secret");
$("#login-button").click();
$(".page.overview").should(appear);
In-memory DB: H2
Play supports initial data via Fixtures
Restore state before each test
Demo integration
Most developers don't log properly
Compact
Machine-readable
Completely traceable
Multiple files
Request ID / Thread ID
Durations
Java stack traces only when needed
Play: Self4J over Log4J
grep/awk are your best friends
Jenkins
Compile + compress resources + unit tests + ui tests
Any green build can go to production
2 servers
Stateless: deployment during working hours
Simple DNS-based load balancing
No loss of sessions
Most of our customers had a previous online bank
With some users
Transition period
Continuous data migration
git-based
Play modules & Selenide: github.com/codeborne
Slides: angryziber.github.io/slides
Sounds fun? job@codeborne.com