FlexPaginator Released! ;)

Chyba każdy programista zetknął się z problemem paginacji czy to na tworzonej przez siebie stronie internetowej, czy też(jak w moim przypadku) w aplikacji flex-owej.
W rozwiązaniach tworzonych w pracy zazwyczaj duże ilości danych prezentowałem za pomocą kontrolki DataGrid w połączeniu z paginatorem udostępnionym pod adresem – link. Jednak wciąż rosnąca ich ilość szybko sprawiła, że wygrzebana w czeluściach internetu kontrolka przestała spełniać oczekiwania. Postanowiłem zmierzyć się z paginacją i stworzyć samodzielnie komponent, który znacznie ułatwił by, a w szczególności przyśpieszył poruszanie się po tysiącach stron udostępnianych danych. Właściwie żeby być szczerym do rozpoczęcia pracy nad kontrolką zachęcił mnie Redliquid, a jej obecny wygląd-funkcjonalność jest w 100% jego pomysłem. :) Zaprezentowany flex-paginator jest zbudowany jeszcze na bazie kontrolek udostępnianych we Flex-ie 3 – planuję jednak jego dalszy rozwój, a więc poprawę wszelkich znalezionych błędów ;), a przy odrobinie większej ilości wolnego czasu przepisanie całości z wykorzystaniem dobrodziejstw Flex-a 4.

Diabeł tkwi w szczegółach, a więc poniżej prezentuję opis kilku najważniejszych opcji FlexPaginator-a.

Do pliku swc paginatora niezbędne jest dołączenie pliku css o nazwie StyleButtons.css, który odpowiada za wygląd wszystkich przycisków. Najważniejsze właściwości paginatora, które powinny zostać ustawione
w kodzie ActionScript lub po stronie mxml-a to:

  • totaItems – ilość wszystkich elementów
  • itemsPerPage – ilość elementów wyświetlanych na stronie
  • pageToDisplay – ilość wyświetlonych przycisków z numerami stron – ustawienie parzystej liczby wyświetlanych stron, skutkuję zamianę jej na nieparzystą ich ilość (takie „zachowanie” wynika z działania paginatora)

Opcjonalna jest natomiast właściwość:

  • selectedPage – numer zaznaczonej strony, po utworzeniu kontrolki domyślnie zostaje zanaczona środkowa strona/przycisk spośród aktualnie wyświetlonych.

Moja kontrolka paginacji zawiera przyciski umożliwiające odpowiednio:

  • skok o jedną stronę do przodu lub do tyłu
  • skok o wybraną ilość stron – wartości w wyświetlonym menu są wygenerowane automatycznie, ta para przycisków pojawia się tylko w przypadku gdy całkowita ilość stron przekracza 50.
  • skok na koniec i początek.

Dodatkowo obsługa zdarzenia „selectedPageChanged” daje możliwość odczytu aktualnie zaznaczonej strony. Wygenerowany paginator wyświetla nieparzystą liczbę stron,
a aktualnie zanaczony numer strony jest podkreślony

Przykładowy kod z zaznaczoną stroną nr 3 oraz plik css odpowiadający za poniższy wygląd paginatora pod linkiem

Wszelkiego rodzaju błędy, sugestię co mogę poprawić lub co zrobiłem tragicznie proszę zgłaszać na code-google (gdzie udostępnie kod projektu oraz plik swc – zakładka Download) lub w komentarzach pod tym czy też kolejnymi wpisami dotyczącymi FlexPaginator-a. ;)

DataGrid z pogrubioną zawartością wierszy

Podczas pracy nad pewną funkcjonalnością musiałem pogrubić zawartość wybranych wierszy w datagrid-zie. „Decyzja” o pogrubieniu zawartości danego wiersza miała być zawarta w każdym pojedyńczym obiekcie dostarczonym do datagrid-a w postaci tablicy (Array). Wewnątrz takiego obiektu zawarta zostanie właściwość „mówiąca” o pogrubieniu.

Przykładowa klasa zawierająca informację każdego wiersza w datagrid-zie mogła by wyglądać następnująco (właściwość „isSpecial” decyduję o pogrubieniu):

