vanetænkning - mønstre for it skuffelse og fiasko
DESCRIPTION
Præsentation i 3 dele der afdækker problemet med Vanetænkning i IT, løsninger på hvordan man kan bryde vanen og dermed skabe grundlaget for IT drevet vækst. Til sidst deler vi erfaringerne fra implementering af vores foreslag i forbindelse med Elektronisk Tinglysnings projektet.TRANSCRIPT
VanetænkningMønstre for IT skuffelse og fiasko
Virksomheders vækst bremses af mangel på finansiering
Berlingske Finans
6 ud af 10 offentlige projekter går over tid og budget
Version2
Hvor står jeres virksomhed?
• Bliver jeres IT projekter leveret til tiden, på budget og med den rette funktionalitet?
• Kører jeres IT systemer problemfrit og stabilt?• Indeholder jeres systemlandskab flere
applikationer der udfører samme eller lignende opgaver?
• Outsourcer/Offshorer I de rigtige opgaver (eller laver I de rigtige opgaver in-house)?
Hvor står jeres virksomhed?
• Er IT projekterne afstemt med forretningens behov?
• Er forretningen aktivt involveret i IT projekterne og investeringerne?
• Balancerer I hele organisationens behov med de individuelle forretningsbehov mht. arkitektur og infrastruktur ?
Virker det her bekendt?
Hvert nyt projekt starter fra scratch
PRODUKT SYN
Vi har behov for et samlet kundeoverblik
Implementer Siebel CRM i Call centeret
Vi skal have bedre styr på vores krav
Køb og installer HP Quality Center
Vi skal have en Service Orienteret arkitektur
Byg en løsning der benytter Web Services i Oracle Service Bus/SeeBeyond/…
SOA
Web Services
Requirement Management tools
BPM
N
Layere
d A
rch
itect
ure
Web
Sp
here
Work
flow
syst
em
Sh
are
Poin
t
Oracle Service bus
Team Foundation
Server
Sub
Vers
ion
Documentum
Portal
Ora
cle
DB
MS
SQ
L S
erv
er
NoS
QL
Policy Manager
WebLogic
.NET
JAVA
Ruby on Rails
iOS
Android
XML
JavaScript
Flash
BlackBerryGit
Hg
Dart
Cloud
Spring
Biz
Talk
Gro
ovy
Sca
la
F#C
#V
B.N
ET
REST
Typisk management tankegang
• Vi vælger de værktøjer og den arkitektur, som Gartner anbefaler
• Flere resourcer på et projekt = Jo hurtigere bliver vi færdige
• 100 udenlandske udviklere er bedre en 10 lokale, selv om den samlede pris er ens
The Silver Bullet
Alt dette medfører
• Høj kompleksitet og et fragmenteret system landskab
• Stort behov for produkt specialister der ikke kan gå på tværs af projekter• Risiko for at hyre vanetænkere i stedet for
tekniske domæne eksperter
Behov for mange ressourcer på projekterne og derfor høje omkostninger
Same procedure as last year?
Same procedure as every year!!!
For!!!
• “Vi har ikke tid til at se på nye teknologier”• “Det kræver flere ressourcer og penge”• “Vi har prøvet og det fungerede ikke”• “Vi er opmærksomme på at vi har
udfordringer”• ”Vi _______________________________”
(Indsæt selv undskyldning)
Åben for nye ideer?
Hvis det tager 1 mand 10 dage at grave et telefonkabel ned, hvor mange mand skal jeg så bruge hvis jeg vil ha det gjort på 2 dage?
5 mand i Danmark
10 mand i Indien. Halv tid og oven i købet til halv pris
Trådløst netværk
Slår du stadigvæk din kone?
Sådan spørger vi oftest
• Hvor kan jeg få 200 udviklere til mit projekt?• Hvor kan jeg få dem billigst?• Hvordan skalerer jeg min tekniske platform til
200 udviklere?• Hvordan styrer jeg så store teams over et langt
projektforløb?
Sådan burde vi spørge
• Hvorfor har jeg behov for 200 udviklere?• Hvordan ville jeg gøre hvis jeg “kun” havde:– 30 udviklere– 3 måneder og ikke 3 år til projektet
• Har jeg behov for distribuerede teams?
Hvordan?Hvad?Hvorfor?
Er løsningen Offshoring
• 10 tekniske domæne eksperter i Danmark til 1000 kr. i timen = 10.000 kr. i timen
• 100 udviklere i Kina/Indien til 200 kr. i timen = 20.000 kr. i timen
Lidt som at købe apps på AppStore det koster jo kun 6 kr.
Projekt økonomi
Produktivitet
Administrativ overhead
Produktivitet
Administrativ overhead
10 tekniske domæne eksperter100 udviklere
Desperation
Inspiration
Desperation
Agenda
• 16:00: Intro v. Diego Børresen Lladó. IDA-IT
• 16:05: Vanetænkning v. Henrik Wivel
• 16:30: Sådan kan vi gøre noget ved det v. Jeppe Cramon
• 17:00: Pause
• 17:20: Elektronisk Tinglysning v. Jeppe Cramon
• 17:55: Tak for god ro og orden
LøsningerMønstre for IT skuffelse og fiasko
Her er løsningerne!
SCRUMXP
LEANAgile
Outsourcing
Hvad var liiiiige vi ville opnå?
At komme tættere på forretningen
Status Quo
Vi har behov for et stærkt fundament for udviklingTi
lpas
ning
Meg
et ti
lpas
set
Lidt
tilp
asse
t
EffektivitetLidt effektiv Meget effektiv
”Vedligeholdelses Zonen” ”Velsmurt IT Maskine”
”Tilpasnings fælden”
11%
74%
7%
8%
% af de 504 adspurgte
+13
-14
-2 -15
+11
-6
+35
”IT understøttet vækst”
% forskel i forhold til det samlede gennemsnit IT udgifterSamlet årlig vækstrateindenfor en 3 årig periode
Kild
e: B
ain
Anal
ysis
+0
Et stærkt fundament er!
• Enkel arkitektur• Arbejdsopgaver og data ejes af ét system• Automatisering• Tests
En IKKE enkel arkitekturKlient
Remote Facade
Applikations Service
Data Access Layer
Data Storage
Domæne Objekt
Domæne Objekt
Data Storage
Data Storage
Data Storage
DataService
DataService
DataService
AktivitetsService
AktivitetsService
Proces Service Proces Service
Klient Klient
Klient
DataService
Det her hjælper heller ikke
En stor Fælles-Model er det enhver arkitekt drømmer om i sin rus
Men som de siger
EN MODEL TIL AT HERSKE OVER DEM ALLE
EN MODEL TIL AT FINDE DEM
EN MODEL TIL AT HENTE DEM ALLE
OG MORKET FORENE DEM/
Stadig en stor model
Kunder
Online Ordering System
Priser
Lager
Salg
Product
Unit PricePromotional PricePromotion End Date
Stock Keeping Unit (SKU)Quantity On Hand (QOH)Location Code
PriceQuantity Ordered
Description
Der er altid flere modeller i spil i store projekter
Men når kode baseret på forskellige modeller kombineres
...
… bliver koden fyldt med fejl, upålidelig og vanskelige at forstå
Kommunikation mellem teammedlemmer bliver forvirrende.
Det er ofte uklart, i hvilken sammenhæng en model IKKE bør
anvendes!
Der mangler kontekst
Mindre modeller og ”genbrug”Enterprise
Web ShopProduct
SKUDescriptionPriceQuantity Ordered… Inventory Service (SAP)
ProductSKUDescriptionQOHLocation Code…
Pricing ServiceProduct
SKUUnit PricePromotional Price…
Lager
Priser
Salg
Kunder
Nu endnu bedre – med ESBEnterprise
Web ShopProduct
SKUDescriptionPriceQuantity Ordered… Inventory Service (SAP)
ProductSKUDescriptionQOHLocation Code…
Pricing ServiceProduct
SKUUnit PricePromotional Price…
Inventory
Pricing
Salg
Kunder
Enterprise Service Bus
Ny og
forbedret
opskrift
Pas på! Det er så nemt at se et produkt som løsningen på alle ens problemer!
Før havde vi 1 problem.Med ESB’en har vi nu 2 problemer
Der mangler stadig forretnings fokus
Processer og tilstandsændringer er vigtige bestanddele
En meget bedre opskrift…Enterprise
Web ShopProduct
SKUDescriptionPriceQuantity Ordered… Inventory Service (SAP)
ProductSKUDescriptionQOHLocation Code…
Pricing ServiceProduct
SKUUnit PricePromotional Price…
Lager
Priser
Salg
Kunder
New SKU Event
New SKU Event
New SKU Event
New SKU Price EventNew SKU
Price Event
Mes
sage
Bus
Hvad er et stærkt fundament?
• Enkel arkitektur• Arbejdsopgaver og data ejes af ét system• Automatisering• Tests
Kort fortalt…
• Få ryddet op i system landskabet…• Fjern overflødige systemer• Fjern systemer der ikke længere har en fornuftig
cost-benefit• Moderniser systemer der stadig kan gøre en forskel• Byg nye systemer der kan differentiere jer fra
resten• …og gør det med udgangspunkt i Neil Nickolaisen’s
Purpose Alignment Model
Neil Nickolaisen’s Purpose Alignment Model
VigtighedLav Høj
Lad det være som det er Hold på niveau medkonkurrenterne
PartnerskabInvester
og differentier
MarkedsDifferentierings
grad
Høj
Lav
Hvad er et stærkt fundament?
• Enkel arkitektur• Arbejdsopgaver og data ejes af ét system• Automatisering• Tests
Automatisering
• Continuous Integration– Koden bliver automatisk bygget og nødvendige
tests bliver udført for verifikation• Opsætning af miljøer– Server opsætning, firewalls, deployment
• Integrations test• der er meget mere at hente her…
Løsningen i ETL
Elektronisk Tinglysning
Baggrundsinformation om Elektronisk Tinglysning for dem der ikke har hørt om det…
ETL – Foreslået Arkitektur
Database
DataService
DataService
DataService
AktivitetsService
AktivitetsService
Proces Service Proces Service
Intern Portal Ekstern Portal
Integrations Service
IntegrationsService
Ora
cle
Serv
ice
Bus
WebLogic Portal
Foreslået ETL Arkitektur
• Fordele– Logisk set en fornuftig afkobling (Single Responsibility
Principle)– Oracle tjener godt
• Ulemper– Logiske lag er blevet til fysiske lag– Høj kompleksitet– Svært at finde ressourcer der kan arbejde med OSB’en– Stabilitet– Performance (både runtime og for udviklerne)– Deployment
ETL – Simplificering af Arkitekturen
Database
Intern Portal Ekstern Portal
Integrations Service
IntegrationsService
Web
Logi
c Se
rver
Data Access Layer
Rige Domæne objekter
Rige domæne objekter
Forretnings Service Forretnings Service
Portal Facade
Java applikationer
Simplificeret ETL Arkitektur
• Fordele– Fysisk og logisk arkitektur er tættere på hinanden– Lav kompleksitet– Stabilitet– Nemmere at finde ressourcer der kan kode Java– Performance (både runtime og for udviklerne)– Deployment
• Ulemper– CV’et bliver ikke boostet med Enterprise Service Bus– Oracle tjener ikke nær så godt…
ETL - Automatisering
• Yderst komplekst domæne område• Reglerne er bestemt af Jura (og ikke logik)• Dækker tinglysninger der er flere hundrede år
gamle• Kompleks logik er påkrævet for at
automatisere jura• Meget kort deadline for 3. forsøg på at bygge
ETL
Elektronisk Tinglysning
• Teknisk valg– Programmeringssprog: Java– Database: Oracle
• Udfordring – Hvordan binder vi Java og Oracle databasen
sammen?
Sådan plejer man at gøre
Java kode
SQL
Betyder at man går fra dette
package dk.tigerteam.mdsd.demo.model.internal;
@Entity@Table(name = "Customer")public class Customer extends AbstractEntity { private static final long serialVersionUID = 2098912667L;
@Basic @Column(name = "name", nullable = false) private String name;
@OneToOne(cascade = { CascadeType.MERGE, CascadeType.PERSIST, CascadeType.REFRESH}, fetch = FetchType.LAZY) @JoinColumn(name = "addressId") @NotNull private dk.tigerteam.mdsd.demo.model.internal.Address address;
@OneToMany(cascade = { CascadeType.MERGE, CascadeType.PERSIST, CascadeType.REFRESH}, targetEntity = Booking.class, mappedBy = "customer", fetch = FetchType.LAZY) private Set<Booking> bookingCollection = new java.util.HashSet<Booking>();
public String getName() { return name; }
public void setName(String name) { this.name = name; } … … … … … … … … … …
}
package dk.tigerteam.mdsd.demo.mode.internal; @Entity@Table(name = "Booking")public class Booking extends AbstractEntity { private static final long serialVersionUID = 170080605L;
@Basic @Column(name = "comment", nullable = false) private String comment;
@Basic @Temporal(TemporalType.TIMESTAMP) @Column(name = "time", nullable = false) private java.util.Date time;
@Basic @Column(name = "timeslot", nullable = false) private int timeslot;
@ManyToOne(cascade = { CascadeType.MERGE, CascadeType.PERSIST, CascadeType.REFRESH}, fetch = FetchType.LAZY) @JoinColumn(nullable = false, name = "customerId") private Customer customer;
public String getComment() { return comment; }
public void setComment(String parameter) { this.comment = parameter; }
public java.util.Date getTime() { return time; } … … … … … … …
}
@Entity@Table(name = "Address")public class Address extends AbstractEntity { private static final long serialVersionUID = 1697028161L;
@Basic @Column(name = "street", nullable = false) private String street;
@Basic @Column(name = "zipCode", nullable = false) private String zipCode;
@Basic @Column(name = "city", nullable = false) private String city;
public String getStreet() { return street; }
public void setStreet(String parameter) { this.street = parameter; } … … …}
Til dette…
Forskellen mellem at mudre og modellere i håndskrevet Java er meget lille
Kan du heller ikke se skoven for bare træer?package dk.tigerteam.mddexample.model.customer;
@javax.persistence.Entitypublic class Customer extends dk.tigerteam.mddexample.model.user.User { private static final long serialVersionUID = 1328488396L;
@javax.persistence.Lob @javax.persistence.Basic @javax.persistence.Column(name = "comment") private String comment;
@javax.persistence.Embedded @javax.persistence.AttributeOverrides({@javax.persistence.AttributeOverride(name = "firstName",column = @javax.persistence.Column(name = "name_firstName") ) , @javax.persistence.AttributeOverride(name = "lastName",column = @javax.persistence.Column(name = "name_lastName") ) }) private dk.tigerteam.mddexample.model.customer.Name name;
@javax.persistence.Embedded @javax.persistence.AttributeOverrides({@javax.persistence.AttributeOverride(name = "street", column = @javax.persistence.Column(name = "address_street") ) , @javax.persistence.AttributeOverride(name = "state",column = @javax.persistence.Column(name = "address_state") ) , @javax.persistence.AttributeOverride(name = "zipCode",column = @javax.persistence.Column(name = "address_zipCode") ) , @javax.persistence.AttributeOverride(name = "city",column = @javax.persistence.Column(name = "address_city") ) , @javax.persistence.AttributeOverride(name = "country",column = @javax.persistence.Column(name = "address_country") ) }) private dk.tigerteam.mddexample.model.customer.Address address;
@javax.persistence.OneToMany(cascade = { javax.persistence.CascadeType.MERGE, javax.persistence.CascadeType.PERSIST, javax.persistence.CascadeType.REFRESH} , targetEntity = dk.tigerteam.mddexample.model.customer.Pet.class, mappedBy = "customer", fetch = javax.persistence.FetchType.LAZY) private java.util.Set<dk.tigerteam.mddexample.model.customer.Pet> petCollection = new java.util.HashSet<dk.tigerteam.mddexample.model.customer.Pet>();
@javax.persistence.OneToMany(cascade = { javax.persistence.CascadeType.MERGE, javax.persistence.CascadeType.PERSIST, javax.persistence.CascadeType.REFRESH} , fetch = javax.persistence.FetchType.LAZY) @javax.persistence.JoinTable(name = "Customer_invoice", joinColumns = @javax.persistence.JoinColumn(name = "CustomerId") , inverseJoinColumns = @javax.persistence.JoinColumn(name = "invoiceId") ) private java.util.Set<dk.tigerteam.mddexample.model.invoice.Invoice> invoiceCollection = new java.util.HashSet<dk.tigerteam.mddexample.model.invoice.Invoice>();
@javax.persistence.OneToMany(cascade = { javax.persistence.CascadeType.MERGE, javax.persistence.CascadeType.PERSIST, javax.persistence.CascadeType.REFRESH} , fetch = javax.persistence.FetchType.LAZY) @javax.persistence.JoinTable(name = "Customer_appointment", joinColumns = @javax.persistence.JoinColumn(name = "CustomerId") , inverseJoinColumns = @javax.persistence.JoinColumn(name = "appointmentId") ) private java.util.Set<dk.tigerteam.mddexample.model.customer.Appointment> appointmentCollection = new java.util.HashSet<dk.tigerteam.mddexample.model.customer.Appointment> ();
public String getComment() { return comment; }
public void setComment(String parameter) { this.comment = parameter; }
public dk.tigerteam.mddexample.model.customer.Name getName() { return name; }
public void setName(dk.tigerteam.mddexample.model.customer.Name parameter) { this.name = parameter; }
public dk.tigerteam.mddexample.model.customer.Address getAddress() { return address; }
public void setAddress( dk.tigerteam.mddexample.model.customer.Address parameter) { this.address = parameter; }
public java.util.Set<dk.tigerteam.mddexample.model.customer.Pet> getPetCollection() { return petCollection; }
public java.util.Set<dk.tigerteam.mddexample.model.invoice.Invoice> getInvoiceCollection() { return invoiceCollection; }
public void setInvoiceCollection( java.util.Set<dk.tigerteam.mddexample.model.invoice.Invoice> parameter) { this.invoiceCollection = parameter; }
public java.util.Set<dk.tigerteam.mddexample.model.customer.Appointment> getAppointmentCollection() { return appointmentCollection; }
public void setAppointmentCollection( java.util.Set<dk.tigerteam.mddexample.model.customer.Appointment> parameter) { this.appointmentCollection = parameter; }}
Versus det du ønskede at kommunikere
Håndholdt konsistens…
@Entitypublic class Customer { @OneToMany( targetEntity = Pet.class, mappedBy = "customer” ) private Set<Pet> petCollection = new HashSet<Pet>();
public Set<Pet> getPetCollection() { return new OneToManySetWrapper<Customer, Pet>(this, petCollection) { @Override protected Customer getOneSideObjectInManySideObject(Pet manySideObject) { return manySideObject.getCustomer(); }
@Override protected void setOneSideObjectInManySideObject(Pet manySideObject, Customer oneSideObject) { manySideObject.setCustomer(oneSideObject); } }; }}
@Entitypublic class Pet { @ManyToOne private Customer customer;
public void setCustomer(Customer parameter) { new ManyToOneWrapper<Customer, Pet>(this) { @Override protected void addManySideObjectToOneSideCollection(Customer oneSide, Pet manySide) { ((WrappedSet<Pet>) oneSide.getPetCollection()).getWrappedCollection().add(manySide); } @Override protected void removeManySideObjectFromOneSideCollection(Customer oneSide, Pet manySide) { ((WrappedSet<Pet>) oneSide.getPetCollection()).getWrappedCollection().remove(manySide); }
@Override protected Customer getOneSideObjectInManySideObject(Pet manySide) { return manySide.customer; }
@Override protected void setOneSideObjectInManySideObject(Pet manySide,Customer oneSide) { manySide.customer = oneSide; } }.updateOneSideObject(parameter); }}
Automatisering
Fra sweatshops til automatisering
På ETL introducerede vi denne procesUML klasse diagrammer
Java kodeHibernate
SQL
WSDLTest
Agil proces
En anden mulighed er…
Byg dit eget sprog
Lyder svært, men er nemt Ru
le L
angu
age
Met
a M
odel
Rule Grammar (i Xtext)
+
Dat
a La
ngua
ge M
eta
Mod
el
+
Editor & IDE
Tekst Editor
Point of No Return, Traditionelt
Tid
Omkostning ved Rework
V 1.0
Hacks!
Freeze
Point of No Return, Model Drevet
Tid
Omkostning ved Rework
V 1.0
Hacks!
Freeze
Slut med at skrive kedelig kode i hånden
Frameworks
(Hibernate/JPA, Entity
Framework)
Libraries (f.eks. Java/.NET)
Skematisk Kode
Interessant Kode
(Skrevet i hånden)
Skrevet I hånden
Model Generator
Hvad får vi så ud af det?
• Højere abstraktionsniveau• Tekniske beslutninger kan udskydes• ”Point of No Return” kan udskydes• Dokumentationen er altid opdateret• Højere kvalitet og Ensartethed• Refaktoreringer er både hurtigere og billigere• Kort udviklingscyklus
Den helt korte version
Vi kan nå det samme med færre ressourcer
Vi kan nå det samme på kortere tid
Vi kan nå mere med de samme ressourcer og på den samme tid
Elektronisk Tinglysning
Spørgsmål?@TigerTeamDK på Twitterhttp://tigerteam.dk