BAD DESIGN czyli zły projekt

, niedziela, 17 kwietnia 2016 0 komentarze

Czym jest tzw. "zły projekt" (BAD DESIGN)
Niestety obecnie w dobie masy frameworków, bibliotek i innych gotowych komponentów korzystając z tych udogodnień zapomina się w ramach projektowania aplikacji czy nawet wielkich systemów o tak podstawowych zagadnieniach jak dobre zaprojektowanie systemu czy aplikacji. Napisałem "niestety", ponieważ złe zaprojektowanie prowadzi nieuchronnie do klęski w postaci:

  • błędów kodu trudno wykrywalnych lub niemożliwych do wykrycia (często rozwiązywanych np. poprzez cykliczne restarty systemów)
  • frustracji ludzi / programistów którzy są zmuszeni do utrzymywania systemu 
  • braku możliwości jakiegokolwiek rozwoju aplikacji czy systemu lub możliwości znacząco utrudnionych
  • ogromnych kosztów wymaganych na rozwój czy poprawę systemu / aplikacji

Wykorzystanie udogodnień jakie w dzisiejszych czasach występują znacząco ułatwia projektowanie systemów jednakże sprawia również, że używając ich następuje tzw. rozleniwienie i oczekiwanie, że zastosowane bibliotek / frameworków zwalnia od myślenia o dobrym projekcie. No dobrze, ale co to jest "złe zaprojektowanie" lub czym się charakteryzuje ? Zadając to pytanie, najprawdopodobniej padnie tyle odpowiedzi ilu ludzi będzie zaangażowanych w debatę i pewnie każdy będzie miał po części rację. Natomiast pytanie brzmi, czy są bezsporne kryteria złej architektury, z którymi są w stanie zgodzić się architekci / inżynierowie, a jeżeli tak to jakie to są kryteria. Niżej przedstawiam propozycję cech, zaczerpniętych z publikacji internetowych, którymi charakteryzuje się zła architektura (myślę, że do zaakceptowania dla każdego inżyniera):

  • system, który jest ciężki do zmiany z uwagi na fakt, że każda wprowadzona zmiana ma wpływ na znaczącą ilość elementów systemu (Rigidity)
  • system, w którym wprowadzenie zmiany w jakimś kawałku kodu powoduje błędy lub uszkodzenia w nieprzewidywalnych innych miejscach systemu (Fragility) 
  • system, w którym komponenty zostały tak zaprojektowane, że są niemożliwe do wyodrębnienia z tego systemu w celu użycia ich w innym systemie (Immobility) 

Oczywiście nie są to jedyne cechy błędnego projektu czy architektury, jednak gdy te w/w występują w projekcie systemu bezspornie można uznać ten projekt za błędy czyli przykład BAD DESIGN.


Enigma2: eServiceCenter - opis i wykorzystanie

, czwartek, 20 września 2012 0 komentarze

W tym artykule umieszczę opis API i wykorzystania dla klasy eServiceCenter.
Klasa eServiceCenter ma zdefiniowaną jedną statyczną funkcję getInstance(), która zwraca obiekt klasy iServiceHandlerPtr.

Obiekt iServiceHandlerPtr daje dostęp do interfejsów umożliwiających określoną obsługę przekazanego jako referencja serwisu:

  • iPlayableServicePtr play(eServiceReference ref)
  • iRecordableServicePtr record(eServiceReference ref)
  • iListableServicePtr list(eServiceReference ref)
  • iStaticServiceInformationPtr info(eServiceReference ref)
  • iServiceOfflineOperationsPtr offlineOperations(eServiceReference ref)


Opis klasy iListableServicePtr, która daje możliwość obsługi serwisu jako listy:
  • [][] getContent(STRING fmt, BOOLEAN sort): pobranie listy podserwisów danego serwisu np. zwraca kanały zgrupowane w bukiet. W przypadku, gdy wybrano zwracanie dokładnie jednej wartości odpowiadającej serwisowi w definicji formatu, każda wartość jest zwracana bezpośrednio jako pozycja listy wynikowej. W przypadku, gdy wybrano zwracanie większej liczby wartości, rezultat składa się z listy tablic (tuple) wartości.
    fmtwymaganyokreślenie formatu i porządku zwracanych danych. Możliwe opcje to:
    RService Reference (as swig object .. this is very slow)
    SService Reference (as python string object .. same as ref.toString())
    CService Reference (as python string object .. same as ref.toCompareString())
    NService Name (as python string object)
    sortopcjonalnyokreśla czy wyniki mają zostać posortowane - domyślnie False
  • eServiceReference getNext(): zwarca informację o następnym serwisie w ramach kursora / iteratora dla listy
  • NUMBER compareLessEqual(eServiceReference ref1, eServiceReference ref2): porównuje ze sobą dwa serwisy i zawraca rezultat w postacji wartości 1 lub 0, gdzie 0 oznacza równość. Priorytet mają katalogi.
  • iMutableServiceList startEdit(): rozpoczyna edycję serwisu katalogowego. Zwraca interfejs umożliwiający akcje edycyjne.


