Każdy użytkownik kłamie

Oryginalny post: Every User Lies

Autor: Jeff Atwood

Heidi Adkisson zaznacza, iż to funkcjonalności sprzedają produkt, ale ludzie, którzy kupują te produkty, często nie używają własności, które zasądziły o zakupie.

Kilka lat temu przeprowadziłam obszerne badanie polegające na obserwowaniu używania określonego sprzętu komputerowego. Większość ludzi posiadało najnowsze modele, z ogromem możliwości. Ale w moich obserwacjach zauważyłam, że tylko jeden "zaawansowany użytkownik" wyszedł poza użycie bazowych, podstawowych funkcjonalności. Ci ludzie zapłacili więcej za funkcjonalności, których nie używali. Niemniej jednak, kiedy opisywali swoje doświadczenia związane z zakupem, jasnym było, iż chcieli używać tych właściwości i szczerze wyrażali taki zamiar. Ale, kiedy produkt został już rozpakowany, paradoks aktywnego użytkownika wziął górę. Nigdy nie zainwestowali choć chwili, aby użyć czegoś poza podstawami (nawet jeśli dodatkowe funkcjonalności mogłyby oszczędzić trochę czasu).

W moim przekonaniu, to ludzkie pragnienie doświadczania kieruje decyzjami podejmowanymi przy zakupach. Koniec końców, ludzkie aspiracje mogą być inne niż są w rzeczywistości.

Zastanawiające jest to, że Heidi użyła przypuszczającego stwierdzenia "mogą być inne", kiedy to wyniki jej własnych badań wykazały, że ludzkie aspiracje i rzeczywistość są niemal zawsze różne. Może chciałaby żyć w świecie, gdzie aspiracje i rzeczywistość nie są tak bardzo rozbieżne. Nie winię jej. Fajnie by było.

Właśnie dlatego tak ważnym jest, aby obserwować, jak zachowują się użytkownicy, a nie tego, jak mówią, że się zachowują. Ludzie, którzy zajmują się tym profesjonalnie, nazywają się "ekonomistami". Obserwacja to potężna umiejętność, jak również nauka tego jak nie zwracać uwagi na to, co ludzie Ci mówią w zamian za ocenianie ich na postawie postępowania. Żadne inne czynności nie są tak dokładnie rozważane jak te, których rezultatem jest wydanie własnych pieniędzy. To dlatego właśnie tylko sobie możesz zawdzięczać to, aby czytać książki typu Freakonomics, albo nawet magazyn The Economist. To również dlatego blog Freakonomics powinien być częścią Twojej regularnej lektury, o ile już nie jest.

Ludzie kłamią nie dlatego, że wszyscy są podłymi kłamcami (niemniej jednak kilku bez wątpienia jest), ale dlatego, że zazwyczaj w pewien sposób kłamią względem siebie. Niektóre kłamstwa są użyteczne. Drobne, "niewinne" kłamstewka przygotowują do społecznej rzeczywistości. Penetracja tych kłamstw i zamierzeń jest jednym z głównych wątków wybitnego serialu telewizyjnego Dr House:

Gregory House, Dr House

Serial pokazuje subtelne połączenie pomiędzy postacią House'a a Sherlockiem Holmesem, które jest odpowiednie, ponieważ w gruncie rzeczy ten serial jest detektywistyczny. Postać Gregory'ego House'a, odgrywana przez doskonałego Hugh Laurie'go, lubi stwierdzenie "Wszyscy kłamią". Analiza wszystkich nieracjonalnych ludzkich zachowań oraz konieczne kłamstwa — niewinne czy nie — prowadzą w kierunku pasjonującej opowieści detektywistycznej w szczególności, gdy stawką są ludzkie życia.

Heidi wspomniała o Paradoksie Aktywnego Użytkownika (pdf), który jako koncept jest znany już od 1987 roku. Gorąco polecam przeczytanie oryginalnego referatu, ale jeśli nie masz czasu, to Jakob Nielsen dostarcza streszczenie:

Użytkownicy nigdy nie czytają instrukcji, tylko natychmiast zaczynają używać oprogramowania. Są umotywowani poprzez chęć rozpoczęcia pracy i natychmiastowego zakończenia zadania: system ich tak bardzo nie obchodzi i nie chcą spędzać zbyt wiele czasu na zaznajomienie się, konfigurację, czy przebrnięcie przez samouczki.

"Paradoks aktywnego użytkownika" jest paradoksem, ponieważ użytkownicy zaoszczędziliby w rezultacie więcej czasu, jeśli nauczyliby się systemu. Ale nie tak postępują ludzie w prawdziwym świecie, więc nie możemy pozwolić inżynierom na tworzenie produktów przeznaczonych dla wyidealizowanych, racjonalnych użytkowników, kiedy to ludzie postępują nieracjonalnie. Musimy projektować pod to, jak użytkownicy faktycznie się zachowują.

Istnieje wiele sposobów na ponowne określenie paradoksu aktywnego użytkownika. Cooper nazywa to nieustanną przeciętnością. Myślę, iż najłatwiejszym sposobem na wyjaśnienie tego jest to: każdy użytkownik kłamie. Zamiast pytać użytkowników, czy kochają Twoje oprogramowanie — oczywiście, że kochają Twoje oprogramowanie, niegrzecznym byłoby mówienie osobom zainteresowanym, jak otępiająco paskudna jest rzeczywistość — rób to, co robi Gregory House. Obserwuj, czy używają Twojego oprogramowania oraz jak go używają. Podczas projektowania polegaj na tych behawioralnych danych, a nie na kłamstwach użytkowników, niezależnie od tego w jak dobrych intencjach one są.

Data publikacji oryginału: 31 stycznia, 2008

KISS oraz YAGNI

Oryginalny post: KISS and YAGNI

Autor: Jeff Atwood

Rico, gość odpowiedzialny za wydajność, pracujący w firmie Microsoft, porusza temat bliski i drogi mojemu sercu

Wątpię w to, aby z mojego artykułu znajdującego się na "Performance Tidbits", ktokolwiek wysnuł wniosek na temat tego, który producent ma przewagę w kwestii wydajności. Jeśli miałbym podsumować moją radę z tego bloga w kilku słowach, to byłoby to "nie używaj OOP w sposób, który nie jest konieczny."

To nie znaczy, aby porzucić funkcje wirtualne, dziedziczenie, czy inne możliwości współczenych języków programowania. Jest zupełnie odwrotnie. Nie tylko sprawiają one, że kod jest bardziej przejrzysty i łatwiejszy w utrzymaniu, ale również poprawiają jego wydajność. Niemniej jednak często bywa tak, że programiści piszą swój kod w sposób zawiły, kiedy to prostsze podejście byłoby równie łatwe w utrzymaniu i bardziej wydajne. Niezależnie od tego, którą programistyczną religię wyznajesz myślę, iż zgodzisz się z tym, że bardziej skomplikowane abstrakcje językowe niekoniecznie wpływają dobrze na architekturę -- raczej jest tak, iż każda bardziej wyrafinowana właściwość języka zaczyna z wynikiem ujemnym i musi jakoś zasłużyć sobie na to, aby tak nie było, poprzez dodanie przejrzystości, łatwości utrzymania, wydajności, itp.

Tak więc, kiedy mówię rzeczy typu "nie używaj delegatów, jeśli zwykły polimorfizm wystarczy", nie mam na myśli tego, abyś ich unikał, tylko to, abyś nie używał ich, jeśli są przesadą.

Nie używaj wyszukanych własności OOP tylko dlatego, że możesz. Wykorzystuj je, jeśli są one w stanie dać konkretny, możliwy do wykazania pożytek w kontekście problemu, który starasz się rozwiązać. Możesz się śmiać, ale tak jak Rico, często zauważam ten problem. Większość programistów nigdy nie stworzyło obiektu, którego by nie polubili. Myślę, iż powinno być na odwrót: każda z tych technik uważana jest za winną, dopóki przed sądem KISS nie zostanie udowodnione inaczej.

