Posts tagged ‘software engineering’

Different Kind of Engineering

2013-11-03 22:59

Have you ever heard the term “architecture” applied to the realm of software? Pretty sure you have. Our discipline, at least on the surface level, seems to borrow a lot of nomenclature from fields related to the construction of buildings. We talk about designs, frameworks, foundations, sometimes even scaffolds or facades.

And, of course, there is this whole convention of referring to programmers as “engineers”. Guess it simply sounds too good as a job title to let it go!

But frivolous as it may be, there is something deeply wrong about drawing analogies between erecting real structures and hacking virtual ones. It’s not even about attributing undue significance to the “mere” activity of sitting behind a screen and hammering at the keyboard; at this point, software development is probably at least as important as civil engineering – perhaps even more so.

The problem is that thinking of developing software as analogous to constructing buildings promotes flawed, unsustainable approaches. What is even more insidious is that they appear perfectly reasonable at first, mature even. It seems intuitively right, after all, to think of software project as something akin to construction project. In both cases you need to satisfy certain requirements, accommodate for interactions with external environment, and fit everything within time and/or budget constrains.

If it seems so right, then why it is so wrong? Well, because the similarity is only apparent, and thus largely superficial.

Design can only be arrived at by building

How common it is to begin construction of a building before its blueprint is finalized? Although few shovels might have tilled the ground here and there, construction engineers generally do not begin laying foundations until the structure’s design is ready. Before even the first bricks form a nascent wall, you can have pretty good idea of how the final thing will look like.

Can you say the same about software project? Certain methodologies (*cough* waterfall) claim to achieve almost the same degree of robustness and predictability, but most of us know how patently ridiculous they are. Not only is the final shape of system unknown when you start writing it, but it is practically unknowable. The design only reveals itself while you are already building, and this is something I’m sure would make the blood of traditional engineers run cold.

Laws of physics are of no concern

There are reasons for those unknowns, however. While real world engineering deals with real world limitations, bits and pixels are often completely unconstrained by those. More than by climate conditions, size of electromagnetic spectrum or the speed of light, software systems are limited by other, existing systems and processes: not necessarily software ones, but often unstable and changing.
As a result, dealing with them can get arbitrarily complex, not to mention that it transitively affects future systems interacting with us.

In comparison, the ground you build upon is quite literally rock solid.

Code is not concrete

Thankfully, there is one aspect of programming that makes all those obstacles somewhat surmountable. Unlike skeletons of skyscrapers, made of reinforced concrete, code is always modifiable. Regardless of how far you’ve progressed with current implementation, you can change and redesign it. Sure, there is typically a requirement to support outside clients through existing API but rarely, if ever, you are limited in how you’re gonna support them.

Frankly, this is something that I often see people struggling to come to terms with. Maybe because of those construction analogies I’ve mentioned, the structure of a program is often perceived as rigid and almost constant.
You are not allowed to tamper with it. You can only extend it in certain, predefined ways. And you better get it right the first time, as there is no going back. It’s almost as if the code was literally set in stone.

This, however, is a massive misconception. Code is meant to be poked and prodded; extended and removed; modified and reverted; and most importantly, hacked on and refactored. The notion of “technical debt” is a beautiful concept that captures all those mechanics. You don’t want to be in debt which is too large, because the interest rates (maintenance costs) will hinder you in the long run. But you also don’t want to have too small credit, or you won’t be able to make new investments (features) and expand your “business”.

Ask for Forgiveness, Not Permission

2013-06-16 6:08

Even though it’s not a part of the Zen of Python, there is a widely accepted principle in Python community that reads:

It’s better to ask for forgiveness rather than permission.

For code, it generally means trying to do something and seeing whether it succeeded, rather than checking if it should succeed and then doing it. The first approach produces something like this:

  1. try:
  2.     print dictionary[key]
  3. except KeyError:
  4.     print "Key not found"

and it’s preferred over the more cautious alternative:

  1. if key in dictionary:
  2.     print dictionary[key]
  3. else:
  4.     print "Key not found"

What I realized recently is that there is much more general level of software development where the exact same principle can be applied. It’s not just about individual pieces of code, or catching exceptions versus checking preconditions. It extends to functions, modules, classes and packages – but more importantly, to the whole process of adding features, extending functionality or even conceiving totally new projects.

Taking a bit simplistic view, this process can be thought of having two extremes. On one end, there is a concept of pure “waterfall”. Every bit of work has to fit into predefined set of phases and no later phase can start before the previous one has completely finished. In this setting, design must be done upfront and all knowledge about the future product has to be gathered before coding starts.
By even this short description, it’s hard to stop thinking about all the hilarious ways the waterfall approach can end badly. Curiously, though, there are still companies that not only follow it but flaunt the fact publicly.

