Skip to content

Entries from July 2009.

Zapobieganie defektom

W artykule Robert Mays opisuje swoje doświadczenia i sugestie związane z zapobieganiem defektom. Artykuł ukazał się w IBM Systems Journal w 1990 roku (niestety adres URL jest już nieaktualny). Zapobieganie defektom składa się z czterech elementów włączonych w proces tworzenia oprogramowania:
  1. spotkania w trakcie których dokonywana jest szczegółowa analiza przyczyn (root cause) błędów i sugerowane są akcje prewencyjne
  2. wdrożenie akcji prewencyjnych w zespole
  3. spotkania przed pracą mające na celu zwrócenie uwagi programistów na sprawy jakości
  4. zbieranie i śledzenie danych
Autor wskazuje, że efektywniej jest zapobiegać pojawianiu się błędów niż je wyszukiwać (inspekcje, testowanie). Wtedy czas przeznaczany typowo na wyszukanie błędów można spożytkować w inny sposób (np. pracując nad kolejnym produktem). Prewencja błędów opiera się na ciągłej analizie przyczyn błędów i usuwanie tych przyczyn poprzez poprawę procesu, metodyki pracy, technologii i narzędzi. Przy analizie przyczyn korzysta się z diagramów przyczynowo - skutkowych (czasami zwanych diagramami Ishikawy od nazwiska twórcy). Proces ten zakłada włączenie różnych aktywności związanych z jakością do codziennej pracy zespołu.

Analiza wykrytych błędów

Podstawową aktywnością w projekcie jest spotkanie poświęcone analizie wykrytych błędów. Zespół próbuje znaleźć przyczyny (root cause) zaistniałych błędów i następnie proponuje wprowadzenie modyfikacji w procesie produkcyjnym, by zapobiec powstaniu takich błędów w porzyszłości. Dla każdego błędu stawiane są następujące pytania:
  • Jaka jest kategoria tego błędu: komunikacja, przeoczenie, brak wiedzy, literówka?
  • W jaki sposób błąd został wprowadzony?
  • W której fazie tworzenia systemu powstał?
  • W jaki sposób można zapobiec powstaniu takiego błędu w przyszłości? W jaki sposób podobne błędy mogą być usunięte z innych części systemu (o ile istnieją a nie zostały jeszcze wykryte przez inne techniki)?
Celem spotkania jest uzyskanie sugestii co do zapobiegania poszczególnym błędom. Nie powinno ono utknąć w zbyt szczegółowych rozważaniach (nie może być za długie). Przy końcu spotkania osoba prowadząca powinna zadać następujące pytania:
  • Czy w analizowanych błędach widać trend, który może oznaczać szerszy problem?
  • Co poszło dobrze podczas poprzedniej fazy? Co przyczyniło się do oszczędzenia czasu?
  • Co poszło źle podczas poprzedniej fazy? Co stanowiło największy problem?
  • Czy można w jakiś sposób poprawić techniki detekcji błędów, narzędzia, komunikację, edukację w stosunku do stanu aktualnego?
Obecność na takim spotkaniu programistów, którzy pracują nad systemem jest konieczna, ponieważ osoba, która wprowadziła błąd może najlepiej określić przyczynę wprowadzenia błędu.

Wprowadzenie korekt w procesie

Zespół wykonawczy (action team) odpowiada za wprowadzenie w życie akcji prewencyjnych zdefiniowanych w trakcie spotkania. Zespół ten typowo obsługuje wszystkie projekty prowadzone w ramach organizacji. Zwykle każdy członek zespołu odpowiada za jeden segment (definicja procesu, dokumentacja, narzędzia, edukowanie, projekt, programowanie, testowanie). Oto możliwe rodzaje akcji zapobiegawczych:
  • Zmiany w procesie produkcyjnym
  • Utworzenie nowych narzędzi
  • Szkolenie pracowników (seminaria, techniczne opisy niektórych aspektów produktu, artykuł na temat powtarzających się błędów)
  • Zmiany w produkcie (systemie informatycznym), które ułatwiają wykrywanie błędów
  • Usprawnienie komunikacji np. automatyczne powiadamianie o zmianach w projekcie dla wszystkich zainteresowanych osób

Mniejsza skala projektów