Opis klasy iStaticServiceInformationPtr:
  • STRING getName(eServiceReference ref)
  • NUMBER getLength(eServiceReference ref)
  • eServiceEvent getEvent(eServiceReference ref, NUMBER start_time=-1)
  • BOOLEAN isPlayable(eServiceReference ref, eServiceReference ignore, BOOLEAN simulate=false)
  • NUMBER getInfo(eServiceReference ref, int w)
  • STRING getInfoString(eServiceReference ref, int w): pobierz informację o parametrze serwisu danym jako 'w' jako String. Wartości parametru 'w' zdefiniowane są w klasie iServiceInformation
  • getInfoObject(eServiceReference ref, int w)
  • BOOLEAN setInfo(eServiceReference ref, int w, int v)
  • BOOLEAN setInfoString(eServiceReference ref, int w, STRING v)


Opis klasy iServiceOfflineOperationsPtr:


Opis klasy iRecordableServicePtr:


Opis klasy iPlayableServicePtr:
  • start()
  • stop()
  • setTarget(int target)
  • iSeekableServicePtr seek()
  • iPauseableServicePtr pause()
  • iServiceInformationPtr info()
  • iAudioTrackSelectionPtr audioTracks()
  • iAudioChannelSelectionPtr audioChannel()
  • iSubserviceListPtr subServices()
  • iFrontendInformationPtr frontendInfo()
  • iTimeshiftServicePtr timeshift()
  • iCueSheetPtr cueSheet()
  • iSubtitleOutputPtr subtitle()
  • iAudioDelayPtr audioDelay()
  • iRdsDecoderPtr rdsDecoder()
  • iStreamableServicePtr stream()
  • iStreamedServicePtr streamed()
  • iServiceKeysPtr keys()


Opis klasy iMutableServiceListPtr, która daje możliwość obsługi serwisu jako listy:
  • flushChanges(): zastosowanie wprowadzonych zmian
  • BOOLEAN addService(eServiceReference ref, eServiceReference before): dodanie serwisu do listy przed serwisem 'before'. Funkcja zwraca informację czy powiodło się dodanie serwisu
  • BOOLEAN removeService(eServiceReference ref): usunięcie serwisu z listy. Zwraca czy powiodło się usunięcie
  • BOOLEAN moveService(eServiceReference ref, NUMBER pos): przesuwa serwis na określoną drugim parameterem pozycję listy
  • BOOLEAN setListName(STRING name): ustawienie nazwy dla listy

Enigma2: eEPGCache - opis klasy i wykorzystanie

, 2 komentarze

Artykuł poświęcam opisowi klasy eEPGCache z pakietu Enigma2.

Funkcje i ich znaczenie wraz z API:

1. setCacheFile(String fileName)
Funkcja ustawia wartość ścieżki do pliku wykorzystywanego w ramach załadowania lub zapisania informacji z bazy EPG - patrz: load() i save(). Parametr fileName powinien być typu STRING.

przykład:

eEPGCache.getInstance().setCacheFile('/hdd/epg.dat')


2. save()
Funkcja służy do zapisu zawartości bazy EPG do wskazanego przy pomocy setChacheFile() pliku płaskiego.


3. load()
Funkcja służy do wciągnięcia zawartości pliku płaskiego wskazanego przez setCacheFile() do bazy EPG.


4. startTimeQuery(eServiceReference ref, NUMBER beginTime = -1, NUMBER minutes = -1)
refwymaganyreferencja do serwisu
beginTimeopcjonalnyczas startu dla zdarzeń zwracanych w kursorze; -1 oznacza brak definicji (dowolny)
minutesopcjonalnydługość odcinka czasowego dla zdarzeń zwracanych w kursorze; -1 oznacza brak definicji (dowolny)
Funkcja służy do inicjalizacji kursora przechodzącego po zdarzeniach EPG. Przygotowany przy użyciu tej funkcji kursor zawiera zdarzenia przecinające odcinek czasu zdefiniowany poprzez beginTime i minutes. Jest powiązana z funkcją getNextTimeEntry(), która to funkcja służy do pobrania następnej w kolejności wartości z kursora. Funkcja zwraca wartość -1 w przypadku, gdy kursor jest pusty.