Sądzę, iż jako programiści, często jesteśmy zbyt optymistyczni w szacowaniu ogólności naszych rozwiązań, za czym idzie to, że tworzymy zawiłe frameworki OOP wokół rzeczy, które mogą nie być w stanie uzasadnić takiego stopnia skomplikowania. Aby zwalczać tę pokusę, sugeruję podążanie za doktryną YAGNI (You Aren't Gonna Need It [Nie będziesz tego potrzebował]). Twórz to, czego potrzebujesz wtedy, gdy tego potrzebujesz, agresywnie refaktoryzując w międzyczasie; nie trać zbyt wiele czasu na planowanie imponujących, nieznanych przyszłych scenariuszy. Dobre oprogramowanie potrafi wyewoluować w to, czym ostatecznie ma się stać.

Data publikacji oryginału: 21 października, 2004

Daj się poznać - podsumowanie zgłoszeń

msdn ultimate

Całkiem niedawno wspominaliśmy na devBlogach o ogłoszeniu konkursu "Daj się poznać". Przypomnijmy, że celem konkursu jest zmotywowanie społeczności polskich programistów do pracy nad własnymi projektami z otwartym kodem źródłowym i opisywania postępów tychże prac na swoich blogach. Ta idea bardzo nam się spodobała, więc z zainteresowaniem śledzimy przebieg konkursu.

Ostatnio (16. sierpnia) upłynął termin zgłoszeń do konkursu i musimy przyznać, że liczba zgłoszonych projektów mocno zaskoczyła zarówno nas, jak i pewnie samego organizatora konkursu — Macieja Aniserowicza. Lista 79 zgłoszonych projektów robi wrażenie — wyłonienie zwycięzcy raczej nie będzie łatwe. Na szczęście Maciej się postarał — i w tym miejscu chcielibyśmy mu pogratulować — postarał się o imponującą liczbę sponsorów, którzy ufundowali cenne nagrody. Do wygrania są między innymi: 3 x subskrypcja MSDN Ultimate, roczna subskrypcja TekPub i ReSharper (nieodzowny plugin do Visual Studio dla programistów .NET chcących zwiększyć swą produktywność).

Pozostaje nam życzyć uczestnikom powodzenia i wytrwałości w rozwijaniu i opisywaniu swoich projektów. Naszych czytelników zachęcamy do zapoznania się ze zgłoszonymi projektami — być może znajdziecie tam coś przydatnego dla siebie albo jakieś projekty zainteresują Was na tyle, że zechcecie się przyłączyć do ich autorów w roli developerów. Wiemy przecież, jak istotne w zawodzie programisty jest ostrzenie piły a samo czytanie cudzego kodu również może być kształcące.

Odnośniki związane z konkursem "Daj się poznać":


Zespół devMedia.pl

Kodowanie a wnioskowanie

Opublikowaliśmy kolejne tłumaczenie w serwisie 97rzeczy:

  • Kodowanie a wnioskowanie (autor: Yechiel Kimchi)
    "Próba wnioskowania na temat poprawności programu często skutkuje formalnym dowodem, który jest dłuższy niż sam kod i z większym prawdopodobieństwem zawiera błędy. Zautomatyzowane narzędzia są tutaj wskazane, jednak ich użycie nie zawsze jest możliwe."

Zachęcamy do lektury,
Zespół devMedia.pl

W Królestwie Rzeczowników

Execution in the Kingdom of Nouns
W Królestwie Rzeczowników
 Mają charakterek, niektóre — w szczególności czasowniki: są najdumniejsze — z przymiotnikami możesz zrobić cokolwiek, ale nie z czasownikami — nie mniej jednak, ja potrafię radzić sobie z nimi wszystkimi! Koniec! Tako rzeczę!
— Humpty Dumpty

Witaj, świecie! Dzisiaj posłuchamy historii o Złym Królu Javie i jego dążeniu do światowego wybicia czasowników.1

Uwaga: ta historia nie ma szczęśliwego zakończenia. Nie jest to także historia dla osób o zajęczych sercach czy gorących głowach. Jeśli łatwo Cię obrazić lub masz tendencje do bycia blogowym niegodziwcem nie do przekonania, proszę przestań czytać już w tym miejscu.

Zanim przejdziemy do opowieści, pozbądźmy się pojęciowego paskudztwa.

Nadmiar śmieci

Wszyscy Javovcy uwielbiają “przypadki użycia”, więc zacznijmy z takowym: konkretnie, wynoszeniem śmieci. Tak jak w “Janek, wynieś śmieci! Przelewają się już!”

Jeśli jesteś normalną, codzienną, przeciętną, anglojęzyczną osobą poproszoną o opisanie czynności wynoszenia śmieci, prawdopodobnie myślisz o tym w mniej-więcej następujący sposób:

 get the garbage bag from under the sink  / wyciągnij worek ze śmieciami spod zlewu
 carry it out to the garage / zanieś go do garażu
 dump it in the garbage can / wrzuć go do kontenera na śmieci
 walk back inside / wróć do środka
 wash your hands / umyj dłonie
 plop back down on the couch / padnij z powrotem na kanapę
 resume playing your video game (or whatever you were doing) / wznów grę na konsoli (czy co tam robiłeś)

Nawet jeśli nie myślisz po angielsku, prawdopodobnie myślałeś o podobnym zbiorze akcji - z tym że w Twoim ulubionym języku. Abstrahując od wybranego języka, czy dokładnych kroków, wynoszenie śmieci jest ciągiem akcji kończącym się śmieciami na zewnątrz i Tobą wewnątrz, wskutek wykonanych przez Ciebie czynności.

Nasze myśli wypełnione są odważnymi, gwałtownymi, namiętnymi czynnościami: żyjemy, oddychamy, chodzimy, rozmawiamy, śmiejemy się, płaczemy, żywimy nadzieję, boimy się, jemy, pijemy, zatrzymujemy się, idziemy, wynosimy śmieci. Ponad wszystko inne, możemy czynić i funkcjonować. Gdybyśmy byli tylko kamieniami leżącymi na słońcu, życie mogłoby być wciąż OK, ale nie bylibyśmy “wolni”. Nasza wolność wynika dokładnie z możliwości robienia czegoś.

Oczywiście, nasze myśli są wypełnione także rzeczownikami. Jemy rzeczowniki i kupujemy rzeczowniki w sklepie, siedzimy na rzeczownikach, śpimy na nich. Rzeczowniki mogą spaść Ci na głowę, w efekcie czego będziesz miał(a) wielki rzeczownik na swoim rzeczowniku. Rzeczowniki są rzeczami, a co my byśmy bez nich zrobili? One są jednak tylko rzeczami, to wszystko: środki przemijające, czy przeminięcie jako takie, czy cenne dobra, czy nazwy obiektów, które obserwujemy wokół nas. Tam jest budynek. Tu jest kamień. Każde dziecko może wskazać rzeczowniki. To zmiany stanu tych rzeczowników czynią je interesującymi.

Zmiana wymaga akcji. Akcja to to, co nadaje życiu smak. Akcje nadają smak własnemu smakowi! W końcu, nie smakują póki ich nie zjesz. Rzeczowniki mogą być wszędzie, ale życie to ciągła zmiana i ciągłe nim zainteresowanie - całe zawarte w czasownikach.

Oczywiście oprócz czasowników i rzeczowników, mamy nasze przymiotniki, przyimki, nasze zaimki, rodzajniki, nieuniknione koniunkcje, smakowite wykrzykniki, i wszystkie inne wspaniałe części mowy, które pozwalają nam myśleć i mówić interesujące rzeczy. Myślę, że możemy się wszyscy zgodzić, że każda z części mowy ma swoje zadanie i wszystkie są ważne. Byłoby szkoda stracić którąkolwiek z nich.

Nie byłoby dziwnie, gdybyśmy nagle zdecydowali, że nie możemy korzystać z czasowników?

Opowiem Wam historię o miejscu, w którym właśnie tak się stało...

Królestwo rzeczowników

W Królestwie Javalandii, gdzie Król Java rządzi krzemową pięścią, ludziom nie wolno myśleć w sposób w jaki robię to ja czy Ty. W Javalandii, widzisz, rzeczowniki są bardzo ważne, na mocy rozkazu samego Króla. Rzeczowniki są najważniejszymi obywatelami Królestwa. Paradują pysznie w swoich wytwornych, pokazowych strojach, dostarczonych przez Przymiotniki, które generalnie mają trochę lżej niż inni. Przymiotniki nie dorastają do pięt Rzeczownikom, ale uważają się za całkiem szczęśliwe za to, że nie urodziły się Czasownikami.

A to dlatego, że Czasowniki w tym Królestwie mają bardzo, bardzo źle.

W Javalandii, na mocy królewskiego dekretu, Czasowniki należą do Rzeczowników. Nie są jednak ich zwierzętami domowymi; nie, Czasowniki w Javalandii wykonują całą pracę w królestwie. Są, w rezultacie, niewolnikami królestwa, a przynajmniej poddanymi i zniewolonymi sługami. Mieszkańcy Javalandii są całkiem kontent z tą sytuacją, i w istocie prawie nie zdają sobie sprawy, że rzeczy mogłyby wyglądać zupełnie inaczej.

Czasowniki w Javalandii są odpowiedzialne za całą pracę, i choć bardzo przez wszystkich pogardzane, żaden Czasownik nie może nigdy podróżować samodzielnie. Jeżeli jakiś czasownik ma się pojawić w jakimś publicznym miejscu, to musi być przez cały czas pod eskortą Rzeczownika.

Oczywiście “eskortować”, będąc Czasownikiem, nie ma możliwości kręcić się bez obstawy; trzeba postarać się o VerbEscorter’a by tą właśnie eskortę umożliwić. Ale co z “postarać się” (facilitate) i “umożliwić” (procure)? Tak się składa, że Facilitator’zy i Procurer’zy są raczej ważnymi Rzeczownikami, których zadaniem jest opieka nad skromnymi “postarać się” (facilitate) i procure (umożliwić), przez Facilitation i Procurement, odpowiednio.

Król, konsultując się z Bogiem Słońce w tej sprawie, groził od czasu do czasu całkowitym wygnaniem wszystkich czasowników z Królestwa Javy. Jeżeli to kiedykolwiek nadejdzie, to mieszkańcy z pewnością będą potrzebowali przynajmniej jednego czasownika do wykonywania całej pracy w państwie, a Król, który słynie z raczej okrutnego poczucia humoru, wskazał, że jego wyborem będzie najprawdopodobniej “execute” (wykonywać, także wyrok śmierci - przyp. tłum.).

Czasownik “execute” i jego synonimowi kuzyni “run”, “start”, “go”, “justDoIt”, “makeItSo”, i im podobni, mogą wykonać pracę dowolnego innego czasownika przez zastąpienie go odpowiednim Wykonawcą (Executioner) i wywołaniem execute(). Musisz poczekać? Waiter.execute().. Umyć zęby? ToothBrusher(myTeeth).go(). Wynieść śmieci? TrahsDisposalPlanExecutor.doIt(). Żaden czasownik nie jest bezpieczny; wszystko może być zastąpione Rzeczownikiem.

W co bardziej patriotycznych zakątkach Javalandii Rzeczowniki całkowicie usunęły Czasowniki. Może wyglądać na to w trakcie okazjonalnych inspekcji, że tam wciąż gdzieś są Czasowniki, uprawiające ziemię i opróżniające nocniki. Jeśli jednak dobrze się przyjrzeć, sekret wyjdzie na jaw: Rzeczowniki mogą przemianować swój Czasownik “execute” nadając im własne imię bez najmniejszego wpływu na ich charakter. Kiedy przyjrzysz się FieldTiller till(), ChamberPotEmptier empty() czy RegistrationManager register(), to co naprawdę zobaczysz to jedną z armii wykonawców (executioners) złego Króla, skrytych pod ubraniami Rzeczownika-właściciela.

Czasowniki w Sąsiadujących Królestwach

W sąsiadujących królestwach języków programowania, wynoszenie śmieci jest sprawą oczywistą, bardzo podobną do tej, którą opisaliśmy wcześniej po angielsku. Tak jak w przypadku Javy, obiekty danych są rzeczownikami, a funkcje są czasownikami2. Ale inaczej niż w Javalandii, obywatele innych królestw mogą się mieszać i łączyć z rzeczownikami i czasownikami zależnie od własnych upodobań, zgodnie z planem na życie.

Dla przykładu, w sąsiadujących światach C-landii, JavaScript-landii, Perl-landii i Ruby-landii, ktoś mógłby wymodelować wynoszenie śmieci jako ciąg akcji - lub, jakby to ująć, czasowników czy funkcji. Jeśli wtedy zaaplikują akcje do odpowiednich obiektów, w odpowiedniej kolejności (weź śmieci, wynieś je na zewnątrz, wrzuć do śmietnika, itd.), zadanie usunięcia nieczystości zakończy się sukcesem, bez zbędnej eskorty i opiekunek potrzebnych do wykonania któregokolwiek kroku.

Rzadko zdarza się, by zaszła potrzeba tworzenia opakowujących rzeczowników do spowicia czasowników w tych królestwach. Nie mają rzeczowników takich jak GarbageDisposalStrategy czy PostGarbageActionCallback do ulokowania Cię z powrotem na Twojej kanapie. Piszą po prostu czasowniki operujące na rzeczownikach leżących w okolicy, a następnie tworzą czasownik nadrzędny, take_out_garbage(), który powiązuje podzadania w odpowiednim porządku.

Te sąsiadujące królestwa generalnie dostarczają mechanizmów do tworzenia ważnych rzeczowników, jeśli zajdzie taka potrzeba. Jeśli pracowici wynalazcy w tych królestwach stworzą zupełnie nową, użyteczną ideę która wcześniej nie istniała, taką jak dom, wóz, czy maszynę do uprawy pól szybszą od człowieka, to mogą nadać tej idei Klasę, która dostarcza nazwy, opisu, jakiegoś stani i instrukcji potrzebnych do działania.

Różnica w tym, że gdy Czasowniki mogą istnieć niezależnie - nie musisz wymyślać dla nich nowych Rzeczowników do ich okiełznania.

Javalandowcy patrzą na swoich sąsiadów z pogardą; tak to już jest w Królestwach Programowania.

Jeśli będziesz kopał dostatecznie długo...

Na przeciwnym krańcu świata istnieje rzadko zaludniony region, w którego królestwach Czasowniki wiodą prym. Są to Królestwa Funkcjonalne, takie jak Haskellia, Ocamlica, Schemeria, i jeszcze kilka innych. Ich mieszkańcy rzadko stykają się z królestwami bliskimi Javalandii. Ponieważ istnieje kilka królestw w okolicy, Królestwa Funkcjonalne muszą patrzyć z pogardą na siebie nawzajem i prowadzić wzajemne wojny, gdy nie mają nic lepszego do roboty.

W Królestwach Funkcjonalnych, Rzeczowniki i Czasowniki są zasadniczo obywatelami tej samej kategorii. Niemniej jednak, Rzeczowniki, bedąc, cóż, rzeczownikami, głównie siedzą bezczynnie. Nie widzą sensu w wykonywaniu czegokolwiek, ponieważ Czasowniki są dość aktywne i robią to wszystko za nie. Nie panują dziwne prawa zobowiązujące do tworzenia Rzeczowników pomocniczych do eskortowania każdego z czasowników, więc jest tam dokładnie tyle Rzeczowników, co Rzeczy w każdym z królestw.

W rezultacie, Czasowniki trzymają wszystko w kupie, wybacz wyrażenie. Jako człowiek z zewnątrz, mógłbyś łatwo odnieść wrażenie, że Czasowniki (tzn., funkcje) są najważniejszymi mieszkańcami. Tak się składa, że dlatego właśnie królestwa te nazywają się Królestwami Funkcjonalnymi, a nie Królestwami Rzeczy.

W najodleglejszych rubieżach, za Królestwami Funkcjonalnymi, leży legendarny świat zwany Lambda the Ultimate. Mówi się, że nie ma tam rzeczowników w ogóle, tylko czasowniki! Są tam “rzeczy”, ale wszystkie one tworzone są z czasowników - nawet liczebniki potrzebne do liczenia owiec (lambs, gra słów) - które są tam najpopularniejszą walutą, jeśli wierzyć plotkom. Liczba zero to po prostu lambda(), 1 to lambda(lambda()), 2 to lambda(lambda(lambda())), i tak dalej. Każda Rzecz w tej krainie, niech będzie rzeczownik, czasownik czy cokolwiek, stworzona jest z pierwotnego czasownika “lambda”3.

Będąc całkiem szczerym, większość Javalandowców jest kompletnie nieświadoma istnienia tej drugiej części świata. Możesz sobie wyobrazić ich szok kulturowy? Mogliby zostać tak skołowani, że wymyśliliby nowe rzeczowniki (takie jak “Ksenofobia”) by wyrazić swoje uczucia.

Czy Javalandowcy są szczęśliwi?

Możnaby pomyśleć, że życie codzienne w Javalandii jest co najmniej trochę dziwne, a co najwyżej mocno niewydajne. Możesz jednak ocenić jak szczęśliwe jest społeczeństwo po piosenkach śpiewanych dzieciom. Te z Javalandii są kapryśnie poetyckie. Dla przykładu, dzieci z Javalandii często recytują sławną pouczającą piosenkę:

For the lack of a nail, / z braku gwoździa,
   throw new HorseshoeNailNotFoundException("no nails!");

For the lack of a horseshoe, / z braku podkowy,
   EquestrianDoctor.getLocalInstance().getHorseDispatcher().shoot();

For the lack of a horse, / z braku konia,
   RidersGuild.getRiderNotificationSubscriberList().getBroadcaster().run(
     new BroadcastMessage(StableFactory.getNullHorseInstance()));

For the lack of a rider, / z braku jeźdźca,
   MessageDeliverySubsystem.getLogger().logDeliveryFailure(
     MessageFactory.getAbstractMessageInstance(
       new MessageMedium(MessageType.VERBAL),
       new MessageTransport(MessageTransportType.MOUNTED_RIDER),
       new MessageSessionDestination(BattleManager.getRoutingInfo(
                                       BattleLocation.NEAREST))),
     MessageFailureReasonCode.UNKNOWN_RIDER_FAILURE);

For the lack of a message, / z braku wiadomości,
   ((BattleNotificationSender)
     BattleResourceMediator.getMediatorInstance().getResource(
       BattleParticipant.PROXY_PARTICIPANT,
       BattleResource.BATTLE_NOTIFICATION_SENDER)).sendNotification(
         ((BattleNotificationBuilder)
           (BattleResourceMediator.getMediatorInstance().getResource(
           BattleOrganizer.getBattleParticipant(Battle.Participant.GOOD_GUYS),
           BattleResource.BATTLE_NOTIFICATION_BUILDER))).buildNotification(
             BattleOrganizer.getBattleState(BattleResult.BATTLE_LOST),
             BattleManager.getChainOfCommand().getCommandChainNotifier()));

For the lack of a battle, / z braku walki,
   try {
       synchronized(BattleInformationRouterLock.getLockInstance()) {
         BattleInformationRouterLock.getLockInstance().wait();
       }
   } catch (InterruptedException ix) {
     if (BattleSessionManager.getBattleStatus(
          BattleResource.getLocalizedBattleResource(Locale.getDefault()),
          BattleContext.createContext(
            Kingdom.getMasterBattleCoordinatorInstance(
              new TweedleBeetlePuddlePaddleBattle()).populate(
                RegionManager.getArmpitProvince(Armpit.LEFTMOST)))) ==
         BattleStatus.LOST) {
       if (LOGGER.isLoggable(Level.TOTALLY_SCREWED)) {
         LOGGER.logScrewage(BattleLogger.createBattleLogMessage(
           BattleStatusFormatter.format(BattleStatus.LOST_WAR,
                                        Locale.getDefault())));
       }
     }
   }

For the lack of a war, / z braku wojny,
   new ServiceExecutionJoinPoint(
     DistributedQueryAnalyzer.forwardQueryResult(
       NotificationSchemaManager.getAbstractSchemaMapper(
         new PublishSubscribeNotificationSchema()).getSchemaProxy().
           executePublishSubscribeQueryPlan(
             NotificationSchema.ALERT,
             new NotificationSchemaPriority(SchemaPriority.MAX_PRIORITY),
             new PublisherMessage(MessageFactory.getAbstractMessage(
               MessageType.WRITTEN,
               new MessageTransport(MessageTransportType.WOUNDED_SURVIVOR),
               new MessageSessionDestination(
                 DestinationManager.getNullDestinationForQueryPlan()))),
             DistributedWarMachine.getPartyRoleManager().getRegisteredParties(
               PartyRoleManager.PARTY_KING ||
               PartyRoleManager.PARTY_GENERAL ||
               PartyRoleManager.PARTY_AMBASSADOR)).getQueryResult(),
       PriorityMessageDispatcher.getPriorityDispatchInstance())).
     waitForService();

Wszystko z braku gwoździa do podkowy.

Pozostaje to wspaniałą radą po dziś dzień.

Pomimo, że opowiadanie tej historii w Javalandii różni się nieco od oryginału Bena Franklina, Javalandowcy czują, że ich wykonanie ma swój własny urok.

Głównym urokiem jest to, że wszyscy mogą obejrzeć architekturę. Architektura jest wyjątkowo wysoce poważana przez Króla Javę - a to dlatego, że złożona jest wyłącznie z rzeczowników. Jak wiemy, rzeczowniki są rzeczami, a rzeczy są cenione ponad wszystkie czynności w Królestwie Javy. Architektura składa się z rzeczy, które możesz zobaczyć i dotknąć, rzeczy, które imponująco piętrzą się przed Tobą, rzeczy, które wydają z siebie satysfakcjonujący stuk gdy przywalisz w nie patykiem. Król Java lubuje się w tych stukach; nie posiada się z zadowolenia, gdy kopie koła podczas wypróbowywania swojego nowego powozu konnego. Jakiekolwiek wady by miała, powyższa opowieść chwali rzeczy.

Jednym z naszych - jako istot ludzkich - pierwszych instyktów jest poszukiwanie schronienia przed żywiołami; im trwalsza nasza osłona, tym bezpieczniej się czujemy. W Javalandii znajduje się mnóstwo rzeczy pozwalających mieszkańcom czuć się bezpiecznie. Oglądają z podziwem twory architektury i myślą “to musi być trwały design”. Uczucie to jest wzmocnione, gdy próbują dokonać zmian w strukturze; potęga architektury zaczyna zrażać na tyle, że czują, że nikt nie jest w stanie zburzyć tej struktury.

Oprócz zalet związanych z trwałą architekturą, wszystko w Javalandii jest ładnie zorganizowane: każdy rzeczownik znajduje się w odpowiednim miejscu. I wszystkie historie przyjmują określony kształt: tworzenie obiektu jest dominującym rodzajem wyrażenia, z menedżerem dla każdej abstrakcji i metodą run() dla każdego menedżera. Przy odrobinie doświadczenia w tego rodzaju modelowaniu, obywatele Javy uświadamiają sobie, że są w stanie wyrazić każdą historię w taki sposób. Istnieje pewien rodzaj “rachunku rzeczowników”, który pozwala na wyrażenie każdej abstrakcji, każdego obliczenia - jakie tylko zechcesz. Wszystko, czego trzeba, to wymagane rzeczowniki, konstruktory dla tych rzeczowników, akcesory do przechodzenia grafu rzeczowników i najważniejsze execute() do zrealizowania czyichś planów.

Mieszkańcy Królestwa Javy nie są jedynie szczęśliwi - oni nie posiadają się z dumy!

StateManager.getConsiderationSetter("Noun Oriented Thinking", State.HARMFUL).run()

Lub, jak to się mówi poza Królestwem Javy, “Programowanie zorientowane rzeczownikowo rozważane jako szkodliwe”.

Programowanie zorientowane obiektowo stawia Rzeczowniki na pierwszej i najważniejszej pozycji. Dlaczego miałbyś się zapuszczać tak daleko, żeby postawić na piedestale jedną z części mowy? Dlaczego jeden rodzaj idei miałby być lepszy od innego? To trochę tak, że PZO uczyniło czasowniki mniej znaczącymi w naszym sposobie myślenia. To dziwnie zakrzywiona perspektywa. Jak to ujął pewnego razu mój przyjaciel Jacob Gabrielson, promowanie Programowania Zorientowanego Obiektowo to jak promowanie Ubierania się Zorientowanego na Spodnie.

Statyczny system typów Javy, jak każdy inni, ma swój zestaw bolączek. Wyjątkowy nacisk na myślenie zorientowane rzeczownikowo (i, w konsekwencji, proces modelowania) jest więcej niż odrobinę niepokojące. Każdy system typów będzie wymagał od Ciebie przekształcenia swoich myśli tak, by pasowały do systemu; wyeliminowanie samodzielnych czasowników wydaje się być jednak krokiem posuniętym poza wszelkie racje i rozsądek.

C++ nie przejawia tego problemu, jako że C++, będąc nadzbiorem C, pozwala na definiowanie samodzielnych funkcji. Ponadto, C++ dostarcza osobnej abstrakcji dla przestrzeni nazw; Java przeładowuje ideę Klasy do reprezentowania przestrzeni nazw, typów zdefiniowanych przez użytkownika, syntaktycznych mechanizmów delegacji, pewnych mechanizmów widoczności i zakresu, i więcej..

Nie zrozum mnie źle; nie twierdzę, że C++ jest “dobry”. Doceniam jednak elastyczność jego systemu typów, przynajmniej w porównaniu z Javą. C++ cierpi z powodu problemów powodujących, że rozsądnie wyglądające zdania powodują, że listenery robią “trzask!” i próbują Cię zabić (dla przykładu, niespodziewane segfaulty czy inne pułapki na nieostrożnych) i może być niesamowicie trudno znaleźć odpowiednią inkantancję do wyrażenia konkretnej myśli w C++. Zakres zwięźle wyrażalnych myśli wykracza jednak daleko poza możliwości Javy; to dlatego, że C++ daje Ci czasowniki, a kto chciałby mówić językiem, który tego nie daje?

Klasy to naprawdę jedyne narzędzie do modelowania, jakiego dostarcza Java; dlatego też, kiedykolwiek wpadniesz na jakiś pomysł, musisz go rzeźbić lub opakowywać lub rozbijać aż stanie się rzeczą - nawet jeśli urodziła się jako akcja, proces czy jakakolwiek inna nie-rzecz.

Naprawdę zrozumiałem, co mówili mi Perlowcy 8 czy 9 lat temu: “Stary, nie wszystko jest obiektem.”

Mimo to dziwnym jest, że Java4 zdaje się być jedynym mainstreamowym językiem zorientowanym obiektowo, który przejawia radykalnie rzeczowniko-centryczny charakter. Prawie nigdy nie znajdziesz AbstractProxyMediator’a czy NotificationStrategyFactory, czy czegokolwiek w tym stylu, w Pythonie czy Ruby’m. Dlaczego są wszędzie w Javie? To pewne, że różnica leży w czasownikach. Python, Ruby, JavaScript, Perl, i oczywiście wszystkie języki Funkcyjne pozwalają Ci deklarować i przekazywać funkcje jako osobne byty bez potrzeby owijania je w klasy.

Z pewnością jest łatwiej zrobić takie rzeczy w językach typowanych dynamicznie; przekazujesz po prostu referencję do funkcji otrzymanej z jej nazwy, i już w gestii strony wywołującej funkcję leży to, by przekazać odpowiednie argumenty i użyć poprawnie zwróconej wartości.

Wiele statycznie typowanych języków posiada - mimo to - funkcje pierwszego rzędu. Są to na przykład języki o rozwlekłym typowaniu jak C i C++, a także języki z inferencją typów jak Haskell czy ML. Języki muszą po po prostu dostarczyć składni do tworzenia, przekazywania i wywoływania literałów funkcyjnych z odpowiednią sygnaturą.

Nie ma powodu, dla którego Java nie mogłaby zwyczajnie dodać funkcji pierwszego rzędu i w końcu dołączyć do dorosłego, nieskrzywionego świata pozwalającego ludziom używać czasowników w ich procesach myślowych. W istocie, istnieje język na JVM zwany Nice, o javovej składni, ale zawierający dość potężne w wyrazie udogodnienia dla korzystania z czasowników: samodzielne funkcje, które Java zmusza do bycia owinięte w Callback’i czy Runnable czy inne im podobne interfejsy by móc się do tychże funkcji odwoływać.

Sun nie musiałby nawet łamać swojej konwencji w której wszystkie funkcje musiałyby być “zawarte” w klasach. Każda anonimowa funkcja mogłaby posiadać niejawny wskaźnik “this” do klasy, w której była zdefiniowana; problem z głowy.

Nie wiem, dlaczego Sun nalega na utrzymanie Javy w Królestwie Rzeczowników. Wątpię, że jest to problem niedocenienia wyborców; dodali genericsy, które są o wiele bardziej złożonym pomysłem; jasnym jest, że nie przejmują się już prostotą języka. To niekoniecznie źle, jako że Java ma już dość ugruntowaną pozycję: więcej sensu ma danie programistom Javy narzędzi, które pozwolą im programować w sposób, w jaki myślą.

Mam szczerą nadzieję, że kiedyś to naprawią, a ja będę mógł wynieść moje śmieci i wrócić do swojej gry komputerowej. Czy co tam robiłem.


[1] Zaczynając od czasownika “tłumić”, który zostaje zastąpiony przez wywołanie VerbEliminatorFactory.createVerbEliminator(currentContext).operate(); to wszystko jednak dopiero przed nami...

[2] Nazwy zmiennych to poprawne rzeczowniki, atrybuty to przymiotniki, operatory zwykle służą jako koniunkcje, varargs jako zaimek “wy (wszyscy)”, i tak dalej; to wszystko leży jednak poza zakresem naszej historii.

[3]Znaczenie czasownika “lambda” to rzekomo “lambdować”.

[4]I prawdopodobnie C#, z racji na podobne korzenie.

Data publikacji oryginału: marzec 30, 2006

Absolutne minimum, które każdy programista powinien koniecznie, absolutnie wiedzieć na temat Unikodu i zestawów znaków (bez wymówek!)

Oryginalny post: The Absolute Minimum Every Software Developer Absolutely, Positively Must Know About Unicode and Character Sets (No Excuses!)

Autor: Joel Spolsky

Czy kiedykolwiek zastanawiałeś się nad tajemniczym tagiem Content-Type? No wiesz, tym, który powinieneś umieścić w HTML-u i nigdy do końca nie wiesz, co powinien zawierać?

Czy kiedykolwiek dostałeś mejla od przyjaciół z Bułgarii z tematem "???? ?????? ??? ????"?

ibm Byłem przerażony, kiedy odkryłem, jak wielu programistów nie jest na bieżąco z tajemniczym światem zestawów znaków, kodowań, Unikodu, całego tego zamieszania. Kilka lat temu beta tester systemu FogBUGZ zastanawiał się, czy może on obsłużyć przychodzącego mejla w języku japońskim. "Japońskim? W Japonii mają mejla? Nie miałem pojęcia." Kiedy przyjrzałem się bliżej komercyjnej kontrolce ActiveX, której używaliśmy do parsowania wiadomości email w formacie MIME, odkryliśmy, że robiła wszystko źle, jeśli chodzi o obsługę zestawów znaków, więc musieliśmy napisać heroiczny wręcz kod, żeby odwrócić całą błędną konwersję, a następnie wykonać ją od nowa. Kiedy spojrzałem na inną komercyjną bibliotekę, ona także miała kompletnie spartaczoną implementację kodów znaków. Korespondowałem z programistą tego pakietu, ale on myślał coś w stylu "nic nie da się z tym zrobić". Jak wielu programistów po prostu chciał, żeby to wszystko jakoś zniknęło z czasem.

Ale to nie zniknie. Kiedy odkryłem, że popularne narzędzie do programowania aplikacji webowych - PHP wykazuje się prawie kompletną ignorancją w zakresie kodowania znaków, beztrosko używając ośmiu bitów na znak, czyniąc prawie niemożliwym tworzenie dobrych międzynarodowych aplikacji webowych, pomyślałem wystarczy.

A więc mam pewną rzecz do ogłoszenia: Jeśli jesteś programistą pracującym w roku 2003 i nie znasz podstaw znaków, zestawów znaków, kodowań, Unikodu i złapię Cię, ukarzę Cię, zmuszając do obierania cebuli przez 6 miesięcy w łodzi podwodnej. Obiecuję, że to zrobię.

I jeszcze jedna rzecz:

TO NIE JEST TAKIE TRUDNE.

W tym artykule dostarczę Ci informacji o tym, co każdy pracujący programista powinien wiedzieć. Cała ta gadka, że "czysty text = ascii = znaki mają po 8 bitów" jest nie tylko mylna, ale beznadziejnie mylna i jeśli nadal programujesz w ten sposób, nie jesteś lepszy od lekarza, który nie wierzy w bakterie. Proszę nie pisz nawet jednej linijki kodu więcej, dopóki nie przeczytasz do końca tego artykułu.

Zanim zacznę, powinienem Cię uprzedzić, że jeżeli jesteś jedną z tych niewielu osób, które wiedzą o internacjonalizacji, uznasz mój cały wywód za lekkie uproszczenie. Staram się tak naprawdę wyznaczyć minimum, które każdy będzie w stanie zrozumieć, a które pozwoli na pisanie kodu mającego szansę działać z tekstem w jakimkolwiek innym języku niż podzbiór angielskiego nie uwzględniający słów z akcentami. I powinienem uprzedzić Cię, że obsługa znaków to tylko mała część, która sprawia, że oprogramowanie działa w różnych językach. Jednak mogę pisać tylko o jednej rzeczy naraz, więc dzisiaj są to zestawy znaków.

Perspektywa historyczna

Najłatwiej zrozumieć to wszystko, idąc chronologicznie.

Prawdopodobnie myślisz, że będę teraz mówił o bardzo starych zestawach znaków takich jak EBCDIC. Hmm, nie będę. EBCDIC nie jest ważny w Twoim życiu. Nie musimy cofać się tak daleko w czasie.

ASCII table W pół-pradawnych czasach, kiedy wymyślano Unixa, a K&R pisali książkę Język ANSI C, wszystko było bardzo proste. EBCDIC miał właśnie ujrzeć światło dzienne. Jedynymi znakami, które się wtedy liczyły, były stare, dobre angielskie litery bez akcentów i mieliśmy dla nich kod nazywany ASCII, który był w stanie reprezentować każdy znak używając liczby między 32 a 127. Spacja miała numer 32, litera "A" - 65, itd. To pozwalało wygodnie zapisać znak na 7 bitach. Większość komputerów w tamtych czasach używało ośmio-bitowych bajtów, także nie tylko mogłeś zapisać każdy możliwy znak zestawu ASCII, ale miałeś cały wolny bit, który, jeśli byłeś złośliwy, mogłeś użyć dla swoich własnych, przebiegłych celów: tępacy w WordStar użyli najbardziej znaczącego bitu, żeby oznaczyć ostatnią literę w słowie, skazując WordStar wyłącznie na angielskie teksty. Kody poniżej 32 były nazywane niedrukowalnymi i używane były na przekleństwa. Ok, żartowałem. Były one używane do znaków kontrolnych, tak jak 7, które sprawiało, że komputer brzęczał, albo 12, które sprawiało, że strona papieru wylatywała z drukarki, aby nowa mogła zostać pobrana.

I wszystko było dobrze zakładając, że mówiłeś po angielsku.

oem Ponieważ bajt ma miejsce na maksymalnie 8 bitów, wielu ludzi zaczęło myśleć "boże, możemy użyć kodów 128-255 dla naszych potrzeb". Problem był w tym, że wielu ludzi wpadło na ten pomysł równocześnie i mieli swoje własne koncepcje na to, co powinno pojawić się w przestrzeni od 128 do 255. IBM-PC miał coś, co miało zostać zapamiętane jako zestaw znaków OEM zawierający litery z akcentami dla języków europejskich i trochę znaków rysujących linie... poziome bloki, pionowe bloki, poziome bloki z małymi dyndałkami dyndającymi z prawej strony itd., można było użyć tych znaków linii, żeby rysować fajniutkie pudełka i linie na ekranie, które można było obejrzeć na komputerach 8088 Twoich pralek chemicznych. Tak naprawdę, jak tylko ludzie zaczęli kupować PC-ty poza Ameryką, różne inne zestawy znaków OEM zaczynały być wymyślane, wszystkie używały ostatnich 128 znaków do swoich własnych potrzeb. Na przykład na niektórych PC-tach znak 130 mógł wyświetlić é, ale na komputerach sprzedawanych w Izraelu była to hebrajska litera Gimel (ג), więc gdy Amerykanie wysyłaliby swoje résumés do Izraela przeczytane zostałoby to jako rגsumגs. W wielu przypadkach, jak w przypadku Rosjan, było wiele różnych pomysłów, co zrobić z tymi górnymi 128 znakami, w rezultacie - nie mogłeś niezawodnie wymieniać dokumentów nawet w obrębie języka rosyjskiego.

W końcu ten OEM dostępny-dla-wszystkich został spisany w standard ANSI. W standardzie ANSI wszyscy zgodzili się co do znaków poniżej 128, co było w zasadzie tym samym, co w ASCII, ale było wiele różnych sposobów na obsługę znaków od 128 wzwyż, zależnie od tego, gdzie żyłeś. Te różne systemy były nazywane stronami kodowymi. Więc dla przykładu w Izraelu DOS używał strony kodowej nazywanej 862, w czasie gdy użytkownicy greccy używali 737. Były one takie same poniżej znaku 128, ale różne od 128 wzwyż, gdzie mieszkały wszystkie śmieszne literki. Wersje narodowe MS-DOSa miały tuziny stron kodowych, obsługujących wszystko od angielskiego po islandzki i miały nawet kilka "wielo-językowych" stron kodowych, które rozumiały Esperanto i Galicyjski na jednym komputerze! Wow! Ale posiadanie, powiedzmy, hebrajskiego i greckiego na jednej maszynie było kompletnie niemożliwe, dopóki nie napisałeś własnego programu, który wyświetlał wszystko używając bitmap, ponieważ hebrajski i grecki wymagają różnych stron kodowych z różną interpretacją wyższych numerów.

W tym samym czasie w Azji wymyślano jeszcze bardziej szalone rzeczy, aby uwzględnić fakt, że azjatycki alfabet zawiera tysiące liter, które nigdy nie zmieściłyby się na 8 bitach. To było zazwyczaj rozwiązywane przez koszmarny system DBCS, tak zwany "dwu-bajtowy zestaw znaków", w którym niektóre litery były przechowywane na jednym bajcie, a niektóre na dwóch. Było dość łatwo przeszukiwać łańcuch znaków wprzód, ale prawie niemożliwe przeszukiwać wstecz. Programiści byli zmuszeni nie używać s++ i s--, aby poruszać się wprzód i w tył, a zamiast tego musieli używać funkcji, takich jak AnsiNext i AnsiPrev w Windows'ie, które wiedziały, jak poradzić sobie z tym bałaganem.

Ale ciągle większość ludzi udawało, że bajt to jeden znak, a znak ma 8 bitów i tak długo, jak nie przenosili łańcuchów znaków z jednego komputera na inny albo nie mówili więcej niż jednym językiem, jakoś to niby zawsze działało. Ale oczywiście jak tylko pojawił się Internet, stał się on raczej popularnym miejscem do przesyłania łańcuchów znaków z jednego komputera na inny i cały ten bałagan zaczął się powoli walić. Na szczęście - wymyślono Unikod.

Unikod

Unikod był odważną próbą stworzenia jednego zestawu znaków, który zawierałby każdy rozsądny system piśmienniczy z całej planety, a także kilka egzotycznych jak klingoński. Niektórzy mylnie uważają, że Unikod to to po prostu kod 16-bitowy, w którym każdy znak zajmuje 16 bitów i dzięki temu można zapisać maksymalnie 65536 znaków. Właściwie - to nie jest prawda. To jest najbardziej popularny mit na temat Unikodu, więc jeśli tak właśnie myślałeś - nie martw się.

Unikod ma tak naprawdę inny sposób myślenia o znakach i musisz zrozumieć ten sposób myślenia Unikodu o rzeczach albo nic nie będzie później zrozumiałe.

Do tej pory zakładaliśmy, że litery są mapowane na kilka bitów, które przechowujemy na dysku lub w pamięci:

A -> 0100 0001

W Unikodzie litera jest mapowana na coś, co nazywa się punktem kodowym, który jest koncepcją czysto teoretyczną. Sposób, w jaki punkt kodowy jest reprezentowany w pamięci lub na dysku, jest inną bajką.

W Unikodzie litera A to koncepcja platoniczna. To bujający w obłokach twór:

A

To platoniczne A jest różne od B i różne od a, ale takie samo jak A i A a także A. Koncepcja, że A w czcionce Times New Roman to ten sam znak, co A w czcionce Helvetica, ale inny niż "a" z małej litery nie jest bardzo kontrowersyjne, ale w niektórych językach określenie czym jest litera może powodować kontrowersje. Czy niemiecka litera ß to naprawdę litera, czy tylko bardziej wydumany sposób napisania ss? Gdy kształt litery zmienia się na końcu słowa, czy jest to inna litera? Hebrajczycy powiedzą "tak", Arabowie - "nie". W każdym razie mądrzy ludzi w konsorcjum Unikodu zastanawiali się nad tym przez ostatnią dekadę lub dłużej, wspierani przez wiele wysoko-politycznych debat i nie musisz się już o te rzeczy martwić. Oni już to wszystko rozpracowali.

Każda platoniczna litera w każdym alfabecie jest przez konsorcjum Unikodu przypisana do magicznego numeru, który pisze się tak: U+0639.  Ten magiczny numer nazywa się punktem kodowym. U+ oznacza "Unikod" a następujące po nim liczby są zapisywane w systemie szesnastkowym. U+0639 to arabska litera Ain. Angielska litera A wyglądałaby tak: U+0041. Możesz je wszystkie odnaleźć, używając programu tablica znaków na Windows'ie 2000/XP albo odwiedzając stronę Unikodu.

Nie ma tak naprawdę limitu na liczbę liter, które może zdefiniować Unikod i w rzeczywistości ilość przekroczyła już 65536, więc nie każda litera w Unikodzie może być wciśnięta w dwa bajty, ale to był tak czy siak mit.

OK, więc mamy łańcuch znaków:

Hello

który, w Unikodzie, odpowiada tym pięciu punktom kodowym:

U+0048 U+0065 U+006C U+006C U+006F.

Po prostu kilka punktów kodowych. Liczb, tak naprawdę. Nie powiedzieliśmy jeszcze, jak przechowywać je w pamięci albo jak reprezentować w wiadomości email.

Kodowania

To właśnie miejsce, w którym kodowania wchodzą do gry.

Najwcześniejsza idea kodowania Unikodu, która doprowadziła do mitu na temat dwóch bajtów, to "hej, zapiszmy po prostu te liczby na dwóch bajtach każdą". Tak więc "Hello" stało się

00 48 00 65 00 6C 00 6C 00 6F

Racja? Nie tak szybko! Nie mogłoby to być równie dobrze:

48 00 65 00 6C 00 6C 00 6F 00 ?

Z technicznego punktu widzenia, mógłbym uwierzyć, że mogłoby. W zasadzie najwcześniejsze implementacje wręcz chciały zapisywać punkty kodowe Unikodu w notacji high-endian lub low-endian w zależności od tego, w której z nich szybszy był konkretny procesor, i nim ktokolwiek zdążył zauważyć, już istniały dwa sposoby na zapisanie Unikodu. A ludzie byli zmuszeni wymyślić dziwną konwencję dopisywania FE FF na początku każdego łańcucha znaków w Unikodzie; to tak zwany Znacznik Kolejności Bitów Unikodu i jeśli zamieniasz swoje wyższe i niższe bajty, to wygląda to tak: FF FE a ludzie czytający Twoje łańcuchy znaków będą wiedzieli, jak zamienić każdy następny bajt. Uff. Jednak nie każdy unikodowy łańcuch znaków występujący w przyrodzie ma znacznik kolejności bajtów na początku.

Hummers

Przez chwilę wydawało się, że to będzie wystarczające, ale programiści narzekali. "Popatrz na te wszystkie zera!" mówili, w końcu byli Amerykanami i patrzyli na angielskie teksty, które rzadko używały punktów kodowych ponad U+00FF. Ponadto byli oni liberalnymi hipisami z Kalifornii, którzy chcieli zachować stary porządek (hihi). Gdyby byli z Teksasu, nie mieli by nic przeciwko pożeraniu dwukrotnej ilości bajtów. Ale te kalifornijskie mięczaki nie mogły znieść podwajania ilości miejsca na łańcuchy znaków, a poza tym istniało wtedy tak dużo tych cholernych dokumentów w różnych odmianach ANSI i DBCS i kto je teraz przekonwertuje? Ja? Przez to większość ludzi ignorowało Unikod przez parę lat, a w międzyczasie wszystko się jeszcze bardziej pogarszało.

Dlatego wymyślono świetną rzecz - UTF-8. UTF-8 był kolejnym systemem przechowywania łańcuchów punktów kodowych Unikodu, tych magicznych numerów U+, w pamięci za pomocą 8-bitowych bajtów. W UTF-8 każdy punkt kodowy z przedziału 0-127 jest zapisywany na pojedynczym bajcie. Tylko punkty 128 i wyżej przechowywane są używając 2, 3 aż do 6 bajtów.

How UTF-8 works

To ma ten elegancki efekt uboczny, że angielskie teksty wyglądają tak samo w UTF-8, jak wyglądały w ASCII, więc Amerykanie nie widzą w tym nic złego. Tylko reszta świata musi się namęczyć. Konkretnie, Hello, które zapisywane było jako U+0048 U+0065 U+006C U+006C U+006F będzie zapisywane jako 48 65 6C 6C 6F, które, zaraz! wygląda tak samo jak w ASCII, w ANSI i w każdym zestawie znaków OEM na całej planecie. A jeśli jesteś na tyle głupi, żeby używać liter z akcentami, liter greckich lub klingońskich, musisz używać kilku bajtów, żeby zapisać pojedynczy punkt kodowy, ale Amerykanie nigdy tego nie zauważą. (UTF-8 ma także tę miłą właściwość, że ignorancki, stary kod przetwarzający łańcuchy znaków używający pojedynczego bajtu 0 jako oznaczenie wartości pustej, nie będzie ścinał łańcuchów znaków).

Póki co opowiedziałem o trzech sposobach kodowania Unikodu. Tradycyjna metoda zapisz-to-na-dwóch-bajtach nazywana jest UCS-2 (ponieważ ma dwa bajty) albo UTF-16 (ponieważ ma 16 bitów), ale musisz wiedzieć, jak rozróżnić UCS-2 z notacją high-endian albo low-endian. No i jest nowy, popularny standard UTF-8, który ma ciekawe właściwości i działa nieźle, jeśli masz do czynienia z tekstem angielskim i upośledzonymi umysłowo programami, które są kompletnie nieświadome świata poza ASCII.

Tak naprawdę istnieje wiele innych metod kodowania Unikodu. Jest coś, co nazywa się UTF-7, który jest bardzo podobny do UTF-8, ale gwarantuje, że najbardziej znaczący bit będzie zawsze zerem, więc gdy przesyłasz Unikod przez jakiś drakoński program pocztowy, który uważa, że 7 bitów to wystarczająco dużo, dziękuję bardzo, to nadal znaki mogą przecisnąć się niezniszczone. Jest UCS-4, który przechowuje punkt kodowy na 4 bajtach, co ma tę dobrą właściwość, że każdy pojedynczy punkt kodowy może być przechowywany na takiej samej liczbie bajtów, ale, o rany, nawet Teksańczycy nie byliby tak beztroscy, żeby marnować taką ilość pamięci.

No i teraz skoro już myślisz w kategoriach platonicznych, idealnych liter, które są reprezentowane za pomocą punktów kodowych Unikodu, to te unikodowe punkty kodowe mogą być zakodowane także w każdym z tradycyjnych schematów kodowych! Na przykład, mógłbyś zakodować łańcuch znaków Unikodu dla wyrazu Hello (U+0048 U+0065 U+006C U+006C U+006F) w ASCII albo kodowaniu greckim OEM albo hebrajskim kodowaniu ANSI albo w jednym z kilku setek kodowań, które zostały dotychczas wymyślone, ale z jednym haczykiem: niektóre litery mogą się nie pojawić! Jeśli nie ma żadnego odpowiednika dla unikodowego punktu kodowego, który starasz się przedstawić w konkretnym kodowaniu, zazwyczaj dostaniesz znak zapytania: ? albo jeśli jesteś naprawdę dobry - pudełko. Który znak dostałeś? -> �

Istnieją setki tradycyjnych kodowań, które potrafią przechowywać tylko niektóre punkty kodowe poprawnie, a wszystkie inne punkty kodowe zamieniają w znaki zapytania. Niektóre popularne kodowania angielskiego to Windows-1252 (standard Windows 9x dla języków zachodnio-europejskich) i ISO-8859-1, inaczej Latin-1 (także użyteczny dla każdego z zachodnio-europejskich języków). Ale próbując zapisać rosyjskie albo hebrajskie litery w tych kodowaniach dostaniemy tylko znaki zapytania. UTF 7, 8, 16, i 32 mają tę fajną właściwość, że potrafią zapisać jakikolwiek punkt kodowy poprawnie.

Najważniejsza prawda na temat kodowań

Jeśli kompletnie zapomnisz wszystko, co właśnie tłumaczyłem, proszę zapamiętaj tylko jedną, ekstremalnie ważną rzecz. Nie ma sensu mieć łańcucha znaków bez wiedzy, jakiego kodowania używa. Nie możesz dłużej chować głowy w piasek i udawać, że "czysty" tekst to ASCII.

Nie istnieje coś takiego, jak Czysty Tekst.

Jeśli masz łańcuch znaków, w pamięci, w pliku albo w wiadomości email, musisz wiedzieć jakiego używa kodowania albo nie jesteś w stanie go zinterpretować i wyświetlić użytkownikom prawidłowo.

Prawie każdy problem typu "moja strona internetowa wygląda jak bełkot" albo "ona nie może przeczytać mojego mejla, kiedy używam akcentów" sprowadza się do jednego naiwnego programisty, który nie zrozumiał prostego faktu, że jeśli nie powiesz wyraźnie, czy dany łańcuch znaków zakodowany jest w UTF-8, ASCII, ISO 8859-1 (Latin 1) albo Windows 1252 (Zachodnio-Europejski), nie można przedstawić tego łańcucha prawidłowo ani nawet powiedzieć, gdzie się kończy. Istnieje ponad setka kodowań, a powyżej punktu kodowego 127 - wszystko może się wydarzyć.

Jak przechowujemy tę informację o tym, jakiego kodowania używa łańcuch znaków? Hmm, są na to standardowe sposoby. Dla wiadomości email powinieneś mieć łańcuch znaków tego typu w nagłówku wiadomości

Content-Type: text/plain; charset="UTF-8"

Dla strony internetowej pomysł był taki, że serwer webowy zwróci podobną informację Content-Type w nagłówku http razem z zawartością strony -- nie w samym HTMLu, ale w jednym z nagłówków odpowiedzi na żądanie, które są wysyłane przed stroną HTML. 

To powoduje problemy. Przypuśćmy, że mamy wielki serwer webowy z wieloma pod-serwisami i setkami stron dodawanymi przez masę ludzi mówiących wieloma różnymi językami i używających różnego kodowania, które akurat wymyśliła im ich kopia Microsoft FrontPage'a. Sam serwer webowy nie za bardzo wie z jakim kodowaniem napisany był poszczególny plik, dlatego nie mógłby wysłać nagłówka Content-Type.

Byłoby całkiem wygodnie umieścić Content-Type dla danego pliku HTML w tym właśnie pliku, używając jakiegoś specjalnego znacznika. Oczywiście to doprowadza purystów do szaleństwa... jak w takim razie czytałbyś ten plik HTML, dopóki nie wiedziałbyś w jakim jest zapisany kodowaniu?! Na szczęście, niemal każde dostępne kodowanie tak samo traktuje znaki między 32 i 127, dlatego zawsze możesz dojść przynajmniej do tego miejsca na stronie HTML bez używania śmiesznych literek:

<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">

Ale ten znacznik meta powinien być naprawdę pierwszą rzeczą w sekcji <head>, ponieważ jak tylko przeglądarka internetowa zobaczy ten tag, przestanie parsować stronę i zacznie ponownie, interpretując wszystko w kodowaniu, które wyspecyfikowałeś.

Co robią przeglądarki internetowe, jeśli nie znajdą żadnego Content-Type ani w nagłówku http, ani w tagu meta? Internet Explorer robi rzecz ciekawą: próbuje zgadnąć, bazując na częstotliwości używania różnych bajtów w typowym tekście w konkretnym kodowaniu, w jakim języku i kodowaniu jest dana strona. Ponieważ starsze, 8 bitowe strony kodowe miały zwyczaj umieszczać swoje litery narodowe w różnych przedziałach między 128 a 255 i ponieważ każdy język używany przez ludzi ma inny charakterystyczny histogram użycia liter w tekście, ma to szansę zadziałać. To całkiem dziwne, ale zdaje się, że działa to na tyle często, że naiwni twórcy stron internetowych, którzy nigdy nie wiedzieli, że potrzebują nagłówka Content-Type, patrzą na swoją stronę w przeglądarce, a ona wygląda ok, dopóki pewnego dnia nie napiszą czegoś, co nie do końca współgra z rozkładem prawdopodobieństwa liter w ich rodzimym języku, Internet Explorer zadecyduje, że to koreański i tak to wyświetli, jednocześnie udowadniając, tak myślę, że prawo Postela, aby "być konserwatywnym w tym, co się wypowiada i liberalnym w tym, co się akceptuje" nie jest, szczerze, zbyt dobrą zasadą inżynierską. No a co biedny czytelnik takiej strony, która napisana była po bułgarsku a wygląda na koreańską (i nawet nie jednolicie koreańską), może zrobić? Idzie do menu Widok | Kodowanie i stara się wypróbować różne kodowania (jest przynajmniej tuzin kodowań dla języków wschodniej Europy), dopóki strona nie wygląda bardziej przyjaźnie. Jeśli tylko wie, że może to zrobić, czego nie wie większość ludzi.

Rose

Do ostatniej wersji CityDesk-u, programu zarządzającego stronami internetowymi opublikowanemu przez moją firmę zdecydowaliśmy się, że wewnętrznie będziemy używać Unikodu w UCS-2 (dwa bajty), czego używa Visual Basic, COM i Windows NT/2000/XP jako swój natywny typ łańcuchów znaków. W kodzie C++ po prostu deklarujemy łańcuchy znaków jako wchar_t ("wide char") zamiast char i używamy funkcji wcs zamiast funkcji str (na przykład wcscat i wcslen zamiast strcat i strlen). Aby stworzyć łańcuch znaków w UCS-2 w kodzie C musisz po prostu umieścić literkę "L" przed łańcuchem tak, jak tutaj: L"Hello".

W momencie, kiedy CityDesk publikuje stronę internetową, konwertuje ją do UTF-8, który jest obsługiwany przez przeglądarki od wielu lat. W taki sposób zakodowanych jest wszystkich 29 wersji językowych strony Joel on Software i nie słyszałem nawet jednej osoby, która miałaby kłopot z ich oglądaniem.

Ten artykuł staje się raczej długi, a nie mogę omówić wszystkiego, co jest do poznania w zakresie kodowania znaków i Unikodu, ale mam nadzieję, że skoro przeczytałeś aż dotąd, wiesz wystarczająco dużo, żeby wrócić do programowania (używając antybiotyków zamiast pijawek i czarów), z czym Cię teraz zostawię.

Data publikacji oryginału: 8 października, 2003


Ruch i Ogień

Oryginalny post: Fire and Motion

Autor: Joel Spolsky

Czasami po prostu nic nie mogę zrobić.

Jasne, przychodzę do biura, krzątam się, sprawdzam pocztę co dziesięć sekund, czytam artykuły w sieci, czy nawet robię coś tak bezmyślnego, jak płacenie rachunku American Express. Powrót do rytmu w pisaniu kodu jednak się po prostu nie zdarza.

Tetris Te ataki nieproduktywności trwają zwykle dzień lub dwa. Bywało jednak i tak w mojej karierze dewelopera, że tygodniami nie byłem w stanie zrobić kompletnie nic. Jak to mówią, nie jestem w rytmie. W strefie czasowej. Gdziekolwiek.

Każdemu zdarzają się wahania nastrojów; dla niektórych ludzi są one delikatne, dla innych istotniejsze lub nawet paraliżujące. I wygląda na to, że okresy nieproduktywności są jakoś skorelowane z chwilami przygnębienia.

Zmusza mnie to do myślenia nad tymi naukowcami, którzy twierdzą, że ludzie nie mogą kontrolować tego, co jedzą. Wtedy każda próba przejścia na dietę jest skazana na bycie krótkoterminową, a ludzie, którzy próbują ją stosować, wracają do swojej naturalnej wagi. Może jako twórca oprogramowania nie jestem w stanie kontrolować, kiedy jestem produktywny, i po prostu muszę przeżywać moje słabsze i mocniejsze chwile i mieć nadzieję na to, że uśrednią się one do liczby linii kodu wystarczającej na to, żeby opłacało się mnie zatrudnić.

 

 
Poczytaj The Onion przez chwilę.
 
 

To, co doprowadza mnie do szaleństwa to fakt, że odkąd tylko zacząłem swoją pierwszą pracę, uświadomiłem sobie, że jako programista średnio spędzam dwie lub trzy godziny dziennie na produktywne kodowanie. Kiedy byłem na letnich praktykach w Microsoft, kolega praktykant powiedział mi, że w rzeczywistości on przychodził do pracy od 12 do 17 każdego dnia. Pięć godzin, odjąć lunch, a jego zespół go uwielbiał, jako że był w stanie zrobić o wiele więcej niż średnia. Okazało się, że dla mnie to też działa. Czuję się odrobinę winny gdy widzę, jak ciężko pracują inni; miałem 2 lub 3 godziny pracy wysokiej jakości w ciągu dnia, a wciąż byłem jednym z najbardziej produktywnych członków zespołu. To jest prawdopodobnie powód, dla którego Peopleware i XP nalegają na pozbycie się nadgodzin i pracę dokładnie 40 godzin w tygodniu - robią tak wiedząc, że nie zmniejszy to wydajności zespołu.

Ale to nie te dni, w ciągu których "tylko" dwie godziny dziennie są efektywne, martwią mnie. Martwią mnie dni, kiedy nie mogę zrobić nic.

Dużo nad tym myślałem. Próbowałem zapamiętać momenty, w których zrobiłem najwięcej w swojej karierze. To prawdopodobnie wtedy, gdy Microsoft przeniósł mnie do pięknego, luksusowego biura z wielkimi oknami wychodzącymi na piękne, kamienne podwórze pełne kwitnących drzewek wiśniowych. Wszystko grało. Miesiącami pracowałem non-stop płodząc szczegółową specyfikację dla Excel Basic - ogromną stertę papieru zawierającą szczegóły gigantycznego modelu obiektowego i środowiska programistycznego. Dosłownie nigdy nie przestawałem. Gdy jechałem do Bostonu na MacWorld, zabierałem ze sobą laptopa i dokumentowałem klasę Okno siedząc na przyjemnym tarasie w HBS.

Jak już raz złapiesz rytm, to dalej łatwo jest go utrzymać. Wiele z moich dni wygląda tak: (1) przyjście do pracy (2) poczta, prasówka, itp. (3) podjęcie decyzji, że równie dobrze mogę zjeść lunch zanim zajmę się pracą (4) powrót z lunchu (5) poczta, prasówka, itp. (6) zdecydowanie się w końcu, że należy zacząć coś robić (7) poczta, prasówka, itp. (8) zdecydowanie się jeszcze raz, że należy zacząć coś robić (9) uruchomienie tego cholernego edytora (10) pisanie kodu non-stop aż uświadomię sobie, że jest 19:30.

Gdzieś między krokiem 8 i 9 jest jakiś problem, bo nie zawsze udaje mi się przeskoczyć tę przepaść. bike trip Dla mnie zwykłe rozpoczęcie pracy jest tą jedyną trudną rzeczą. Obiekt w spoczynku pozostaje w spoczynku. Jest coś niesamowicie ciężkiego w moim mózgu, coś niesamowicie trudnego do poruszenia, ale jak już tylko się zacznie poruszać z pełną prędkością, pozostaje w ruchu bez żadnego wysiłku. To jak z rowerem, którym masz wyjechać na samodzielną wycieczkę - gdy tylko zaczniesz jechać na tym rowerze, trudno uwierzyć, jak ciężko go zmusić do poruszania się, ale jak tylko się uda - wydaje się być zupełnie łatwym go prowadzić.

Być może to jest właśnie klucz do produktywności: po prostu zacząć. Być może gdy  programowanie w parach działa, to działa dlatego, że zostało umówione z Twoim kolegą, zmuszając was obu do zaczęcia pracy.

Joel in the Army

Gdy byłem izraelskim spadochroniarzem generał zatrzymał się przy nas by wygłosić małą mowę na temat strategii. W walkach piechoty, powiedział, jest tylko jedna strategia: Ogień i Ruch. Poruszać się w kierunku przeciwnika, strzelając ze swojej broni. Ogień zmusza go do schowania się i uniemożliwia strzelanie do Ciebie. (To właśnie żołnierze mają na myśli, gdy mówią: "osłaniaj mnie". Oznacza to "strzelaj do naszego wroga tak, żeby musiał się czołgać i nie mógł strzelać do mnie w czasie, gdy będę przebiegał przez tę ulicę, tu." Działa.) Ruch pozwala Ci zdobywać terytorium i zbliżyć się do wroga na odległość pozwalającą Ci łatwiej trafić w cel. Jeśli się nie poruszasz, wróg zaczyna decydować co się wydarzy, a to nie za dobrze. Jeśli nie strzelasz, to wróg zacznie strzelać, przyszpilając Cię tam, gdzie jesteś.

Pamiętałem to przez długi czas. Zauważyłem, że niemalże każda ze strategii wojskowych, od walk powietrznych do wielkoskalowych manewrów morskich, opiera się na idei Ognia i Ruchu. Zajęło mi kolejne 15 lat uświadomienie sobie, że zasada Ognia i Ruchu to sposób, w jaki załatwiasz sprawy w życiu. Musisz poruszać się do przodu, każdego dnia. Nie ma znaczenia, że Twój kod jest kulawy, pełen błędów i nikt go nie chce. Jeśli poruszasz się do przodu, pisząc kod i poprawiając błędy, czas jest po Twojej stronie. Uważaj, gdy Twoja konkurencja strzela do Ciebie. Czy chcą po prostu zmusić Cię do reagowania na ich salwy, byś nie mógł się poruszać do przodu?

Pomyśl o historii strategii dostępu do danych oferowanych przez Microsoft. ODBC, RDO, DAO, ADO, OLEDB, teraz ADO.NET - Wszystko Nowe! Czy są to technologiczne imperatywy? Wynik pracy niekompetentnej grupy projektantów, którzy muszą wymyślać od nowa sposób dostępu do danych każdego roku? (W rzeczywistości to prawdopodobnie to.) Wynikiem końcowym jest jednak ogień osłoniający. Konkurencja nie ma innego wyjścia, jak tylko portować i nadążać ze zmianami; czas ten mogliby spędzić na pisaniu nowych atrakcji. Spójrz bliżej na krajobraz świata oprogramowania. Firmy, które radzą sobie dobrze to te, które najmniej zależą od dużych firm i nie muszą tracić swojego czasu na aktualizacje, czy wprowadzanie poprawek do błędów, które pojawiają się tylko na Windows XP. Firmy, które potykają się to te, które spędzają zbyt dużo czasu na wróżeniu z fusów w która stronę pójdzie Microsoft w przyszłości. Ludzie martwią się .NETem i decydują się przepisać całą architekturę pod .NET myśląc, że muszą. Microsoft strzela do Ciebie, a to tylko ogień osłaniający - po to, żeby oni mogli pójść do przodu, a Ty nie, bo tak właśnie gra się w tą grę, Józek. Czy zamierzasz wspierać Hailstorm? SOAP? RDF? Wspierasz to ponieważ Twoi klienci tego potrzebują, czy dlatego że ktoś do Ciebie strzela, a Ty czujesz, że musisz odpowiedzieć? Zespoły ds. sprzedaży w dużych firmach rozumieją ogień osłaniający. Idą do swoich klientów i mówią: "OK, nie musisz od nas kupować. Możesz kupić od najlepszego dostawcy. Upewnij się jednak, że dostaniesz produkt wspierający (XML/SOPA/CDE/J2EE), gdyż w przeciwnym przypadku sam Zamknięsz się w Bagażniku". Gdy wtedy małe firmy próbują sprzedać swój produkt w to miejsce, wszystko co słyszą to posłusznych CTO papugujących "Czy macie J2EE?". I marnują cały swój czas na dostosowanie do J2EE nawet jeśli to nie powoduje wzrostu sprzedaży, i nie daje im możliwości odróżnienia się od a siebie samych. To cecha z ptaszkiem - robisz to, ponieważ ptaszek mówi, że to masz, ale nikt nie będzie z tego korzystał czy tego potrzebuje. To jest ogień osłaniający.

Ogień i Ruch, dla małych firm jak moja, oznacza dwie rzeczy. Musisz mieć czas po swojej stronie i musisz poruszać się do przodu każdego dnia. Wcześniej czy później, wygrasz. Wszystko, co zrobiłem wczoraj, to drobna poprawka schematu kolorów w FogBUGZ. To jest OK. Jest coraz lepiej, cały czas. Każdego dnia nasze oprogramowania jest coraz lepsze, a my mamy więcej klientów - i tylko to się liczy. Póki nie jesteśmy firmą rozmiaru Oracle, nie musimy zastanawiać się nad wielkimi strategiami. Musimy po prostu przychodzić co dzień do pracy i jakoś włączyć edytor.

 
Jest coraz lepiej...

Data publikacji oryginału: styczeń 6, 2002

Rocznica devBlogów

W dniu 29 lipca 2010 roku upłynął równo rok od momentu powstania serwisu devBlogi.pl, a zarazem Grupy devMedia.pl. Wieść o powstaniu naszego serwisu rozniosła się stosunkowo prędko i w dość dynamiczny sposób zaczęło przybywać stałych czytelników (około 1300 na dzień dzisiejszy).

Co przyniósł nam ostatni rok? Co się zmieniło? Jakie są nowości?

Otóż przez ostatnie 12 miesięcy powstało 93 wpisów na blogu. Na początku tworzone przez dwóch tłumaczy (założycieli - immortal, rafek), a następnie również przez osoby, które zaoferowały swoją pomoc w zakresie tłumaczeń. W kolejności przybywali do nas: mixer, asgaroth oraz ostatnio mxs. Pragniemy dodać, iż cały czas jesteśmy otwarci na nowych tłumaczy - każdy może spróbować swoich sił! :)

