SlideShare a Scribd company logo
1 of 38
Download to read offline
O klasycznej programistycznej elegancji
http://my.opera.com/rato53/albums/
Jakub Marchwicki
Technical Consultant
Java, Lua, PHP
i tak od 9lat
marchwicki.pl/blog
@kubamarchwicki
Kanon piękna?
© vitra
Kanon piękna?
„Any fool can
write code that a
computer can
understand. Good
programmers
write code that
humans can
understand“
Refactoring: Improving the Design of Existing Code, 1999
Martin Fowler jeszcze raz
Joshua Bloch
Effective Java
I sure wish I had
this book ten
years ago
James Gosling
Kent Beck
„Many people
don’t realize how
readable code
can be and how
valuable that
readability is.
Kent has taught
me so...“ Martin Fowler
Implementation patterns
Communication
Simplicity
Flexibility
A wszystko dlatego że
największym kosztem
oprogramowania
będzie i tak jego
utrzymanie
Kryteria dobrego kodu
© http://www.agileadvisor.com/
private static boolean isOlderExtremeVersion(String d1, String d2) {
String[] dateOneA = dateOne.split("-");
String[] dateTwoA = dateTwo.split("-");
if ((Integer.valueOf(dateOneA[0]).intValue() >
Integer.valueOf(dateTwoA[0]).intValue())
|| (Integer.valueOf(dateOneA[0]).intValue() ==
Integer.valueOf(dateTwoA[0]).intValue()
&& Integer.valueOf(dateOneA[1]).intValue() >
Integer.valueOf(dateTwoA[1]).intValue())
|| (Integer.valueOf(dateOneA[0]).intValue() ==
Integer.valueOf(dateTwoA[0]).intValue()
&& Integer.valueOf(dateOneA[1]).intValue() ==
Integer.valueOf(dateTwoA[1]).intValue()
&& Integer.valueOf(dateOneA[2]).intValue() >
Integer.valueOf(dateTwoA[2]).intValue())) {
return false;
}
return true;
}
Nie będzie Eclipsa...
public class Person {
private String firstName;
private String lastName;
private long birthDate;
}
public class Student extends Person {
private int year;
}
public class Professor extends Person {
private String[] specjalities;
}
public class Lecture {
private String title;
private Professor professor;
private Student[] students;
}
Wyobraźmy sobie model...
public boolean equals(Object o) {
if (!(o instanceof Person))
return false;
final Person p = (Person) o;
return firstName.equals(p.firstName)
&& lastName.equals(p.lastName)
&& birthDate == p.birthDate;
}
public int hashcode() {
int result = 17;
result = 37*result + firstName.hashCode();
result = 37*result + lastName.hashCode();
result = 37*result + (int)(birthDate ^ birthDate >>> 32);
return result;
}
A teraz piszemy...
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + Arrays.hashCode(specjalities);
return result;
}
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (!super.equals(obj)) {
return false;
}
if (!(obj instanceof Professor)) {
return false;
}
Professor other = (Professor) obj;
if (!Arrays.equals(specjalities, other.specjalities)) {
return false;
}
return true;
}
lub generujemy...
public String toString() {
return "Professor [specjalities=" +
Arrays.toString(specjalities) + "]";
}
to samo tyczy się toString()'a
public boolean equals(Object o) {
if (o == null) { return false; }
if (o == this) { return true; }
if (o.getClass() != getClass()) { return false; }
final Student s = (Student) o;
return new EqualsBuilder()
.appendSuper(super.equals(o)).append(year, s.year)
.isEquals();
}
public int hashcode() {
return new HashCodeBuilder(17, 37)
.appendSuper(super.hashcode()).append(year)
.toHashCode();
}
public String toString() {
return new ToStringBuilder(this)
.appendSuper(super.toString()).append("year", year)
.toString();
}
ale przy setce encji się nie chcieć
public boolean equals(Object o) {
if (o instanceof Lecture) {
Lecture l = (Lecture) o;
return Objects.equal(professor, l.professor)
&& Objects.equal(students, l.students)
&& Objects.equal(title, l.title);
}
return false;
}
public int hashcode() {
return Objects.hashCode(title, professor, students);
}
public String toString() {
return Objects.toStringHelper(this)
.add("professor", professor)
.add("students", students)
.toString();
}
albo mniej fundamentalnie
public void addLectureWithCommons(Lecture lecture, Venue venue,
int dayOfTheWeek, int hour) {
Validate.isTrue(dayOfTheWeek > 0 && dayOfTheWeek <= 7,
"There are only 7 days of the week");
Validate.isTrue(hour >= 0 && hour < 23, "Day has only 24hours");
Validate.notNull(lecture != null, "Lecture cannot be null");
Validate.notNull(venue != null, "Venue cannot be null");
// reminder omitted
}
public void addLectureWithGuava(Lecture lecture, Venue venue,
int dayOfTheWeek, int hour) {
Preconditions.checkArgument(dayOfTheWeek > 0 && dayOfTheWeek <= 7,
"There are only 7 days of the week");
Preconditions.checkArgument(hour >= 0 && hour < 23,
"Day has only 24hours");
Preconditions.checkArgument(lecture != null, "Lecture cannot be null");
Lecture localLecture = Preconditions.checkNotNull(lecture);
Venue localVenue = Preconditions.checkNotNull(venue);
// reminder omitted
}
defensive programming
String[] csv;
for (String line : csv) {
String[] elements = line.split(",");
// reminder omitted
}
for (String line : csv) {
String[] r = StringUtils.split(line, ",");
r = StringUtils.stripAll(r);
}
for (String line : csv) {
Splitter.on(",")
.trimResults()
.omitEmptyStrings()
.split(line);
}
a później zawsze trafimy na String'a
public interface LectureService {
public Student[] getStudentsByYear(int year);
public Student[] getStudentsOlderThan(int age);
public Student[] getStudentsByBirthDate(Date date);
}
i kilka operacji 'biznesowych'
public Student[] getStudentsByYear(int year) {
final List<Student> students = new ArrayList<Student>();
for (Student s : lecture.getStudents()) {
if (s.getYear() == year) {
students.add(s);
}
}
return students.toArray(new Student[] {});
}
które sprowadzają się...
public Student[] getStudentsByBirthDate(Date date) {
final List<Student> students = new ArrayList<Student>();
for (Student s : lecture.getStudents()) {
Calendar studentBirth = Calendar.getInstance();
studentBirth.setTimeInMillis(s.getBirthDate());
Calendar desiredDate = Calendar.getInstance();
desiredDate.setTime(date);
if (studentBirth.get(Calendar.YEAR) ==
desiredDate.get(Calendar.YEAR)
&& studentBirth.get(Calendar.MONTH) ==
desiredDate.get(Calendar.MONTH)
&& studentBirth.get(Calendar.DATE) ==
desiredDate.get(Calendar.DATE)) {
students.add(s);
}
}
return students.toArray(new Student[] {});
}
... do niemal ...
public Student[] getStudentsOlderThan(int age) {
final List<Student> students = new ArrayList<Student>();
for (Student s : lecture.getStudents()) {
Calendar c = Calendar.getInstance();
c.setTimeInMillis(s.getBirthDate());
c.add(Calendar.YEAR, age);
Calendar now = Calendar.getInstance();
now.setTime(new Date());
if (c.before(now)) {
students.add(s);
}
}
return students.toArray(new Student[] {});
}
... tego samego.
public Student[] getStudentsOlderThan(int age) {
final List<Student> students = new ArrayList<Student>();
for (Student s : lecture.getStudents()) {
DateMidnight dt = new DateMidnight()
.withMillis(s.getBirthDate())
.plusYears(age);
if (dt.isBeforeNow()) {
students.add(s);
}
}
return students.toArray(new Student[] {});
}
i abstahując od użycia JodaTime
private Student[] getStudents(Predicate predicate) {
final List<Student> students = new ArrayList<Student>();
for (Student s : lecture.getStudents()) {
if (predicate.evaluate(s)) {
students.add(s);
}
}
return students.toArray(new Student[] {});
}
Don't Repeat Yourself
Predicate predicate = new Predicate() {
@Override
public boolean evaluate(Object arg0) {
if (arg0 instanceof Student) {
Student s = (Student) arg0;
DateMidnight dt = new DateMidnight()
.withMillis(s.getBirthDate())
.plusYears(age);
if (dt.isBeforeNow()) {
return true;
}
}
return false;
}
};
No a ten predykat?
Predicate<Student> predicate = new Predicate<Student>() {
@Override
public boolean apply(Student input) {
DateMidnight dt = new DateMidnight()
.withMillis(input.getBirthDate())
.plusYears(age);
if (dt.isBeforeNow()) {
return true;
}
return false;
}
};
No a ten predykat? (2)
private Student[] getStudents(Predicate predicate) {
final List<Student> students = new ArrayList<Student>();
for (Student s : lecture.getStudents()) {
if (predicate.evaluate(s)) {
students.add(s);
}
}
return students.toArray(new Student[] {});
}
i jeszcze na koniec, zamiast...
protected Student[] getStudents(Predicate<Student> predicate) {
Iterable<Student> students = Iterables
.filter(Arrays.asList(lecture.getStudents()), predicate);
return Iterables.toArray(students, Student.class);
}
... może być w ogóle ślicznie
Student[] students = service.promoteStudents(2);
Predicate<Student> predicate = new Predicate<Student>() {
public boolean apply(Student input) {
if (input.getYear() == year) {
return true;
}
return false;
}
};
Function<Student,Student> function = new Function<Student,Student>(){
public Student apply(Student input) {
input.setYear(year + 1);
return input;
}
};
Iterables.filter();
Iterables.transform();
Jak już jest prawie funkcyjnie...
Guava to nie tylko <generics>
© Kevin Bourrillion, Google, Inc.
private Map<Student, List<Lecture>> classes =
new HashMap<Student, List<Lecture>>();
// ...
for (Lecture lecture : lectures) {
for (Student student : lecture.getStudents()) {
if (service.classes.containsKey(student)) {
service.classes.get(student).add(lecture);
} else {
List<Lecture> l = new ArrayList<Lecture>();
l.add(lecture);
service.classes.put(student, l);
}
}
}
kiedyś było tak...
private Multimap<Student, Lecture> classes =
ArrayListMultimap.create();
// ...
for (Lecture lecture : lectures) {
for (Student student : lecture.getStudents()) {
service.classes.put(student, lecture);
}
}
Map<Student, Collection<Lecture>> map = classes.asMap();
Collection<Lecture> lectures = classes.values();
Set<Student> students = classes.keySet();
for (Map.Entry<Student, Lecture> entry : classes.entries()) {}
... a teraz witamy Multimap i Multiset
Map<Student, Collection<Lecture>> map = classes.asMap();
"JM" => {"Fizyka", "Chemia", "Matematyka"}, "TD" => {"Chemia", Biologia"}
Collection<Lecture> lectures = classes.values();
{"Fizyka", "Matematyka", "Chemia", "Biologia"}
Set<Student> students = classes.keySet();
{"JM", "TD"}
for (Map.Entry<Student, Lecture> entry : classes.entries()) {}
{"JM"=>"Fizyka", "JM"=>"Matematyka", "JM"=>"Chemia", "TD"=>"Biologia", ...}
Collection<Lecture> lectures = classes.get("JM");
{"Fizyka", "Chemia", "Matematyka"}
Multimap i Multiset (2)
ImmutableSet<Student> students =
ImmutableSet.copyOf(service.getStudentsByYear(2));
Set<Student> students =
Collections.unmodifiableSet(
new LinkedHashSet<Student>(
Arrays.asList(service.getStudentsByYear(2))));
Immutability
new Person("Ridge", "Forrster");
Person person = new Person.Builder()
.withName(“Ridge”)
.withSurname(“Forrester”)
.build();
Immutability with builders
http://www.marchwicki.pl/blog/2010/11/building-a-pojo-in-an-elegant-way/
Dziękuje
http://marchwicki.pl/blog
@kubamarchwicki
http://www.delicious.com/kuba.marchwicki/beautifulcode
http://www.assembla.com/code/km_jug/subversion/nodes

More Related Content

What's hot

Java весна 2013 лекция 2
Java весна 2013 лекция 2Java весна 2013 лекция 2
Java весна 2013 лекция 2
Technopark
 
Advanced Java Practical File
Advanced Java Practical FileAdvanced Java Practical File
Advanced Java Practical File
Soumya Behera
 
Scala 2013 review
Scala 2013 reviewScala 2013 review
Scala 2013 review
Sagie Davidovich
 
Kotlin, 어떻게 동작하나요
Kotlin, 어떻게 동작하나요Kotlin, 어떻게 동작하나요
Kotlin, 어떻게 동작하나요
Chang W. Doh
 

What's hot (20)

Scala taxonomy
Scala taxonomyScala taxonomy
Scala taxonomy
 
Hey Kotlin, How it works?
Hey Kotlin, How it works?Hey Kotlin, How it works?
Hey Kotlin, How it works?
 
(chapter 6) A Concise and Practical Introduction to Programming Algorithms in...
(chapter 6) A Concise and Practical Introduction to Programming Algorithms in...(chapter 6) A Concise and Practical Introduction to Programming Algorithms in...
(chapter 6) A Concise and Practical Introduction to Programming Algorithms in...
 
Java_practical_handbook
Java_practical_handbookJava_practical_handbook
Java_practical_handbook
 
TechTalk - Dotnet
TechTalk - DotnetTechTalk - Dotnet
TechTalk - Dotnet
 
分散式系統
分散式系統分散式系統
分散式系統
 
Java весна 2013 лекция 2
Java весна 2013 лекция 2Java весна 2013 лекция 2
Java весна 2013 лекция 2
 
Racing To Win: Using Race Conditions to Build Correct and Concurrent Software
Racing To Win: Using Race Conditions to Build Correct and Concurrent SoftwareRacing To Win: Using Race Conditions to Build Correct and Concurrent Software
Racing To Win: Using Race Conditions to Build Correct and Concurrent Software
 
Rainer Grimm, “Functional Programming in C++11”
Rainer Grimm, “Functional Programming in C++11”Rainer Grimm, “Functional Programming in C++11”
Rainer Grimm, “Functional Programming in C++11”
 
Lecture1 classes3
Lecture1 classes3Lecture1 classes3
Lecture1 classes3
 
Scala traits training by Sanjeev Kumar @Kick Start Scala traits & Play, organ...
Scala traits training by Sanjeev Kumar @Kick Start Scala traits & Play, organ...Scala traits training by Sanjeev Kumar @Kick Start Scala traits & Play, organ...
Scala traits training by Sanjeev Kumar @Kick Start Scala traits & Play, organ...
 
From Java to Parellel Clojure - Clojure South 2019
From Java to Parellel Clojure - Clojure South 2019From Java to Parellel Clojure - Clojure South 2019
From Java to Parellel Clojure - Clojure South 2019
 
Advanced Java Practical File
Advanced Java Practical FileAdvanced Java Practical File
Advanced Java Practical File
 
Scala 2013 review
Scala 2013 reviewScala 2013 review
Scala 2013 review
 
Introduction à dart
Introduction à dartIntroduction à dart
Introduction à dart
 
Kotlin, 어떻게 동작하나요
Kotlin, 어떻게 동작하나요Kotlin, 어떻게 동작하나요
Kotlin, 어떻게 동작하나요
 
Александр Гранин, Функциональная 'Жизнь': параллельные клеточные автоматы и к...
Александр Гранин, Функциональная 'Жизнь': параллельные клеточные автоматы и к...Александр Гранин, Функциональная 'Жизнь': параллельные клеточные автоматы и к...
Александр Гранин, Функциональная 'Жизнь': параллельные клеточные автоматы и к...
 
The Macronomicon
The MacronomiconThe Macronomicon
The Macronomicon
 
OSDC.fr 2012 :: Cascalog : progammation logique pour Hadoop
OSDC.fr 2012 :: Cascalog : progammation logique pour HadoopOSDC.fr 2012 :: Cascalog : progammation logique pour Hadoop
OSDC.fr 2012 :: Cascalog : progammation logique pour Hadoop
 
Network
NetworkNetwork
Network
 

Viewers also liked (7)

Rando vélo juillet 2010
Rando vélo juillet 2010Rando vélo juillet 2010
Rando vélo juillet 2010
 
Inputs
InputsInputs
Inputs
 
About the site.org
About the site.orgAbout the site.org
About the site.org
 
Pec_JuliaGUY
Pec_JuliaGUYPec_JuliaGUY
Pec_JuliaGUY
 
[PL] Metadane - dane o danych
[PL] Metadane - dane o danych[PL] Metadane - dane o danych
[PL] Metadane - dane o danych
 
About the site.org
About the site.orgAbout the site.org
About the site.org
 
GeeCON 2012 hurdle run through ejb testing
GeeCON 2012 hurdle run through ejb testingGeeCON 2012 hurdle run through ejb testing
GeeCON 2012 hurdle run through ejb testing
 

Similar to [PL] O klasycznej, programistycznej elegancji

Better Software: introduction to good code
Better Software: introduction to good codeBetter Software: introduction to good code
Better Software: introduction to good code
Giordano Scalzo
 
Fee managment system
Fee managment systemFee managment system
Fee managment system
fairy9912
 
import school.; import school.courses.;public class Main { p.pdf
import school.; import school.courses.;public class Main { p.pdfimport school.; import school.courses.;public class Main { p.pdf
import school.; import school.courses.;public class Main { p.pdf
annaiwatertreatment
 
Scala in practice
Scala in practiceScala in practice
Scala in practice
patforna
 
AST Transformations at JFokus
AST Transformations at JFokusAST Transformations at JFokus
AST Transformations at JFokus
HamletDRC
 
Working effectively with legacy code
Working effectively with legacy codeWorking effectively with legacy code
Working effectively with legacy code
ShriKant Vashishtha
 
Starting with Main.java, where I tested everythingimport College..pdf
Starting with Main.java, where I tested everythingimport College..pdfStarting with Main.java, where I tested everythingimport College..pdf
Starting with Main.java, where I tested everythingimport College..pdf
aptind
 

Similar to [PL] O klasycznej, programistycznej elegancji (20)

How to Start Test-Driven Development in Legacy Code
How to Start Test-Driven Development in Legacy CodeHow to Start Test-Driven Development in Legacy Code
How to Start Test-Driven Development in Legacy Code
 
Better Software: introduction to good code
Better Software: introduction to good codeBetter Software: introduction to good code
Better Software: introduction to good code
 
Fee managment system
Fee managment systemFee managment system
Fee managment system
 
Modul Praktek Java OOP
Modul Praktek Java OOP Modul Praktek Java OOP
Modul Praktek Java OOP
 
Code Smells y Refactoring o haciendo que nuestro codigo huela (y se vea) mejo...
Code Smells y Refactoring o haciendo que nuestro codigo huela (y se vea) mejo...Code Smells y Refactoring o haciendo que nuestro codigo huela (y se vea) mejo...
Code Smells y Refactoring o haciendo que nuestro codigo huela (y se vea) mejo...
 
The Future of JVM Languages
The Future of JVM Languages The Future of JVM Languages
The Future of JVM Languages
 
Functional C++
Functional C++Functional C++
Functional C++
 
TDC2016SP - Trilha .NET
TDC2016SP - Trilha .NETTDC2016SP - Trilha .NET
TDC2016SP - Trilha .NET
 
Introduction à Dart
Introduction à DartIntroduction à Dart
Introduction à Dart
 
import school.; import school.courses.;public class Main { p.pdf
import school.; import school.courses.;public class Main { p.pdfimport school.; import school.courses.;public class Main { p.pdf
import school.; import school.courses.;public class Main { p.pdf
 
Scala in practice
Scala in practiceScala in practice
Scala in practice
 
AST Transformations at JFokus
AST Transformations at JFokusAST Transformations at JFokus
AST Transformations at JFokus
 
Working effectively with legacy code
Working effectively with legacy codeWorking effectively with legacy code
Working effectively with legacy code
 
TypeScript Introduction
TypeScript IntroductionTypeScript Introduction
TypeScript Introduction
 
Static and const members
Static and const membersStatic and const members
Static and const members
 
JavaScript - Agora nervoso
JavaScript - Agora nervosoJavaScript - Agora nervoso
JavaScript - Agora nervoso
 
Anti patterns
Anti patternsAnti patterns
Anti patterns
 
Starting with Main.java, where I tested everythingimport College..pdf
Starting with Main.java, where I tested everythingimport College..pdfStarting with Main.java, where I tested everythingimport College..pdf
Starting with Main.java, where I tested everythingimport College..pdf
 
Ast transformations
Ast transformationsAst transformations
Ast transformations
 
Kotlin @ Coupang Backend 2017
Kotlin @ Coupang Backend 2017Kotlin @ Coupang Backend 2017
Kotlin @ Coupang Backend 2017
 

More from Jakub Marchwicki (6)

Test with Spock like the first officer
Test with Spock like the first officerTest with Spock like the first officer
Test with Spock like the first officer
 
Design principles 4 hackers - tech3camp (28142014)
Design principles 4 hackers - tech3camp (28142014)Design principles 4 hackers - tech3camp (28142014)
Design principles 4 hackers - tech3camp (28142014)
 
JEE.next()
JEE.next()JEE.next()
JEE.next()
 
[PL] Jak programować aby nie zwariować
[PL] Jak programować aby nie zwariować[PL] Jak programować aby nie zwariować
[PL] Jak programować aby nie zwariować
 
GeeCON 2013 - EJB application guided by tests
GeeCON 2013 - EJB application guided by testsGeeCON 2013 - EJB application guided by tests
GeeCON 2013 - EJB application guided by tests
 
[PL] Jak programować aby nie zwariować?
[PL] Jak programować aby nie zwariować?[PL] Jak programować aby nie zwariować?
[PL] Jak programować aby nie zwariować?
 

Recently uploaded

Cloud Frontiers: A Deep Dive into Serverless Spatial Data and FME
Cloud Frontiers:  A Deep Dive into Serverless Spatial Data and FMECloud Frontiers:  A Deep Dive into Serverless Spatial Data and FME
Cloud Frontiers: A Deep Dive into Serverless Spatial Data and FME
Safe Software
 
+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...
+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...
+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...
?#DUbAI#??##{{(☎️+971_581248768%)**%*]'#abortion pills for sale in dubai@
 
Why Teams call analytics are critical to your entire business
Why Teams call analytics are critical to your entire businessWhy Teams call analytics are critical to your entire business
Why Teams call analytics are critical to your entire business
panagenda
 

Recently uploaded (20)

Cloud Frontiers: A Deep Dive into Serverless Spatial Data and FME
Cloud Frontiers:  A Deep Dive into Serverless Spatial Data and FMECloud Frontiers:  A Deep Dive into Serverless Spatial Data and FME
Cloud Frontiers: A Deep Dive into Serverless Spatial Data and FME
 
[BuildWithAI] Introduction to Gemini.pdf
[BuildWithAI] Introduction to Gemini.pdf[BuildWithAI] Introduction to Gemini.pdf
[BuildWithAI] Introduction to Gemini.pdf
 
MS Copilot expands with MS Graph connectors
MS Copilot expands with MS Graph connectorsMS Copilot expands with MS Graph connectors
MS Copilot expands with MS Graph connectors
 
Biography Of Angeliki Cooney | Senior Vice President Life Sciences | Albany, ...
Biography Of Angeliki Cooney | Senior Vice President Life Sciences | Albany, ...Biography Of Angeliki Cooney | Senior Vice President Life Sciences | Albany, ...
Biography Of Angeliki Cooney | Senior Vice President Life Sciences | Albany, ...
 
How to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected WorkerHow to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected Worker
 
FWD Group - Insurer Innovation Award 2024
FWD Group - Insurer Innovation Award 2024FWD Group - Insurer Innovation Award 2024
FWD Group - Insurer Innovation Award 2024
 
ICT role in 21st century education and its challenges
ICT role in 21st century education and its challengesICT role in 21st century education and its challenges
ICT role in 21st century education and its challenges
 
Corporate and higher education May webinar.pptx
Corporate and higher education May webinar.pptxCorporate and higher education May webinar.pptx
Corporate and higher education May webinar.pptx
 
2024: Domino Containers - The Next Step. News from the Domino Container commu...
2024: Domino Containers - The Next Step. News from the Domino Container commu...2024: Domino Containers - The Next Step. News from the Domino Container commu...
2024: Domino Containers - The Next Step. News from the Domino Container commu...
 
Apidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, Adobe
Apidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, AdobeApidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, Adobe
Apidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, Adobe
 
+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...
+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...
+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...
 
Exploring Multimodal Embeddings with Milvus
Exploring Multimodal Embeddings with MilvusExploring Multimodal Embeddings with Milvus
Exploring Multimodal Embeddings with Milvus
 
AWS Community Day CPH - Three problems of Terraform
AWS Community Day CPH - Three problems of TerraformAWS Community Day CPH - Three problems of Terraform
AWS Community Day CPH - Three problems of Terraform
 
Why Teams call analytics are critical to your entire business
Why Teams call analytics are critical to your entire businessWhy Teams call analytics are critical to your entire business
Why Teams call analytics are critical to your entire business
 
Strategize a Smooth Tenant-to-tenant Migration and Copilot Takeoff
Strategize a Smooth Tenant-to-tenant Migration and Copilot TakeoffStrategize a Smooth Tenant-to-tenant Migration and Copilot Takeoff
Strategize a Smooth Tenant-to-tenant Migration and Copilot Takeoff
 
Boost Fertility New Invention Ups Success Rates.pdf
Boost Fertility New Invention Ups Success Rates.pdfBoost Fertility New Invention Ups Success Rates.pdf
Boost Fertility New Invention Ups Success Rates.pdf
 
Apidays New York 2024 - APIs in 2030: The Risk of Technological Sleepwalk by ...
Apidays New York 2024 - APIs in 2030: The Risk of Technological Sleepwalk by ...Apidays New York 2024 - APIs in 2030: The Risk of Technological Sleepwalk by ...
Apidays New York 2024 - APIs in 2030: The Risk of Technological Sleepwalk by ...
 
presentation ICT roal in 21st century education
presentation ICT roal in 21st century educationpresentation ICT roal in 21st century education
presentation ICT roal in 21st century education
 
Navigating the Deluge_ Dubai Floods and the Resilience of Dubai International...
Navigating the Deluge_ Dubai Floods and the Resilience of Dubai International...Navigating the Deluge_ Dubai Floods and the Resilience of Dubai International...
Navigating the Deluge_ Dubai Floods and the Resilience of Dubai International...
 
Ransomware_Q4_2023. The report. [EN].pdf
Ransomware_Q4_2023. The report. [EN].pdfRansomware_Q4_2023. The report. [EN].pdf
Ransomware_Q4_2023. The report. [EN].pdf
 

[PL] O klasycznej, programistycznej elegancji

  • 1. O klasycznej programistycznej elegancji http://my.opera.com/rato53/albums/
  • 2. Jakub Marchwicki Technical Consultant Java, Lua, PHP i tak od 9lat marchwicki.pl/blog @kubamarchwicki
  • 5. „Any fool can write code that a computer can understand. Good programmers write code that humans can understand“ Refactoring: Improving the Design of Existing Code, 1999
  • 8. Effective Java I sure wish I had this book ten years ago James Gosling
  • 9. Kent Beck „Many people don’t realize how readable code can be and how valuable that readability is. Kent has taught me so...“ Martin Fowler
  • 10. Implementation patterns Communication Simplicity Flexibility A wszystko dlatego że największym kosztem oprogramowania będzie i tak jego utrzymanie
  • 11. Kryteria dobrego kodu © http://www.agileadvisor.com/
  • 12. private static boolean isOlderExtremeVersion(String d1, String d2) { String[] dateOneA = dateOne.split("-"); String[] dateTwoA = dateTwo.split("-"); if ((Integer.valueOf(dateOneA[0]).intValue() > Integer.valueOf(dateTwoA[0]).intValue()) || (Integer.valueOf(dateOneA[0]).intValue() == Integer.valueOf(dateTwoA[0]).intValue() && Integer.valueOf(dateOneA[1]).intValue() > Integer.valueOf(dateTwoA[1]).intValue()) || (Integer.valueOf(dateOneA[0]).intValue() == Integer.valueOf(dateTwoA[0]).intValue() && Integer.valueOf(dateOneA[1]).intValue() == Integer.valueOf(dateTwoA[1]).intValue() && Integer.valueOf(dateOneA[2]).intValue() > Integer.valueOf(dateTwoA[2]).intValue())) { return false; } return true; } Nie będzie Eclipsa...
  • 13. public class Person { private String firstName; private String lastName; private long birthDate; } public class Student extends Person { private int year; } public class Professor extends Person { private String[] specjalities; } public class Lecture { private String title; private Professor professor; private Student[] students; } Wyobraźmy sobie model...
  • 14. public boolean equals(Object o) { if (!(o instanceof Person)) return false; final Person p = (Person) o; return firstName.equals(p.firstName) && lastName.equals(p.lastName) && birthDate == p.birthDate; } public int hashcode() { int result = 17; result = 37*result + firstName.hashCode(); result = 37*result + lastName.hashCode(); result = 37*result + (int)(birthDate ^ birthDate >>> 32); return result; } A teraz piszemy...
  • 15. public int hashCode() { final int prime = 31; int result = 1; result = prime * result + Arrays.hashCode(specjalities); return result; } public boolean equals(Object obj) { if (this == obj) { return true; } if (!super.equals(obj)) { return false; } if (!(obj instanceof Professor)) { return false; } Professor other = (Professor) obj; if (!Arrays.equals(specjalities, other.specjalities)) { return false; } return true; } lub generujemy...
  • 16. public String toString() { return "Professor [specjalities=" + Arrays.toString(specjalities) + "]"; } to samo tyczy się toString()'a
  • 17. public boolean equals(Object o) { if (o == null) { return false; } if (o == this) { return true; } if (o.getClass() != getClass()) { return false; } final Student s = (Student) o; return new EqualsBuilder() .appendSuper(super.equals(o)).append(year, s.year) .isEquals(); } public int hashcode() { return new HashCodeBuilder(17, 37) .appendSuper(super.hashcode()).append(year) .toHashCode(); } public String toString() { return new ToStringBuilder(this) .appendSuper(super.toString()).append("year", year) .toString(); } ale przy setce encji się nie chcieć
  • 18. public boolean equals(Object o) { if (o instanceof Lecture) { Lecture l = (Lecture) o; return Objects.equal(professor, l.professor) && Objects.equal(students, l.students) && Objects.equal(title, l.title); } return false; } public int hashcode() { return Objects.hashCode(title, professor, students); } public String toString() { return Objects.toStringHelper(this) .add("professor", professor) .add("students", students) .toString(); } albo mniej fundamentalnie
  • 19. public void addLectureWithCommons(Lecture lecture, Venue venue, int dayOfTheWeek, int hour) { Validate.isTrue(dayOfTheWeek > 0 && dayOfTheWeek <= 7, "There are only 7 days of the week"); Validate.isTrue(hour >= 0 && hour < 23, "Day has only 24hours"); Validate.notNull(lecture != null, "Lecture cannot be null"); Validate.notNull(venue != null, "Venue cannot be null"); // reminder omitted } public void addLectureWithGuava(Lecture lecture, Venue venue, int dayOfTheWeek, int hour) { Preconditions.checkArgument(dayOfTheWeek > 0 && dayOfTheWeek <= 7, "There are only 7 days of the week"); Preconditions.checkArgument(hour >= 0 && hour < 23, "Day has only 24hours"); Preconditions.checkArgument(lecture != null, "Lecture cannot be null"); Lecture localLecture = Preconditions.checkNotNull(lecture); Venue localVenue = Preconditions.checkNotNull(venue); // reminder omitted } defensive programming
  • 20. String[] csv; for (String line : csv) { String[] elements = line.split(","); // reminder omitted } for (String line : csv) { String[] r = StringUtils.split(line, ","); r = StringUtils.stripAll(r); } for (String line : csv) { Splitter.on(",") .trimResults() .omitEmptyStrings() .split(line); } a później zawsze trafimy na String'a
  • 21. public interface LectureService { public Student[] getStudentsByYear(int year); public Student[] getStudentsOlderThan(int age); public Student[] getStudentsByBirthDate(Date date); } i kilka operacji 'biznesowych'
  • 22. public Student[] getStudentsByYear(int year) { final List<Student> students = new ArrayList<Student>(); for (Student s : lecture.getStudents()) { if (s.getYear() == year) { students.add(s); } } return students.toArray(new Student[] {}); } które sprowadzają się...
  • 23. public Student[] getStudentsByBirthDate(Date date) { final List<Student> students = new ArrayList<Student>(); for (Student s : lecture.getStudents()) { Calendar studentBirth = Calendar.getInstance(); studentBirth.setTimeInMillis(s.getBirthDate()); Calendar desiredDate = Calendar.getInstance(); desiredDate.setTime(date); if (studentBirth.get(Calendar.YEAR) == desiredDate.get(Calendar.YEAR) && studentBirth.get(Calendar.MONTH) == desiredDate.get(Calendar.MONTH) && studentBirth.get(Calendar.DATE) == desiredDate.get(Calendar.DATE)) { students.add(s); } } return students.toArray(new Student[] {}); } ... do niemal ...
  • 24. public Student[] getStudentsOlderThan(int age) { final List<Student> students = new ArrayList<Student>(); for (Student s : lecture.getStudents()) { Calendar c = Calendar.getInstance(); c.setTimeInMillis(s.getBirthDate()); c.add(Calendar.YEAR, age); Calendar now = Calendar.getInstance(); now.setTime(new Date()); if (c.before(now)) { students.add(s); } } return students.toArray(new Student[] {}); } ... tego samego.
  • 25. public Student[] getStudentsOlderThan(int age) { final List<Student> students = new ArrayList<Student>(); for (Student s : lecture.getStudents()) { DateMidnight dt = new DateMidnight() .withMillis(s.getBirthDate()) .plusYears(age); if (dt.isBeforeNow()) { students.add(s); } } return students.toArray(new Student[] {}); } i abstahując od użycia JodaTime
  • 26. private Student[] getStudents(Predicate predicate) { final List<Student> students = new ArrayList<Student>(); for (Student s : lecture.getStudents()) { if (predicate.evaluate(s)) { students.add(s); } } return students.toArray(new Student[] {}); } Don't Repeat Yourself
  • 27. Predicate predicate = new Predicate() { @Override public boolean evaluate(Object arg0) { if (arg0 instanceof Student) { Student s = (Student) arg0; DateMidnight dt = new DateMidnight() .withMillis(s.getBirthDate()) .plusYears(age); if (dt.isBeforeNow()) { return true; } } return false; } }; No a ten predykat?
  • 28. Predicate<Student> predicate = new Predicate<Student>() { @Override public boolean apply(Student input) { DateMidnight dt = new DateMidnight() .withMillis(input.getBirthDate()) .plusYears(age); if (dt.isBeforeNow()) { return true; } return false; } }; No a ten predykat? (2)
  • 29. private Student[] getStudents(Predicate predicate) { final List<Student> students = new ArrayList<Student>(); for (Student s : lecture.getStudents()) { if (predicate.evaluate(s)) { students.add(s); } } return students.toArray(new Student[] {}); } i jeszcze na koniec, zamiast...
  • 30. protected Student[] getStudents(Predicate<Student> predicate) { Iterable<Student> students = Iterables .filter(Arrays.asList(lecture.getStudents()), predicate); return Iterables.toArray(students, Student.class); } ... może być w ogóle ślicznie
  • 31. Student[] students = service.promoteStudents(2); Predicate<Student> predicate = new Predicate<Student>() { public boolean apply(Student input) { if (input.getYear() == year) { return true; } return false; } }; Function<Student,Student> function = new Function<Student,Student>(){ public Student apply(Student input) { input.setYear(year + 1); return input; } }; Iterables.filter(); Iterables.transform(); Jak już jest prawie funkcyjnie...
  • 32. Guava to nie tylko <generics> © Kevin Bourrillion, Google, Inc.
  • 33. private Map<Student, List<Lecture>> classes = new HashMap<Student, List<Lecture>>(); // ... for (Lecture lecture : lectures) { for (Student student : lecture.getStudents()) { if (service.classes.containsKey(student)) { service.classes.get(student).add(lecture); } else { List<Lecture> l = new ArrayList<Lecture>(); l.add(lecture); service.classes.put(student, l); } } } kiedyś było tak...
  • 34. private Multimap<Student, Lecture> classes = ArrayListMultimap.create(); // ... for (Lecture lecture : lectures) { for (Student student : lecture.getStudents()) { service.classes.put(student, lecture); } } Map<Student, Collection<Lecture>> map = classes.asMap(); Collection<Lecture> lectures = classes.values(); Set<Student> students = classes.keySet(); for (Map.Entry<Student, Lecture> entry : classes.entries()) {} ... a teraz witamy Multimap i Multiset
  • 35. Map<Student, Collection<Lecture>> map = classes.asMap(); "JM" => {"Fizyka", "Chemia", "Matematyka"}, "TD" => {"Chemia", Biologia"} Collection<Lecture> lectures = classes.values(); {"Fizyka", "Matematyka", "Chemia", "Biologia"} Set<Student> students = classes.keySet(); {"JM", "TD"} for (Map.Entry<Student, Lecture> entry : classes.entries()) {} {"JM"=>"Fizyka", "JM"=>"Matematyka", "JM"=>"Chemia", "TD"=>"Biologia", ...} Collection<Lecture> lectures = classes.get("JM"); {"Fizyka", "Chemia", "Matematyka"} Multimap i Multiset (2)
  • 36. ImmutableSet<Student> students = ImmutableSet.copyOf(service.getStudentsByYear(2)); Set<Student> students = Collections.unmodifiableSet( new LinkedHashSet<Student>( Arrays.asList(service.getStudentsByYear(2)))); Immutability
  • 37. new Person("Ridge", "Forrster"); Person person = new Person.Builder() .withName(“Ridge”) .withSurname(“Forrester”) .build(); Immutability with builders http://www.marchwicki.pl/blog/2010/11/building-a-pojo-in-an-elegant-way/