przykład:
if ptr.startTimeQuery(ref) != -1:
    self.session.open(EPGSelection, ref)
else:
    self.session.open(MessageBox, "Sorry no epg currently available for this service.", MessageBox.TYPE_INFO)


5. eServiceEvent getNextTimeEntry()
Funkcja zwraca następną w kolejności wartość z kursora zainicjalizowanego przez startTimeQuery(). Wywołanie funkcji możliwe jest jedynie po wcześniejszym zainicjalizowaniu.


6. eServiceEvent lookupEventTime(eServiceReference ref, NUMBER begin, NUMBER direction)
refwymaganyreferencja do serwisu
beginopcjonalnyokreślenie horyzontu czasowego dla wyszukiwania zdarzenia; -1 oznacza bieżącą datę
directionopcjonalnydefinicja kierunku przeszukiwania - wartości [-1,0,1]

Funkcja przeszukuje EPG w celu znalezienia zdarzenia dla określonego przez ref serwisu. Zwracane w wyniku działania funkcji jest zdarzenie poprzednie (direction=-1), bieżące (direction=0) lub następne (direction=1) dla horyzontu czasowego określonego przez parametr begin. W przypadku ustawienia parametru begin na wartość -1, brana jest bieżąca data jako horyzont czasowy.

przykład:
queryTime=self.begin+(self.end-self.begin)/2
rec_ref = self.session.nav.getCurrentlyPlayingServiceReference()
evt = eEPGCache.getInstance().lookupEventTime(rec_ref, queryTime)

epg = eEPGCache.getInstance()
ref = self.session.nav.getCurrentlyPlayingServiceReference()
ptr = ref and ref.valid() and epg.lookupEventTime(ref, -1)
ptr = epg.lookupEventTime(ref, ptr.getBeginTime(), +1)
event = epg.lookupEventTime(serviceref, -1, 0)

def getEvent(self):
    service = self.navcore.getCurrentService() 
    info = service and service.info() 
    ret = info and info.getEvent(self.now_or_next) 
    if not ret and info:
        refstr = info.getInfoString(iServiceInformation.sServiceref)
        ret = eEPGCache.getInstance().lookupEventTime(eServiceReference(refstr), -1, self.now_or_next and 1 or 0)
    return ret


7. eServiceEvent lookupEventId(eServiceReference ref, NUMBER event_id)
refwymaganyreferencja do serwisu
event_idwymaganyidentyfikator zdarzenia do wyszukania
Funcja służy do wyszukania w podanym serwisie zdarzenia o określonym parametrem identyfikatorze.

przykład:
event = eEPGCache.getInstance().lookupEventId(service.ref, eventid)


8. [][] lookupEvent([STRING fmt, (eServiceReference ref, NUMBER queryType, NUMBER pe1, NUMBER pe2)])
fmtwymaganyFormat zwracanych danych - opis niżej
refwymaganyreferencja do serwisu
queryTypewymaganytyp zadawanego zapytania - możliwe wartości w tabeli poniżej
pe1wymaganyparametr dodatkowy 1 - zależny od kontekstu ustawionego przez queryType - tabela poniżej
pe2opcjonalnyparametr dodatkowy 2 - zależny od kontekstu ustawionego przez queryType - określa koniec zakresu czasowego - tabela poniżej

Tabela możliwych wartości pola formatu:
WARTOŚĆOPIS
0PyLong(0)
IEvent Id (id zdarzenia)
BEvent Begin Time (czas rozpoczęcia zdarzenia)
DEvent Duration (czas trwania zdarzenia)
TEvent Title (tytuł zdarzenia)
SEvent Short Description (krótki opis zdarzenia)
EEvent Extended Description (rozszerzony opis zdarzenia)
CCurrent Time (bieżący czas)
RService Reference (referencja do serwisu)
NService Name (nazwa serwisu)
nShort Service Name (krótka nazwa serwisu)
XFlaga nie związana ze zwracanym rezultatem określająca, że zwracana ma być minimum jedena pozycja w tabeli wynikowej odpowiadająca każdemu serwisowi nawet, gdy nie znaleziono zdarzeń dla serwisu. W przypadku, gdy nie znaleziono zdarzeń w wynikowym wierszy tabeli wartości nieokreślone są zwracane jako None

