Author Archives: Paweł Trojanowski

Czemu konkatenacja stringów jest wolniejsza niż użycie stringbuildera?

O tym że StringBuilder append jest dużo szybszy niż zwykła konkatenacja w języku C# wiedziałem, jednak nie miałem pojęcia jaka jest skala tych różnic i co za tym stoi. Nie zawsze mam czas na to żeby sprawdzać dlaczego coś działa tak a nie inaczej, ale tym razem miałem więc przygotowałem proste omówienie tego zjawiska 😉

String w języku C# (JAVA również) są niezmienne. Oznacza to, że metody działające na łańcuchach nie mogą nigdy zmienić wartości ciągu. Łączenie ciągów za pomocą += działa poprzez przydzielanie pamięci dla zupełnie nowego ciągu, który jest połączeniem dwóch poprzednich. Każda nowa konkatenacja wymaga zbudowania całkowicie nowego obiektu String a co za tym idzie zaalokować część pamięci w której będzie się nowy obiekt znajdował. To zajmuję czas i zwiększa użycie pamięci.

Z drugiej strony StringBuilder wstępnie alokuje bufor, a dodając do niego łańcuchy, nie trzeba go ponownie przypisywać (zakładając, że początkowy bufor jest wystarczająco duży). Co zwiększa wydajność i znacznie mniej obciąża pamięć.

Czy to oznacza że StringBuilder jest zawsze najlepszym rozwiązaniem? No właśnie nie zawsze, ponieważ w przypadku niedużych ciągów znaków ilość pamięci alokowanej i narzut wydajnościowy przewyższa proste użycie Stringa, a kod staje się nieco mniej czytelny niż proste wywołanie return string1 + string2;

Kod porównujący wydajność obu sposobów

public static void ZwyklaKonkatenacja()
{
	var tekst = "";
	Stopwatch test1 = Stopwatch.StartNew();
	test1.Start();
	for (int i = 0; i < 100000; i++)
	{
		tekst += "Y";
	}
	test1.Stop();
	Console.WriteLine("Konkatenacja " + test1.ElapsedMilliseconds + " ms");
}

public static void KonkatenacjaStringBuilder()
{
	var sb = new System.Text.StringBuilder();
	Stopwatch test2 = Stopwatch.StartNew();
	test2.Start();
	for (int i = 0; i < 100000; i++)
	{
		sb.Append("Y");
	}
	test2.Stop();
	Console.WriteLine("StringBuilder " + test2.ElapsedMilliseconds + " ms");
}

Wyniki szybkości działania funkcji

Wpis został zainspirowany przez kolegę z pracy, który ostatnio optymalizuje co tylko się da. Zaskoczył mnie, ponieważ wiedziałem że różnica jest, ale nie spodziewałem się że jest aż tak ogromna. Tak więc wielkie podziękowania.

jQuery – Zaznaczanie tekstu na stronie (podkreślanie)

Dostałem tydzień temu informację że w systemie jaki tworzę nagle zaczął się źle zaznaczać filtrowany tekst w tabelach. A mianowicie zamiast zaznaczać się tylko tekst, który jest wyszukiwany zaczął się zaznaczać tekst niemalże do końca linii. Najdziwniejsze w tej historii jest to że w ciągu tygodnia nie robiłem żadnej aktualizacji systemu, która mogłaby taki błąd wprowadzić. Może coś w przeglądarkach wprowadzono o czym nie wiem?? Może. Ale znalazłem kod, który realizuje to zadanie idealnie:

/*
 * jQuery Highlight plugin
 *
 * Based on highlight v3 by Johann Burkard
 * http://johannburkard.de/blog/programming/javascript/highlight-javascript-text-higlighting-jquery-plugin.html
 *
 * Code a little bit refactored and cleaned (in my humble opinion).
 * Most important changes:
 *  - has an option to highlight only entire words (wordsOnly - false by default),
 *  - has an option to be case sensitive (caseSensitive - false by default)
 *  - highlight element tag and class names can be specified in options
 *
 * Usage:
 *   // wrap every occurrance of text 'lorem' in content
 *   // with <span class='highlight'> (default options)
 *   $('#content').highlight('lorem');
 *
 *   // search for and highlight more terms at once
 *   // so you can save some time on traversing DOM
 *   $('#content').highlight(['lorem', 'ipsum']);
 *   $('#content').highlight('lorem ipsum');
 *
 *   // search only for entire word 'lorem'
 *   $('#content').highlight('lorem', { wordsOnly: true });
 *
 *   // don't ignore case during search of term 'lorem'
 *   $('#content').highlight('lorem', { caseSensitive: true });
 *
 *   // wrap every occurrance of term 'ipsum' in content
 *   // with <em class='important'>
 *   $('#content').highlight('ipsum', { element: 'em', className: 'important' });
 *
 *   // remove default highlight
 *   $('#content').unhighlight();
 *
 *   // remove custom highlight
 *   $('#content').unhighlight({ element: 'em', className: 'important' });
 *
 *
 * Copyright (c) 2009 Bartek Szopka
 *
 * Licensed under MIT license.
 *
 */