Każdy z członków zespołu sam wybiera, co chce tłumaczyć. Niektóre wpisy wykazały się szczególną popularnością i zanotowały ponad 10 tysięcy odsłon. Dla przypomnienia były to:

Niezmiernie cieszy nas fakt, iż udaje nam się dostarczać Wam dobrej jakości branżowe teksty. Oczywiście bez Was ten serwis nie mógłby istnieć - naszą główną motywacją są Wasze komentarze, oceny i słowa uznania.

Na dzień dzisiejszy w serwisie znajdują się tłumaczenia takich postaci jak Jeff Atwood, Joel Spolsky, czy Steve Yegge. Jakich Waszym zdaniem bloggerów brakuje?

W miarę wzrostu popularności devBlogów, postanowiliśmy stworzyć dodatkowe dwa miejsca dla naszej programistycznej społeczności. Na początku roku 2010 uruchomiliśmy serwis devPytania.pl, który zrealizowany jest na tej samej platformie, co znany wszystkim StackOverflow. Następnie podjęliśmy się przetłumaczenia książki pt. "97 rzeczy, o których każdy programista wiedzieć powinien", czego efektem jest strona 97rzeczy.

Mając na uwadze fakt, iż zapewne większość z Was pracuje zawodowo w branży programistycznej, pozwoliliśmy sobie na opublikowanie ankiety dotyczącej zarobków programistów w Polsce. Oddaliście w sumie ponad 1000 głosów. Wyniki ankiety dostępne są na razie w postaci prostej mapki. W niedalekiej przyszłości postaramy się dostarczyć dokładniejszy raport.