public dynamic class PersonVo
{
		public var name:String;
		public var surname:String;
		public var email:String;

  /**
		 * If this property is true, row in DataGrid is bold
		 *
		 * @var Boolean
		 * */
		public var isSpecial:Boolean;

		private var _date:Date;

		/**
		 * Get formatted date
		 *
		 * @retrun String
		 * */
		public function get dateStr():String
		{
			var dateFormatter:DateFormatter = new DateFormatter();
			dateFormatter.formatString = "DD-MM-YYYY";

			return dateFormatter.format(_date);
		}

		public function set dateStr(value:String):void
		{
			_date = DateFormatter.parseDateString(value);
		}

		public function PersonVo(name:String = null, surname:String = null,
					date:Date = null, email:String = null, isSpecial:Boolean = false)
		{
			this.name = name;
			this.surname = surname;
			this._date = date;
			this.email = email;
			this.isSpecial = isSpecial;
		}
}

Następnie należy utworzyć DataGrid-a wraz z kolumnami wyświetlającymi informację, którymi jesteśmy zainteresowani oraz itemrenderer w którym obsłużone zostanie pogrubienie poszczególnych wierszy. Kod mojego przykładowego datagrid-a zawiera kolumnę „Imię i nazwisko” łączącą dwie właściwości z klasy PersonVo za pomocą funkcji anonimowej, email oraz sformatowaną datę urodzenia.

<?xml version="1.0" encoding="utf-8"?>
<mx:DataGrid xmlns:fx="http://ns.adobe.com/mxml/2009"
				 xmlns:s="library://ns.adobe.com/flex/spark"
				 xmlns:mx="library://ns.adobe.com/flex/mx"
				 itemRenderer="{new ClassFactory(DGItemRenderer)}">
	<mx:columns>
		<!--This simple anonymous function in DataGridColumn concatenates two string: name and surname from value object-->
		<mx:DataGridColumn headerText="Imię i Nazwisko"
		labelFunction="{function(personVo:PersonVo,
									dgColumn:DataGridColumn):String
						{return personVo.name + ' ' + personVo.surname; }}"
						   width="200"/>
		<mx:DataGridColumn headerText="Email"
						   dataField="email"
						   width="250"/>
		<mx:DataGridColumn headerText="Data urodzenia"
						   dataField="dateStr"
						   width="120"/>
	</mx:columns>
	<fx:Script>
		<![CDATA[
			import dataGridItermRenderers.DGItemRenderer;
			import vo.PersonVo;
		]]>
	</fx:Script>
</mx:DataGrid>

Najważniejsza część całej zabawy-jest klasa itemrenderera zawierająca przesłoniętą właściwość „data”. W jej wnętrzu sprawdzany jest typ dostarczonej wartości ponieważ podczas tworzenia DataGrida przekazywane są do niej obiekty poszczególnych kolumn, którymi nie byłem zainteresowany. W dalszej kolejności właściwość wykonuję się przy wypełnieniu każdej komórki poszczególnych kolumn co jak widać daję możliwość sterowania wyglądem ich zawartości poprzez ręczne ustawienie styli.

public class DGItemRenderer extends DataGridItemRenderer
{
		public function DGItemRenderer()
		{
			super();
		}

		/**
		 * Property is execute on each column in each row
		 *
		 * @param PersonVo|Object value Object using in item renderer
		 */
		override public function set data(value:Object):void
		{
			if (value is PersonVo && value)
			{
				//In this property i check if PersonVo is special
				//When isSpecial == true i bold cell in this column
				var boldValue:String = (PersonVo)(value).isSpecial == true ? "bold" : "normal";
				setStyle("fontWeight", boldValue);
			}
			super.data = value;
		}
}

Wynikiem tych zabiegów są oczekiwane pogrubione zawartości wierszy w DataGridzie. link

Dlaczego używam eclipse w wersji 3.3

