poniedziałek, 31 sierpnia 2015

Spark i FP w nowym roku szkolnym

To jest czwarte podejście do napisania wstępu by nie był zbyt nudny - wykorzystajmy sprawdzoną mieszankę listy wypunktowanej i hiszpańskiej finezji!!

  • Masa ciekawych prezentacji na JUGu tej jesieni! KLIKNIJ W KALENDARZ - OLEEEEEEE!
  • I do tego dalsze warsztaty ze Scali - OLEEEEEEE!
  • Raz w kontekście nauki Sparka - OLEEEEEEE!
  • "A co to jest spark?"
  • To się własnie dowiesz - OLEEEEEEEEEE!
  • A dwa to ciekawsza nauka języka poprzez stopniowa naukę programowania funkcyjnego - OLEEEEEEE!

Lista planowanych spotkań :

  1. Apache Spark - Wprowadzenie
  2. Apache Spark - Aspekty bardziej zaawansowane
  3. Apache Spark - Dataframes
  4. Apache Spark - Machine Learning podstawy

Po najlepszym wstępnie, który byłem w stanie wymyślić przychodzi część dalsza...

Spark i łatwiejsza nauka

Jeśli kogoś interesuje temat BigData, który ostatnio nazywa się FastData albo InnaData (chociaz IData może być już opatentowana) to Spark przedstawia dosyć ciekawe aspekty edukacyjne. Bo o ile aby napisać "Hadoop hello world" albo trzeba ogarnąć jakiś obraz na maszynę wirtualną albo przebrnąć przez konfigurację kilku xmli to w przypadku Sparka - 1) ściągamy zipa 2) rozpakowujemy 3) startujemy konsolę ... i można działać!

Oczywiście problemy mogę pojawić się na windowsie ale nie będę śmiał się z windowsa bo bill gates podobno wydaje na poprawe życia krajach trzeciego świata niż ludzie wyslali lajków pod demotami na fejsie. W każdym razie...

Polecana platforma do nauki to Ubuntu i generalnie można działać. Widziałem próby ruszenia warsztatów z hadoopem i to bolało a tutaj powinno być łatwo bo ---> uwaga, pojawia się drugi fajny buzzword ---> Spark jest stworzony przez ludzi od DATASCIENCE i oni są przyzwyczajeni, że narzędzia są dla nich łatwe i przyjazne w użyciu (i w sumie fajnie)

Ciekawsza informatyka i zmierzch "risorsa"

Dlaczego warto się nauczyć Sparka i Machine Learning? Zanim zajmiemy się innymi zachętami - najpierw motywator klasyczny :

Teraz można by zrobić długi wywód o homeostazie i ujemnym sprzężeniu zwrotnym w ekonomii ale tak na logike - jak ktoś nie chce robić całe życie CRUDów to musi się nauczyć czegoś innego aniżeli CRUDów (no chyba, że chce robić CRUDy, płacić raty i czuć spełnienie poprzez nowy kredens - to jest kwestia dyskusyjna czy model Cobolowy da się powtórzyć kiedy nowe technologie napierdalaja z taką prędkością, że stare systemy może zacząć sie opłacać przepisywać aniżeli utrzymywać?). I co innego na przykład można robić? NA edx był w wakacje ciekawy "Scalable Machine Learning" także na sparku i tam był ciekawy problem do rozwiązania:

Jest zeskanowany mózg myszy :
I teraz trzeba go obrobić i generalnie taki skan to jest własnie dużo danych i trzeba to robić mądrze :

I wiele innych ciekawych rzeczy - jak na przykąłd analiza białek coś tam coś tam DNA coś tam

A jak to nie przemawia to jeszcze raz

Jaki to ma związek ze scalą? Spark jest napisany w Scali i jest to język dla niego natywny. I w sumie na czymś tak praktycznym nauka powinna być przyjemniejsza. Plus jest coś jeszcze jeden front...

A jeśli nic z tego cie drogi czytelniku nie przekonało do przyjścia na warsztaty - to zazwyczaj jest też darmowa pizza.

FP i życie codzienne

Zaraz po mobilizacji 22 października zrobię wykład na podstawie książki - https://manning.com/books/functional-and-reactive-domain-modeling. Generalnie jeśli tylko uda się wyminąć flejma OOP vs FP to otwiera się pola do naprawdę niesamowitych konstrukcji.