Opis parametrów związanych z typem zapytania:
TYPOPISPE1PE2
2zapytanie o identyfikator zdarzeniawartość identyfikatora zdarzeniaNiedotyczy
-1zapytanie o zdarzenia przed określonym parametrem pe1 czasemhoryzont czasowy dla wyszukania (-1 - obecna data)data określająca datę końca dla zakresu przeszukiwania
0zapytanie o zdarzenia przecinające określony parametrem pe1 czashoryzont czasowy dla wyszukania (-1 - obecna data)data określająca datę końca dla zakresu przeszukiwania
+1zapytanie o zdarzenia po określonym parametrem pe1 czasiehoryzont czasowy dla wyszukania (-1 - obecna data)data określająca datę końca dla zakresu przeszukiwania

Funkcja służy do wyszukiwania informacji o zdarzeniach dla podanych parametrów. Informacja zwracana jest w postaci tablicy dwuwymiarowej, gdzie pierwszy wymiar definiuje poszczególne elementy kursora (wyszukane zdarzenia), a drugi wymiar to wartości odpowiadające zdarzeniu które są określone polem Format (dane pojedynczego zdarzenia). Pola czasowe typu NUMBER definiowane są jako liczba sekund od daty EPOCH (w systemach unixowych początek roku 1970).

Przykłady:
events = eEPGCache.getInstance().lookupEvent(['IBDTSENC', (ref, 0, begintime, endtime)])

search = ['IBDCTSERNX']
if services: # It's a Bouquet
    search.extend([(service, 0, -1) for service in services])
events = eEPGCache.getInstance().lookupEvent(search)

search = ['IBDCTSERNX']
if services: # It's a Bouquet
    search.extend([(service, 0, -1) for service in services])
events = eEPGCache.getInstance().lookupEvent(search)
print 'The first event duration: %s'%(str(events[0][2]))

event = eEPGCache.getInstance().lookupEvent(['ESX', (ref, 2, int(idev))])


9. [][] search((STRING fmt, NUMBER size, NUMBER queryType, pe1, pe2))
fmtwymaganyFormat zwracanych danych - opis niżej
sizewymaganymaksymalna liczba zwróconych wierszy
queryTypewymaganytyp zadawanego zapytania - możliwe wartości w tabeli poniżej
pe1wymaganyparametr dodatkowy 1 - zależny od kontekstu ustawionego przez queryType - tabela poniżej
pe2opcjonalnyparametr dodatkowy 2 - zależny od kontekstu ustawionego przez queryType


Tabela możliwych wartości pola formatu:
WARTOŚĆOPIS
IEvent Id (id zdarzenia)
BEvent Begin Time (czas rozpoczęcia zdarzenia)
DEvent Duration (czas trwania zdarzenia)
TEvent Title (tytuł zdarzenia)
SEvent Short Description (krótki opis zdarzenia)
EEvent Extended Description (rozszerzony opis zdarzenia)
RService Reference (referencja do serwisu)
NService Name (nazwa serwisu)
nShort Service Name (krótka nazwa serwisu)

Opis parametrów związanych z typem zapytania:
TYPOPISPE1PE2
0wyszukaj zdarzenia podobne (SIMILAR_BROADCASTINGS_SEARCH)referencja do serwisu w postaci stringaidentyfikator zdarzenia
1wyszukaj zdarzenia o określonym dokładnie tytule (EXAKT_TITLE_SEARCH)tekst do wyszukania
  • 0 = wielkość liter ma znaczenia (CASE_CHECK)
  • 1 = wielkość liter nie ma znaczenia (NO_CASECHECK)
2wyszukaj zdarzenia zawierające tekst w tytule (PARTIAL_TITLE_SEARCH)tekst do wyszukania
  • 0 = wielkość liter ma znaczenia (CASE_CHECK)
  • 1 = wielkość liter nie ma znaczenia (NO_CASECHECK)

Funkcja służy do wyszukiwania informacji o zdarzeniach dla podanych parametrów. Informacja zwracana jest w postaci tablicy dwuwymiarowej, gdzie pierwszy wymiar definiuje poszczególne elementy kursora (wyszukane zdarzenia), a drugi wymiar to wartości odpowiadające zdarzeniu które są określone polem Format (dane pojedynczego zdarzenia).

Przykład:
l = eEPGCache.getInstance().search(('RIBND', 1024, eEPGCache.SIMILAR_BROADCASTINGS_SEARCH, refstr, event_id))


W ramach wykorzystania klasy eEPGCache polecam zapoznać się z klasami:

--- Component.ServiceList !!
--- ServiceReference
--- enigma.eServiceEvent
--- Navigation.Navigation
--- enigma.iStaticServiceInformationPtr
--- enigma.iServiceInformationPtr

Enigma2: Opis kodów dla parametru flag w pliku keymap.xml

, piątek, 31 sierpnia 2012 0 komentarze

