piątek, 1 maja 2009

Ile powinno kosztować oprogramowanie?

Na pytanie zadane w tytule chyba najłatwiej byłoby odpowiedzieć:

Tyle, ile ktoś jest w stanie za nie zapłacić.

Jest to jednak odpowiedź jak w dowcipie z matematykiem:

Balonem na wycieczkę wybrali się fizyk z chemikiem, jednak w wyniku zażartej dyskusji na temat wyższości jednej nauki nad drugą, zgubili się. Lecieli tak już kilka godzin nie wiedząc gdzie są, wreszcie zobaczyli na ziemi człowieka. Postanowili się więc zapytać:
- Panie! Gdzie jesteśmy?
Po pewnej chwili padła odpowiedź:
- W balonie!
Na to fizyk do chemika:
- mmhm... Ten który nam odpowiedział to musi być matematykiem, odpowiedź jest w stu procentach przemyślana, w stu procentach prawidłowa i ... w stu procentach niepotrzebna!

Nie chciałbym więc, by mój artykuł został uznany za nie potrzebny i nie odpowiadający na postawione pytania. Dodatkowym utrudnieniem jest fakt, że zadane pytanie jest mało precyzyjne i trudno stwierdzić jakiej odpowiedzi może oczekiwać je zadający...

Zastanówmy się więc z jakimi kosztami możemy mieć do czynienia. Może to być koszt licencji jaka ma być udzielona kupującemu lub koszt wytworzenia oprogramowania. W pierwszym przypadku należy zrobić badania rynku, znaleźć podobne produkty, spróbować ocenić ile klient jest w stanie zapłacić, na podstawie tych informacji można oszacować cenę licencji na użytkowanie. Co jednak należy zrobić gdy chcemy sprzedać kod źródłowy, pomysł i licencję na dalszy rozwój tego oprogramowania? Wtedy znaczącym elementem wyceny jest oszacowanie kosztów wytworzenia oprogramowania. Jak to zrobić? Wydawałoby się to na pierwszy rzut oka proste - analizujemy ile przepracowaliśmy (my lub nasz team) nad tym oprogramowaniem: ile godzin, dni, czy miesięcy, mnożymy to przez pewną stawkę i mamy koszt. Takie szacowanie może być jednak trudne, zwłaszcza gdy tworzenie tego oprogramowania było dodatkowym zajęciem, skąd więc wziąć choćby przybliżony czas poświęcony na wytworzenie. Poza tym jak przekonać potencjalnego kupca, że to oprogramowanie tyle kosztuje?

Tutaj z pomocą przychodzą odpowiednie metody wyceny (to dobrze, że już ktoś przed nami miał taki problem ;) ). Jedną z tych metod jest COCOMO lub COCOMO II (COnstructive COst MOdel II) (ew. informacje w polskiej Wikipedii dostępne są tutaj: http://pl.wikipedia.org/wiki/COCOMO). Spotkałem się z wykorzystaniem tej metodologii na stronie udostępniające open source'owe oprogramowanie Argo UML, którego kod źródłowy (ponad 600 tys linii w Javie) został oszacowany na ponad 9 mln. dolarów. Ciekawe wyliczenie ;).

Jak posługiwać się więc tą metodologią? Najważniejszym jest fakt określenia ile linii kodu ma nasze oprogramowanie, później z wykorzystaniem pewnych równań i współczynników (takich jak komplikacja projektu, zaawansowanie grupy programistycznej, kosztu roboczo-godziny) wyliczamy ostateczny koszt.

W wyliczeniach może pomóc nam kalkulator, np. dostępny tutaj: http://www.cms4site.ru/utility.php?utility=cocomoii.

Co sądzicie o tej metodologii? (zapraszam do dyskusji przy pomocy komentarzy)

Zapraszam do przeczytania kontynuacji tego artykułu.

Na koniec chciałbym zadać jeszcze jedno pytanie: Jak wyznaczyć ilość linii w oprogramowaniu? (często jest to o tyle trudne, że trzeba zliczyć dane pochodzące z kilkuset plików).

Moją propozycją jest poniższy kod napisany w C# (domyślnie zlicza tylko pliki *.CS ale modyfikacja tego jest bardzo prosta). Jak go używać? Wystarczy tylko wskazać katalog w którym to oprogramowanie znajdzie wszystkie pliki *.CS i policzy w nich linie.

W ramach ćwiczenia zapraszam do policzenia linii w poniższym kodzie i wyznaczenie jego kosztu. Ja wolę nie liczyć, bo się jeszcze okaże, że rozrzutny jestem ;).

using System;
using System.Collections.Generic;
using System.Text;
using System.IO;
using System.Windows.Forms;

