Dlaczego koszt tworzenia oprogramowania jest tak wysoki?
W dzisiejszych czasach jest zbyt wiele osób, które chciałyby stworzyć własną aplikację z funkcjami Ubera, szybko, tanio i profesjonalnie.
Gdyby tylko to było takie łatwe...
Dostarczenie oprogramowania w ramach czasowych, budżetowych i jakościowych jest trudną sztuką. Poznanie języka programowania czy narzędzi to dopiero początek drogi programisty.
Prawdziwe komercyjne programowanie to ciągłe zderzanie się z ogromną złożonością i wieloaspektowością budowanego oprogramowania. Jest to nieuniknione, skoro oczekujemy że zrobiony przez nas automat będzie działał bez ingerencji człowieka w każdej sytuacji jaka może wystąpić w realnym życiu. Tego nie da się przeskoczyć.
Programowanie to praca kreatywna
Codzienne radzenie sobie z rozwiązywaniem problemów wymaga sporego doświadczenia i wiedzy zdobytej w pocie czoła, co już ogranicza mocno ilość kandydatów do tej pracy.
Oprócz tego u każdego dobrego inżyniera oprogramowania można znaleźć takie szczególne "umiejętności" jak:
- cierpliwość,
- brak zaufania do wszelkich przyjętych z góry założeń,
- dociekliwość w ustalaniu wymagań biznesowych,
- dbałość o szczegóły techniczne, bo od tego często zależy sukces,
- łatwość ciągłego decydowania pomiędzy większą jakością a rozsądnym czasem dostarczenia działającego produktu,
- odpowiedzialność za tworzony system, przede wszystkim w kontekście jego realnego użycia w biznesowej rzeczywistości, niż ograniczanie się tylko do tego co powie klient
- umiejętności szybkiego odróżniania zabiegów zwiększających jakość kodu pod względem ich obiektywnych korzyści.
Wyjaśnię bliżej o co ważnego chodzi w ostatnim punkcie.
Produkt można ulepszać w nieskończoność.
Jednakże znana zasada 80/20 - czyli uzyskanie 80% efektu zajmuje 20% czasu - ma tutaj swoje miejsce.
Koniecznością jest odróżnianie tych zabiegów, które w rzeczywistości zleceniodawcy nie wiele zmienią od tych bardzo ważnych, które mają realny wpływ na koszty i przewidywalność postępów prac rozwojowych w przyszłości. Przykładem takich ważnych kroków podczas budowania nowego oprogramowania są ustalenia o jego wewnętrznej architekturze.
Typowym dla mniej doświadczonych programistów jest:
- niedoszacowanie czasu potrzebnego na zrobienie projektu,
- niedocenianie problemów jakie stoją przed nimi do rozwiązania,
- nie branie pod uwagę prac nad "ukończeniem" produktu.
Tworzenie oprogramowania jest bardzo trudne. Owszem wielu ludzi potrafi programować. Owszem są kursy, które przygotowują od zera do tego rzemiosła i zapewniają, że w rok ich kursant może tworzyć komercyjny software. Problem pojawia się, gdy zaczynamy oczekiwać też jakości. Tworzenie oprogramowania na "miarę" jest zawsze czasochłonne i złożone. Bardziej niż większości ludzi się wydaje. Bardziej nawet niż większości programistom się wydaje.
Rozwiązywanie problemów nie jest proste
Gdy celem jest rozwiązanie mniej typowego problemu czy zautomatyzowanie nietypowego procesu w firmie, samo zrozumienie i analiza będzie również czasochłonna. W każdym przypadku, gdy klient przychodzi ze zleceniem na zrobienie programu, nie wie faktycznie jakie konkretnie funkcje powinny być zaimplementowane. Nie chodzi tutaj nawet o zrozumienie samego problemu, który ten biznesmen chce rozwiązać w swojej firmie.
Większy problem jest z tym jak go rozwiązać lub chociaż jak go częściowo rozwiązać?
Jak zoptymalizować określony proces w firmie czy warto robić to poprzez program?
Jaką funkcjonalność zaimplementować w pierwszej kolejności?
Należy wybrać procesy wewnątrz firmy, gdzie proste usprawnienie da największy zysk. Tym lepiej jeśli usprawniany proces jest wąskim gardłem, którego udrożnienie pozwoli na natychmiastowy skok produktywności całej firmy. Trudno przewidzieć z góry czy implementacja takich funkcji opłaci się firmie. To wszystko wychodzi w trakcie. Nie raz trudno przewidzieć realny zwrot z inwestycji w pakiet godzin pracy dewelopera nad określoną funkcją.
Dlatego zawsze przygotowujemy tzw. MVP. Jest to najbardziej okrojona wersja wyobrażonego produktu. Wprowadza się do niej tylko kluczowe funkcje, zwykle pracujące tylko w najbardziej typowym scenariuszu. Jeśli ten etap pracy rozwiąże problem lub chociaż go zmniejszy, wtedy można śmiało iść dalej i rozwinąć te funkcje o mniej typowe scenariusze i przypadki szczególne lub dopisać inne funkcje.
Teraz, UWAŻAJ!
Czy zwróciłeś uwagę na trzy stwierdzenia faktu powyżej, które mają miejsca jakby “po fakcie”?
Oto one:
- jeśli ten etap pracy rozwiąże problem,
- mniej typowe scenariusze,
- inne funkcje.
Bardzo często dzieje się tak, że tych informacji nie udaje się przewidzieć, przed rozpoczęciem prac.
Klient często nie wie czego potrzebuje
Nie dlatego, że nie odrobił zadania. Po prostu rzeczywistość jest złożona i trudna do przewidzenia. Dlatego właśnie buduje się takie MVP, aby jak najmniejszym kosztem zweryfikować pomysł.
Co więcej nie chodzi tylko o porównanie kosztów i zwrotu z inwestycji. Nadawanie priorytetu jest również istotne szczególnie w realiach startupowych, gdzie źródłem zmartwień jest nie tylko “jak dostarczyć usługę?” ale też - a może nawet przede wszystkim - “jaką dostarczyć usługę?” Diabeł tkwi w szczegółach. Najpiękniej zrealizowane usługi upadają, bo nikt ich nie używa.
Jeśli klient chce wejść na rynek z nową usługą, to w pierwszej kolejności powinien jak najszybciej sprawdzić:
- które jej cechy będą pożądane przez jednostki z grupy docelowej - za które będą oni gotowi zapłacić,
- które cechy byłyby zbędnym kosztem,
- które cechy wręcz popsułyby produkt.
Jak myślisz jaka jest czwarta informacja, która jest niewiadomą na początku działalności prawie każdego startupu? Otóż czy w ogóle na ten typ usługi będzie wzięcie?
Przyszłość może powiedzieć, że cały pomysł na startup trzeba wyrzucić do kosza (albo odłożyć na półkę na kilka lat)!
Programiści doskonale zdają sobie z tego sprawę...
Przed napisaniem nowego oprogramowania stoimy przed wieloma niewiadomymi. Stanowią one nie lada wyzwanie. Dlatego stosujemy tzw. “metodologię Lean”. W największym skrócie polega ona m.in. na odciąganie w czasie jak najwięcej decyzji. Innymi słowy unikamy robienia jakichkolwiek “założeń” co do spraw, które nie zostały dobrze poznane. Nowe pomysły testujemy najmniejszym kosztem. W ten sposób minimalizujemy koszty błędów i pomyłek, które są przecież nie do uniknięcia.
Dobry zespół deweloperski będzie bardzo skrupulatny podczas przygotowywania planu szczególnie przed pierwszym etapem MVP. Dołoży wszelkich starań do tego aby software, który zbudują był zgodny z “faktycznymi” potrzebami biznesu klienta. Co równie ważne, prócz tego skupi się wokół tzw. “core features” czyli najbardziej krytycznych funkcjonalności.
Nie jest to łatwe zadanie. Wymaga sporej pieczołowitości, cierpliwości i dozy nieufności do rzeczy “pewnych”. Taki deweloper musi być mocno proaktywny jeśli chce spełnić dobrze swoją rolę. Ma on myśleć za klienta, dalej niż klient, on sam jest odpowiedzialny za znalezienie miejsc, których klient nie wziął pod uwagę czy wręcz zapewniał, że już to sam przemyślał.
Analiza i przewidywanie
Dobry deweloper nie może poprzestać na zrozumieniu co ma być zaimplementowane. Musi on poznać jaki ostatecznie problem w życiu firmy ma być rozwiązany. Cel dewelopera powinien być tożsamy z celem biznesowym klienta.
Klient najlepiej rozumie swój biznes. Natomiast strona techniczna jest niemal wyłącznie znana tylko deweloperowi. Dlatego to on powinien z własnej inicjatywy dbać o rzetelne doradztwo. Jest to szczególnie istotne, ze względu na powszechnie występujące słabe zrozumienie specyfiki tworzenia programów komputerowych.
Oprócz strony technicznej dbamy również o dobrą analizę. Często spotyka się biznesmenów, którzy widzą swoją firmę bardziej w skali makro i nie dostrzegają szczegółów. Procesu w informatyce nie da się zaprojektować “mniej więcej”.
Dobra analiza procesu z życia, który ma być zmodelowany, wymaga niebywałej dociekliwości.
Przewidzenie na etapie projektowania możliwie jak najwięcej przypadków szczególnych, jakie mogą wystąpić w ramach procesu ma ogromne znaczenie. To się przekłada na pieniądze. Gdy taki “szczegół” jest odkryty dopiero w trakcie developmentu, uwzględnienie go w systemie może wymagać ogromnych nakładów czasu ze względu na potrzebę gruntownego przebudowywania aplikacji.
Pieniądze zaoszczędzone przy wyborze tańszego zespołu deweloperskiego bardzo często są niczym w porównaniu do pieniędzy, które będzie trzeba wydać w przyszłości na naprawienie błędów lub wręcz napisania od nowa całych kawałków systemu. Zrozumienie dogłębne problemów i specyfiki danego biznesu może wymagać czasu. Dalej tego czasu będzie wymagało wyłuskanie tzw. “core objectives” czyli głównych potrzeb.
Kolejnym krokiem jest szczegółowe prześledzenie implementowanego procesu i przewidzenie przypadków szczególnych i niuansów, które mogą wystąpić w przyszłości. Te trzy etapy stanowią analizę tego co ma być zrobione. Najwięcej zależy od dobrze wykonanej roboty już w tak wczesnej fazie. To natomiast wymaga właśnie:
- odpowiedniej ilości czasu,
- szczególnych cech takich jak wspomniana dociekliwość (czasem wręcz drobiazgowość), cierpliwość,
- poczucia odpowiedzialności ze strony deweloperów za sukces biznesowy projektu.
Jeszcze nie doszliśmy do programowania, a istotne koszty mogą być już poniesione! Otóż programowanie nie zaczyna się nigdy od programowania. Chyba, że jest to programowanie z pobudek czysto hobbystycznych. Ale to nawet i w takim przypadku bez dobrego zrozumienia, jaki chcę osiągnąć rezultat, nic użytecznego z takiego programowania nie powstaje.
Oprogramowania po prostu nie da się zrobić “byle szybciej”, bo wcześniej czy później się potkniemy. To jest nieuniknione!
Owszem idealny produkt nie istnieje i można też przesadzić z jego jakością, kiedy koszty będą zdecydowanie przewyższać korzyści. Trzeba to też umieć wyważyć. Jest to niestety sztuką, co oznacza że można ją spotkać tylko w towarzystwie dobrego doświadczenia i wiedzy. Nikt się z tym nie rodzi.
Naturalnie to jak wiele uwagi należy poświęcić analizie i projektowaniu będzie zależeć od skali projektu i jego potencjału rozwojowego. Mały projekt można zrobić dobrze i jednocześnie na skróty. Oczywiście tylko do pewnego stopnia. Gdyby jednak biznes wszedł na nowe fale i chciał iść dalej z tym produktem, najlepszą decyzją może się wtedy okazać stworzenie produktu od nowa. Wszystko to sprawa wyczucia i zdrowego rozsądku.
Czy wiesz jaka jest następna faza rozwoju produktu software'owego? Czy pomyślałeś, że chodzi o projektowanie?
Projektowanie i programowanie
Na tym etapie trzeba podjąć szereg decyzji dotyczących ram programowanego produktu. Ramy czyli to, jak poszczególne technologie ze sobą współpracują i które z nich stanowią bazę do tego co ma powstać.
Oczywistym jest, że nie tworzy się nigdy programów tzw. “od zera”. To byłoby po pierwsze nierealne, a po drugie bardzo nierozsądne. Korzysta się z tzw. “warstw” pośrednich poprzez które, programista dużo efektywniej “dogaduje się z zimną maszyną”. Chodzi tu przykładowo o dobór takich elementów jak:
- język programowania,
- biblioteki kodów (w wybranym języku programowania), które robią najbardziej podstawowe czynności programistyczne niejako z automatu - aby nie “wymyślać koła od nowa”,
- frameworki, które mają już w sobie zaimplementowane typowe funkcje i rozwiązują najbardziej typowe problemy, jakie spotyka się w danym typie aplikacji jak np. aplikacja webowa,
- silnik bazy danych,
- narzędzia automatyzujące budowanie i wgrywanie produktu na serwer.
A to dopiero początek
Przechodząc do samego już programowania tutaj bardzo dużą rolę odgrywa porządek i czystość kodu. Innymi słowy odpowiednia dyscyplina i stosowanie dobrych praktyk programistycznych jest nie do przecenienia. Dobre stosowanie tzw. “wzorców projektowych” przychodzi dopiero z doświadczeniem. Jest ono zawsze wyrazem dobrego smaku. Tu nie ma jednoznacznych reguł, które wystarczy mechanicznie stosować i uzyska się dobre rezultaty. Dlatego dobre programowanie jest sztuką.
Co zyskuje przedsiębiorca z tego, że zainwestował w dobrze napisany kod?
Przede wszystkim to, że kod "nie boi się" zmieniać i ewoluować. Zmienność i nieprzewidywalność to jedyna stała cecha rzeczywistości. Tak, ta ironia jest tu celowa. Źle napisany kod jest bardzo "sztywny", to znaczy bardzo trudny do modyfikowania. Dużo czasu programisty może kosztować dodanie jednej, prostej funkcji. Nawet mała zmiana jednej logiki czy naprawa błędu może przysporzyć sporo pracy. Mówi się tutaj o tak zwanym długu technologicznym.
Mądry i proaktywny programista będzie ograniczał ten dług do minimum. Nierozważny, idący na skróty, podejmujący złe decyzje będzie go zaciągał. Przez jakiś czas on może nie być zauważalny ale wcześniej czy później da o sobie znać i wtedy nie będzie już tak przyjemnie. Może to nigdy nie nastąpić tylko w przypadku projektów o krótkim czasie "życia".
Tutaj wymieniłem nieprzewidziane duże nakłady na pracę programisty jako jeden ze skutków źle zaprojektowanego i napisanego kodu. Nie jest on jednak jedynym. Ten drugi jest nie mniej bolesny, a może nawet bardziej.
Dobrzy programiści są bardzo niechętni do pracy przy “złym” kodzie.
Bardzo szanują swój czas oraz warsztat wypracowywany przez lata. Mają świadomość tego, że życie jest zbyt krótkie by je marnować na pracę ze złym kodem. Wtedy przedsiębiorca ma do wyboru dwie alternatywy:
- szukać rzetelnego zespołu i być przygotowanym na "drogie" oferty,
- spodziewać się programistów, którzy zostawią po sobie jeszcze większy nieporządek i też sporo błędów.
Pół biedy jeśli w drugim scenariuszu zleceniobiorca zmieści się w zaproponowanym przez siebie terminie.
Stosowanie dobrych praktyk
Jedną z bardzo ważnych praktyk jest tworzenie testów automatycznych równolegle do budowanych funkcjonalności produktu. Testy automatyczne to krótkie sekwencje kodu, które weryfikują czy dana funkcjonalność działa i spełnia określone wymaganie. Dla ludzi z boku ta praktyka może często wydawać się zbyt drogą inwestycją. Fakty pokazują jednak coś odwrotnego.
Otóż każda jedna, nawet najmniejsza zmiana w jednym miejscu programu może wywrzeć uboczny efekt na dowolną inną część programu. Programy komputerowe to bardzo złożone bestie dlatego łatwo o błędy, nawet stosując się do najlepszych wzorców programistycznych. W ciągu jednego dnia programista wykonuje masę małych kroków - zmian w programie. Siłą rzeczy zatem ma on nie mało okazji do popełnienia błędu, od małego do dużego. Rzecz w tym by je na bieżąco wyłapywać. Do tego właśnie bardzo przydają się testy automatyczne.
Po zaimplementowaniu nowej cechy w programie lub modyfikacji działania już istniejącej tudzież po naprawie błędu zdrowy na duchu i umyśle programista nie będzie nigdy spokojny, że to co zrobił
- działa dokładnie wg założeń,
- nie popsuło czegoś innego w programie.
Dopóki...
No właśnie, co należy zrobić przed wgraniem zmiany na “produkcję” by móc potem spać spokojnie?
To naturalne, należy to przetestować!
Czy powinniśmy to robić ręcznie?
Z testami automatycznymi oczywiście wiąże się dodatkowy, całkiem istotny nakład pracy. Powszechne jest rezygnowanie z nich celem optymalizacji kosztów. Osoby tak myślące zwykle nie są świadome konsekwencji.
Otóż ilość przeobrażeń jakim ulega produkt podczas swojego życie jest zwykle bardzo duża. Mądrość też mówi, że powinno się sprawdzić wszystkie funkcje programu czy działają dalej tak samo. Gdyby po każdej takiej zmianie produktu chcielibyśmy testować wszystko ręcznie to szybko spotkają nas poniższe problemy:
- składnik kosztu rozwoju tego oprogramowania, jakim jest weryfikacja szybko zacznie rosnąć,
- testowanie będzie wykonywane wyrywkowo czyli nierzetelnie,
- powtarzalne testy ręczne do niezwykle monotonna i demotywująca czynność.
Teraz, uwaga, będzie najlepsze, a raczej najgorsze jeśli nie stosuje się testów jednostkowych.
Konsekwencja psychologiczna
Strach przed dokonywaniem zmian - jakakolwiek zmiana ciągnie za sobą ryzyko defektu. Programista boi się odpowiedzialności dlatego może ograniczać zmiany do tych koniecznych. Można powiedzieć, że mamy wtedy kod, który "boi się zmian". “Dobry” kod nigdy nie staje się taki po pierwszym napisaniu. On zawsze jest efektem ewolucji wielu przeobrażeń zwanych inaczej “iteracjami”.
Bardzo trudno jest rozwiązać wielki problem od razu. Co więcej człowiek bojąc się trudnych problemów, ma tendencję do ich unikania. Dużo lepiej jest wybierać z dużego problemu te malutkie i rozwiązywać je pojedynczo, jeden po drugim.
Testy automatyczne dają programiście znacznie większą pewność siebie i śmiałość tak przy programowaniu nowych funkcji jak i poprawianiu błędów czy ulepszaniu struktury kodu. A to zwyczajnie przekłada się na większe tempo pracy.
Podsumowując, kod który "boi się" zmieniać jest z góry skazany na niską jakość.
Zgodnie z dobrymi zwyczajami test do nowej funkcji pisze się “zanim” jeszcze przystąpi się do jej implementowania. Testy takie powinny być traktowane jako nieodłączną część zadania. Programiści nie powinni w ogóle pytać klienta o to czy je chce czy nie, gdyż jest to po prostu częścią dobrej sztuki, którą wszak uprawiają.
Kolejną z fundamentalnych praktyk jest tzw. “peer review” czyli wzajemne ocenianie swojej pracy przez kolegów. Jeden umysł nigdy nie wychwyci tylu niuansów i przypadków szczególnych co dwa lub trzy umysły. Każdy ma trochę inną percepcję, inne doświadczenie i wiedzę oraz co bardzo istotne ta druga osoba nie jest zaangażowana w to zadanie i przez to łatwiej jest jej o dystans i inną perspektywę wobec kodu.
Dobry zespół programistów ma wypracowane metody pracy, których się bezwzględnie trzyma. Nie robi wyjątku pod "byle" pretekstem jak krótkie terminy.
Na zakończenie
Jak widzisz, tworzenie oprogramowania to bardzo złożony i czasochłonny proces, który wymaga od zespołu programistycznego nielada wiedzy technicznej, szczególnej staranności przy "produkowaniu" kodu, oraz dociekliwości przy poznawaniu realnych problemów, jakie klient chce rozwiązać.
Będąc tego świadom, mam nadzieję, że będzie Ci łatwiej rozmawiać z firmą programistyczną i zadawać pytania, aby lepiej zrozumieć "obietnicę" ich konkretnej wyceny.