Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

[PL] O klasycznej, programistycznej elegancji

1,072 views

Published on

This presentation is only in Polish.

Slajdy z prezentacji grupy JUG, 25 listopada 2010

Published in: Technology
  • Be the first to comment

  • Be the first to like this

[PL] O klasycznej, programistycznej elegancji

  1. 1. O klasycznej programistycznej elegancji http://my.opera.com/rato53/albums/
  2. 2. Jakub Marchwicki Technical Consultant Java, Lua, PHP i tak od 9lat marchwicki.pl/blog @kubamarchwicki
  3. 3. Kanon piękna? © vitra
  4. 4. Kanon piękna?
  5. 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
  6. 6. Martin Fowler jeszcze raz
  7. 7. Joshua Bloch
  8. 8. Effective Java I sure wish I had this book ten years ago James Gosling
  9. 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. 10. Implementation patterns Communication Simplicity Flexibility A wszystko dlatego że największym kosztem oprogramowania będzie i tak jego utrzymanie
  11. 11. Kryteria dobrego kodu © http://www.agileadvisor.com/
  12. 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. 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. 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. 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. 16. public String toString() { return "Professor [specjalities=" + Arrays.toString(specjalities) + "]"; } to samo tyczy się toString()'a
  17. 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. 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. 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. 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. 21. public interface LectureService { public Student[] getStudentsByYear(int year); public Student[] getStudentsOlderThan(int age); public Student[] getStudentsByBirthDate(Date date); } i kilka operacji 'biznesowych'
  22. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 32. Guava to nie tylko <generics> © Kevin Bourrillion, Google, Inc.
  33. 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. 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. 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. 36. ImmutableSet<Student> students = ImmutableSet.copyOf(service.getStudentsByYear(2)); Set<Student> students = Collections.unmodifiableSet( new LinkedHashSet<Student>( Arrays.asList(service.getStudentsByYear(2)))); Immutability
  37. 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/
  38. 38. Dziękuje http://marchwicki.pl/blog @kubamarchwicki http://www.delicious.com/kuba.marchwicki/beautifulcode http://www.assembla.com/code/km_jug/subversion/nodes

×