niedziela, 14 października 2012

Czym jest HAK?

Haki w kodzie

Wszystkie dzieci wiedzą, że hacki są złe bo zmniejszają jakość kodu ale czy czy ktoś z was zastanawiał się "jaka jest istota haka"? Jak go zdefiniować i po czym rozpoznać, że właśnie zastosowaliśmy hak? W celu uzyskania odpowiedzi wciśnij 5.

Rozpatrywany przypadek (u)życia





Kod poniżej stanowi próbę implementacji wspomnianej specyfikacji. Mamy klasę "Osobą" , która to klasa zawiera pewną narodowość określającą wytrzymałość alkoholową.

 
 public class HAK {
    public static void main(final String[] args) {
        final Osoba polak = new Osoba(POLAK);
        final Osoba rosjanin = new Osoba(ROSJANIN);
        final Osoba anglik = new Osoba(ANGLIK);

        System.out.println("10 promili");
        System.out.println("polak : " + (polak.czyPrzezyje(10) ? "przezyje" : "nie przeżyje"));
        System.out.println("rosjanin: " + (rosjanin.czyPrzezyje(10) ? "przezyje" : "nie przeżyje"));
        System.out.println("anglik : " + (anglik.czyPrzezyje(10) ? "przezyje" : "nie przeżyje"));
    }

    static class Osoba {
        private final Narodowosc narodowosc;

        private Osoba(final Narodowosc narodowosc) {
            this.narodowosc = narodowosc;
        }

        public boolean czyPrzezyje(final int promile) {
            return narodowosc.getLimitAlkoholowy() > promile;
        }
    }

    static enum Narodowosc {
        POLAK(16), ROSJANIN(16), ANGLIK(3);

        private final int limitAlkoholowy;

        private Narodowosc(final int limitAlkoholowy) {
            this.limitAlkoholowy = limitAlkoholowy;
        }

        public int getLimitAlkoholowy() {
            return limitAlkoholowy;
        }

    }
}

Gdy odpalimy program zobaczymy, że ze wspomnianej trójki: Polak,Rosjanin i Anglik - ten ostatni nie powinien przeżyć. Na razie wygląda to nieźle ale co się stanie gdy nasz Anglik postanowi opuścić swą zmąconą kryzysem ojczyznę, przyjąć obywatelstwo naszego pięknego kraju co zaowocuje pojawieniem się w jego obiekcie Narodowości "POLAK"? Program pochopnie uspokoi pijącego co może doprowadzić do tragedii!!! (podobny efekt może się pojawić gdy Rosja podbije Europę Zachodnią)

Czas na hak

Najszybszy hak :
 

 public boolean czyPrzezyje(final int promile) {
            return narodowosc.getLimitAlkoholowy() > promile 
&& nieprawdaZeBylAnglikiem();
        }

Można oczywiście przechować pierwotną narodowość i jej właśnie użyć do znalezienia limitu alkoholowego ale co gdy taka parka angielska przyjmie polskie obywatelstwo i powije dziecko w naszym przecudownym kraju? Jaki limit alkoholowy będzie miał ten potomek? Chyba intuicyjnie czujemy, że taki sam jak rodzice. I teraz pojawia się krytyczny moment a) możemy iść dalej w haki:
 

 public boolean czyPrzezyje(final int promile) {
            return narodowosc.getLimitAlkoholowy() > promile 
&& sprawdzCzyJegoPrzodkowieOdIlusTamPokolenTeżByPrzezyli();
        }

b) Możemy chwilę się zastanowić dlaczego pomimo tego, że specyfikacja nic o tym nie mówiła to historia przodków wpływa na wytrzymałość alkoholową. Powinno nas to doprowadzić do pewnej generalnej reguły, która określi jednoznacznie przypadki, z którymi męczyliśmy się do tej pory

Czas na generalna regułę

 

 public class OgolnaZasada {

    public static void main(final String[] args) {
        final Osoba polak = new Osoba(POLAK);
        final Osoba rosjanin = new Osoba(ROSJANIN);
        final Osoba anglik = new Osoba(ANGLIK);

        System.out.println("10 promili");
        System.out.println("polak : " + (polak.czyPrzezyje(10) ? "przezyje" : "nie przeżyje"));
        System.out.println("rosjanin: " + (rosjanin.czyPrzezyje(10) ? "przezyje" : "nie przeżyje"));
        System.out.println("anglik : " + (anglik.czyPrzezyje(10) ? "przezyje" : "nie przeżyje"));
    }

    static class Osoba {
        private final Genotyp genotyp = Gatunek.budujGenotyp();
        private final Narodowosc narodowosc;

        private Osoba(final Narodowosc narodowosc) {
            this.narodowosc = narodowosc;
        }

        public boolean czyPrzezyje(final int promile) {
            return genotyp.okreslWlasciwosc("WYTRZYMALOSC_ALKOHOLOWA") < promile;
        }

    }

    static class Genotyp {
        private final Map geny;

        public Genotyp(final Map genyInicjalizujące) {
            geny = genyInicjalizujące;
        }

        public int okreslWlasciwosc(final String nazwaWłaściwości) {
            return geny.get(nazwaWłaściwości);
        }
    }

    static class Gatunek {
        public static Genotyp budujGenotyp() {
            final Map geny = new HashMap();
            geny.put("WYTRZYMALOSC_ALKOHOLOWA", obliczOdziedziczonąWytrzymałośćAlkoholową());
            return new Genotyp(geny);
        }

        private static int obliczOdziedziczonąWytrzymałośćAlkoholową() {
            return new Random(currentTimeMillis()).nextInt() % 16;
        }
    }
}

Czas zdefiniować Hak

W świetle podanego przykładu będzie to miejscowe rozwiązanie problemu olewajac generalną zasadę, która być może nie została nawet wykryta. Wszystko się zjebie gdy albo : 1) generalna regułą się zmieni (Anglicy zwiększą odporność alkoholową) lub: 2) Generalna zasada zacznie się manifestować w innych, jeszcze nie zhaczonych miejscach kodu (np. dołożymy Włocha)

Oczywiście rozwiązanie z genami może okazać się hakiem w kontekście jakiejś szerszej reguły

Brak komentarzy:

Prześlij komentarz