jQuery.extend({
    highlight: function (node, re, nodeName, className) {
        if (node.nodeType === 3) {
            var match = node.data.match(re);
            if (match) {
                var highlight = document.createElement(nodeName || 'span');
                highlight.className = className || 'highlight';
                var wordNode = node.splitText(match.index);
                wordNode.splitText(match[0].length);
                var wordClone = wordNode.cloneNode(true);
                highlight.appendChild(wordClone);
                wordNode.parentNode.replaceChild(highlight, wordNode);
                return 1; //skip added node in parent
            }
        } else if ((node.nodeType === 1 && node.childNodes) && // only element nodes that have children
                !/(script|style)/i.test(node.tagName) && // ignore script and style nodes
                !(node.tagName === nodeName.toUpperCase() && node.className === className)) { // skip if already highlighted
            for (var i = 0; i < node.childNodes.length; i++) {
                i += jQuery.highlight(node.childNodes[i], re, nodeName, className);
            }
        }
        return 0;
    }
});

jQuery.fn.unhighlight = function (options) {
    var settings = { className: 'highlight', element: 'span' };
    jQuery.extend(settings, options);

    return this.find(settings.element + "." + settings.className).each(function () {
        var parent = this.parentNode;
        parent.replaceChild(this.firstChild, this);
        parent.normalize();
    }).end();
};

jQuery.fn.highlight = function (words, options) {
    var settings = { className: 'highlight', element: 'span', caseSensitive: false, wordsOnly: false };
    jQuery.extend(settings, options);

    if (words.constructor === String) {
        words = [words];
    }
    words = jQuery.grep(words, function(word, i){
      return word != '';
    });
    words = jQuery.map(words, function(word, i) {
      return word.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, "\\$&");
    });
    if (words.length == 0) { return this; };

    var flag = settings.caseSensitive ? "" : "i";
    var pattern = "(" + words.join("|") + ")";
    if (settings.wordsOnly) {
        pattern = "\\b" + pattern + "\\b";
    }
    var re = new RegExp(pattern, flag);

    return this.each(function () {
        jQuery.highlight(this, re, settings.element, settings.className);
    });
};

Łatwa i darmowa synchronizacja danych między komputerami

Lubię posiadać kopię zapasowe swoich danych w wielu miejscach, żeby w przypadku awarii dysku czy też jakiś zdarzeń losowych nie mieć problemu z odzyskiwaniem danych. Dlatego dotychczas używałem chmur plikowych takich jak Dropbox czy OneDrive. Jednak powyżej jakieś ilości składowanych danych w chmurze, trzeba zacząć za takie składowanie danych płacić. Dodatkowy problem, który uważam że jest dość ważny, to to że nie mamy pewności gdzie znajdują się dane i czy ktoś nieuprawniony nie ma do nich dostępu.

Dlatego zacząłem szukać jakiegoś rozwiązania, które miałoby na celu zminimalizować ryzyko utraty danych, działałoby i synchronizowałoby moje dane tylko na moich komputerach i byłoby względnie tanie a najlepiej darmowe.

Takim rozwiązaniem jest Syncthing, który jest multiplatformową aplikacją do wymiany danych między urządzeniami. Nie wymaga kupna serwera, czy zewnętrznego stałego adresu IP i jest całkowicie darmowe.

W moim przypadku akurat to oprogramowanie jest uruchomione na serwerze 24h/7, ale nie jest to konieczne. Wystarczy włączyć komputery, które mają się synchronizować.

Muszę przyznać, że byłem bardzo zaskoczony ilością funkcji zawartych w tym programie. Okazało się, że jest możliwość tak jak w Dropboxie tworzyć historię zmian plików, udostępniać udział tylko do odczytu (co jest bardzo ważne w przypadku gdy nie chcemy żeby ktoś miał możliwość nadpisania pliku), czy też synchronizować dane z komórki.

W celu udostępnienia udziału kolejnemu komputerowi wystarczy wygenerować specjalny kod, który po przesłaniu w formie tekstowej lub QR może zostać synchronizowany na innym komputerze, ale dopiero po akceptacji na komputerze udostępniającym dane.

