![Page 1: [PL] O klasycznej, programistycznej elegancji](https://reader033.vdocuments.pub/reader033/viewer/2022060111/5563a65bd8b42aae0d8b4f17/html5/thumbnails/1.jpg)
O klasycznej programistycznej elegancji
http://my.opera.com/rato53/albums/
![Page 2: [PL] O klasycznej, programistycznej elegancji](https://reader033.vdocuments.pub/reader033/viewer/2022060111/5563a65bd8b42aae0d8b4f17/html5/thumbnails/2.jpg)
Jakub MarchwickiTechnical ConsultantJava, Lua, PHPi tak od 9lat
marchwicki.pl/blog@kubamarchwicki
![Page 3: [PL] O klasycznej, programistycznej elegancji](https://reader033.vdocuments.pub/reader033/viewer/2022060111/5563a65bd8b42aae0d8b4f17/html5/thumbnails/3.jpg)
Kanon piękna?
© vitra
![Page 4: [PL] O klasycznej, programistycznej elegancji](https://reader033.vdocuments.pub/reader033/viewer/2022060111/5563a65bd8b42aae0d8b4f17/html5/thumbnails/4.jpg)
Kanon piękna?
![Page 5: [PL] O klasycznej, programistycznej elegancji](https://reader033.vdocuments.pub/reader033/viewer/2022060111/5563a65bd8b42aae0d8b4f17/html5/thumbnails/5.jpg)
„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
![Page 6: [PL] O klasycznej, programistycznej elegancji](https://reader033.vdocuments.pub/reader033/viewer/2022060111/5563a65bd8b42aae0d8b4f17/html5/thumbnails/6.jpg)
Martin Fowler jeszcze raz
![Page 7: [PL] O klasycznej, programistycznej elegancji](https://reader033.vdocuments.pub/reader033/viewer/2022060111/5563a65bd8b42aae0d8b4f17/html5/thumbnails/7.jpg)
Joshua Bloch
![Page 8: [PL] O klasycznej, programistycznej elegancji](https://reader033.vdocuments.pub/reader033/viewer/2022060111/5563a65bd8b42aae0d8b4f17/html5/thumbnails/8.jpg)
Effective Java
I sure wish I had this book ten
years agoJames Gosling
![Page 9: [PL] O klasycznej, programistycznej elegancji](https://reader033.vdocuments.pub/reader033/viewer/2022060111/5563a65bd8b42aae0d8b4f17/html5/thumbnails/9.jpg)
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
![Page 10: [PL] O klasycznej, programistycznej elegancji](https://reader033.vdocuments.pub/reader033/viewer/2022060111/5563a65bd8b42aae0d8b4f17/html5/thumbnails/10.jpg)
Implementation patterns
CommunicationSimplicityFlexibility
A wszystko dlatego żenajwiększym kosztem
oprogramowania będzie i tak jego
utrzymanie
![Page 11: [PL] O klasycznej, programistycznej elegancji](https://reader033.vdocuments.pub/reader033/viewer/2022060111/5563a65bd8b42aae0d8b4f17/html5/thumbnails/11.jpg)
Kryteria dobrego kodu
© http://www.agileadvisor.com/
![Page 12: [PL] O klasycznej, programistycznej elegancji](https://reader033.vdocuments.pub/reader033/viewer/2022060111/5563a65bd8b42aae0d8b4f17/html5/thumbnails/12.jpg)
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...
![Page 13: [PL] O klasycznej, programistycznej elegancji](https://reader033.vdocuments.pub/reader033/viewer/2022060111/5563a65bd8b42aae0d8b4f17/html5/thumbnails/13.jpg)
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...
![Page 14: [PL] O klasycznej, programistycznej elegancji](https://reader033.vdocuments.pub/reader033/viewer/2022060111/5563a65bd8b42aae0d8b4f17/html5/thumbnails/14.jpg)
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...
![Page 15: [PL] O klasycznej, programistycznej elegancji](https://reader033.vdocuments.pub/reader033/viewer/2022060111/5563a65bd8b42aae0d8b4f17/html5/thumbnails/15.jpg)
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...
![Page 16: [PL] O klasycznej, programistycznej elegancji](https://reader033.vdocuments.pub/reader033/viewer/2022060111/5563a65bd8b42aae0d8b4f17/html5/thumbnails/16.jpg)
public String toString() {return "Professor [specjalities=" +
Arrays.toString(specjalities) + "]";}
to samo tyczy się toString()'a
![Page 17: [PL] O klasycznej, programistycznej elegancji](https://reader033.vdocuments.pub/reader033/viewer/2022060111/5563a65bd8b42aae0d8b4f17/html5/thumbnails/17.jpg)
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ć
![Page 18: [PL] O klasycznej, programistycznej elegancji](https://reader033.vdocuments.pub/reader033/viewer/2022060111/5563a65bd8b42aae0d8b4f17/html5/thumbnails/18.jpg)
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
![Page 19: [PL] O klasycznej, programistycznej elegancji](https://reader033.vdocuments.pub/reader033/viewer/2022060111/5563a65bd8b42aae0d8b4f17/html5/thumbnails/19.jpg)
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
![Page 20: [PL] O klasycznej, programistycznej elegancji](https://reader033.vdocuments.pub/reader033/viewer/2022060111/5563a65bd8b42aae0d8b4f17/html5/thumbnails/20.jpg)
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
![Page 21: [PL] O klasycznej, programistycznej elegancji](https://reader033.vdocuments.pub/reader033/viewer/2022060111/5563a65bd8b42aae0d8b4f17/html5/thumbnails/21.jpg)
public interface LectureService {public Student[] getStudentsByYear(int year);public Student[] getStudentsOlderThan(int age);public Student[] getStudentsByBirthDate(Date date);
}
i kilka operacji 'biznesowych'
![Page 22: [PL] O klasycznej, programistycznej elegancji](https://reader033.vdocuments.pub/reader033/viewer/2022060111/5563a65bd8b42aae0d8b4f17/html5/thumbnails/22.jpg)
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ę...
![Page 23: [PL] O klasycznej, programistycznej elegancji](https://reader033.vdocuments.pub/reader033/viewer/2022060111/5563a65bd8b42aae0d8b4f17/html5/thumbnails/23.jpg)
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 ...
![Page 24: [PL] O klasycznej, programistycznej elegancji](https://reader033.vdocuments.pub/reader033/viewer/2022060111/5563a65bd8b42aae0d8b4f17/html5/thumbnails/24.jpg)
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.
![Page 25: [PL] O klasycznej, programistycznej elegancji](https://reader033.vdocuments.pub/reader033/viewer/2022060111/5563a65bd8b42aae0d8b4f17/html5/thumbnails/25.jpg)
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
![Page 26: [PL] O klasycznej, programistycznej elegancji](https://reader033.vdocuments.pub/reader033/viewer/2022060111/5563a65bd8b42aae0d8b4f17/html5/thumbnails/26.jpg)
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
![Page 27: [PL] O klasycznej, programistycznej elegancji](https://reader033.vdocuments.pub/reader033/viewer/2022060111/5563a65bd8b42aae0d8b4f17/html5/thumbnails/27.jpg)
Predicate predicate = new Predicate() {@Overridepublic 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?
![Page 28: [PL] O klasycznej, programistycznej elegancji](https://reader033.vdocuments.pub/reader033/viewer/2022060111/5563a65bd8b42aae0d8b4f17/html5/thumbnails/28.jpg)
Predicate<Student> predicate = new Predicate<Student>() {@Overridepublic 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)
![Page 29: [PL] O klasycznej, programistycznej elegancji](https://reader033.vdocuments.pub/reader033/viewer/2022060111/5563a65bd8b42aae0d8b4f17/html5/thumbnails/29.jpg)
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...
![Page 30: [PL] O klasycznej, programistycznej elegancji](https://reader033.vdocuments.pub/reader033/viewer/2022060111/5563a65bd8b42aae0d8b4f17/html5/thumbnails/30.jpg)
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
![Page 31: [PL] O klasycznej, programistycznej elegancji](https://reader033.vdocuments.pub/reader033/viewer/2022060111/5563a65bd8b42aae0d8b4f17/html5/thumbnails/31.jpg)
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...
![Page 32: [PL] O klasycznej, programistycznej elegancji](https://reader033.vdocuments.pub/reader033/viewer/2022060111/5563a65bd8b42aae0d8b4f17/html5/thumbnails/32.jpg)
Guava to nie tylko <generics>
© Kevin Bourrillion, Google, Inc.
![Page 33: [PL] O klasycznej, programistycznej elegancji](https://reader033.vdocuments.pub/reader033/viewer/2022060111/5563a65bd8b42aae0d8b4f17/html5/thumbnails/33.jpg)
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...
![Page 34: [PL] O klasycznej, programistycznej elegancji](https://reader033.vdocuments.pub/reader033/viewer/2022060111/5563a65bd8b42aae0d8b4f17/html5/thumbnails/34.jpg)
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
![Page 35: [PL] O klasycznej, programistycznej elegancji](https://reader033.vdocuments.pub/reader033/viewer/2022060111/5563a65bd8b42aae0d8b4f17/html5/thumbnails/35.jpg)
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)
![Page 36: [PL] O klasycznej, programistycznej elegancji](https://reader033.vdocuments.pub/reader033/viewer/2022060111/5563a65bd8b42aae0d8b4f17/html5/thumbnails/36.jpg)
ImmutableSet<Student> students = ImmutableSet.copyOf(service.getStudentsByYear(2));
Set<Student> students = Collections.unmodifiableSet(
new LinkedHashSet<Student>(Arrays.asList(service.getStudentsByYear(2))));
Immutability
![Page 37: [PL] O klasycznej, programistycznej elegancji](https://reader033.vdocuments.pub/reader033/viewer/2022060111/5563a65bd8b42aae0d8b4f17/html5/thumbnails/37.jpg)
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/
![Page 38: [PL] O klasycznej, programistycznej elegancji](https://reader033.vdocuments.pub/reader033/viewer/2022060111/5563a65bd8b42aae0d8b4f17/html5/thumbnails/38.jpg)
Dziękuje
http://marchwicki.pl/blog
@kubamarchwicki
http://www.delicious.com/kuba.marchwicki/beautifulcode
http://www.assembla.com/code/km_jug/subversion/nodes