Opisane w artykule praktyki stosowane są w projektach dużej skali (kilkadziesiąt, kilkaset osób). Naturalnie pojawia się pytanie czy techniki zapobiegania defektom można stosować w projektach mniejszych (kilka, kilkanaście osób) lub w takich, gdzie struktura zespołu jest rozproszona (coraz częściej zdarza się, że zespół jest rozproszony geograficznie). Według mnie jest to jak najbardziej możliwe. Oczywiście należy dopasować działanie do wielkości i charakteru zespołu:
  • Analizę błędów można przeprowadzić przy użyciu kanału e-mail. Jest to mało absorbująca forma kontaktu (nie wymaga obecności w jednym czasie wszystkich członków zespołu)
  • Rolę zespołu wykonawczego muszą przejąć członkowie zespołu wraz z automatycznym sprawdzaniem przyjetych reguł w kodzie (analizatory statyczne)
Uważam, że w każdej wielkości projektu korzyści wynikające z zapobiegania defektom są warte poświęconego czasu. Łatwiej jest problem usunąć raz niż wielokrotnie łatać powstałe w jego wyniku skutki na etapie testowania produktu.

Django 1.1 released

New version (1.1) of very popular web framework Django has been released. New version includes ORM improvements, better testing performance, conditional view processing and URL namespaces.

ORM Improvements

One of SQLObject benefits over Django ORM was in my opinion  possibility to make aggregations without issuing raw SQL-s. This feature is now present in Django allowing to make more efficient reports implementation.

Model improvements

A table can be marked now as "unmanaged": syncdb/reset will not touch such table. Also: proxy models and deferred fields now are present.

Testing improvements

Big optiomalisation for unit testing fans like me: tests are run in one transaction, so performance is much better than before. I don't use Django unit test infrastructure (selected nosetests for this task), but it's pleased to hear about this improvement. Hope it will make unit testing more popular among Django programmers.

django-logo-negative

Wydajność SAN na przykładzie RPS w OVH

SAN (Storage Area Network) jest w dużym uproszczeniu sieciowym systemem plików. Pozwala scentralizować zasoby dyskowe z kilku fizycznych serwerów i udostępnić je poprzez sieć przy wykorzystaniu np. NFS lub iSCSI. Daje to znaczne oszczędności dzięki czemu można zaoferować tanie serwery dedykowane oparte o Inel Atom i sieciowy dysk.

Taką właśnie ofertę przygotowało ponad rok temu francuskie OVH. Entuzjastyczne opinie (serwer dedykowany za taką cenę!) dość szybko zostały ostudzone poprzez informacje o bardzo słabej wydajności dostępu do macierzy dyskowej po sieci. Użytkownicy informowali o spadku wydajności dysku do 400 kB/sek. (współczesne dyski dają zwykle kilkadziesiąt MB/sek.).

Ostatnio OVH po wielu walkach zapanowało jak się zdaje nad QOS dla dysku, ale wyższa gwarancja transferu jest okupiona odpowiednio większym kosztem.

Z tego przykładu można wysnuć następujące wnioski:

  • w przyrodzie nie ma czegoś takiego jak "unlimited"
  • współdzielone zasoby bez limitów zwykle kończą się jakimś mechanizmem limitowania ze względu na skończoną przepustowość

Trend do wprowadzania limitów obserwujemy też w hostingu (coraz więcej dostawców mierzy aktywnie zużycie zasobów we współdzielonym hostingu). Mechanizmy typu VPS (gwarantowane stałe zasoby) stają się także coraz bardziej popularnym wyborem dla twórców serwisów internetowych.

Vim: mixed fileencodings

