Opinie
Co do konkretów to :
Mam dobrą wiadomość - będzie jeszcze więcej Scali,ooooooooojjjj będzie jej dużo dużo dużo więcej. Ale powinno być ciekawie i mam nadzieję opinie będę spójnie szły na tak.
Lesson learned
Dobre komentarze są miłe, przyjemne i stanowią opium dla ego ale czasem nie są zbytnio rozwijające. Jak na razie najlepszy komentarz jaki miałem w życiu to był ten o tym, że pisanie długich kawałków kodu jest nudne dla publiki i teraz na prezentację przygotowuję sobie szablony.
W opiniach pojawiło się kilka ciekawych komentarzy z interesującymi obserwacjami :
- trochę nerwowa atmosfera, aczkolwiek łagodzona żartami ;) - (Tego nie rozumiem - raz, że tym razem przed prezentacją nie wziąłem Napalmu a dwa to zacząłem regularnie pijać Melisę)
- Mikrofon :3 - To jest umiejętność, którą dopiero muszę posiąść - korzystanie z mikrofonu. Do tej pory - gdy nie było mikrofonu - starałem się mówić donośnie i teraz zajmie chwilę kalibrowanie tego nawyku pod mikrofon. Na tej prezentacji nie chciałem kombinować pod to pierwsza pod nowym logiem ale kiedyś może zrobię taką bez kodowania z chodzeniem po scenie i gestykulacja. Wtedy z mikrofonem będę wyglądał jak prawdziwy wodzirej! A tak ogólnie mikrofon to chyba dobry pomysł
- Początek prezentacji mógłby być lepszy. Co to za puszczanie jakichś słabych kawałków z ligi mistrzów. Kiedyś Paweł zaczynał cyckami i było ok. - Od razu chcę wszystkich uspokoić - nigdy nie zaczynałem swoimi! Cycków nie będę pokazywał bo podobno dziewczyny się wtedy wstydzą i nie chcą przychodzić :(
Kod
Nie chcę mi się pisać wszystkiego linia po linii dlatego też skupię się na najważniejszych fragmentach koderskiego wywodu.
Do teog na tym blogu nie mamy chyba jeszcze żadnego formatera kodu także wrzucę linijki w zwykłe "pre"
Uświadom potrzebę
Zauważyłem, że większość dyskusji o wyjątkach w świecie Javowym zakłada checked albo unchecked bez dopuszczenia trzeciej drogi (chyba, że ktoś walnie suchara z kodami błędu). Większość ludzi bardziej przychyla się do unchecked exceptions bo mniej jest z nimi prądu.
Ciekawszym wyzwaniem jest pokazanie wad wyjątków unchecked poprzez nawiązanie do pierwszego flejm WARa GOTO considered harmful considered harmful considered harmful
public static void main(String[] args) {
try {
System.out.println("linia1");
System.out.println("linia2");
System.out.println("linia3");
gotoLine6();
System.out.println("linia4");
System.out.println("linia5");
} catch (GoTo e) {
System.out.println("linia6");
}
}
private static void gotoLine6() {
System.out.println("goooooto line6");
throw new GoTo();
}
i wynik
linia1 linia2 linia3 goooooto line6 linia6
Podważ dogmaty
Do dalszych wywodów zainspirowała mnie jedna z prezentacji Erika Meijera gdzie przedstawił on setter i getter - teoretycznie mechanizmy znane i poniżane od wielu lat - z zupełnie innej perspektywy
- get[A] to nic innego jak funkcja Unit=>A
- set[A] to nic innego jak funkcja A=>Unit
i podobnie możemy sobie zanalizować błahą wydawało by się metodę
int metoda(int a,int b)
zaczęliśmy od Javy8 bo to bardzo dobry pomost pomiędzy Javą i Scalą.
W każdym razie mamy tę metodkę i co możemy o niej powiedzieć - no patrząc na typy przyjmuje dwa inty i też zwraca inta.
int metoda(int a,int b){ return a+b; }Na razie jest spoko :
int metoda(int a,int b){ return a-b; }Budujemy napięcie - na razie nie widać problemów
int metoda(int a,int b){ return a*b; }I teraz zaczynają się schody
int metoda(int a,int b){ return a/b; }Wsio się kompiluje a sam kompilator nic nie podkreśla
newWay.metoda(4, 2); // spoko newWay.metoda2(4, 0); //Exception in thread "main" java.lang.ArithmeticException: / by zero
No i dlaczego?!?! Przecież kompilator pokazuje wyraźnie, że zwraca inta. Czy ArithmeticException jest intem? Jeśli będziecie grali w pokera i powiecie, że wchodzicie za "ArithmeticException" to raczej nikt was nie zrozumie... Jeśli pani w sklepie alkoholowym zapyta ile macie lat - również zdanie "mam ArithmeticException lat" nie będzie miało sensu...
Wskaż rozwiazanie
Jak odzyskać kontrolę nad typami i zaufanie kompilatora? Nie chce mi się wkleiać całego wywodu krok po kroku także ten tego :
Optional<Integer> metoda(int a,int b){
if(b!=0)
return Optional.of(a/b);
else
return Optional.empty();
}
Był też przykład domenowy
Repository r=new Repository();
//dane
Optional<Double> data = r.findUser("Roman")
//domain 1
.filter(DomainPolicy::isAllowed)
//domain 2
.map(u->u.getSalary())
.flatMap(FinancialService::calculateTax);
//ui
Optional<String> ui = data.map(t->"<h1>"+t+"</h1>");
System.out.println(ui.orElse("404 not found"));
(...)
static class FinancialService{
static Optional<Double> calculateTax(Integer amount){
if(amount!=0)
return Optional.of(amount*1.23/amount);
else
return Optional.empty();
}
}
static class DomainPolicy{
static boolean isAllowed(User u){
return u.getSalary() > 15;
}
}
Idea jest następująca :
- Mamy kilka domen/poddomen/paczek/zakresów/płaszczyzn tematycznych - nieważne jak się to zwie
- W każdej domenie mamy zestaw dedykowanych funkcji,które operują na typach z tej domeny. Małe, krótkie i łatwe do testowania
- Optional udostępnia maszynerię, która może wywoływać te funkcje domenowe w kontekście obiektu, którego może nie być.
- Funkcje same w sobie nic o tym nie wiedzą co sprawia, że są mniej zależne od kontekstu, łatwiejsze w użyciu i dużo dużo łatwiejsze do testowania niż sprawdzanie jakichś wyjątków
Pokaż, że w scali da się napisać szybciej i przyjemniej
tutaj przynajmniej można wkleić cały program : case class User(name:String,salary:Int)
object Repository{
private val data=Map[String,User]("Roman"->User("Roman",20))
def findUSer(n:String)=data.get(n)
}
def calculateTax(amount:Int)=if(amount!=0) Some(amount+1.23/amount) else None
//> calculateTax: (amount: Int)Option[Double]
def domainPolicy(u:User)=u.salary>15 //> domainPolicy: (u: jug.wyjatki.NewWayWork.User)Boolean
Repository
.findUSer("Roman")
.filter(domainPolicy)
.map(_.salary)
.flatMap(calculateTax)
.map(t=>s"<h1>$t</h1>")
.getOrElse("404 not found") //> res3: String = <h1>20.0615</h1>
Trochę magii
Ale czy Option podobnie jak checked exception nie brudzi nam API? Czy można jakoś ładnie dostosować dostosować "czysta metodę" do użycia Option tak poprostu - z automatu?
Przykład do własnego sprawdzenia : def lift[A,B](f:A=>B):Option[A]=>Option[B]=a=> a.map(f)
def metoda1(a: Int) = a + 1
val lifted1=lift(metoda1)
lifted1(Some(5))
Plus wersja z wzorcem "Job Security"
def lift[A,B](f:A=>B):Option[A]=>Option[B]=_ map f
A to dopiero początek - więcej ciekawych przykładów w książce :
Co jeszcze Było?
- Jak for w Scali umożliwia wywołanie metody przyjmującej dwa Optiony
- Try - czyli konstrukcja w Scali, któ©a poza info o sukcesie niesie też informacje o błędzie
- No i dałem też przykład jak Akka obsługą wyjątków naprawia system z aktorami. To miała być druga część ale to koniec końców za dużo zamieszania wprowadziło ze względu na limit czasu
No i na koniec fajnie by było gdyby więcej osób zaczęło coś przygotowywać. No i była jeszcze jedna opinia, że takie prezentacje około godziny są w sam raz. Ludzie przychodzą zmęczeni po pracy i w sumie trudno im wysiedzieć więcej.