The other end is sometimes called “cowboy coding”, an almost derogatory term for churning out code without regard to pretty much any methodology whatsoever. Like in case of waterfall, it sometimes (very rarely) works, but it’s more so by accident rather than by design. And like pure waterfall, it also doesn’t really exist in nature, as long as more than one programmer is involved.

If we frame the spectrum like this, with the two completely opposite points at the edges, the natural tendency is to search for the middle ground. But if we subscribe to the titular principle of asking for forgiveness rather than permission, the right answer will clearly be shifted towards the “lean” side.
What is permission here? That’s a green light from design, architecture, requirements, UX and similar standpoints. You wouldn’t mind having all these before you start coding, but it is not absolutely crucial. Not having it, you can still do things: code, prototype, explore, and see how things pan out.
Even if you end up ripping it all apart, or maybe even fail to produce anything notable, you will still accrue useful knowledge. Say you have to throw away most of the week’s work because you’ve learned you need to do it differently. So what? With the insight you have gained along the way, it may very well take just a few hours now.

And so thou shalt be forgiven.

Tags: , ,
Author: Xion, posted under Programming » Comments Off on Ask for Forgiveness, Not Permission

Ideas Worth Spreading: Issue Tracking

2012-03-11 17:15

Real-world metaphors are quite abundant when discussing topics related to IT and programming. They seem to be particularly useful when introducing newcomers, although it’s equally easy to point out mature and established techniques that originate from non-digital world (OOP anyone?…). Regardless, the flow of ideas seems to be extremely one-directional, and I think that’s very unfortunate. There’s wealth of concepts specific to IT or software industry that the general public would benefit from knowing about.

One of those, in my not-so-humble opinion, is the idea of issue tracking. I suppose vast majority of readers is intimately familiar with it but let’s put it into words anyway, for the sake of clarity and explicitness. The concept revolves around a system which allows its users to create tickets describing various issues pertaining to some particular project, or part of it, or process, or any similar endeavor. Those tickets necessarily consist of title and content, very much like emails. Usually though, they also have few additional fields that are more meta, and describe the ticket itself. Typical examples include:

  • A type or category for ticket. In software project, the distinction between bug and feature request is of utmost importance, although several more kinds of tickets (e.g. documentation-related tasks) are pretty well known too.
  • Status of a ticket, indicating what’s currently happening with the issue in question. Did it arise only recently, or some work on it has been already done? Maybe it was successfully resolved, or maybe there are more information needed to push the case further… Either way, that’s what ticket status should tell us.
  • Person currently responsible for issue – the one it has been assigned to. For new issues, this field usually points at project manager, who is subsequently dividing work among members of their team.

Lastly, every ticket allows for discussion in a forum-like manner, and for adding comments to any metadata changes we make.

That’s it, in a nutshell. It doesn’t seem very complicated and frankly, it may not sound very innovative either. Why do I think such a concept is worthy of attention in broader context, then?…

class Fish extends Animal?…

2011-09-22 22:24

Pisałem już wcześniej o tym, że ostatnimi czasy programowanie obiektowe nie ma zbyt dobrej prasy i swego rodzaju modą stało się jego krytykowanie. Nie jest to oczywiście trend zupełnie pozbawiony podstaw. Z jednej bowiem strony dla pewnych problemów lepsze wydają się inne paradygmaty: np. dla modelu żądanie-odpowiedź (typowego dla aplikacji webowych) najwyraźniej całkiem dobrze sprawdza się programowanie funkcyjne. Z kolei zastosowania wymagające dużej wydajności (np. programowanie grafiki 3D czasu rzeczywistego) mogą istotnie nie tolerować narzutu związanego z polimorfizmem funkcji wirtualnych – albo przynajmniej tak się wydaje tym, którzy się nimi zajmują.

Sądzę jednak, że spory udział ma tu też pewien powszechny (niestety) zwyczaj krytykowania rzeczy, których nie do końca rozumiemy. Szerokie kręgi zatacza bowiem pewien specyficzny sposób opacznego interpretowania idei OOP-u. Jego źródła upatruję w wielu (może nawet większości) kursach, książkach, tutorialach, artykułach i wszelkiego rodzaju materiałach instruktażowych dla początkujących adeptów programowania. Sam dodałem swój niechlubny wkład do tego stanu rzeczy, do czego się tu otwarcie przyznaję. No cóż, nikt mnie ostrzegł – ani wtedy (czyli jakieś 6 lat temu), ani nawet teraz.
A ostrzeżenie jest absolutnie niezbędne. Także dlatego, że co najmniej raz słyszałem, jak owo mylne pojęcie na temat OOP-u stało się poważnym argumentem w rzeczowej poza tym dyskusji na temat jego zalet i (głównie) wad. Nawet ważniejszym powodem jest jednak to, iż niewłaściwa interpretacja założeń programowania obiektowego może prowadzić do źle zaprojektowanych systemów, które trudno się potem konserwuje i rozbudowuje.