Oczywiście nie warto 100 procentowo ufać żadnemu oprogramowaniu, dlatego też zalecam jednak wrażliwe dane synchronizować po uprzednim spakowaniu archiwizatorem z odpowiednio trudnym hasłem.

4Mobility w Poznaniu pierwszy tydzień testów

Temat car-sharingu jest na tyle nowoczesny, że gdy pojawiła się sposobność skorzystałem z okazji i opisuję tu moje spostrzeżenia, choć to temat nie związany bezpośrednio z informatyką, ale czy na pewno? Zwłaszcza, że do obsługi tej usługi używane jest dość sporo technologii, która jak wynika z moich testów działa (ale czy idealnie?).

Co to w ogóle jest car-sharing?

Wg. Wikipedii jest to „system wspólnego użytkowania samochodów osobowych. Samochody udostępniane są za opłatą użytkownikom przez operatorów floty pojazdów, którymi są różne przedsiębiorstwa, agencje publiczne, spółdzielnie, stowarzyszenia lub grupy osób fizycznych.

Stosowanie tego systemu zwiększa intensywność wykorzystania pojazdów w ciągu doby, co prowadzi do zahamowania wzrostu liczby samochodów rejestrowanych prywatnie.”

Czyli jeżeli potrzebuję się przemieścić w mieście, to odpalam aplikację wybranego car-sharingu i szukam najbliższe auto, rezerwuję i gdy podejdę do niego mogę otworzyć odpalić i pojechać w docelowe miejsce w granicach działania usługi (w przypadku Poznania jest to granica miasta z wyjątkami).

Dlaczego zająłem się akurat 4Mobility skoro już kilka innych firm działa w Poznaniu?

Mówiąc krótko, zachęcili mnie pojazdami i ofertą. Zwykle w ramach car-sharingu mamy do czynienia z małymi ekonomicznymi pojazdami, które nie są zbyt dynamiczne, ale pozwalają zmieścić się na już i tak ograniczonych miejscach parkingowych w centrum polskich miast. Jednak tutaj jest inaczej, ponieważ dostajemy do użytkowania auta z segmentu premium, czyli np. Audi A3 sportback, A3 limousine, czy Q3. Nie są to małe auta, ale dają zdecydowanie więcej frajdy z jazdy niż auta miejskie. Dodatkowo oferta na start jest bardzo dobra, jednak nie będę jej tutaj przytaczał, ponieważ podejrzewam że niedługo się zmieni a nie chciałbym robić reklamy/antyreklamy usługi.

Jakie są moje odczucia po tygodniowych testach?

Audi A3

Muszę przyznać że jest wiele plusów tej usługi jak i kilka minusów. Zaczynając od plusów, to właśnie świetne auta, bardzo korzystna cena, dobre rozłożenie aut na mapie poznania (nie zdarzyło mi się żebym był dalej niż 1 km od auta) oraz darmowe parkingi miejskie.

Są również minusy, takie jak źle działająca aplikacja mobilna na moim telefonie (Samsung Galaxy S8), niestety aplikacja działa niestabilnie, crashuje się, przyciśnięcie jakiegokolwiek przycisku jest bardzo ciężkie i wymaga wielokrotnego wciskania. Zdarzył mi się też mały incydent, że nie mogłem zamknąć auta z uwagi na brak karty paliwowej lub dowodu rejestracyjnego, których nie ruszałem a które znajdowały się w slocie gdzie było ich miejsce. Jedak po chwili udało mi się rozwiązać problem wyciągając i wkładając te dokumenty z powrotem do slotu.

Czy to są poważne problemy, oczywiście że nie i zakładam że w ciągu najbliższych tygodni zostaną rozwiązane a nam pozostanie jedynie cieszyć się dynamiczną jazdą świetnymi, nowymi autami.

Idea wszystko jako usługa

Od jakiegoś czasu nawet tutaj na blogu promuję podejście „Everything as a service (EaaS)”, która jest mi szczególnie bliska, ponieważ sam tworzę rozwiązania, które aspirują do takiego miana. Jest to bardzo wygodne rozwiązanie dla ludzi, którzy na co dzień nie potrzebują danego dobra, a gdy nagle przez chwilę jest im to dobro potrzebne, to nie ma sensu żeby je kupowali. Lepiej w takim wypadku w jakiś sposób to dobro wypożyczyć, co jest świetnie realizowane w chmurach, właśnie car-sharingu czy też innych usługach opartych o ten model. Rozumiem, że moje podejście jest związane z tym że mieszkam w dużym mieście i mam dostęp do tego typu dóbr, ale skoro już mieszkam to czemu nie mam sobie ułatwiać życia i zamiast posiadać własny rower, korzystać z roweru miejskiego. Zamiast kupować auto miejskie przemieszczać się car-sharingami, itp.

