Download - Abstractie (Dutch)
Write('A');
abstractie
wat?waarom?hoe?valkuilenconclusie
wat?
“Abstraction is the process of generalization by reducing the information content of a concept in
order to retain only information which is relevant for a particular purpose.”
-- Wikipedia (ed.)
waarom?
bestanden
mappen
multi-tasking
vensters
knoppen
invoer velden
hoe?
printChar('N');printChar('a');printChar('a');printChar('m');printChar(':');printChar(' ');
char[] vnBuffer = new char[255];int vnLength = 0;char inp;do { inp = readChar(); vnBuffer[vnLength] = inp; vnLength++;while (inp != '\n');
printChar('A');printChar('c');printChar('h');printChar('t');printChar('e');printChar('r');printChar('n');printChar('a');printChar('a');printChar('m');printChar(':');
char[] anBuffer = new char[255];int anLength = 0;do { inp = readChar(); anBuffer[anLength] = inp; anLength++;while (inp != '\n');
printChar('H');printChar('a');printChar('l');printChar('l');printChar('o');printChar(' ');int i = 0;while(i < vnLength) { printChar(vnBuffer[i]); i++;}printChar(' ');i = 0;while(i < anLength) { printChar(anBuffer[i]); i++;}
printChar('N');printChar('a');printChar('a');printChar('m');printChar(':');printChar(' ');
char[] vnBuffer = new char[255];int vnLength = 0;char inp;do { inp = readChar(); vnBuffer[vnLength] = inp; vnLength++;while (inp != '\n');
printChar('A');printChar('c');printChar('h');printChar('t');printChar('e');printChar('r');printChar('n');printChar('a');printChar('a');printChar('m');printChar(':');
char[] anBuffer = new char[255];int anLength = 0;do { inp = readChar(); anBuffer[anLength] = inp; anLength++;while (inp != '\n');
printChar('H');printChar('a');printChar('l');printChar('l');printChar('o');printChar(' ');int i = 0;while(i < vnLength) { printChar(vnBuffer[i]); i++;}printChar(' ');i = 0;while(i < anLength) { printChar(anBuffer[i]); i++;}
printChar('N');printChar('a');printChar('a');printChar('m');printChar(':');printChar(' ');
char[] vnBuffer = new char[255];int vnLength = 0;char inp;do { inp = readChar(); vnBuffer[vnLength] = inp; vnLength++;while (inp != '\n');
printChar('A');printChar('c');printChar('h');printChar('t');printChar('e');printChar('r');printChar('n');printChar('a');printChar('a');printChar('m');printChar(':');
char[] anBuffer = new char[255];int anLength = 0;do { inp = readChar(); anBuffer[anLength] = inp; anLength++;while (inp != '\n');
printChar('H');printChar('a');printChar('l');printChar('l');printChar('o');printChar(' ');int i = 0;while(i < vnLength) { printChar(vnBuffer[i]); i++;}printChar(' ');i = 0;while(i < anLength) { printChar(anBuffer[i]); i++;}
printChars(new char[] { 'N', 'a', 'a', 'm', ':', ' '}, 6);char[] vnBuf = new char[255];int vnLength = readChars(vnBuf);
printChars(new char[] { 'A', 'c', 'h', 't', 'e', 'r', 'n', 'a', 'a', 'm', ':', ' '}, 12);char[] anBuf = new char[255];int anLength = readChars(vnBuf);
printChars(new char[] {'H', 'a', 'l', 'l', 'o', ' '}, 6);printChars(vnBuf, vnLength);printChars(anBuf, anLength);
String voornaam = readLine("Naam: ");String achternaam = readLine("Achternaam: ");print("Hallo " + voornaam + " " + achternaam);
FullName fn = FullName.read();fn.printGreeting();
readNameAndPrintGreeting();
goed abstractie niveau?
readNameAndPrintGreeting();
nieuwe eis: vraag ook naar leeftijd
readNameAndPrintGreeting();
nieuwe eis: vraag ook naar leeftijd✖
FullName fn = FullName.read();fn.printGreeting();
nieuwe eis: vraag ook naar leeftijd
FullName fn = FullName.read();fn.printGreeting();
nieuwe eis: vraag ook naar leeftijd✖
String voornaam = readLine("Naam: ");String achternaam = readLine("Achternaam: ");print("Hallo " + voornaam + " " + achternaam);
nieuwe eis: vraag ook naar leeftijd
String voornaam = readLine("Naam: ");String achternaam = readLine("Achternaam: ");int leeftijd = stringToInt(readLine("Leeftijd: "));print("Hallo " + voornaam + " " + achternaam + ", jij bent " + leeftijd + " jaar oud.");
nieuwe eis: vraag ook naar leeftijd ✔
goed abstractie niveau afhankelijk van
goed abstractie niveau afhankelijk van
gebruik nu
goed abstractie niveau afhankelijk van
gebruik nu
gebruik later
Web applicaties in Java/Seam
View ControllerModel
Data: Hibernate@Entitypublic class Blog { protected String _title = ""; public String getTitle() { return _title; } public void setTitle(String value) { _title = value; } @ManyToOne protected User _author; public User getAuthor() { return _author; } public void setAuthor(User author) { _title = value; } @OneToMany(mappedBy="_blog", targetEntity=BlogEntry.class) @Cascade(...) protected List<BlogEntry> _entries; public List<BlogEntry> getEntries() { return _entries; } public void setEntries(List<BlogEntry> entries) { _entries = entries; }}
View: JSF<html ...> ... <body> ... <h:form> <table> <tr><td><h:outputText value="Title: "/></td><td><h:inputText value="#{editBlogEntry.e.title}" /></td></tr><tr><td><h:outputText value="Created: "/></td><td><rich:calendar value="#{editBlogEntry.e.created}" popup="true" datePattern="dd/MM/yyyy" .../></td></tr><tr><td><h:outputText value="Content: "/></td><td><h:inputTextarea value="#{editBlogEntry.e.content}"/></td></tr><tr><td><h:outputText value="Status: "/></td><td><h:selectOneMenu value="#{editBlogEntry.e.status}"> <s:selectItems value="#{editBlogEntry.blogEntryStatusList}" var="blogEntryStatus" label="#{blogEntryStatus.name}" /> <s:convertEntity/> </h:selectOneMenu></td></tr> </table> <h:actionLink action=”#{editBlogEntry.save()}”/></h:form> ... </body> </html>
Controller@Stateful @Name(“editBlogEntry”)public class EditBlogEntry { ... @In @Out private BlogEntry e;
public void setE(e) { this.e = e; }
public BlogEntry getE() { return this.e; }
public void save() { em.persist(e); } ...}
Configuratie<?xml version="1.0" ?><web-app ...> <context-param> <param-name>facelets.LIBRARIES</param-name> <param-value>/WEB-INF/blog.taglib.xml</param-value> </context-param> <filter> <filter-name>Seam Filter</filter-name> <filter-class>org.jboss.seam.servlet.SeamFilter</filter-class> </filter> <filter> <filter-name>UrlRewriteFilter</filter-name> <filter-class>org.tuckey.web.filters.urlrewrite.UrlRewriteFilter</filter-class> <init-param> <param-name>logLevel</param-name> <param-value>WARN</param-value> </init-param> </filter> <filter-mapping> <filter-name>Seam Filter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> <filter-mapping> <filter-name>UrlRewriteFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> <servlet> <servlet-name>Faces Servlet</servlet-name> <servlet-class>javax.faces.webapp.FacesServlet</servlet-class> <load-on-startup>1</load-on-startup> </servlet> <servlet> <servlet-name>Seam Resource Servlet</servlet-name> <servlet-class>org.jboss.seam.servlet.SeamResourceServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>Faces Servlet</servlet-name> <url-pattern>*.seam</url-pattern> </servlet-mapping> ...</web-app>
allemaal hetzelfde
allemaal hetzelfde
Gebruiker
allemaal hetzelfde
Gebruikermakenwijzigenverwijderenkoppelen
allemaal hetzelfde
Gebruikermakenwijzigenverwijderenkoppelen
Bericht
allemaal hetzelfde
Gebruikermakenwijzigenverwijderenkoppelen
Berichtmakenwijzigenverwijderenkoppelen
allemaal hetzelfde
Gebruikermakenwijzigenverwijderenkoppelen
Berichtmakenwijzigenverwijderenkoppelen
Reactie
allemaal hetzelfde
Gebruikermakenwijzigenverwijderenkoppelen
Berichtmakenwijzigenverwijderenkoppelen
Reactiemakenwijzigenverwijderenkoppelen
allemaal hetzelfde
Gebruikermakenwijzigenverwijderenkoppelen
Berichtmakenwijzigenverwijderenkoppelen
Reactiemakenwijzigenverwijderenkoppelen
boiler plate code
Data@Entitypublic class Blog { protected String _title = ""; public String getTitle() { return _title; } public void setTitle(String value) { _title = value; } @ManyToOne protected User _author; public User getAuthor() { return _author; } public void setAuthor(User author) { _title = value; } @OneToMany(mappedBy="_blog", targetEntity=BlogEntry.class) @Cascade(...) protected List<BlogEntry> _entries; public List<BlogEntry> getEntries() { return _entries; } public void setEntries(List<BlogEntry> entries) { _entries = entries; }}
Data
entity Blog { author -> User (inverse=User.blogs) title :: String entries <> Set<BlogEntry>}
@Entitypublic class Blog { protected String _title = ""; public String getTitle() { return _title; } public void setTitle(String value) { _title = value; } @ManyToOne protected User _author; public User getAuthor() { return _author; } public void setAuthor(User author) { _title = value; } @OneToMany(mappedBy="_blog", targetEntity=BlogEntry.class) @Cascade(...) protected List<BlogEntry> _entries; public List<BlogEntry> getEntries() { return _entries; } public void setEntries(List<BlogEntry> entries) { _entries = entries; }}
Pagina’s<html ...> ... <body> ... <h:form> <table> <tr><td><h:outputText value="Title: "/></td><td><h:inputText value="#{editBlogEntry.e.title}" /></td></tr><tr><td><h:outputText value="Created: "/></td><td><rich:calendar value="#{editBlogEntry.e.created}" popup="true" datePattern="dd/MM/yyyy" .../></td></tr><tr><td><h:outputText value="Content: "/></td><td><h:inputTextarea value="#{editBlogEntry.e.content}"/></td></tr><tr><td><h:outputText value="Status: "/></td><td><h:selectOneMenu value="#{editBlogEntry.e.status}"> <s:selectItems value="#{editBlogEntry.blogEntryStatusList}" var="blogEntryStatus" label="#{blogEntryStatus.name}" /> <s:convertEntity/> </h:selectOneMenu></td></tr> </table> <h:actionLink action=”#{editBlogEntry.save()}”/></h:form> ... </body> </html>
@Stateful @Name(“editBlogEntry”)public class EditBlogEntry { ... @In @Out private BlogEntry e;
public void setE(e) { this.e = e; }
public BlogEntry getE() { return this.e; }
public void save() { em.persist(e); } ...}
Pagina’s
define page editBlogEntry(e : BlogEntry) { form{ table{ row{ "Title: " input(e.title) } row{ "Created: " input(e.created) } row{ "Content: " input(e.content) } row{ "Status: " input(e.status) } action("Save", save()) } } action save() { e.save(); return blogEntry(e); }}
<html ...> ... <body> ... <h:form> <table> <tr><td><h:outputText value="Title: "/></td><td><h:inputText value="#{editBlogEntry.e.title}" /></td></tr><tr><td><h:outputText value="Created: "/></td><td><rich:calendar value="#{editBlogEntry.e.created}" popup="true" datePattern="dd/MM/yyyy" .../></td></tr><tr><td><h:outputText value="Content: "/></td><td><h:inputTextarea value="#{editBlogEntry.e.content}"/></td></tr><tr><td><h:outputText value="Status: "/></td><td><h:selectOneMenu value="#{editBlogEntry.e.status}"> <s:selectItems value="#{editBlogEntry.blogEntryStatusList}" var="blogEntryStatus" label="#{blogEntryStatus.name}" /> <s:convertEntity/> </h:selectOneMenu></td></tr> </table> <h:actionLink action=”#{editBlogEntry.save()}”/></h:form> ... </body> </html>
@Stateful @Name(“editBlogEntry”)public class EditBlogEntry { ... @In @Out private BlogEntry e;
public void setE(e) { this.e = e; }
public BlogEntry getE() { return this.e; }
public void save() { em.persist(e); } ...}
Pagina’s<html ...> ... <body> ... <h:form> <table> <tr><td><h:outputText value="Title: "/></td><td><h:inputText value="#{editBlogEntry.e.title}" /></td></tr><tr><td><h:outputText value="Created: "/></td><td><rich:calendar value="#{editBlogEntry.e.created}" popup="true" datePattern="dd/MM/yyyy" .../></td></tr><tr><td><h:outputText value="Content: "/></td><td><h:inputTextarea value="#{editBlogEntry.e.content}"/></td></tr><tr><td><h:outputText value="Status: "/></td><td><h:selectOneMenu value="#{editBlogEntry.e.status}"> <s:selectItems value="#{editBlogEntry.blogEntryStatusList}" var="blogEntryStatus" label="#{blogEntryStatus.name}" /> <s:convertEntity/> </h:selectOneMenu></td></tr> </table> <h:actionLink action=”#{editBlogEntry.save()}”/></h:form> ... </body> </html>
@Stateful @Name(“editBlogEntry”)public class EditBlogEntry { ... @In @Out private BlogEntry e;
public void setE(e) { this.e = e; }
public BlogEntry getE() { return this.e; }
public void save() { em.persist(e); } ...}
Pagina’s
define page editBlogEntry(e : BlogEntry) { derive editPage from e}
<html ...> ... <body> ... <h:form> <table> <tr><td><h:outputText value="Title: "/></td><td><h:inputText value="#{editBlogEntry.e.title}" /></td></tr><tr><td><h:outputText value="Created: "/></td><td><rich:calendar value="#{editBlogEntry.e.created}" popup="true" datePattern="dd/MM/yyyy" .../></td></tr><tr><td><h:outputText value="Content: "/></td><td><h:inputTextarea value="#{editBlogEntry.e.content}"/></td></tr><tr><td><h:outputText value="Status: "/></td><td><h:selectOneMenu value="#{editBlogEntry.e.status}"> <s:selectItems value="#{editBlogEntry.blogEntryStatusList}" var="blogEntryStatus" label="#{blogEntryStatus.name}" /> <s:convertEntity/> </h:selectOneMenu></td></tr> </table> <h:actionLink action=”#{editBlogEntry.save()}”/></h:form> ... </body> </html>
@Stateful @Name(“editBlogEntry”)public class EditBlogEntry { ... @In @Out private BlogEntry e;
public void setE(e) { this.e = e; }
public BlogEntry getE() { return this.e; }
public void save() { em.persist(e); } ...}
10-50x
WebDSL code
WebDSL compiler
Java applicatie(Java, JSF, Hibernate)
valkuilen
entity User { username :: String password :: Secret}
entity Update { user -> User date :: DateTime text :: Text}
entity User { username :: String password :: Secret}
entity Update { user -> User date :: DateTime text :: Text}
define page home() { for(u : Update) { output(u.user.username) ": " output(u.text) spacer }}
entity User { username :: String password :: Secret}
entity Update { user -> User date :: DateTime text :: Text}
define page home() { for(u : Update) { output(u.user.username) ": " output(u.text) spacer }}
define page home() { header{ "Twitr" } spacer for(u : Update) { output(u.user.username) ": " output(u.text) spacer } "(C) Zef Hemel"}
define page login() { header{ "Twitr" } spacer var u : User
form { "Login: " input(u) action("Login", login())
action login() { session.user := u; return home(); } } spacer "(C) Zef Hemel"}
define page login() { header{ "Twitr" } spacer var u : User
form { "Login: " input(u) action("Login", login())
action login() { session.user := u; return home(); } } spacer "(C) Zef Hemel"}
template abstractie!
define template main() { header{ "Twitr" } spacer body() "(C) Zef Hemel"}
define page home() { main() define body() { for(u : Update) { output(u.user.username) ": " output(u.text) spacer } }}
WebDSL code
WebDSL compiler
Template expander
Java applicatie(Java, JSF, Hibernate)
template expanderdefine page home() { main() define body() for(u : Update) { output(u.user.username) ": " output(u.text) spacer } }}
define page home() { header{ "Twitr" } spacer for(u : Update) { output(u.user.username) ": " output(u.text) spacer } "(C) Zef Hemel"}
maar...
JSF had ook al templates
WebDSL code
WebDSL compiler
Template expander
Java applicatie(Java, JSF, Hibernate)templates
WebDSL code
WebDSL compiler
Template expander
Java applicatie(Java, JSF, Hibernate)templates
templates
WebDSL code
WebDSL compiler
Template expander
Java applicatie(Java, JSF, Hibernate)templates
templates
herimplementeerttemplates
abstraction inversion
WebDSL code
WebDSL compiler
Template expander
Java applicatie(Java, JSF, Hibernate)templates
templates
herimplementeerttemplates
abstraction inversion
WebDSL code
WebDSL compiler
Template expander
Java applicatie(Java, JSF, Hibernate)templates
templates
herimplementeerttemplates
slechte abstractie
“All non-trivial abstractions, to some
degree, are leaky.”
-- Joel Spolsky
abstracties verbergen implementatie
abstracties verbergen implementatie
dat lukt eigenlijk nooit volledig
abstracties verbergen implementatie
dat lukt eigenlijk nooit volledig
WebDSL templates
abstracties verbergen implementatie
dat lukt eigenlijk nooit volledig
WebDSL templatesNFS/SMB
abstracties verbergen implementatie
dat lukt eigenlijk nooit volledig
WebDSL templatesNFS/SMBtwee-dimensionale arrays
abstracties verbergen implementatie
dat lukt eigenlijk nooit volledig
WebDSL templatesNFS/SMBtwee-dimensionale arraysSQL
conclusie
abstractie is essentieel
abstractie is essentieelmoeilijk
denk kritisch na
denk kritisch na
heb ik dit vaker gedaan?
denk kritisch na
heb ik dit vaker gedaan?gaat iemand dit vaker doen?
ja?
abstraheer