O jakiego więc rodzaju konfuzji tu mówimy?

Niekoniecznie należy słuchać ekspertów

2011-06-20 22:45

Nieodłączną częścią realizacji projektu programistycznego jest wybór używanych technologii. Dotyczy to zarówno samego początku, jak i późniejszych etapów, gdy czasami trzeba zdecydować się np. na skorzystanie z jakiejś biblioteki X lub jej zamiennika Y. Takie dylematy mają i koderzy-amatorzy (co często uzewnętrzniają na przeróżnych forach ;]), i firmy tworzące oprogramowanie komercyjnie. Decyzję trzeba jednak w końcu podjąć; czy są jakieś uniwersalne kryteria, którymi można się kierować?
Inżynieria oprogramowania każe zwykle zdać się na poprzednie doświadczenia lub wiedzę ekspertów. Ta druga opcja jest często preferowana wobec braku podstaw (tj. wspomnianych doświadczeń) do skorzystania z pierwszej. Wydaje się to rozsądne. W końcu osoba, która bardzo dobrze zna dane rozwiązanie, powinna mieć też odpowiednie pojęcie o tym, czy aplikuje się ono do konkretnego problemu.

A jednak mam co do tego całkiem poważne wątpliwości. Potrafiłbym znaleźć kilka sensownych argumentów na to, że osoba biegła w stosowaniu danej technologii nie musi być wcale dobrym doradcą. W grę mogą bowiem wchodzić silne czynniki zaburzające solidność osądu eksperta. Przychodzą mi na myśl zwłaszcza dwa:

  • Osoba świetnie znająca jakieś rozwiązanie jest z pewnością taką, która zastosowała je w co najmniej kilku projektach. Kto wie, być może nawet zakończyły się one sukcesem ;) Niezależnie od ich wyniku, zdobyte przy okazji doświadczenie prawdopodobnie nauczyło naszego eksperta, jak powinien radzić sobie z przeróżnymi kruczkami, niejasnościami, niedoróbkami, brakami czy wręcz jawnymi bugami występującymi w danej platformie czy bibliotece. Jeśli wielokrotnie i z powodzeniem dawał sobie z nimi radę, jest wielce prawdopodobne, iż będzie (nawet nieświadomie) umniejszał ich znaczenie podczas “obiektywnej” oceny całego rozwiązania. Po prostu z perspektywy czasu nie będą się one wydawały aż tak dolegliwe, jakie mogą być w rzeczywistości dla osoby słabiej obeznanej z daną technologią.
  • Nasz ekspert od rozwiązania X na pewno poświęcił sporo czasu i mocy obliczeniowej swoich neuronów na dokładnie zapoznanie się z jego szczegółami. Wysiłek ten sprawił przy okazji, że w naturalny sposób zaczął on wyżej cenić X-a, ponieważ w ten sposób potwierdzał w swoich oczach słuszność decyzji, aby rozwijać swoją znajomość tego zagadnienia. Dzięki tej (znów: zwykle nieświadomej) praktyce, nasz ekspert zapobiegł powstaniu dysonansu poznawczego (cognitive dissonance) lub przynajmniej znacząco go zredukował. Efektem ubocznym tego zjawiska jest jednak zaburzone postrzeganie wartości X-a jako rozwiązania, związane głównie z tzw. błędem potwierdzania (confirmation bias) lub zaprzeczania (disconfirmation bias). Krótko mówiąc, nasz ekspert generalnie przywiązuje większą wagę do pozytywnych ocen X-a, a mniejszą do negatywnych. Niezbyt dobrze wróży to jego obiektywności.

Jak wynika z powyższych argumentów, wypowiedziane przez eksperta zdanie na temat przydatności jakiegoś rozwiązania niekoniecznie musi być obiektywne i wartościowe. Oczywiście nie twierdzę, że największe pole do popisu przy podejmowaniu decyzji powinni mieć wobec tego początkujący, bo to z kolei zakrawa na przegięcie w drugą stronę :) Sądzę jednak, że najbardziej kompetentnymi i obiektywnymi osobami byłyby takie, które wprawdzie stosowały dane rozwiązanie w praktyce, ale nie są w nim całkiem biegłe. A już zupełnie dobrze byłoby wówczas, jeśli mają one też pewne pojęcie o porównywalnych, alternatywnych rozwiązaniach.

Czas do końca projektu

2010-11-28 15:04