Środowisko eclipse wykorzystuję do programowania w języku php – Zend Framework. Od ponad pół roku jest to niezmiennie leciwa już wersja 3.3. Dlaczego nie zmieniłem jej na nowszą np. 3.5? Skłoniły mnie do tego zaledwie dwie jakże istotne dla mnie kwestie. Zastrzegam jednak, że być może to co tutaj zaprezentuję wynika z mojej niewiedzy związanej z eclipse, liczę więc na ewentualny „odzew”. :)

Rozważmy następujące kody dwóch przykładowych klas:

class SampleClass
{
	public function __construct()
	{

	}

	/**
	 * Przykladowa funkcja
	 *
	 * @param String $str Obiekt string
	 * @param array $arr Obiekt array
	 * @param String|array $obj Obiekt mieszany
	 *
	 * @return array
	 */
	public function myFunction($str, $arr, $obj)
	{
		return array('str' => $str, 'arr' => $arr, 'obj' => $obj);
	}
}

class MyClass
{
	/**
	 * Przykladowa klasa
	 *
	 * @var SampleClass
	 */
	private $_sampleClass;

	public function __construct()
	{
		$this->_sampleClass = new SampleClass();
		$this->_sampleClass->myFunction('str', array('arr' => 'dd'), 'str2');
	}
}

W zasadzie nic nadzwyczajnego. W jednej klasie przykładowa metoda, w drugiej natomiast utworzenie instancji klasy oraz wywołanie metody „myFunction”. Wszystko opatrzone w odpowiednie komentarze.

Dwa powody dla których nie zrezygnuję ze starego poczciwego eclipse 3.3:

Powód I:

Podczas korzystania z utworzonej wcześniej instancji klasy wywołanie metody sprowadza się do wpisania strzałki tuż po nazwie obiektu. Taka operacja skutkuję piękną chmurką prezentującą listę metod czy też zmiennych danej klasy.

Eclipse w wersji 3.5 „wypluwa” owe podpowiedzi niezwykle wolno Od momentu pojawienia się strzałki do chwili „wyplucia” listy metod i zmiennych mija katastrofalnie dużo czasu!!!! Osobiście piszę bardzo szybko na klawiaturze przez co jakiekolwiek opóźnienie w pojawieniu się podpowiedzi jest niezwykle irytujące. Żadnych efektów poprawiających powyższy stan rzeczy nie przynosi ustawienie opóźnienia autoaktywacji na 1 czy też 0 milisekund w opcjach znajdujących się: Window->Preferences->PHP->Editor-CodeAssist.

Całkowicie inaczej wygląda to w Eclipse 3.3. Tam niemal każde „strzałkowe” odwołanie powoduję natychmiastową podpowiedz.

Powód II:

Poniżej przedstawiam szereg screenów ukazujących proces wywołania metody „myFunction” z klasy „SampleClass” w eclipse 3.3 oraz 3.5.

Eclipse 3.5:

wywolanie_metody_3_5

Eclipse 3.3:

wywolanie_metody_3_3

uzupelnienie_arg_3_5

uzupelnienie_arg_3_3

Faktem jest, że język php nie jest językiem silnie typowanym, więc teoretycznie każda przekazywana wartość do metody „myFunction” może być dowolnego typu. O ile w obu omawianych przeze mnie wersjach eclipse, chmurki zawierające opis metody i parametrów wyglądają identycznie o tyle już sam proces uzupełniania wartościami argumentów funkcji jest nieco inny. Eclipse 3.3 także na tym etapie sugeruję jakiego typu powinny być wartości parametrów przekazywane do metody. Niestety zabrakło tego w nowszym wydaniu i od dawna nic się w tej kwestii nie zmienia.

Być może eclipse 3.5 gdzieś w swoim gąszczu ustawień konfiguracyjnych zawiera opcję, które pozwalają zrównać tą wersję w wygodzie użytkowania do eclipse 3.3 niestety jak dotąd nie było mi dane ich odnaleźć. Ubolewam nad tym faktem ponieważ niektóre najnowsze wersję wykorzystywanych przeze mnie eclipsowych pluginów odmawiają już współpracy z wersją 3.3.