Popularność serwisu devBlogi, czy devPytania można śledzić na wykresach, które wyświetlane są w stopkach serwisów. Dodatkowo, uruchomiliśmy profil Grupy devMedia.pl na Twitterze, który posłuży za nasz oficjalny mikro-blog.

Dziękujemy Wam wszystkim za udział w życiu społeczności dev*. Propozycje, sugestie oraz krytykę zostawiajcie w komentarzach, a my postaramy się uczynić nasze serwisy jeszcze lepszymi! :)

Zespół devMedia.pl.

Zasada skautów

Opublikowaliśmy kolejne tłumaczenie w serwisie 97rzeczy:

  • Zasada skautów (autor: Robert C. Martin (Uncle Bob))
    "Skauci mają zasadę: 'Zawsze zostawiaj obozowisko czystsze niż je zastałeś.' Jeśli zastaniesz bałagan, posprzątaj go niezależnie od tego, kto był jego sprawcą. Celowo ulepszaj środowisko dla następnych obozowiczów."

Zachęcamy do lektury,
Zespół devMedia.pl

Prawo Nieszczelnych Abstrakcji

Oryginalny post: The Law of Leaky Abstractions

Autor: Joel Spolsky

Jest jedna magiczna i zupełnie kluczowa rzecz w działaniu Internetu na której codziennie polegasz. Dzieje się to w protokole TCP, jednym z podstawowych elementów składających się na Internet.