Czy to ma sens?

Myślę, że firmy, które aktualnie inwestują w ten typ usług nie zarabiają bo są prekursorami i ludzie jeszcze nie rozumieją i trochę się boją korzystać z tych usług. Jednak zakładam że w ciągu kilku lat ludzie nauczą się korzystać z tego i doceniać wartość a wtedy właśnie te firmy, które weszły stosunkowo wcześnie już będą miały gotową infrastrukturę i niemalże monopol na świadczenie danej usługi. Tak więc wróżę duży sukces tego typu usług, tylko mam nadzieję że pozostaną tak tanie jak obecnie, bo ja już zacząłem korzystać.

Wysłałem maila z kilkoma pytaniami odnośnie tej usługi, więc jak tylko dostanę odpowiedź, rozszerzę artykuł o konkretne informację, być może również techniczne (jeżeli firma uchyli rąbka tajemnicy).

Gdzie przenieść środowisko programistyczne (chmura, dedyk, vps)?

W dzisiejszych czasach wszystko związane z IT zaczyna przenosić się do sieci, chodzi mi o streamingi muzyki, filmów, pliki archiwizujemy na dropboxach czy innych drive’ach. Dlatego zadałem sobie pytanie, czy nie byłoby dobrym pomysłem przenieść swoje środowisko programistyczne do sieci?

W jednym z poprzednich wpisów opisywałem że kupiłem sobie komputer z dość dobrymi podzespołami do moich rozwiązań programistycznych i z uwagi na wydajne i stabilne łącze pracuje na nim zamiast lokalnie na komputerze. Jednak ostatnio zacząłem coraz bardziej odczuwać minusy tego rozwiązania, ponieważ dostawca internetu zaczął szwankować a ja kilka razy w miesiącu przez kilka godzin nie miałem dostępu do serwera. A to nie może się zdarzać, bo jednak w przypadku spotkania z klientem tłumaczenie że pewnie internet w domu się zawiesił może postawić mnie w złym świetle, a dodatkowo każda godzina przestoju w pracy kosztuje coraz więcej.

Zacząłem więc szukać alternatywnych rozwiązań. Pierwszym rozwiązaniem o którym pomyślałem była chmura. Miała wiele zalet, np. to że mogłem szybko i tanio utworzyć instancję a następnie płacić tylko za godziny pracy serwera. To rozwiązanie się bardzo dobrze sprawdza pod względem technicznym, ale finansowo jednak nie do końca. Okazało się że w ciągu miesiąca pracy w takim środowisku kilka razy zdarzyło mi się nie wyłączyć serwera po pracy a co za tym idzie przez następne kilkanaście godzin naliczane były mi opłaty za działający serwer. W wyniku takich niedopatrzeń niestety w ciągu miesiąca straciłem tyle pieniędzy za ile miałbym serwer dedykowany dostępny 24h na dobę. Dodatkowym minusem jest niewielka ilość powierzchni dyskowej na dysku systemowym, przez co byłem zmuszony dopłacić za dodatkowy dysk SSD co już znacząco przekracza próg opłacalności tego rozwiązania. Najwidoczniej do tego chmura się nie najlepiej nadaje.

Zwróciłem również uwagę na VPSy, jednak z tego rozwiązania zrezygnowałem na starcie z uwagi na ograniczenia ilości rdzeni na maszynę, wolne dyski, bo jednak współdzielone i stosunkowo wysoki koszt, ponieważ serwer w takiej konfiguracji jaką wymagam nie różnił się praktycznie ceną z dedykiem w podobnej konfiguracji w jednej z polskiej serwerowni.

W końcu zwróciłem się w kierunku serwera dedykowanego i tutaj oferty są na prawdę korzystne, ponieważ za dobry serwer z 4 rdzeniami ponad 3Ghz, 32GB Ram i dwoma dyskami 120 GB i Windows Server 2012 z RDS za 300 zł netto. Pewnie można taniej, ale akurat taka konfiguracja mi odpowiada w 100%. Plusy są takie same jak powyżej, ale nie mamy minusa w postaci zmiennej kwoty w zależności od nieuwagi, a dodatkowo zawsze można postawić na takim serwerze coś więcej niż tylko środowisko programistyczne.

Na ten moment ciężko mi określić czy takie rozwiązanie jest idealne, ale na pewno będę je dalej sprawdzał i napiszę za jakiś czas tak jak teraz kontynuuję wpis o pracy na serwerze zdalnym.

Jak zabezpieczyć środowisko programistyczne przed awarią