Szybkość oraz wygoda jaką ze sobą niosą powyższe opcję sprawia, że wciąż kurczowo trzymam się eclipse 3.3.

Błąd podczas uruchamiania Eclipse "JVM terminated. Exit code=13"

Ściągnąłem Eclipse w wersji 3.3 następnie rozpakowałem archiwum do folderu o nazwie „eclipse 3.3″. Podczas pierwszego uruchomienia otrzymałem dość interesujące „powitanie” – widoczne na screen-ie poniżej.

JVM terminated. Exit code=13

Okazuję się, że problem stanowiła tutaj nazwa folderu w którym umieściłem eclipse – jej zmiana przyniosła porządany efekt. Trywialne, ale dłuższą chwilę zajęło mi dotarcie do rozwiązania. :)

Generowanie pliku csv na podstawie tabeli w bazie danych

Format CSV jest prostym sposobem przechowywania danych w pliku tekstowym. Polega na zapisie kolejnych wartości wierszy pobranych z arkusza kalkulacyjnego bądź z bazy danych odzielając je określonym separatorem (najczęściej jest to przecinek bądź średnik). Wygenerowany plik CSV często zawiera w pierwszym wierszu nazwy kolumn. MySql dzięki funkcji „Concat_Ws” pomaga w trywialny sposób zwrócić dane sformatowane dane do postaci pliku csv.

Utworzyłem tabelę „person” której strukturę wraz z przykładowymi danymi prezentuję poniżej:

Tabela do wygenerowania pliku csv

Oczekiwana postać pliku to – linia pierwsza reprezentująca nazwy kolumn, kolejne linie zawierające pobrane dane jako separator zostanie użytyh przecinek.

Zapytanie formatujące dane:

SELECT CONCAT_WS(',', name, surname, age) AS 'Imię, Nazwisko, Wiek' FROM person

Funkcja „Concat_Ws” jako jeden z argumentów przyjmuje separator którym oddzieli zwracane wyniki. Nazwa kolumny w zapytaniu jest odpowiednikiem pierwszego wiersza
z pliku csv.

Wynik zapytania:

Wynik zapytania

Wewnątrz skryptu tworzącego csv wystarczy już tylko przeiterować po otrzymanych wynikach zapisując je do oczekiwanego pliku. :)

Porównywanie dat w ActionScript

Implementując pewną funkcjonalność stanąłem przed prostym problemem porównania dwóch dat. W ActionScript do tego celu służy klasa ObjectUtil,
a w niej metoda compareDate.

public static function dateCompare(a:Date, b:Date):int
{
				if (a == null && b == null)
					return 0;

				if (a == null)
					return 1;

				if (b == null)
					return -1;

				var na:Number = a.getTime();
				var nb:Number = b.getTime();

				if (na < nb)
					return -1;

				if (na > nb)
					return 1;

				return 0;
}

Jam można zauwazyć wewnątrz metody daty porównywane są na podstawie zwróconej ilości milisekund od roku 1970 metodą getTime. Potrzebowałem jednak czegoś bardziej specyficznego, mianowicie chciałem porównać daty pomijając przy tym czas (godziny, minuty itd.). Utworzyłem w tym celu nową metodę w której trzeci parametr określa taką możliwość.

public function compareDate(a:Date, b:Date, compareWithTime:Boolean=false):int
{
				var aa:Date;
				var bb:Date;

				if (a == null && b == null)
				{
						return 0;
				}

				if (a == null)
				{
						return 1;
				}

				if (b == null)
				{
						return -1;
				}

				if (compareWithTime)
				{
						return ObjectUtil.dateCompare(a, b);
				}
				else
				{
						//porownanie bez czasu
						//tworze nowe obiekty dat wylaczajac przy tym czas
						aa = new Date(a.fullYear, a.getMonth(), a.getDate());
						bb = new Date(b.fullYear, b.getMonth(), b.getDate());

						return ObjectUtil.dateCompare(aa, bb);
				}
}

Przeprowadziłem test dla dwóch dat i otrzymałem następujące wyniki:

var dOne:Date = new Date(2010, 2, 20, 12, 12, 12);
var dTwo:Date = new Date(2010, 2, 20, 12, 11, 12);

