38
O klasycznej programistycznej elegancji http://my.opera.com/rato53/albums/

[PL] O klasycznej, programistycznej elegancji

Embed Size (px)

DESCRIPTION

This presentation is only in Polish. Slajdy z prezentacji grupy JUG, 25 listopada 2010

Citation preview

Page 1: [PL] O klasycznej, programistycznej elegancji

O klasycznej programistycznej elegancji

http://my.opera.com/rato53/albums/

Page 2: [PL] O klasycznej, programistycznej elegancji

Jakub MarchwickiTechnical ConsultantJava, Lua, PHPi tak od 9lat

marchwicki.pl/blog@kubamarchwicki

Page 3: [PL] O klasycznej, programistycznej elegancji

Kanon piękna?

© vitra

Page 4: [PL] O klasycznej, programistycznej elegancji

Kanon piękna?

Page 5: [PL] O klasycznej, programistycznej elegancji

„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

Martin Fowler jeszcze raz

Page 7: [PL] O klasycznej, programistycznej elegancji

Joshua Bloch

Page 8: [PL] O klasycznej, programistycznej elegancji

Effective Java

I sure wish I had this book ten

years agoJames Gosling

Page 9: [PL] O klasycznej, programistycznej elegancji

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

Implementation patterns

CommunicationSimplicityFlexibility

A wszystko dlatego żenajwiększym kosztem

oprogramowania będzie i tak jego

utrzymanie

Page 11: [PL] O klasycznej, programistycznej elegancji

Kryteria dobrego kodu

© http://www.agileadvisor.com/

Page 12: [PL] O klasycznej, programistycznej elegancji

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

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

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

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

public String toString() {return "Professor [specjalities=" +

Arrays.toString(specjalities) + "]";}

to samo tyczy się toString()'a

Page 17: [PL] O klasycznej, programistycznej elegancji

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Guava to nie tylko <generics>

© Kevin Bourrillion, Google, Inc.

Page 33: [PL] O klasycznej, programistycznej elegancji

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

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

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

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

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

Dziękuje

http://marchwicki.pl/blog

@kubamarchwicki

http://www.delicious.com/kuba.marchwicki/beautifulcode

http://www.assembla.com/code/km_jug/subversion/nodes