TCP to metoda przesyłania danych, która jest niezawodna. Rozumiem przez to, że kiedy wysyłasz wiadomość przez sieć z wykorzystaniem TCP dotrze ona na miejsce w formie niezmienionej i nieuszkodzonej.

Używamy TCP do wielu rzeczy, takich jak przeglądanie stron internetowych lub wysyłanie emaili. To niezawodność TCP zapewnia nam, że wszystkie ekscytujące emaile ze Wschodniej Afryki docierają w idealnym stanie. O tak.

Dla porównania, jest inna metoda transmitowania danych, która nazywa się IP i jest zawodna. Nikt nie obieca, że Twoje dane dotrą do celu, a mogą gdzieś po drodze ulec zabałaganieniu. Jeśli wysyłasz wiele komunikatów z wykorzystaniem IP, nie bądź zaskoczony, jeśli tylko połowa z nich dotrze, niektóre z nich w innej kolejności niż były wysyłane, a niektóre zamienione na inne komunikaty. Być może te nowe będą zawierać zdjęcia uroczych małych orangutanów lub – co bardziej prawdopodobne – dużo nienadających się do przeczytania śmieci, które wyglądają jak temat emaila z tajwańskim spamem.

Teraz magia: TCP jest skonstruowane na bazie IP. Innymi słowy, TCP musi wysyłać dane w sposób niezawodny, używając zawodnego narzędzia.