Prawdopodobnie każdemu z Was kiedyś przytrafiła się awaria dysku twardego, czy też kupno nowego komputera i odtworzenie środowiska programistycznego na innym komputerze kosztowało Was dużo pracy i czasu, a niektóre dobrze skonfigurowane programy już nigdy nie były tak wygodne jak wcześniej.

Był to dla mnie poważny problem, którego nie potrafiłem przez dłuższy czas rozwiązać i choć systemy backupowania potrafią już robić kopię całych partycji, było to dla mnie zbyt uciążliwe i wymagało mojej uwagi. Jednak po zakupie porządnego komputera do programowania zacząłem się znów interesować wirtualizacją i to podsunęło mi świetny pomysł, że po co mam pracować bezpośrednio na maszynie jak mogę pracować na maszynie wirtualnej.

I teraz pewnie odezwą się głosy, że tracę część mocy obliczeniowej na środowisko hypervisora, że łącząc się przez pulpit zdalny ze swoją maszyną wirtualną mam niewielkie lagi i utraty płynności wyświetlanego obrazu i nawet z tymi głosami mogę się zgodzić, ale takie rozwiązanie ma także wiele zalet.

A zaletą jest to, że gdy chcę zrobić backup maszyny wirtualnej, to mogę skorzystać z metody snapshotów (do której nie jestem przekonany) lub po prostu zatrzymać maszynę wirtualną na kilka minut i przekopiować pliki na dysk sieciowy. Czyli zapewniam sobie w ten sposób kopię całego środowiska ze wszystkimi programami, plikami i przeglądarkami, które potrzebuję i w razie potrzeby mogę szybko odtworzyć na innym komputerze maszynę wirtualną i dalej pracować. Dzięki czemu nie tracę czasu w przypadku poważnych problemów.

Kolejną zaletą jest oddzielenie środowiska developerskiego od środowiska prywatnego, bo jednak co by nie powiedzieć jestem trochę bałaganiarzem w trakcie pracy i mój pulpit szybko zapełnia się różnego rodzaju śmieciami, których nie chciałbym mieć na prywatnym komputerze. A w ten sposób mam jeden komputer, który jest jednocześnie prywatnym i firmowym.

Niektórzy korzystają z mechanizmu snapshotów czego ja akurat nie potrzebuję, ale widzę pewne plusy tego rozwiązania, takie jak możliwość cofnięcia się do punktu z przed zaśmiecenia systemu zbędnymi danymi. Jednak ja wyszedłem z założenia, że i tak jak będę chciał się cofnąć to po prostu załaduję odpowiedni backup, który jest kopią całościową a snapshoty są przyrostowe, czyli w przypadku kopiowania tylko kolejnych plików przyrostowych jest to mniej bezpieczna metoda.

Ewentualnie polecam również stworzenie sobie środowiska developerskiego w chmurze, ponieważ tam też mamy możliwość ustalenia backupów całościowych, kopiowania środowiska i mamy dostęp praktycznie wszędzie, ale jest to rozwiązanie niestety dosyć drogie. Nawet jeżeli zdecydujemy się włączać instancję tylko na czas pracy, to wychodzi około 200 zł miesięcznie, a to pozwala w ciągu roku kupić już jakiś w miarę dobry komputer do programowania.

Podsumowując: By dobrze zabezpieczyć się przed utratą danych, programów i konfiguracji warto pracować na wirtualnej maszynie. Skonfigurowanie i zainstalowanie systemu na środowisku wirtualnym chwilę trwa, jak każda instalacja systemu na nowym komputerze, ale po jakimś czasie bardzo możliwe że się zwróci w postaci łatwego przeniesienia środowiska na inny komputer.

5 błędów które popełniają młodzi programiści