namespace CodeBaseCosts
{
  class Program
  {
    [STAThread]
    static void Main( string[] args )
    {
      FolderBrowserDialog folderBrowserDialog1 = new FolderBrowserDialog();
      if ( folderBrowserDialog1.ShowDialog() == DialogResult.OK )
      {
        ulong count = CountLines( folderBrowserDialog1.SelectedPath, ".cs" );
        Console.WriteLine( "directory:{0} - lines={1}", folderBrowserDialog1.SelectedPath, count );
      }
      Console.WriteLine( "end" );
      Console.ReadLine();
    }
    private static ulong CountLines( string directoryPath, string extension )
    {
      ulong count = 0;
      try
      {
        Console.Write( "." ); // progress bar ;)
        // 1. get the information of the directory
        DirectoryInfo directoryInfo = new DirectoryInfo( directoryPath );
        // 2. get content of the directory and go through each subdirectory
        foreach ( DirectoryInfo d in directoryInfo.GetDirectories() )
        {
          count += CountLines( d.FullName, extension );
        }
        //3. loop through each file in the directory, and add lines
        foreach ( FileInfo f in directoryInfo.GetFiles() )
        {
          if ( f.Extension == extension )
            using ( var reader = File.OpenText( f.FullName ) )
            {
              while ( reader.ReadLine() != null )
              {
                count++;
              }
            }
        }
      }
      catch
      {
        //it is possible that we receive an exception (e.g. directory cannot be accessed due to access privilidges
        // we do nothing, we just skip this node.
      }
      Console.WriteLine();
      return count;
    }
  }
}

6 komentarzy:

  1. Pare zastrzeżeń co do metody liczenia. Zliczasz także puste linie, bo w przypadku pustych linii Reader nie zwróci ci null'a tylko string.Empty. Poza tym co z liniami zbudowanymi z samych białych znaków. Puste one czy nie? Dodatkowo ta rekursja..fuuj. Nie lepiej jak wzorzec użyć *.cs i skorzystać z przeciążonej metody GetFiles?
    GetFiles("*.cs", SearchOption.AllDirectories) choć w takim wypadku możesz mieć problem bo jak rzuci wyjątkiem to nic nie dostaniesz, ale w sumie chyba to lepsze niż zafałszowany wynik spowodowany połknięciem wyjątku (i zerowym komunikacie o jego wystąpieniu). A tak w ogóle to bym poszedł w LINQu tu :)
    Poza tym ciekawy tekst :)

    Pozdrawiam,
    Paweł

    OdpowiedzUsuń
  2. Po poście odnośnie kodu (mam nadzieję, że się ukaże) teraz odnośnie samej metryki.

    Wyliczanie ceny na podstawie liczby linii ma kilka wad. Po pierwsze dużo zależne od wyboru języka, tak więc musimy wziąć to pod uwagę przy wycenie (nie sądzę, aby ten kalkulator to uwzględniał). Dodatkowo liczba linii znacząco zależy od programisty piszącego kod. Korzystając z LINQu (ale nie tylko) da się dla przykładu powyższy kod napisać w 2-3 liniach. Czy to znaczy że jest mniej warty? Mnie wydaje się, że lepszym sposobem jest po prostu wyliczenie kosztu roboczogodziny dla programisty, architekta, PM i jeszcze kto w projekcie bierze udział i na podstawie ich "zużycia" w projekcie wyliczyć koszt. Oczywiście koszty projektu powinny pokryć amortyzację zużytego sprzętu i koszty stałe no i odpowiedni zysk.
    Oczywiście i taki sposób wyznaczania ceny nie jest doskonały. Zapewne żaden nie jest.

    Co do przekonywania klienta, że oprogramowanie jest tyle warte? Należy wykazać jakie zyski będzie miał jego biznes z użycia naszego oprogramowania lub też lepiej - pokazać jakie straty będzie miał biznes bez jego użycia :)

    OdpowiedzUsuń
  3. Dziękuję za wszystkie uwagi (zarówno w komentarzach jak i w mailach). Jeśli chodzi o sprawy związane z metodą i wyliczeniami to dodatkowe informacje na ten temat umieściłem w moim kolejny post'cie. Jest to pewnego rodzaju próba uzasadnienia, że ten sposób wyliczeń ma jakikolwiek sens i że nadaje się do pewnego oszacowania kosztów. Chociaż nie jest on doskonały, ale jak kolega Pawlos napisał: "Zapewnie żaden nie jest.".
    Tutaj chciałbym przypomnieć jedną z moich uwag, że nie zawsze jesteśmy wstanie oszacować ile pracy włożyliśmy w projekt, więc nie koniecznie wiemy jakie zasoby on pochłonął.
    Jeśli chodzi o dołączony kod programu, to przyznaję, że nie włożyłem wiele wysiłku w jego napisanie i zależało mi przede wszystkim na napisaniu w szybki sposób programiku, który zrealizuje zadany cel.
    Jeszcze raz dziękuję za komentarze, gdyby ktoś miał jeszcze coś ciekawego do dodatnia to zapraszam.
    Pozdrowienia!

    OdpowiedzUsuń
  4. Nie wiem na ile praktyczne zastosowanie będzie miało takie zdanie, ale wartość programu można określić jako zysk (pieniężny) klienta który je zastosuje. Możnaby spróbować oszacować aktulane koszty procesu, koszty usprawnionego procesu, i wyznaczyć np. roczny zysk z zastosowania programu.

    OdpowiedzUsuń
  5. wc --lines $(find katalog | grep '\.cs$')
    Mam wrażenie, że ta jedna linijka jest tyle samo warta co 58 lini kodu w C#

    OdpowiedzUsuń
  6. Ten kod mógłby być za około 150 euro jeżeli w przeliczeniu na złotówki, wyszło by około 750 zł (Oczywiście wszystko zależy od wartości euro która się cały czas zmienia i zmienia.)

    OdpowiedzUsuń

Posty powiązane / Related posts