Jeśli temat podchwyci to i z tego tez będą jakieś warsztaty. A niezależnie od tego Artur Czajka rozpocznie serię o programowaniu funkcyjnym z Haskellem :

Na nowy rok

Gorąco zachęcam wszystkich do uczestniczenia w budowie społeczności IT w Łodzi.

I Ogólnie polecam mniej tego :

A więcej tego :

poniedziałek, 10 sierpnia 2015

Soczewki,Obiektywy,Lenses

Ten artykuł zaczyna się serio oczywistych stwierdzeń o geterach i seterach i o tym, ze pojawiła się masa artykułów odnośnie tego, że są złe i też pojawiła się seria artykułów o tym, ze są dobre i ze jedni i drudzy się hejtowali.

A skoro mamy to za sobą to z getterami było tak:

Z enkapsulacją jakoś tak:

Czy brak/obecność getterów i setterów to pełne spektrum możliwości? Otóż co ciekawe nie. Poniżej zupełnie inna technika, która wychodzi poza pudełko obiektowych dysput. Idea jest taka by każdy sobie obejrzał i sam zdecydował czy to ma dla niego sens...

Soczewki

Zaczynamy od czegoś co obija się o profanacje czyli damy pola bez modyfikatora private :

public class User {
    String name;
    String email;
}

Ale co ciekawe nie ma tez modyfikatora public. Ciekawe jak to jest z edukacją wśród młodzieży i czy to część wiedzy powszechnej, że brak modyfikatora w javie to równeiż modyfiaktor. pakietowy.

I na przykład z byle jakiego miejsca się tutaj nie dostanę.

public class OuterClass {
    public static void main(String args[]) {
        User user=new User();
        //user.name="Stefan"; //Oj nie nie nie , Co to to nie!
    }
}

Osiągnęliśmy więc pewien poziom enkapsulacji - może nie obiektowej ale "paczkowej". Ale jak ustawić to pole bez gettera jeśli go nie ma? Otóż on jest ale gdzieś indziej.

Out of the box

No własnie gdzie może być ten getter. Na pewnie w tej samej paczce ale w zupełnie innej klasie :

Taka sytuacja

public class UserModule {
    public static Function<User,String> getName=u->u.name;
    public static BiConsumer<User,String> setName= (u,n)->u.name=n;

    //ciekawiej
    public static Function<User,Consumer<String>> setNameCurrying=u->n->u.name=n;

}

Powyższe funkcje są na razie jedynym sposobem dostępu do naszego obiektu :
import static blog.UserModule.*;
public class OuterClass {
    public static void main(String args[]) {
        User user=new User();

        setName.accept(user,"Stefan");
        System.out.println(getName.apply(user));

        setNameCurrying.apply(user).accept("Zofia");
        System.out.println(getName.apply(user));
    }
}

No i fajnie ale poza aspektem naukowo-artystycznym - oddzielenie funkcji od obiektu ma jeden ciekawy aspekt praktyczny - jedno i drugie można niezależnie komponować.

Trochę inna kompozycja

Weźmy coś takiego - to jest taki niby agregat ale aby nikt mnie nie łapał za słówka nie będę tego nazywał agregatem:

public class User {
    String name;
    Email email;
}

class Email{
    String address;
}

O ile jeszcze pamiętam Jave to klasa Email tez jest w zakresie pakietowym i nie widać jej na zewnątrz.

I dalej

//package setters
static Function<User,Consumer<Email>> setEmail=user->newEmail->user.email=newEmail;
static Function<Email,Consumer<String>> setAddress=email->newAddress->email.address=newAddress;
    //package getters
static Function<User,Email> getEmail=u->u.email;
static Function<Email,String> getAddress=e->e.address;

I teraz, i teraz to się stanie, teraz to będzie...teraz to będzie... ściana
public class Kombinatoryka {
    public static Function<User,Consumer<String>> composeSet(Function<User,Consumer<Email>> f1,Function<Email,Consumer<String>> f2){
        //return  ... I co teraz? ściana? To jest przykład na to, że wszelkie wywołanai bez typu zwracanego, czyli wszelkie konsumery
        //komponują się chu***owo
        //mozna niby tak ale to jest bez sensu bo możemy zapomnieć o wszelkiej generalizacji biblioteki
        return u->{
            Email email=UserModule.getEmail.apply(u);
            return f2.apply(email);
        };
    }
}

