• A perfect continuous integration system

    One of the fundamental concept of agile software development is Continuous Integration (CI). You can read more about it here, for instance. In this post I'll try to define elementary things that in my humble opinion could build a ground for perfect continuous integration environment. Your comments on my concept will be also appreciated.

    For this post I assume GNU environment, and statically-compiled languages like C++. However, such recipe can be easily rearranged to other compilers, languages, and environments.

    1. CI server
    First things go first. In order to facilitate the concept of CI we need some kind of automation software. Amount of this kind of software is fair big, so we can pick up one that fits our needs. The most popular is Jenkins (derivative from Hudson), as it is free and covers a lot of functionality. It is also easily extendable, thanks to over 400 plugins. From the other side, we have commercial applications, like for instance, Bamboo by Atlassian. I can't compare these two, but I assume that such a comparison would be similar to comparing MS Word with OpenOffice.org. For full list of well-known CI servers refer to this list.

    2. Unit & Module tests
    When we have our CI server running we are able to start defining jobs it will take car of. I do not mention basic "build" job, as it is obvious. Every knows that good code should be tested as much as possible. We can distinguish between standard Unit Tests (UT), that are likely to be written by developers and Module Tests (MT), that are preferably written by software testers. Personally I prefer to have one test runner to evaluate all UT and MT tests. This runner should output report in a form that is consumable by the CI server.

    3. Lint for code and documentation
    Before development on specific project is started, it is good idea to establish kind of coding convention and have a tool that will check whether software that is written follows rules specified in that document. This tool can be merged with standard lint tools like, for instance, this one, so hard-to-find errors are reported in the early stages of software development. Examples of such errors are: uninitialized variable, lack of assignment operator while copy constructor is defined, and so on.
    We should also pick documentation system like, for example, doxygen and a tool that will check whether documentation is well written. People tends to ignore that, which is sad, because undocumented code is kind of useless for future maintainers and developers.

    4. Coverage and profiling
    When we have UT and MT integrated into our automation process, we likely are want to know how much code is really tested and what is overall performance of this code. For former case we have tools like gcov that will help us determine final test coverage in percents. For latter case there is available gprof, which output can be reorganized, so CI server can handle it. Example of such a tool is gprof2dot.py. This simply way we are able to see call graphs directly from our CI site and find out bottlenecks in the software we are developing.

    5. Memory leaks hunter
    Another thing that may be useful is tracing memory leaks (in case of languages that are statically compiled). We can use tool like valgrind to perform such operations. By using dedicated plugins for our CI server we are able to see overall trend of memory that was leaked in the software during run-time and figure out from where those leaks come from.

    6. Cyclomatic complexity
    Cyclomatic complexity helps us to determine how complex the software under production actually is. You can find more information about it here. I find this kind of tools very useful, therefore they are included in this list.

    That's it! If you think that something crucial is missing here do not hesitate to write your opinions in comments!
  • Moving to Nokia Siemens Networks

    I decided to change company I work for few days ago. Today it's my first day I am working for Nokia Siemens Networks.

    I would like to kindly thank to everyone who worked with me during last years. I consider Gigaset AG as a place of competeness and cooperation. I wish my new employeer could offer me at least similar possibilities I met at Gigaset AG.
  • ACCU 2012 - Random thoughs

    I consider this post as a kind of small conclusions after ACCU 2012 conference in Oxford, UK I took part in.


    1. Python, range, and for-loop
    Those who are familiar with python syntax are not surprised with following listing:
    for i in range (10):
    print i
    It's python, so nothing interresting already happened. Here's the question: how can we achieve similar syntax in C++?
    I believe you agree with me that this is not possible in C (unless you use ninja pre-processor macros). C++2003 doesn't help too much here, even with template stuff. However, in C++11 (with origin library written by Andrew Sutton) it seems to be possible:
    for (const auto& i: bounded_range<int>(1, 10))
    {
    std::cout << i << std::endl;
    }
    When I saw presentation about origin library for the first time I though "WAT?!"[1]. After some time I started to realize how much C++11 will change capatibilities of C++ language at all. Now I wonder if following snippets could also be rewritten to C++11 with minimal syntax changes :-).
    for i, j in enumerate (alphabet): # alphabet = ['a', 'b', ..., 'z']
    print i, j
    for i in zip(range(1, 10), range(10, 20)):
    print i

    2. Funny fact about endl
    Interresting thing: if we dig enough deep into implementation of C++ STL, we are likely to find something like that:
    template<class charT, class traits>
    inline basic_ostream<charT, traits>& endl(basic_ostream<charT, traits>& os)
    {
    os.put(os.widen('\n'));
    os.flush();
    return os;
    }
    I'm aware that this isn't hitting performance and makes code less clear, but instead of:
    std::cout << "Hello, world!" << std::endl;
    you can actually write
    std::endl(std::cout << "Hello, world!");
    not to say that std::endl is generally slower than simple "\n";

    3. Designing APIs: two important rules
    Designing user-friendly, error-prone, easy, understandable, and eventually functional API is very hard task. But when you do, you must follow specific rules so final API is not a crap. Besides other rules I find these are also very important, but sometimes not followed:
    • do not mix abstraction level in your API
    • do not provide two functions which essentially perform the same work
    And now time comes for rationale. In the first case when you accidentally mix abstraction level, users of your library might end up with something similar to following.
    Scene scene;
    Object object;
    scene.AddObject(object);
    Renderer.Render(screen, scene);
    Renderer.PutPixel(0, 1, Color(255, 255, 0));
    Renderer.SwapFramebuffers();
    In above snippet we can easily see that Renderer class should perform high-level tasks related to rendering some sort of scene with objects. However, the API mix abstraction levels, so user is confused and starts using methods that manipulate on single pixels. After that, another method SwapFramebuffers is evaluated, but at this level it should have been hidden from the user. If the user wanted more control about what's displayed on the screen, he would access some lower layer instead of Renderer class, which is supposed to do the work without much effort spent on configuring things.

    Not following second rule may be even worse. Consider following example.
    Scene scene;
    ObjectManager objectManager;
    Object object;
    // Adding object to scene, case I
    scene.AddObject(object);
    // Adding object to scene, case II
    objectManager.pushObjectToScene(object, scene);
    // Rendering scene, case I
    Renderer.Render(screen, scene);
    // Rendering scene, case II
    scene.AssignScreen(screen);
    Renderer.Render(scene);
    Above snippet is quite confusing, isn't it? Basically, when you create a lot of paths in your API that lead to the same effect you can accidentally confuse library users. In effect instead of giving possibilities you make library less-understandable and less-convenient.


    I think that would be all I got for this time. Hope that helps you in any area.
  • Własny bootloader w AT&T

    Zaczęło się dosyć niewinnie - pewnego razu w celu sprawdzenia swojej pamięci RAM (coś nawalało) zaciągnąłem i odpaliłem program memtest86 na komputerze. Kiedy wykonywał on swoje testy zacząłem się zastanawiać w jaki sposób skonstruowany jest program typu bootloader. Całe te rozmyślania zaprowadziły mnie do szatańskiej idei napisania własnego bootloadera, czyli sprawdzenia tego po "kowbojsku".

    Od początku byłem przekonany, że nie wyjdzie z tego nic bogatego - raczej taka studencka bieda. Skupiłem się więc na najprostszym zadaniu, czyli wyświechtany "Hello, world!". Z drugiej strony mimo swojej prostoty pisanie takiego bootloadera może dużo nauczyć. W sieci znalazłem kilka stron opisujących tworzenie systemów operacyjnych od podstaw (np. tu lub tu), ale wszystkie one przykłady podane były w składni NASM. Nie obchodziło mnie za bardzo co jest lepsze... znalazłem pustkę w polskim internecie i zamierzałem ją wypełnić. Co prawda wspomniany memtest86 i jak się później okazało bootloader Minixa używały składni AT&T - ale na szczęście nie wiedziałem o tym, popsuło by mi to zabawę.

    Opis tego co się dzieje po uruchomieniu komputera znajdziecie na wymienionych stronach. Przydaje się również znienawidzony za czasów studiów, a doceniony po studiach using as. Bez tablicy przerwań BIOS też nie zbo(ot|j)ujemy za wiele, więc warto ją mieć pod ręką. Kończąc słowo wstępu, a zaczynając jednocześnie czyn, powstaje taki oto kod:
      1 .code16  
    2 _begin:
    3 .section .text
    4 .globl _start
    5
    6 _start:
    7 movw $0x07c0, %ax # Tutaj startujemy (BIOS).
    8 movw %ax, %ds # Ustawiamy stos (4K).
    9 movw %ax, %ss
    10
    11 movw $message, %si # Wkładamy wiadomość do rejestru.
    12 movb $0x0e, %ah
    13 movb $0x4f, %bh
    14
    15 _repeat:
    16 lodsb
    17 cmpb $0, %al
    18 je _loop
    19 int $0x10
    20 jmp _repeat
    21
    22 _loop:
    23 movb $0x07, %ah
    24 movb $0, %al
    25 jmp _loop #...
    26
    27 message:
    28 .byte 10, 13, 10, 13, 10, 13, 10, 13, 10, 13, 10, 13, 10, 13, 10, 13
    29 .byte 10, 13, 10, 13, 10, 13, 10, 13, 10, 13, 10, 13, 10, 13, 10, 13
    30 .ascii "Komputer zostal zablokowany\r\n"
    31 .byte 10, 13
    32 .ascii "Uzytkownik tego komputera odwiedzal zakazane przez prawo strony internetowe, na ktorych rozpowszechniane sa tresci nazistowskie. W celach prewencyjnych komputer zostal zablokowany, a identyfikator sprzetowy wyslany do jednostki EUROPOL Wroclaw.\r\n"
    33 .byte 10, 13
    34 .ascii "Jezeli uwazasz, ze komunikat pojawil sie na wskutek bledu, prosimy o kontakt z konsultantem pod numerem telefonu +48XXXYYYZZZ.\r\n"
    35 .byte 10, 13
    36 .byte 10, 13
    37 .byte 10, 13, 0
    38 message_len:
    39 .long . - message
    40
    41 .section .text
    42
    43 _end: # Dwa ostatnie bajty sektora MBR
    44 .org 510 # muszą być ustawione na 0xaa55.
    45 .byte 0xaa, 0x55
    46
    47
    Tak, też było mi ciężko w to uwierzyć - jak mogło wyjść tak krótko? Co tak właściwie się tutaj dzieje?

    Pierwszą rzeczą jaką należy zrobić po uruchomieniu to nastawić stos i inne niezbędne segmenty pamięci (7-10). W następnych liniach stać się może wszystko. Dosłownie wszystko. W moim prostym przypadku wyświetlam stringa na ekranie (11-14). W tym celu do rejestru si podaję adres wiadomości, a następnie wywołuję przerwanie BIOS numer 16 podając jako parametr 14 (górny bajt rejestru A). I to wszystko, w zasadzie. Na koniec uzupełniamy plik, aby kończył się dwoma bajtami 0xaa55 i zajmował łącznie 512 bajtów (rozmiar sektora uruchomieniowego).

    Kompilacja i stworzenie obrazu płyty jest nieco trudniejsza niż w przypadku NASMu, ale jak to mawiają ludzie ja tego nie zrobię?!. Z pewnością przyda się krótki plik Makefile, żeby za każdym razem nie trzeba było się zastanawiać jak się to budowało.

    Potrzebne nam będą pliki pomocnicze: ten oraz ten. Pierwszy z nich to obraz dyskietki floppy, a drugi to Makefile. Nie zostaje nic jak wpisać szatańskie polecenie `make` i czekać na obraz płyty. Płytkę można oczywiście sobie wypalić, aby się przekonać na własnych chipach, że wszystko huczy. Zanim jednak do tego dojdzie proponuję skonfigurować jakąś maszynę wirtualną i na niej przeprowadzać testy. Osobiście przetestowałem temat na netbooku. Oto co zobaczyłem po wypaleniu obrazu na zwykłą pamięć USB i odpowiednim przestawieniu BIOSa w komputerze:

    Image captured by a digital camera
    Dziękuję za uwagę.
  • [PL] SMS PDU - Format wiadomości w praktyce

    Popularne SMSy przesyłane mogą być w dwóch formatach: tekstowym lub PDU (ang. Protocol Data Unit). Z oczywistych przyczyn pierwszy wariant jest używany rzadziej. Możliwości, jakie mamy zaś w PDU są następujące.

    • 7 bity na znak - rozwiązanie pozwalające na uzyskanie max. 160 znaków na SMS,
    • 8 bity na znak - opcja pośrednia, 140 znaków,
    • 16 bitów na znak - czyli dla bogatych (70 znaków/SMS).
    Powyższe skomplikowane obliczenia uwzględniają nagłówek PDU, więc proszę mnie nie posądzać o nieumiejętność dzielenia :-). Format wspomnianego nagłowka jest całkiem nieźle opisany w tym miejscu.
    Koniec części teoretycznej. Odpalamy swój najlepszy edytor tekstowy (vim), zaprzągamy ulubiony język (python), i ... dewelopujemy na wesoło.
     1 #!/usr/bin/env python
    2 # -*- coding: utf-8 -*-
    3
    4 def int2hex (n):
    5 s = '%X'%n
    6 if int(len(s))%2 == 1:
    7 s = '0'+s
    8 return s
    9
    10 def encode_message (message):
    11 pdu = ""
    12 l = len (message)
    13 message += '\0'
    14
    15 # Wyznaczamy rozmiar tekstu po upakowaniu.
    16 msglen = int (len(message)*7/8)
    17
    18 # Inicjujemy bufor i zmienne.
    19 buf = [0] * msglen
    20 c = shift = 0
    21
    22 # Dla każdego septetu...
    23 for n in range(msglen):
    24 # Przeskok po każdej paczce 7 bajtów.
    25 if shift == 6:
    26 c += 1
    27
    28 # Wyznaczamy oktet z dwóch septetów.
    29 shift = n % 7
    30 lb = ord(message[c]) >> shift
    31 hb = (ord(message[c+1]) << (7-shift) & 255)
    32 buf[n] = lb+hb
    33
    34 c += 1
    35
    36 # Łączymy wiadomość z jej rozmiarem w postać heksadecymalną.
    37 pdu = chr(l) + ''.join(map(chr, buf))
    38 return ''.join(["%02x" % ord(n) for n in pdu])
    39
    40 def encode_SMS (dest_number, text):
    41 # Zaczynamy od szablonu SMSa.
    42 smspdu = "001100"
    43
    44 # Dodajemy długość numeru i jego format.
    45 smspdu += int2hex(len(dest_number)) + '81'
    46
    47 # Dodajemy numer nadawcy.
    48 tmp_number = dest_number
    49 if len(tmp_number) % 2 == 1:
    50 tmp_number += 'F'
    51 i = 0
    52 while i < len(tmp_number):
    53 smspdu = smspdu + tmp_number[i+1] + tmp_number[i]
    54 i += 2
    55
    56 # Dodajemy id protokołu, pole DCS i okres ważności.
    57 smspdu += '0000FF'
    58
    59 # Dodajemy dł. wiadomości no i samą wiadomość :-).
    60 smspdu += int2hex(len(text))
    61 smspdu += encode_message(text)
    62
    63 return smspdu
    Zaletą pythona jest to, że kod w nim napisany jest prawie samo-dokumentujący się. Jeżeli deklarujesz się jako profesjonalny programista, ale jednak nie rozumiesz co się dzieje powyżej, to (nie chce mi się wymyślać żadnych epitetów, po prostu zacytuję pewnego pana):
    to prawdopodobnie masz jeszcze szanse na jakąś karierę, nie wiem, w polityce chyba wiele nie trzeba, musisz tylko dobrze wyglądać w krawacie
    Powyższy kod całkiem dobrze się sprawuje pod warunkiem, że wszystko uda się upakować w jednej wiadomości. W innych wypadkach mogą dziać się różne rzeczy, od bełkotu wyświetlającego się na twojej komórce do niczego - SMS nie dochodzi w ogóle i nikt nie wie dlaczego (sytuacje rodem z politechniki), bramka twierdzi, że wiadomość wysłała, a komórka milczy. Wracając jeszcze raz do dokumentacji szybko znajdujemy informacje jako by przy długich wiadomościach istotną rolę odgrywał tzw. nagłówekUDH. Dodajmy więc małą modyfikację:
     1 message = '\x00\x00\x00\x00\x00\x00' + message
    ...
    ? for i, ch in enumerate (udh):
    ? buf[i] = ord(ch)
    Pierwszą linię dodajemy dokładnie na początku funkcji encode_SMS, a pętlę zaraz po upakowaniu wiadomości (czyli zaraz za pierwszą pętlą we wcześniej opisanej funkcji encode_SMS.

    Na zakończenie powiem coś o sprzęcie. Można zakupić takie urządzenie które nazywa się chyba modemem GPRS. To taki mały pierdolnik podpinany do komputera przez USB i udostępniający mu internet. Nie jestem pewien na 100%, lecz bardzo prawdopodobne, że do tego modemu można podpiąć się za pomocą np. telnetu i wysyłać komendyHayes'a. Ja, szczęśliwie, miałem możliwość obcowania z pełnoprawną bramką GSM, która mieściła w sobie do 30 kart SIM pozwalając nieźle naspamować ]:->. Dziękuję za dotrwanie do końca.