var resultOne:int = compareDate(dOne, dTwo, false);
var resultTwo:int = compareDate(dOne, dTwo, true);

//resultOne = 0; dOne = dTwo
//resultTwo = 1; dOne > dTwo

Żegnaj .NET World…

Po wielomiesięcznej przerwie postanowiłem odświeżyć „przyjaźń” z moim blogiem. Ten oto wpis jest prawdopodobnie końcem pewnego etapu w moim programistycznym życiu.

Pierwsza zmiana jest taka, że znalazłem, a właściwie to ona mnie znalazła, pracę. Kilka miesięcy temu stanąłem przed realnym wyborem swojej ścieżki zawodowej – pozostanie przy technologii .NET czy rozpoczęcie nauki czegoś dość odmiennego?? Podobno jeżeli ktoś potrafi programować to bez problemu nauczy się dowolnego języka (w granicach rozsądku ;)) czy też z łatwością zgłębi tajniki nowej technologii.

Mogę na dzień dzisiejszy śmiało powiedzieć, że jest to w sporej części prawda, bo oto przez ostatnie miesiące z ogromną przyjemnością zajmuję się implementacją aplikacji internetowych przy użyciu technologii dostarczanej przez firmę Adobe – Flex.

Druga zmiana wynikająca z pierwszej to moja decyzja o pozostaniu przy tym czym się aktualnie zajmuję. Platforma .NET oraz wszystko czego się nauczyłem obcując z technologiami Microsoft-u pozostanie już raczej tylko moim „hobby”. Jak dotąd nie żałuję rzucenia się na głęboką wodę i oby nic mojego dobrego samopoczucia wynikającego z obecnej pracy nie zmieniło. Trzecia zmiana jest konsekwencją pożegnania i dotyczy nie tylko nowej tematyki zamieszczanej tutaj treści, ale także samego tytułu który tak radośnie witał wszystkich odwiedzających moje skromne blogowe progi. ;) Myślę jednak, że jeszcze zdarzy mi się jak już wyżej napisałem „hobbystycznie” wspomnieć o swoich .NET-owych korzeniach.

Na koniec chciałbym podziękować społeczności skupiającej się wokół portalu codeguru.pl, mojemu nauczycielowi „Języków programowania”, dzięki któremu robię to co robię…

Dziękuję również koledze bojkar-owi, dzięki któremu się nie poddałem oraz koledze redliquid-owi, który swoim przykładem zachęca mnie każdego dnia w pracy do ciągłego pogłębiania wiedzy. :)

Żegnaj .NET World! Witaj nowe, nieznane… :)

Prosty błąd – proste rozwiązanie

Zmagam się od jakiegoś czasu z ASP .NET Web Service-ami. Utworzyłem nowy Web Service i postanowiłem zmienić nazwę pliku Web Servicu ze standardowego Service1 na ServiceAdmin. Zmiana przebiegła bezproblemowo po uruchomieniu otrzymałem taki oto błąd:

webserviceerror

Zgodnie ze wskazówkami błędu swoją uwagę skierowałem na plik .asmx – standardowo kliknąłem dwukrotnie w Visual Studio oczekując na pojawienie się magicznej xml-owej linijki. Niestety Visual Studio przekierował mnie do kodu Web Servicu. Po dobrych 10 minutach moje mało spostrzegawcze oczy po kliknięciu prawym przyciskiem myszy na plik ujrzały opcję: Open With… -> XML Editor:

<%@ WebService Language="C#" CodeBehind="ServiceAdmin.asmx.cs" Class="WBAdmin.Service1" %>

Visual Studio nie zrefaktorował atrybutu „Class” – wprowadziłem ręcznie to czego potrzebował kompilator podczas uruchamiania.

<%@ WebService Language="C#" CodeBehind="ServiceAdmin.asmx.cs" Class="WBAdmin.ServiceAdmin" %>

W przeglądarce ujrzałem magiczne „Hellow World”. ;)

Zewnętrzne źródło danych w raportach MS Access