Żeby zrozumieć dlaczego to jest magia, rozważmy następujący, dość analogiczny, choć trochę szalony scenariusz osadzony w świecie rzeczywistym.

Wyobraźmy sobie, że mamy sposób na wysyłanie aktorów z Broadway’u do Hollywoodu, który polega na usadzeniu ich w samochodach i przewozie przez kraj. Niektóre z tych samochodów się rozbiły, zabijając nieszczęsnych aktorów. Czasami aktorzy upili się po drodze i zgolili głowy lub sprawili sobie tatuaże na nosach i stali się zbyt brzydcy, aby pracować w Hollywood. Często aktorzy przybywali w innej kolejności niż byli wysyłani, ponieważ wybierali inne trasy. Wyobraźmy sobie teraz nową usługę: Hollywood Express, która polega na dostarczaniu aktorów do Hollywood, zapewniając jednocześnie, że (a) dotrą (b) w kolejności (c) w nienaruszonej formie. Magia polega na tym, że Hollywood Express nie ma żadnej innej metody dostarczania aktorów niż zawodna metoda pakowania ich do samochodów i przewiezienia przez kraj. Hollywood Express sprawdza, czy wszyscy aktorzy dotarli w idealnym stanie i, jeśli nie, powiadamiają biuro odpowiedzialne za wysyłkę, aby przesłali bliźniaka. Jeśli aktorzy przybywają w złej kolejności Hollywood Express przestawia ich. Jeśli wielkie UFO podczas swojej podróży do Strefy 51 rozbije się gdzieś na autostradzie w Newadzie, czyniąc ją tym samym nieprzejezdną, wszyscy aktorzy, którzy mieli jechać tą drogą są kierowani przez Arizonę, a Hollywood Express nawet nie informuje reżyserów w Kalifornii co się stało. Bo dla nich aktorzy po prostu przyjeżdżają trochę wolniej niż zwykle i nie muszą nic słyszeć o rozbiciu UFO.