Oszacowanie czasu potrzebnego do wykonania danego projektu to odwieczny problem inżynierii oprogramowania. Być może w ostatnich latach coś się w tym względzie zmieniło, ale jeśli nie, to wciąż pozostaje aktualna sugestia, że najskuteczniejszym sposobem jest po prostu… zapytanie kogoś kompetentnego :) Najwyraźniej wypracowanie jakichś ścisłych i skutecznych metod oceny nakładu pracy i czasu przy tworzeniu oprogramowania jest wciąż poza naszym zasięgiem i trzeba się uciekać do metod typu \pi * drzwi – z naciskiem na drzwi.
Sam mam kilka teorii na temat tego, czemu tak jest. Jedną z nich jest postulat, że do różnego rodzaju projektów należy stosować różne modele przewidujące czas ich trwania. Owych rodzajów jest zaś dokładnie trzy i są to bardzo proste kategorie. Wyróżniam mianowicie projekty zbyt proste, odpowiednie i zbyt trudne. Określenia te odnoszą się – jak można się domyślić – do stopnia trudności danego projektu dla zespołu, który go wykonuje. Nie należy jednak traktować ich zbyt dosłownie ;)

I tak przez projekt zbyt prosty rozumiem taki, którego główne wyzwanie (czyli główna funkcjonalność) jest w gruncie rzeczy łatwe do zrozumienia i zaprojektowania, a co za tym idzie także do zakodowania. Spotykając się z takim zadaniem, możemy bez dużego wysiłku wypracować dla niego rozwiązanie, które wystarczy “tylko” zaimplementować.
Paradoksalnie jednak tutaj mogą zacząć się schody. Kiedy główny problem jest już za nami, i to bardzo szybko, motywacja do kontynuowania prac spada. Mimo że zwykle pozostaje jeszcze sporo do zrobienia, nie są to już czynności wymagające dużego wysiłku intelektualnego, więc często mogą być po prostu nudne. Tempo sukcesywnie więc spada w miarę zbliżania się do końca.

Dokładnie odwrotnie jest z kolei w przypadku projektów zbyt trudnych. Gdy główny problem jest tak skomplikowany, że przez długi czas nie wiadomo, jak właściwie się do niego zabrać, postęp prac jest nikły. W pewnym momencie jednak (miejmy nadzieje) przychodzi olśnienie – albo raczej seria mniejszym “eurek” – i od tego momentu wszystko nabiera bardzo dużego przyspieszenia. I nawet po rozwiązaniu głównego problemu nie musi ono wcale zwalnia, lub inaczej: nawet jeśli zwalnia, to efekt ten nie jest łatwo zauważalny w skali czasowej całego przedsięwzięcia.

Trzecia kategoria leży natomiast pośrodku między dwiema powyższymi. Projekt jest odpowiedni, jeśli przez cały czas trwania prezentuje mniej więcej podobny poziom trudności dla zespołu, który go wykonuje. Oznacza to, że jego główny problem daje się rozwiązać systematycznie i sekwencyjnie, nie zaś prawie automatycznie (w przypadku projektów zbyt łatwych) lub tylko za pomocą nagłego odkrycia (jak w przypadku projektów zbyt trudnych).

Tym trzem kategoriom projektów możemy przypisać krzywe określające poziom zaawansowania prac w zależności od czasu. Nietrudno jest zauważyć, że dla przedsięwzięć zbyt łatwych będzie to funkcja logarytmiczna, dla zbyt trudnych – wykładnicza, zaś dla odpowiednich będzie ona zbliżona do linii prostej:

Jeśli umiemy rozpoznać, do której z tych trzech kategorii należy nasz projekt, to niewykluczone, że możemy spróbować uniknąć niektórych pomyłek przy szacowaniu czasu pozostałego do końca projektu. Dla projektów zbyt łatwych można na przykład łatwiej niż zwykle ulec złudzeniu planowania i nie docenić czasu pozostałego do końca prac, kierując się tym, iż na początku “idzie jak z płatka”. Dla zbyt trudnych można natomiast błędnie ekstrapolować początkowe trudności w przyszłość i wnioskować, że projekt będzie trwał całe lata (podczas gdy może trwać miesiące lub… dekady, w zależności od tego, kiedy nastąpi “olśnienie”).

Najważniejszym wnioskiem – jeśli moje przemyślenia są prawdziwe – jest jednak korzyść, jaką daje zapewnienie, by projekt był odpowiedni. Wówczas szansa na wiarygodne oszacowanie pozostałego czasu jest znacznie zwiększona, bo mówimy wtedy o ekstrapolacji funkcji w przybliżeniu liniowej. Żeby jednak móc korzystać z tej pożytecznej cechy, musimy postarać się o odpowiednie dobranie zespołu do zadania… lub odwrotnie :)

 


© 2023 Karol Kuczmarski "Xion". Layout by Urszulka. Powered by WordPress with QuickLaTeX.com.