Podczas praktyk studenckich które odbyłem kilka tygodni temu zapoznałem się z możliwościami tworzenia raportów w Microsoft Access. Pracowałem nad rozwoje oprogramowania raportującego. Jednym z postawionych przede mną zadań było stworzenie mechanizmu umożliwiającego wywoływanie procedur składowanych z MS SQL Server i podpięcie otrzymanych wyników do utworzonych wcześniej raportów. Uzyskane wyniki miałem „zapakować” w Visual Basic-owy twór zwany RecordSet-em i podpiąć go bezpośrednio do raportu.

Uruchomienie procedury składowanej z poziomu MS Access utworzonej np. w MS SQL Server umożliwia tzw. kwerenda przekazująca. Cały ciężar związaną z wykonaniem zapytania czy też wspomnianej już procedury składowanej spada na „barki” silnika bazodanowego do którego zostanie wysłane polecenie. Mamy proste narzędzia do tworzenia raportów w MS Access – natomiast filtrowanie i przechowywanie ogromnych ilości danych przed udostępnienem ich w raporcie pozostawiamy większemu silnikowi bazodanowemu. – I to wszystko dzięki magicznej kwerendzie przekazującej. :)

Kod tworzący tymczasowo taką kwerende i jej wywołanie przedstawia się następująco:

Funkcja tworząca i wykonująca zapytanie SQL lub procedure składowaną.

'qSQL = Zapytanie do bazy danych
'return RecordSet
Public Function ExecutePassThruQuery(qSQL As String) As Recordset
    Dim db As DAO.Database
    Dim qryDef As DAO.QueryDef
    Dim recSet As DAO.Recordset
    Dim queryName As String

    On Error GoTo ErrorHandling:
    'Obiekt bazy danych
    Set db = CurrentDb

    'Nazwa tymczasowej kwerendy przekazujacej
    queryName = "tempQuery"
    'Usuniecie kwerendy jesli istnieje
    RemovePassThruQueryIfExists (queryName)

    'Utworzenie nowej kwerendy przekazujacej
    Set qryDef = db.CreateQueryDef(queryName)

    qryDef.ReturnsRecords = True
    'polaczenie z baza danych
    qryDef.Connect = connectionString
    qryDef.SQL = qSQL

    'Zwraca obiekt Recordset-u z danymi, w przeciwnym wypadku zwraca Nothing
    Set ExecutePassThruQuery = qryDef.OpenRecordset(dbOpenSnapshot)

    Set db = Nothing
    Set qryDef = Nothing
    Set recSet = Nothing

    Exit Function
ErrorHandling:
    MsgBox Err.Description
End Function

Funkcja wywołująca pracedure składowaną (wykorzystuje powyższą funkcję do utworzenia i wywołania bezpośrednio na bazie danych procedury) – wzasadzie tworzy specyficzny string w postaci np. „nazwa_procedury parametr1, parametr2, parametr3″.

'params = kolekcja parametrow procedury skladowanej jesli jakies przyjmuje
'procName = nazwa procedury skladowanej
'return DAO.RecordSet
Public Function CallStoredProcedure(procName As String, params As Collection) As Recordset
    Dim recSet As DAO.Recordset
    Dim queryName As String
    Dim counter As Integer

    On Error GoTo ErrorHandling:

    queryName = "tempQuery"

    'Dolaczam parametry do procedury
    If Not params Is Nothing Then
        If params.Count > 0 Then
            procName = procName & " " & CStr(params(1))
            For counter = 2 To params.Count
                procName = procName & ", " & CStr(params.Item(counter))
            Next counter
        End If
    End If

    'Wywoluje Funkcje zwracajaca rezultat wykonanej procedury skladowanej
    Set recSet = ExecutePassThruQuery(procName)

    Set CallStoredProcedure = recSet

    Set recSet = Nothing

    Exit Function
ErrorHandling:
    MsgBox Err.Description
End Function

Dodatkowo utworzyłem procedurę usuwającą tymczasową kwerende przekazującą.