Nikt nie jest idealny i zdaję sobie sprawę że nie można od nikogo tego wymagać, jednak mój wpis nie ma za zadanie wyśmiewać się z błędów młodych programistów tylko zwrócić uwagę na błędy, które popełniają. Jest to lista całkowicie subiektywna i prawdopodobnie nie zawiera 99% błędów popełnianych przez programistów, ale akurat z takimi sytuacjami się spotkałem i wiem że po poprawie tych błędów było już dużo lepiej.

  1. Nie używanie breakpointów i nie sprawdzanie wartości zmiennych – nie wiem czy to z lenistwa, czy niewiedzy zauważyłem że nowo zatrudnieni programiści nie używają breakpointów w trakcie pracy nad problematycznym kodem. Rozumiem że niektórych błędów się można domyślić, ale przejście wykonania kodu krok po kroku ułatwia zrozumienie co się dzieje, co oczywiście polecam.
  2. Nie szukanie rozwiązań problemów w internecie – tutaj prawdopodobnie jest to lenistwo, ponieważ łatwiej zapytać kolegę z pracy jak rozwiązać problem niż zacząć szukać na własną rękę, ale polecam jednak spróbować najpierw szukać w google i jeżeli w krótkim czasie nie znajdziesz problemu, spytać współpracownika. Każde pytanie zadane współpracownikowi wybija go z pracy, więc warto ograniczać to tylko do najważniejszych tematów.
  3. Nie proszenie o pomoc lub proszenie o pomoc zbyt częste – tutaj przewija się temat zbyt częstego zadania pytań z poprzedniego punktu, ale również dodałem element nie pytania w ogóle. Rozumiem, że czasami programista nie chce ujawnić swojej niewiedzy, ale wierzcie mi lub nie, niewiedza i tak wyjdzie prędzej czy później. Więc nie bój się pytać jeżeli nie masz już żadnego sensownego pomysłu na rozwiązanie problemu.
  4. Nie przewidywanie nietypowych warunków działania algorytmu – to jest notoryczny problem nowych programistów, ponieważ nie rozwiązali odpowiedniej ilości błędów i nie potrafią ich przewidzieć. Tutaj mogę doradzić tylko jedno, próbuj zepsuć działanie programu na wszelkie sposoby po napisaniu kodu, a jeżeli ktoś wytknął Ci błąd, to podpatrz jak on doszedł do tego że go popełniłeś.
  5. Nie szukanie rozwiązań problemu w projekcie – ten punkt trochę wynika również z nieznajomości projektu w którym się piszę kod. Ale nie można się tak tłumaczyć, ponieważ nawet jeżeli nie znamy projektu w 100% to możemy przynajmniej spróbować poszukać, czy w kodzie któregoś modułu nie ma jakiegoś kawałka kodu który przyda się podczas tworzenia kodu. Ważne jest żeby inni pracownicy również uważali na swój kod i pisali go możliwie uniwersalnie. Zasada jest taka: jeżeli masz napisać jakąś funkcję, która się przyda w wielu miejscach projektu to przemyśl lub zapytaj współpracownika gdzie taki kod powinien się znaleźć. W różnych firmach są różne podejścia i czasami w zależności od zastosowania kodu powinien on znaleźć się w określonym miejscu i w takim momencie musisz pytać bo sam możesz nie dojść do tego jak zrobić to dobrze.

A dla ludzi współpracujących z młodymi programistami polecam code review. Wiem że to brzmi jak strata czasu, ale tylko w ten sposób jesteście w stanie wcześnie wykryć złe nawyki programisty i nauczyć go tego co w waszej firmie jest pożądane.