To jest, w przybliżeniu, magia TCP. Informatycy lubią nazywać to abstrakcją: uproszczenie czegoś znacznie bardziej skomplikowanego, które znajduje się pod spodem. Jak się okazuje, wiele aspektów programowania sprowadza się do tworzenia abstrakcji. Czym jest biblioteka do łańcuchów znaków? Jest metodą na sprawienie wrażenia, że komputer potrafi operować na łańcuchach znaków równie prosto jak na liczbach. Czym jest system plików? Jest metodą na sprawianie wrażenia, że dysk twardy nie jest tylko zbiorem wirujących magnetycznych talerzy, które potrafią przechowywać bity w wybranych lokalizacjach, ale raczej hierarchicznym systemem folderów-w-folderach, zawierających pojedyncze pliki, które ostatecznie zawierają ciągi bajtów.

Wróćmy do TCP. Na początku – ze względu na prostotę – powiedziałem małe kłamstewko i niektórym z Was zapewne wylatuje już para z uszu, bo tak to Was zdenerwowało. Powiedziałem, że TCP gwarantuje, że Twoja wiadomość dotrze. Tak naprawdę, nie gwarantuje. Jeśli Twój domowy wąż przeżuł kabel sieciowy prowadzący do Twojego komputera i żadne pakiety IP nie mogą przepłynąć , wtedy TCP nie może na to nic poradzić i Twoja wiadomość nie dotrze. Jeśli podpadłeś administratorom systemu w swojej firmie i ukarali Cię przyłączając do przeładowanego huba, tylko niektóre z Twoich pakietów przejdą. TCP będzie działać, ale wszystko stanie się naprawdę powolne.