Podejście numer dwa bez konsumerów

Tym razem zwracamy wynik naszego działania :
static BiFunction<User,Email,User> setEmail=(user,newEmail)->{user.email=newEmail; return user;};
static BiFunction<Email,String,Email> setAddress=(email,newAddress)->{email.address=newAddress;return email;};

Czy tym raazem się uda? Nie:)
public class Kombinatoryka {
    public static BiFunction<User,String,User> composeSet(BiFunction<User,Email,User> outer,BiFunction<Email,String,Email> inner){
        (user,newAddress)->outer.apply(u,inner.apply(//i znowu ściana, jak wyłuskac z usera email?))
    }

Aby myśleć o kompozycji musimy dorzucić przynajmniej jeden getter.
public class Kombinatoryka {
    public static BiFunction<User,String,User> composeSet(BiFunction<User,Email,User> outer,
                                                            BiFunction<Email,String,Email> inner,
                                                            Function<User,Email> outerGet){
        return (user,newAddress)->outer.apply(user,inner.apply(outerGet.apply(user),newAddress));
    }
}

Tak jest to trochę zamotane. Co możemy zrobić?Najpierw tak

interface GenericLens<O,V>{
        BiFunction<O,V,O> setter();
        Function<O,V> getter();
    }

Później tak
static class UserLens implements GenericLens<User,Email>{
        @Override
        public BiFunction<User, Email, User> setter() {
            return (user,newEmail)->{user.email=newEmail; return user;};
        }

        @Override
        public Function<User, Email> getter() {
            return u->u.email;
        }
    }

    static class EmailLens implements GenericLens<Email,String>{

        @Override
        public BiFunction<Email, String, Email> setter() {
            return (email,newAddress)->{email.address=newAddress;return email;};
        }

        @Override
        public Function<Email, String> getter() {
            return e->e.address;
        }
    }

Następnie tak :
public static <Outer,Inner,Value> GenericLens<Outer,Value> composeLens(
            GenericLens<Outer,Inner> outerLens,
            GenericLens<Inner,Value> innerLens
    ){
            return new GenericLens<Outer, Value>() {
                @Override
                public BiFunction<Outer, Value, Outer> setter() {
                    return (outer,value)->{
                        Inner inner = outerLens.getter().apply(outer);
                        Inner newInner = innerLens.setter().apply(inner, value);
                        return outerLens.setter().apply(outer,newInner);
                    };
                }

                @Override
                public Function<Outer, Value> getter() {
                    return outer->{
                        Function<Outer, Inner> outerGetter = outerLens.getter();
                        Function<Inner, Value> innerGetter = innerLens.getter();
                        Inner inner = outerGetter.apply(outer);
                        return innerGetter.apply(inner);
                    };
                }
            };
    }

I na końcu tak :
static GenericLens<User,String> userEmailLens=Kombinatoryka.composeLens(new UserLens(),new EmailLens());

Co uzyskaliśmy

Teoretycznie mamy enkapsulację obiektów i znowu teoretycznie generyczny mechanizm do kompozycji działań na tych obiektach. Ale wygląda to przerażająco. Niby można sobie założyć, że część z tego kodu byłaby zamknięta przed oczami świata gdzieś w bibliotece...

Czy są inne opcje?

Inne Opcje

Generlanie w Javie nie znalazłem, żadnej biblioteki, która implementuje opisany mechanizm. W scali do dyspozycji jest całkiem ciekawa biblioteczka https://github.com/julien-truffaut/Monocle

libraryDependencies ++= Seq(
 "com.github.julien-truffaut" %% "monocle-generic" % "1.1.1",
 "com.github.julien-truffaut" %%  "monocle-generic" % "1.1.1",
 "com.github.julien-truffaut" %%  "monocle-macro"   % "1.1.1"
)
import monocle.macros.GenLens
case class Email(address:String)
case class User(name:String,email:Email)

val userEmailLens=GenLens[User](_.email)
val emailAddressLens=GenLens[Email](_.address)

val u=User("Stefan",Email("stefan@wp.pl"))

val userAddressLens=userEmailLens composeLens emailAddressLens
val nowyUser=userAddressLens.set("stefan@gmail.com")(u)
nowyUser // User(Stefan,Email(stefan@gmail.com))

I to w zasadzie to tyle kodu potrzeba...