Sometimes you have to edit files in different chatacters encodings using the same terminal (that is configured, let's say, for UTF-8). It's very easy by using the following Vim configuration:

set fileencodings=utf-8,iso-8859-2

This setting allows Vim to automatically detect encoding from list and select first that match. If your terminal is in different encoding file will be converted on-the-fly.

Happy Vim-ing!

Apache to Lighttpd migration

Lighttpd is smaller and faster alternative to Apache web server. You can handle bigger traffic with the same memory and CPU constraints (it's important on virtual servers where resources are limited). Let's see how we can convert existing Apache+FastCGI stacks into Lighttpd:

Global options

There's special syntax to add options to all virtuals:

global {
    dir-listing.activate = "disable"
    server.follow-symlink = "enable"
}

In above example two config values are set: one is responsible for disabling directory listings ("Options +Indexes" in Apache), second for FollowSymlink counterpart.

Declaring virtual hosts

Lighttpd uses conditionals to specify configuration in general and the same strategy applies for virtuals definitions:

$HTTP["host"] =~ ".*aplikacja.info" {
    (...)
}

Above syntax matches domain and all subdomains. Pretty simple isn't it?

mod_rewrite rewritten

Let's see how RewriteRules could be translated into Lighttpd configuration syntax:

url.rewrite-once = (
    "^/$" => "/index.php",
    "^/\?(.*)$" => "/index.php?$1",
)

Above code converts URL without script path to /index.php and any other url into /index.php?ANY-URL.

Old school cgi-s

Sometimes you want (have to) call scripts using good old protocol: CGI (Common Gateway Interface). It's inefficient method (process creation overhead every request), but have one benefit: memory is freed directly after proces finish. Example:

cgi.assign = ( ".cgi" => "" )

This syntax defines that any script with given extension will be executed as CGI. "" means we use default script interpreter (declared by #!/path/to/file syntax).

Hide some files from HTTP

Sometimes you want to block access by HTTP to only specified URLs (and do not allow, for instance, to download you config file with database login & password). This can be achieved by the following syntax:

$HTTP["url"] !~ "^/index.php|^/static" {
    url.access-deny = ("")
}

In above example only /index.php and all content from static subdirectory is available (other URLs will give 401 unauthorized error).

PHP in FastCGI mode

It's very easy to setup PHP in FastCGI mode in Debian:

lighttpd-enable-mod fastcgi

Above command symlinks /etc/lighttpd/conf-available/10-fastcgi.conf to /etc/lighttpd/conf-enabled/10-fastcgi.conf. You must restart Lighttpd in order to see effects. Lets dig inside this config file:

server.modules   += ( "mod_fastcgi" )

## Start an FastCGI server for php (needs the php5-cgi package)
fastcgi.server    = ( ".php" =>
    ((
    "bin-path" => "/usr/bin/php-cgi",
    "socket" => "/tmp/php.socket",
    "max-procs" => 1,
    "idle-timeout" => 20,
    "bin-environment" => (
    "PHP_FCGI_CHILDREN" => "1",
    "PHP_FCGI_MAX_REQUESTS" => "10000"
    ),
    "bin-copy-environment" => (
    "PATH", "SHELL", "USER"
    ),
    "broken-scriptfilename" => "enable"
    ))
)

Wordpress rządzi (ponownie)

Powrót na platformę Wordpress z Chronicle - tym razem hostowany we własnym zakresie. Dlaczego?

  • Możliwość łatwego dodawania komentarzy + gotowe mechanizmy antyspamowe
  • Nieco wygodniejsze tworzenie treści (przez przeglądarkę)

"Projekt" kontra "Przyrost" w inżynierii oprogramowania

Idealny projekt

Jakiś czas temu spotkałem się ze stwierdzeniem, że każdy system informatyczny który nie jest odpowiednio zaprojektowany przed rozpoczęciem prac programistycznych jest z góry skazany na "zatarcie się" w ciągu dwóch lat (znaczny wzrost kosztu wprowadzania zmian, "wypalanie się" zespołu). Programista, który te słowa wypowiedział (a z którym mam przyjemność pracować nad jednym z systemów), hołduje zasadzie, że najbezpieczniej jest zaprojektować wszystkie możliwe rozszerzenia systemu na początku, dzięki czemu unika się kosztownego procesu refaktoryzacji. Jeśli zaś znajdziemy się w sytuacji kiedy prace już ruszyły to nie ma już nadziei na płynny rozwój systemu.

Takie podejście do tworzenia systemów trąci aż zanadto metodą Waterfall (model kaskadowy), gdzie kolejne etapy powstawania systemu są uszeregowane w czasie (wymagania, projekt, implementacja, testy). Istnieje w nim ukryte założenie, że jest możliwe nieomylne wyznaczenie pełnych celów i zadań systemu na początku oraz zaprojektowanie odpowiedniej struktury która te cele i zadania spełni. Właśnie: założenie nieomylności jest chyba najtrudniejsze do spełnienia.

Dlaczego niektórzy programiści wierzą w idealny projekt? Zapewne wiele razy mieli do czynienia z systemami w których musieli rozszerzać funkcjonalność a napotykali na konieczność ingerencji w wewnętrzną strukturę aplikacji i związaną z tym konieczność pełnego przetestowania systemu (wprowadzone zmiany mogły zaburzyć działanie istniejącej funkcjonalności). "Gdybyśmy zaprojektowali wszystko wcześniej" - myślą - "nie było by takich kłopotów z nową funkcjonalnością". Czy aby na pewno?

Alternatywa: przyrost

Jako alternatywę dla Waterfall proponowane są metody przyrostowe (razem z modnych w ostatnich latach ruchem Agile). Zakłada się w nich, że dokładniejszą wiedzę na temat pożądanego działania systemu można uzyskać w serii kroków przybliżających  do celu. Klient po każdej iteracji dostaje do dyspozycji system który niesie już jakąś wartość użytkową. Dzięki temu wcześnie można zbadać zdolność zespołu do realizacji projektu (tzw. velocity) i dokonywać korekt kierunku i priorytetów bazując na informacji uzyskanej z działających wersji systemu.

Jednakże taki sposób działania (pominięcie etapu projektowania na korzyść przyrostowego tworzenia kodu systemu) ma bardzo złą sławę. Ponieważ nie ma dobrej architektury kod jest trudny w utrzymaniu, co wiąże się z dużą rotacją programistów i z naturalnym w takim przypadku zniechęceniu. Jeśli jesteś, Czytelniku, osobą która kiedykolwiek miała do czynienia z systemami spadkowymi pozostawionymi po poprzedniuku zapewne wiesz o czym mówię.

Czy więc będziemy zawsze skazani na rolę wróżki przepowiadającej przyszłość która jest podstawą modelu kaskadowego?

Bezpieczny przyrost

Podstawowym ryzykiem związanym z przyrostowym rozwojem systemu jest duże prawdopodobieństwo zagmatwania struktury kodu w trakcie dodania nowej funkcjonalności. Zagmatwana struktura jest bardzo podatna na błędy i błędy takie są trudne do wyśledzenia i usunięcia (nie mówiąc już o pro aktywnym zapobieganiu defektom). Aby na bieżąco poprawiać strukturę systemu stosuje się refaktoryzację. Polega ona na takiej modyfikacji struktury by istniejąca funkcjonalność nie została naruszona. Ale sam proces refaktoryzacji nie jest pozbawiony ryzyka. Zmiany w strukturze mogą spowodować wstrzyknięcie nowych błedów które będą niwelować pozytywny efekt poprawienia struktury.

Aby refaktoryzacja była bezpieczna z punktu widzenia jakości systemu należy zastosować środki zapobiegawcze w postaci automatycznych testów. Dlaczego od razu zaznaczam, że powinny być one zautomatyzowane? Przeprowadzenie kompletu testów przez zespół testowy oznacza czas i koszty. Jeśli udaje się proste błędy wyłapać w sposób automatyczny (np. regresję na podstawie zapisanych i uruchamianych automatycznie scenariuszy) to jest to znaczny zysk.

Przyrostowy rozwój oprogramowania wymaga zastosowania dodatkowych technik mających na celu minimalizowanie ryzyka związanego z poplątaną strukturą systemu i z możliwymi błędami. Podstawowymi narzędziami są: refaktoryzacja i testy jednostkowe.

2

Trac/Agilo software helps track bugs

Trac from Edgewall is very useful piece of software that try to combine Wikis with bug tracker. Let's see how we can employ this tool for Agile projects!

Wiki syntax

First of all, Trac is a wiki. It can link to other pages by using WellKnownWikiSyntax. This way you can create ad-hoc page graph structure and share information inside your team (deployment documentation, help pages for instance). You can of course add structure to your pages by creating sections, bolding, enumeration etc.

Another great feature is that you can embed wiki syntax inside comments (yeah!, wanted add emphasis to Mantis comment anytime in the past?).

Requirements gathering tool

Trac allows to collect requirements and split them into user stories and task. It allows you to add hierarchy to your documentation. Any item (requirement, user story, task) can have different workflow and those workflows could be easily customized.

Bug tracker

And last (but not least) Trac is a bugtracker. Like typical Bugzilla/Mantis it can collect problem reports and allows to create workflow to fix and verify results. You can link bugs to user stories, requirements etc. thanks to internal linking. Better - you can connect your Version Control System (SVN, Bazaar, GIT) to automatically close bugs by using bug id embeded in comments (pretty speed-up)! You can also link directly from comments/description to VCS changesets (for example to implement changeset-based code review).

And finally ...

Remember: it's just a tool. Any tool requires some time to master, but if you're patient you can achieve superb results. Of course any tool can do damage if improperly used. I believe flexible Wiki-like nature of Trac can lead to better solutions thanks to dynamic process evolution instead of a priori process definition.

Darwin rules!

trac_logo