Poniżej zestawienie znaczeń związanych z parametrem flag dla pojedynczej pozycji z pliku keymap.xml definiującego mapowanie klawiszy pilota na odpowiednie akcje enigmy.

m - MAKE - normalne naciśnięcie klawisza - zdarzenie obsługiwane raz po naciśnięciu
l - LONG - długie naciśnięcie klawisza - zdarzenie obsługiwane raz po 5-ciu powtórkach, powtórki są obsługiwane do zwolnienia
b - BREAK - zwolnienie klawisza - zdarzenie obsługiwane raz po zwolnieniu klawisza
r - REPEAT - powtarzanie włączone / klawisz zablokowany - zdarzenie obsługiwane po m wielokrotnie do czasu zwolnienia klawisza

Dobrą praktyką jest otwieranie okien dialogowych z użyciem flagi b zamiast m.

Enigma2 - tworzenie pakietów OPKG

, poniedziałek, 20 sierpnia 2012 0 komentarze

W tym artykule opiszę proces tworzenia i przeglądania pakietów OPKG, czyli plików z rozszerzeniem IPK. Na początek informacja w jaki sposób rozpakować pakiet. Powiedzmy, że chcemy podejrzeć zawartość pakietu enigma.ipk. W tym celu należy wykonać następujące kroki:

1. Utwórz katalog tymczasowy:

mkdir ./tmp

2. Wejdź do katalogu tmp:

cd tmp

3. Rozpakować zawartość pakietu IPK:

ar -ox ../enigma2.ipk

4. Rozpakować zawartość archiwów:

gunzip ./*.tar.gz

5. Wypakować pliki TAR:

tar xf ./data.tar
tar xf ./control.tar

6. Usunąć pliki TAR:

rm *.tar

Jeżeli chodzi o strukturę pakietu OPKG to jest ona następująca:

package.opk (ar)
+- debian-binary (text)
+- control.tar.gz (tarball)
...+- control (text)
...+- preinst (script)
...+- postinst (script)
...+- prerm  (script)
...+- postrm (script)
+- data.tar.gz (tarball)
...+- system
......+- bin
.........+- opkg-hello (program)

W strukturze jest stały plik tekstowy debian-binary, następnie spakowane skrypty kontrolne control.tar.gz, a następnie spakowane archiwum docelowe, czyli dane data.tar.gz.
Teraz przejdziemy do procesu tworzenia pakietu. W celu utworzenia pakietu wykonujemy:

1. Tworzymy katalog tmp

mkdir ./tmp

2. Wchodzimy do katalogu tmp:

cd tmp

3. Tworzymy plik tekstowy debian-binary z zawartością "2.0"
4. Tworzymy pliki kontrolne i pakujemy je do archiwum control.tar.gz. Do tworzenia archiwum TAR.GZ uzywany komendy:

tar zcvf control.tar.gz LISTA PLIKÓW/KATALOGÓW

5. Pliki danych pakujemy z docelową strukturą katalogową do data.tar.gz
6. Tworzymy pakiet przy użyciu komendy:

ar -r enigma2.ipk LISTA PLIKÓW/KATALOGÓW

Poniżej znajdują się przykładowe zawartości skryptów kontrolnych.

1. Skrypt control:

Package: enigma2-plugin-extensions-sample                                                                             
Version: 1.2-rc1                                                                                                                  
Description: My Sample Plugin                                                                                 
Maintainer: MASL                                                                                      
Section: base                                                                                                                     
Architecture: mipsel                                                                                                              
Priority: optional                                                                                                                
Homepage: xxxxxx                                                                                                                  
Depends: enigma2                                                                                                                  
Source: xxxxx

2. Skrypt postinst:

#!/bin/sh                                                                                                                         
echo ""                                                                                                                           
echo "********************************************************"                                                                   
echo "*  My Plugin                              *"                                                                       
echo "*  Support:  masl@xxx.pl                *"                                                                             
echo "*  Mod by MASL (c) 2012     *"                                                                                  
echo "********************************************************"                                                                   
echo ""                                                                                                                           
echo "Sample Plugin successfully installed! You should restart enigma2 now"                                                          
echo ""                                                                                                                           
exit 0  

2. Skrypt postrm:

#!/bin/sh                                                                                                                                                                                                                                                        rm -rf /usr/lib/enigma2/python/Plugins/Extensions/SamplePlugin                                                              
echo "Plugin removed! You should restart enigma2 now!"                                                                                                                                                                                                        
exit 0


GlossyBlue Blogger by Black Quanta. Theme & Icons by N.Design Studio
Entries RSS Comments RSS