'Usuwa tymczasowa kwerende
'queryName = nazwa kwerendy do usuniecia
Private Sub RemovePassThruQueryIfExists(queryName)
    Dim qryDef As QueryDef
    Dim db As Database

    On Error GoTo ErrorHandling
    Set db = CurrentDb

    For Each qryDef In db.QueryDefs
        If qryDef.Name = queryName Then
            db.QueryDefs.Delete (qryDef.Name)
            Exit For
        End If
    Next

    Set qryDef = Nothing
    Set db = Nothing
    Exit Sub
ErrorHandling:
    MsgBox Err.Description
End Sub

Załóżmy, że wywoływana procedura składowana w MS SQL Server ma nazwę „mojaProcedura” i pobiera dwa parametry typu VARCHAR. Wartości parametrów które chcemy przekazac do procedury są następujące: param1 = „ala”, param2 = „ola”. Kwerenda przekazująca w swoim wnętrzu miała by string w takiej oto postaci: „mojaProcedura ala, ola”.

Wywołanie:

Dim recSet As DAO.Recordset
Dim col As New Collection

col.Add "ala"
col.Add "ola"

Set recSet = CallStoredProcedure "mojaProcedura", col

W zasadzie to wszystko – tyle wystarczy, aby otrzymac obiekt RecordSet-u który następnie możemy bez żadnych przeszkód podpiąć do utworzonego wcześniej w MS Access raportu. :)

To co dała mi praktyka i to czego nie dała mi szkoła

Majowym wpisem pod tytułem „Pierwsza praca” rozpocząłem poszukiwania miejsca gdzie mógłbym odbyć praktykę zawodową. Wiele firm zajmujących się produkcją oprogramowania realizuje programy letnich praktyk studenckich skierowane do studentów ostatnich lat studiów. Kierując się bardzo pomocnymi komentarzami pod wspomnianym wyżej wpisem rozpocząłem wysyłanie CV. Zakładałem, że na drodze do upragnionych pierwszych poczynań programistycznych stanie mi rozmowa kwalifikacyjna (to raczej naturalne), problem znalezienia lokum w mieście do którego się udam itd. – Jednak nie przypuszczałem, że dodatkowo uczelnia na której studiuje (PWSZ w Białej Podlaskiej) dołączy do tej listy.

Szanse sprawdzenia swoich umiejętności dała mi lubelska firma „UHC CompuGROUP holding” – zajmująca się tworzeniem oprogramowania dla sektora medycznego. Określiłbym, że rekrutacja odbyła się w dwóch etapach – przesłanie CV zakończyło się prośbą o dostarczenie „próbek kodu” – aplikacji które napisałem do tej pory. Następnie po kilkudniowej ciszy otrzymałem telefon i odbyła się 2,5 godzinna rozmowa wstępna :). Kilka dni później dowiedziałem się – kto będzie moim opiekunem praktyk oraz do jakiego działu zostałem przydzielony (Dział Systemów Ekonomicznych). Pozostało mi dopiąć kwestie formalne o czym napiszę szerzej pod koniec.

Moim głównym celem było zmierzenie się z realnymi problemami na stanowisku programisty. Otrzymałem pierwsze zadanie – opiekun rzeczowo wytłumaczył mi co mam zrobić, jakiego wyniku oczekuje. Moje potknięcia i niedociągnięcia były traktowane z pełną wyrozumiałością, co niesamowicie mnie motywowało do cięższej pracy. Miałem czas na naukę, nie obawiałem się pytać nawet o najgłupsze rzeczy, atmosfera panująca w UHC przerosła moje najśmielsze oczekiwania. Mimo, że nie do końca zajmowałem się tym czym bym chciał – wcale mi to nie przeszkadzało! To co robiłem sprawiało mi ogromną przyjemność. :)

Praktyki uzmysłowiły mi, że jeżeli trafie w przyszłości do firmy takiej jak UHC to szybko się rozwinę. Szukajcie właśnie takiej pozytywnej atmosfery gdy stawiacie pierwsze kroki ku wymarzonej pracy czy też praktyki. Polecam przeczytać wpis Procenta – dzięki któremu zwracałem uwagę na wszystko co się wokół dzieje już podczas rozmowy kwalifikacyjnej.