To jest to, co nazywam nieszczelną abstrakcją. TCP próbuje zapewnić kompletną abstrakcję nad zawodną siecią, ale czasami ta sieć wymyka się abstrakcji spod kontroli i zaczynasz odczuwać rzeczy od których nie można się uchronić. To jest przykład na to, co nazwałem Prawem Nieszczelnych Abstrakcji:

Wszystkie nietrywialne abstrakcje, do pewnego stopnia, są nieszczelne.

Abstrakcje zawodzą. Czasami mniej, czasami bardziej. Jest wyciek. Rzeczy idą źle. Tak dzieje się w przypadkach, kiedy mamy do czynienia z abstrakcjami. Oto kilka przykładów.

  • Coś tak prostego jak iterowanie po dwuwymiarowej tablicy może mieć zupełnie różną wydajność, jeśli robisz to horyzontalnie zamiast wertykalnie. W zależności od „struktury drewna” – jeden kierunek może powodować znacznie więcej błędów stronicowania niż inny, a przeładowanie stron jest wolne. Nawet programiści assemblera powinni móc zakładać, że mają dużą i płaską przestrzeń adresową, ale pamięć wirtualna sprawia, że jest to abstrakcja. Zaczyna ona przeciekać, kiedy pojawiają się błędy stronicowania i niektóre odwołania do pamięci trwają znacznie więcej nanosekund niż inne.
  • Język SQL ma na celu poddać abstrakcji kroki procedur potrzebnych do zadawania zapytań bazie danych. Pozwala Ci określić to, co chcesz otrzymać i pozwolić bazie zdefiniować kroki procedury do tego potrzebne. Ale w niektórych przypadkach zapytania SQL są tysiące razy wolniejsze niż inne, równoważne pod względem logicznym. Słynny przykład pokazuje, że niektóre serwery SQL są znacznie szybsze jeśli napiszesz „where a=b and b=c and a=c” zamiast  „where a=b and b=c”, pomimo tego, że wyniki są takie same. Nie zajmujesz się procedurą, określasz tylko specyfikację. Ale czasami abstrakcja przecieka i powoduje potwornie duże pogorszenie wydajności. Musisz wtedy uciec się do analizy zapytań, przestudiować co dzieje się źle i określić, jak sprawić, aby zapytania działały szybciej.
  • Pomimo tego, że sieciowe biblioteki takie jak NFS i SMB pozwalają Ci traktować pliki na odległych maszynach „jak gdyby” były lokalne, czasami połączenie jest bardzo powolne albo urywa się. Plik przestaje wyglądać na lokalny i jako programista musisz napisać jakiś kod, aby sobie z tym poradzić. Abstrakcja „odległy plik jest taki sam jak lokalny” przecieka. Oto konkretny przykład dla administratorów Unixa. Jeśli umieścisz katalogi domowe użytkowników na zamontowanym dysku NFS (pierwsza abstrakcja) i Twoi użytkownicy stworzą pliki .forward, aby przekazywać wszystkie swoje emaile gdzieś indziej (druga abstrakcja) wtedy, kiedy przyjdzie nowy email a serwer NFS przestanie działać, email nie zostanie przeforwardowany, ponieważ nie uda się odnaleźć pliku .foreward. Wyciek w abstrakcji spowodował, że kilka wiadomości przepadło.
  • Klasy łańcuchów znaków w C++ mają na celu sugerować, że łańcuchy znaków są wbudowanymi typami danych. Próbują poddać abstrakcji fakt, że łańcuchy są trudne i pozwolić działać Ci jakby gdyby były równie łatwe jak liczby całkowite. Prawie wszystkie klasy stringów w C++przeciążają operator +, więc możesz pisać s + „bar” żeby skonkatenować. Ale wiesz co? Nie ważne jak bardzo by próbowali, nigdzie na Ziemi nie znajdą klasy w C++, która pozwoliłaby napisać „foo” + „bar”, ponieważ literały łańcuchów znaków w C++ zawsze są typu char*, nigdy string. Abstrakcja ma wyciek, którego język nie pozwoli zatkać. (Co zaskakujące, historia ewolucji C++ może być sprowadzona do historii prób zatkania wycieku w abstrakcji łańcuchów znaków. Dlaczego nie można po prostu dodać natywnej klasy string do języka? – to wykracza poza moje pojmowanie w tym momencie.)
  • I wreszcie, nie możesz jechać zbyt szybko, kiedy leje. Mimo, że Twój samochód ma zamontowane wycieraczki, reflektory i dach i grzejnik, wszystko abyś nie musiał przejmować się faktem, że pada (wszystkie te zamontowane rzeczy sprawiają, że pogoda poddaje się abstrakcji). Ale czekaj, musisz pamiętać o utracie przyczepności i fakcie, że deszcz jest czasami na tyle intensywny, że widoczność jest bardzo ograniczona. Jedziesz więc wolniej, ponieważ pogoda nigdy nie może być całkowicie poddana abstrakcji. Ze względu na prawo nieszczelnych abstrakcji.

Jednym z powodów dla których prawo nieszczelnych abstrakcji jest tak problematyczne jest fakt, że abstrakcje tak naprawdę nie ułatwiają naszego życia w stopniu w jakim byśmy chcieli. Kiedy uczę kogoś jak programować w C++ byłoby wspaniale gdybym nigdy nie musiał mówić mu o char* i arytmetyce wskaźników. Byłoby wspaniale gdybym mógł od razu przejść do stringów w STL. Ale pewnego dnia ten ktoś napisze kod „foo” + „bar” i wtedy staną się naprawdę dziwne rzeczy, a ja będę musiał zatrzymać się i – chcąc nie chcąc - nauczyć go czym jest char*. Albo, pewnego dnia będzie chciał wywołać funkcję Windows API, której dokumentacja mówi, że ma ona argument typu OUT LPTSTR i nie będzie wiadomo jak ją wywołać dopóki nie pozna się char*, wskaźników, Unicode’a, wchar_t i pliku nagłówkowego TCHAR oraz całej masy innych przeciekających rzeczy.

Podczas nauczania kogoś jak programować pod COM, byłoby wspaniale gdybym mógł po prostu nauczyć go korzystania z wizardów Visual Studio i wszystkich opcji generacji kodu, ale kiedy coś pójdzie inaczej niż powinno, kompletnie nie będzie wiadomo co się stało, jak to debugować i jak przywrócić działającą postać. Muszę nauczyć go co to jest IUnknown i CLSID i ProgIDS i... proszę!

Podczas nauczania kogoś jak programować w ASP.NET, byłoby wspaniale gdybym mógł po prostu nauczyć go, że może kliknąć dwa razy na obiekty i pisać kod, który wykona się na serwerze, kiedy użytkownik kliknie na te obiekty. Istotnie, ASP.NET wprowadza abstrakcję zacierającą różnicę między pisaniem kodu HTML do obsługi hiperlinku (<a>) i kodu do obsługi kliknięcia na przycisk. Ale pojawia się problem: projektanci ASP.NET musieli ukryć fakt, że w HTML nie ma możliwości wysłania formularza hiperlinkiem. Obchodzą to generując linie kodu JavaScript i dołączając obsługę zdarzenia onclick do hiperlinku. Abstrakcja przecieka. Jeśli użytkownik ma wyłączony JavaScript, wtedy aplikacja w ASP.NET nie będzie działać prawidłowo i jeśli programista nie rozumie, jak działa ta abstrakcja w ASP.NET, nie będzie miał zielonego pojęcia, co mogło pójść źle.

Prawo przeciekającej abstrakcji oznacza, że kiedykolwiek ktoś proponuje jakieś nowe super narzędzie do generowania kodu, które uczyni nas tak bardzo efektywnymi, pojawiają się ludzie, którzy mówią „najpierw naucz się jak to zrobić manualnie, dopiero później używaj tego super narzędzia oszczędzającego czas”. Narzędzia do generowania kodu, które mają na coś nakładać abstrakcję , podobnie jak wszystkie abstrakcje, przeciekają. Jedynym sposobem na kompetentne radzenie sobie z tymi przeciekami jest zrozumienie jak abstrakcje działają i - względem czego. Więc abstrakcje oszczędzają czas na pracę, ale nie oszczędzają czasu na naukę.

A to wszystko oznacza, paradoksalnie – pomimo, że mamy narzędzia programistyczne coraz to wyższego poziomu z coraz lepszymi abstrakcjami – że stanie się wprawnym programistą staje się jeszcze trudniejsze.

Podczas moich praktyk w Microsoft pisałem bibliotekę do stringów na Macintoshe. Typowe zadanie: napisz strcat, które zwraca wskaźnik do ostatniego znaku nowego stringa. Kilka linii kodu w C. Wszystko co robiłem było zaczerpnięte prosto z K&R – cienkiej książki o programowaniu w języku C.

Dzisiaj, podczas pracy w CityDesk, potrzebuję znać Visual Basic, COM, ATL, C++, InnoSetup, wewnętrzne mechanizmy Internet Explorera, wyrażenia regularne, DOM, HTML, CSS i XML. Wszystko wysokiego poziomu, w porównaniu z zagadnieniami z K&R. Ale, cały czas muszę znać rzeczy z K&R, inaczej byłbym spalony.

Dziesięć lat temu mogliśmy przypuszczać, że nowe paradygmaty programowania sprawią, że programowanie stanie się prostsze. Rzeczywiście, abstrakcje, które stworzyliśmy przez te lata pozwalają nam operować na nowych poziomach, z którymi nie mieliśmy do czynienia dziesięć albo piętnaście lat temu, takimi jak programowanie GUI i programowanie sieciowe. I rzeczywiście, te wspaniałe narzędzia, jak współczesne obiektowe języki z formularzami, pozwalają nam wykonywać naszą pracę znacznie szybciej. Ale nagle, pewnego dnia, będziemy musieli zidentyfikować problem z wyciekającą abstrakcją, a to zabierze 2 tygodnie. Kiedy potrzebujesz zatrudnić programistę głównie do programowania w VB, nie wystarczy zatrudnić programistę VB, ponieważ będzie on kompletnie zablokowany, kiedy abstrakcja VB zacznie przeciekać.

Prawo Nieszczelnych Abstrakcji ściąga nas w dół.

Data publikacji oryginału: 11 listopada, 2002

Related Posts with Thumbnails