Wyszukiwanie binarne [C#]

Wyszukiwanie binarne jest algorytmem opierającym się na metodzie dziel i zwyciężaj, który w czasie logarytmicznym stwierdza, czy szukany element znajduje się w uporządkowanej tablicy i jeśli się znajduje, podaje jego indeks. Algorytm, który napisałem korzysta z bibliotek dodatkowych (linq czy Collections.Generic), które są dostępne w C# a niekoniecznie będą dostępne w innych językach programowania, ale jeżeli chodzi o założenia algorytmu to jest on przepisywalny w łatwy sposób na C++ czy JAVA bo semantyka tych języków jest bardzo podobna.

Ważne: Działa on dla listy o wielkości większej niż 1. Nie wdrażałem tego zabezpieczenia z uwagi że generuję losowo listę o ilości elementów większej niż 1.


using System;
using System.Collections.Generic;
using System.Linq;

namespace Wyszukiwanie_binarne
{
    class Program
    {
        static void Main(string[] args)
        {
            Random rand = new Random();

            // tworzę listę i wypełniam losowymi danymi
            List<int> listaLiczb = new List<int>();
            for (int i = 0; i < 100; i++) listaLiczb.Add(rand.Next(0, 1000));

            // czyszczę listę z powtórzonych wartości i sortuję
            listaLiczb = listaLiczb.Distinct().ToList();
            listaLiczb.Sort();

            Console.WriteLine("Liczby na liście:");
            Console.WriteLine(String.Join(",", listaLiczb));

            Console.WriteLine("Podaj liczbę której pozycję szukasz:");
            var szukanaLiczba = int.Parse(Console.ReadLine());

            Console.WriteLine("Poszukiwana liczba znajduje się na liście pod indexem: ");
            try
            {
                Console.Write(Szukaj(listaLiczb, szukanaLiczba));
            }
            catch (Exception)
            {
                Console.Write("Podana liczba nie znajduje się na liście!");
            }

            Console.ReadKey();
        }

        public static int Szukaj(List<int> przeszukiwanaLista, int szukanaLiczba)
        {
            // ilość elementów w liście
            var iloscElementow = przeszukiwanaLista.Count();

            // jeżeli ilość elementów wynosi jeden to znaczy że liczba nie została znaleziona
            if (iloscElementow == 1) throw new Exception("Podana liczba nie znajduje się na liście!");
            
            // wyliczenie połowy z ilości elementów
            var polowa = iloscElementow / 2;

            // wyciągnięcie z listy wartości środkowego elementu
            var srodkowyElement = przeszukiwanaLista[polowa];

            // jeżeli wartość środkowego elementu jest większa niż szukana liczba, to weź pierwszą połowę listy i przekaż do funkcji Szukaj()
            if (srodkowyElement > szukanaLiczba) return Szukaj(przeszukiwanaLista.Take(polowa).ToList(), szukanaLiczba);

            // jeżeli wartość środkowego elementu jest mniejsza niż szukana liczba, to weź drugą połowę listy i przekaż do funkcji Szukaj()
            else if (srodkowyElement < szukanaLiczba) return Szukaj(przeszukiwanaLista.Skip(polowa).ToList(), szukanaLiczba) + polowa; // tutaj dodajemy index połowy, poniważ znaleziona liczba będzie z drugiej połowy listy

            // Jeżeli jest równa co szukana liczba to zwróć index aktualnej połowy
            return polowa;
        }
    }
}


 

Zapobieganie pożarom – czyli jak lepiej tworzyć oprogramowanie z użyciem metodyki programowania zwinnego

Gdy zaczyna się pożar…

Najgorszym momentem podczas tworzenia oprogramowania jest chwila w której dowiadujemy się że końcowy produkt nie jest zgodny z oczekiwaniami klienta i prawdopodobnie czas doprowadzenia produktu do stanu oczekiwanego będzie dużo dłuższy niż zakładaliśmy.

Jak daleko trzeba się cofnąć jeżeli dopiero podczas testowania znajdziemy błąd analizy oczekiwań klienta źródło: Wikipedia.org

Zwykle nie jest to wina tylko jednej strony, ale wynika ze złożenia braku zrozumienia klienta, a z drugiej strony klient też nie do końca potrafi określić czego potrzebuje. Jednak zwykle wina pozostanie jednak po naszej stronie, ponieważ to my zgodziliśmy się na warunki klienta. Następnie trwa gaszenie pożaru, czyli łatanie oprogramowania lub kary umowne i utrata klienta, co nie jest zbyt optymistyczną perspektywą.

Jednak okazuje się że jest sposób na to żeby się uchronić przed niektórymi błędami. A sposobem na to jest metodyka programowania zwinnego (nie jest to panaceum na problemy ale na pewno pomoże). Oczywiście dla każdego to określenie może znaczyć co innego, ważne żeby jej fundamenty były oparte na wzajemnym sprawdzaniu się klienta i wykonawcy.

Samych metodyk zwinnych jest wiele i trzeba się zastanowić jaką chcemy wdrożyć i jak dużo chcemy z niej czerpać. Może nawet ktoś skusi się wykorzystać kilka pomysłów z jednej a kilka z innej i też może się to okazać poprawne, ważne żeby to robić z głową.

Jak się to u mnie robi?

  1. Projekt jest dzielony na sprinty, czyli okres czasu (1 do max 2 tygodnie) w którym zakładamy wykonanie zaplanowanych zadań,
  2. Każdego dnia odbywa się daily, na którym zespół zbiera się żeby wymienić się wykonaną pracą z poprzedniego dnia i przekazuje informację na temat aktualnych prac (punkt dla większego zespołu powyżej 3-4 osób i ważne jest żeby nie przekroczyć 15 – 20 min na takie spotkanie, ponieważ gdy jest dłużej to spada efektywność pracy w danym dniu),
  3. Ostatniego dnia każdego sprintu odbywa się demo, czyli prezentacja wykonanych zadań przed klientem (bardzo ważny punkt),
  4. Oraz ostatni punkt – planowanie zadań na następny sprint.

Oprócz sprintów określane są jeszcze kamienie milowe, czyli momenty w których ma zostać wdrożona jakaś większa funkcjonalność, przy czym ważne jest żeby każdy znał cel i datę w której powinien zostać osiągnięty.

Dlaczego demo w sprincie jest takie ważne? ponieważ jest to ten moment w którym klient dowiaduje się co w ciągu tego sprintu udało się nam zrobić i w jaki sposób to działa. Jeżeli się okaże że minęliśmy się z założeniami klienta lub zostały one źle sformułowane, to ostatecznie tracimy jedynie jeden sprint i możemy gasić malutki płomień zamiast wielomiesięcznego pożaru. Swoją drogą porównanie do pożaru jest bardzo dobre, ponieważ mały płomień zwykle da się ugasić i nie powinien poczynić wielkich strat, ale jeżeli stracimy nad nim panowanie lub nie będziemy wiedzieć że się rozprzestrzenia to może pochłonąć cały nasz dobytek, czyli projekt nad którym długo pracowaliśmy.

Ale pamiętaj że nie tylko demo jest ważne i w zasadzie te 4 (ewentualnie przy mniejszym zespole 3) punkty które napisałem to jest taki plan minimum, które warto wdrożyć, a ponieważ przeszedłem przez różne firmy i różne sposoby zarządzania projektem, mogę powiedzieć że ten sposób jest dla mnie najbardziej odpowiedni i daje pojęcie na temat tego ile pozostało jeszcze pracy.

Planowanie, jak to robić?

Nie jest to proste i przez pierwsze sprinty w których miałem sam szacować czas pracy na wykonanie określonych zadań wszystko mi się rozjechało i nie domknąłem sprintu. Dlatego dam Wam kilka pomysłów na to jak to robić trochę łatwiej.

  1. Wszystkie zadania jakie są do zrobienia w ramach projektu powinny zostać rozdzielone na moduły, grupy i kolejne mniejsze jednostki w zależności od złożoności projektu (lepiej zadanie na tydzień rozłożyć na dwa zadania po 2,5 dnia bo to już tak nie przeraża, a dodatkowo łatwiej jest oszacować czas) i umieszczone w pliku dostępnym dla całego zespołu,
  2. Jeżeli zadanie wydaje się zbyt ogólne, to rozpisz w kilku punktach co powinno zostać zrobione w takim zadaniu (łatwiej oszacować czas pisania małej funkcji niż dużego modułu),
  3. Wybierz i oszacuj czas wykonania zadań w sprincie a następnie w zespole skonsultuj czy oszacowany przez ciebie czas jest odpowiedni (być może ktoś podsunie ci pomysł jak to zadanie wykonać szybciej lub wyprowadzi cię z błędu i wyjaśni dlaczego w takim czasie się nie da tego zrobić),
  4. Staraj się nie przekraczać 2 godzin na planowanie, ponieważ wiem że w większości wypadków da się zaplanować pracę w zespole ok 5 osób w takim czasie, a ludzie i tak już będą coraz gorzej myśleć.

Nie rozumiem dlaczego mam to wdrażać, przecież to trwa tyle czasu

Na początku ja też tak myślałem i strasznie demotywowało mnie to że muszę znów oszacować swój czas (co szło mi słabo) i pewnie się nie wyrobię, a tracę czas na głupoty, które i tak mi nic nie dają. I tak było przez kilka sprintów, po czym nagle zacząłem mimowolnie wsiąkać w to. Okazało się po dłuższym czasie że nawet to zrozumiałem 🙂 a teraz nie mogę inaczej pracować. Okazuje się że teraz nie dość że potrafię zaplanować sobie sprint i z dużą dozą prawdopodobieństwa dobrze oszacować czas zadań (o ile nie będzie dużo wrzutek, czyli dodatkowych zadań, które trzeba zrobić w czasie sprintu) i coraz rzadziej zdarza mi się że przed deadline muszę się spinać i siedzieć po nocach. Właśnie idea programowania zwinnego również chroni przed tym, ponieważ na każdym małym etapie widzisz ile jeszcze zostało ci do końca projektu.

Taki pro-tip dla firm, które jeszcze nie wdrożyły metodyki zwinnej a chciałyby: jest wiele warsztatów i szkoleniowców, którzy przekonają i pokażą jak to robić dobrze. Ważne jest żeby zespół lub jego manager tego chciał bo po chwili męki będą z tego same korzyści.

Czy ta metodyka sprawdza się tylko w programowaniu?

Sądzę że nie, zwłaszcza że w coraz większej ilości firm jest ona wdrażane, tylko nikt jej tak nie nazywa. Wg. mnie każda praca twórcza powinna być dzielona na mniejsze kawałeczki dzięki czemu łatwiej to w jakiś sposób ogarnąć rozumem, a przecież nikt nie będzie mówił że tego się używa w programowaniu więc nie możesz używać gdzie indziej. W każdej firmie można znaleźć jakieś fajne pomysły, tylko warto sprawdzić czy są one dobre dla naszej firmy i jeżeli tak to się nie zniechęcać, bo gdybym się zniechęcił to nie poznałbym tak dobrego sposobu zarządzania projektem.