Pozdrawiam i jeszcze raz dziękuję Markowi, Tomkowi, Andrzejowi, Gabrysiowi i Kamilowi za wspaniałą atmosferę i to wszystko czego się od Was nauczyłem. :)

Jak już wspomniałem największą przeszkodą do odbycia upragnionych praktyk była uczelnia na której studiuje. W PWSZ w Białej Podlaskiej studenci II roku na kierunku informatyka mają obowiązek odbycia 4 tygodniowej praktyki studenckiej – wypełniłem ten obowiązek jednak miejsce praktyk odbiegało dalece od moich oczekiwań. Byłem świadomy, że większość firm tworzących oprogramowanie przyjmuję tak naprawdę studentów III roku, aby mogli się zmierzyć z realiami programistycznymi. Postanowiłem fakt ukończenia III roku uwieńczyć zdobyciem miejsca gdzie postawie pierwsze kroki w prawdziwej pracy.

Poproszono mnie w firmie UHC o umowę na praktyki z moją uczelnią – pomyślałem, że nie będzie z tym problemu mimo, że będą to moje fakultatywne (ponadprogramowe) praktyki. Zadzwoniłem, więc do Działu Spraw Studenckich skąd skierowano mnie do Działu Praktyk.

Odpowiedz Pani kierownik działu: Nie wydajemy umowy na praktyki ponadprogramowe.

Nie straciłem jeszcze nadziei i zgodnie z podpowiedzią z firmy zadzwoniłem do Biura Karier które na niektórych uczelniach podpisuję takie umowy
i nie ma z tym najmniejszego problemu.

Odpowiedz biura karier: Jest Pan pierwszą osobą pytająca o takie rzeczy. Proszę się skierować do Działu Praktyk. :/

Ostatnia deska ratunku – napisałem do prorektora uczelni. Pismo wróciło do działu praktyk i zgadnijcie co ? :) Żal.pl – Odpowiedź identyczna jak wyżej – Nie wydajemy bo…. Ciekaw jestem jaką opinie wyraził Pan prorektor pod moim podaniem – Jeśli w ogóle jakąś wyraził… Nakreśliłem odpowiednim osobom w firmie całą sytuację – przesłano mi firmowy druk umowy między uczelnią, a UHC z którym osobiście (jak dotąd załatwiałem wszystko telefonicznie) udałem się na uczelnie. Odwiedziłem Biuro Karier, skąd powędrowałem do Instytutu Zarządzania (zabawnie ;)) tam Pani poinformowała mnie, że za dwa dni przekaże moją umowę odpowiedniej osobie.

Uwaga teraz najlepsza część tej parodii – W tym samym czasie w firmie ktoś stanął „na głowie” i znalazł sposób, aby podpisać ze mną umowę z wyłączeniem uczelni. Wróciłem do domu przeczytałem maila z tą informacja i sprawa była załatwiona. W mojej głowie pojawiła się myśl – skoro mam już wszystko załatwione to sprawdzę jednak czy uczelnia pomoże w rozwoju swojemu studentowi i podpisze przedłożony druk. Mijają dwa dni – docieram na uczelnie o wyznaczonej godzinie, zgłaszam się do przemiłej Pani i… – „Ojej zapomniałam, ale zaraz zaniosę to Pani doktor..” :) – Uśmiechnąłem się tylko – Bez komentarza… Pani doktor zerknęła i poleciła mi iść z tym do dyrektora instytutu informatyki – paranoja. :) Wziąłem umowę – zrobiłem
z niej ładną kulkę i wyrzuciłem do kosza.

Oto w jaki sposób PWSZ w Białej Podlaskiej pomogło mi odbyć praktyki studenckie, oto jak władze uczelni wsparły moją własną inicjatywę, oto
w jaki sposób wsparły moją chęć rozwoju.

Brawo PWSZ!

Tylko dzięki postawie odpowiednich osób w firmie UHC nie kosztowało mnie to, więcej nerwów za co Bardzo Dziękuję.