Zamiast klawisza F7Kompilacja - rozumiana w najszerszym sensie "budowania" wynikowej aplikacji - to najwyraźniej całkiem serious business. Używając wyłącznie jednego IDE (zwłaszcza gdy jest nim Visual Studio), można długo nie zdawać sobie z tego sprawy. W końcu jedną z funkcji środowisk programistycznych jest właśnie maksymalne uproszczenie tego procesu. Idealnie ze strony użytkownika wymagane jest tylko wydanie polecenia zbudowania projektu, a czasem - w przypadku budowania w tle - nawet i to nie jest potrzebne.
Nie zawsze jednak tak było i także obecnie nie zawsze proces kompilacji programu może być czymś, co uważamy za automatycznie załatwione. Wiedzą o tym zwłaszcza aktywni uczestnicy projektów open source, a szczególnie tych pisanych w językach bez jedynie słusznych IDE czy kompilatorów - takich jak C, C++ czy Java. Nic dziwnego, że właśnie z ich otoczenia wywodzą się systemy zautomatyzowanego budowania projektów.
Starym, wysłużonym i trochę już niedzisiejszym, ale wciąż szeroko używanym jest GNU Make. To z niego prawdopodobnie wywodzą się takie podstawowe koncepcje automatycznej kompilacji jak choćby target, czyli rodzaju "punktu wejścia" całego procesu. Dwa polecenia typowo służące zainstalowaniu programu ze źródeł na systemach linuksowych:
to właśnie wywołania GNU Make dla dwóch różnych targetów: domyślnego (uruchamiającego kompilację) i install (wykonującego inne czynności instalacyjne). Między targetami występują acykliczne zależności, określające wymaganą kolejność przeprowadzania poszczególnych kroków procesu budowy, a także pozwalające na pominięcie tych, które nie są aktualnie potrzebne. Dla przykładu, domyślny target może zajmować się linkowaniem, więc do działania wymagać skompilowanych modułów. Zależeć wtedy będzie od targetów, które zajmują się właśnie kompilacją. Przy dobrze napisanym pliku makefile wykonają się jedynie te odnoszące się do plików z kodem, w których faktycznie nastąpiły zmiany od czasu ostatniej budowy projektu.
Ponieważ zarówno składnia, jak i możliwości GNU Make (ograniczające się głównie do uruchamiania poleceń powłoki) pozostawiają wiele do życzenia, pojawiły się w końcu inne tego typu narzędzia. Potrzebowała ich głównie wieloplatformowa Java i stąd wziął się Apache Ant (skrót od Another Neat Tool). Nie straszy on już składnią opartą na tabulatorach; zamiast tego straszy XML-em ;-) Mimo większej przenośności międzysystemowej (abstrakcja operacji na plikach i katalogach) nadal brakuje mu jednak uniwersalności językowej, która zresztą nie wydaje się wcale celem istnienia Anta. Pomimo wyraźnego zorientowania na Javę da się go jednak z powodzeniem używać w projektach pisanych również w innych językach.
Te dwa rozwiązania to oczywiście nie jedyne systemy automatycznego budowania, z którymi możemy się spotkać. Z innych ciekawe są chociażby CMake czy Apache Maven. Warto się z nimi zapoznać, by na widok paczki, która oprócz kodu zawiera tylko plik build.xml lub makefile nie wpadać w popłoch :)
Porady odnośnie ubarwiania koduWszyscy wiemy, że Notatnik to bardzo dobry edytor kodu. Wystarcza w zupełności, o ile tylko jesteśmy w stanie zorientować się w gąszczu liter, cyfr i symboli bez żadnych wizualnych wskazówek w postaci ich kolorowania. Jakoś dziwnym trafem miażdżąca większość programistów preferuje jednak edytować kod odpowiednio "odmalowany" przez IDE. Widać nie potrafią docenić piękna kodowania na monochromatycznym monitorze ;-)
A nieco poważniej mówiąc: kolorowanie kodu to istotna sprawa, gdyż jest to kwestia komfortu naszych drogocennych narządów wzroku. Ponieważ miałem do czynienia z wieloma edytorami kodu i środowiskami programistycznymi, wydaje mi się, że mogę dość sensownie wypowiedzieć się na temat tego, jak należy ustawić kolory dla poszczególnych składników kodu, by były one komfortowe.

Najważniejszy jest tu prawdopodobnie odpowiedni kontrast, który nie wyraża się wyłącznie różnicą jasności między tłem a tekstem - zwłaszcza w systemie RGB. Powiedziałbym zresztą, że dla każdego jest to kwestia raczej subiektywna. Znam osoby, które świetnie czują się w kolorystyce rodem niemal z Matriksa: czarne tło i biały tekst, który miejscami przechodzi w jaskrawe kolory, wyraźnie odcinające się na ciemnym ekranie (jak zielony lub purpurowy). Pozwolę sobie jednak zaryzykować stwierdzenie, że takich osób nie ma zbyt wiele :) Powszechniejsza zdaje się konfiguracja z jasnym tłem; ma ona też tę zaletę, że po przełączeniu się do innego okna raczej nie doznamy żadnego "szoku świetlnego", jako że dokumentacje i większość stron internetowych trzymają się raczej jasnych barw.
Zaznaczam jednak, że 'jasne' tło nie musi wcale znaczyć 'białe'. Dopasowując kontrast, dobrze jest poeksperymentować z tłem lekko żółtym, zielonym czy niebieskim. Nie należy aczkolwiek przesadzać i ustawiać mniej niż ~80-procentową intensywność w którymś z kanałów RGB - w efekcie tło będzie najprawdopodobniej zbyt ciemne.
Analogicznie warto też przyjrzeć się domyślnemu kolorowi kodu (zazwyczaj jest to ten stosowany do identyfikatorów w rodzaju zmiennych lokalnych). Nie musi on wcale być absolutnie czarny; zamiast tego można wypróbować coś w rodzaju RGB(30, 30, 30).

Oczywiście ów domyślny kolor kodu to zazwyczaj tylko jedna z wielu barw używanych przez IDE. Obecnie środowiska wyróżniają mnóstwo osobnych elementów kodu, pozwalając każdemu z nich mieć przypisany inny kolor. Nie zalecałbym jednak przesady w korzystaniu z tej funkcjonalności, bo przy odrobinie źle pojętej kreatywności możemy otrzymać schemat kolorów świecący niczym choinka, gdzie dodatkowo najdłuższy ciąg o tej samej barwie nie liczy więcej niż dwa wyrazy. Pamiętajmy, że tutaj ważna jest użyteczność. To, jak bardzo dany element jest wyróżniony i wygląda inaczej niż inne, powinno odpowiadać jego ważności. Typowa kolejność, począwszy od najbardziej istotnych tokenów, wygląda mniej więcej tak:
Ta lista może rzecz jasna podlegać dostosowaniu pod własne upodobania, a także pod możliwości używanego IDE (część nie obsługuje niestety kolorowania semantycznego, które rozróżnia np. typy od innych nazw). Każdy język dodałby tu też specyficzne dla siebie elementy, sytuujące się zazwyczaj gdzieś w drugiej połowie stawki. W końcu, wewnątrz każdej z tych grup możliwe są też dodatkowe rozróżnienia - lecz, jak już wspomniałem, należy korzystać z nich ostrożnie.
Triki z PowerShellem #16 – ParametryPisząc mniej lub bardziej regularnie o PowerShellu, zdołałem zaprezentować całkiem pokaźną kolekcję różnych skryptów. Część z nich do działania wymagała podania dodatkowych danych. Jeśli są one w miarę niezmienne, można je zapisać w samym kodzie jako pseudo-stałe. Jeżeli jednak każde użycie skryptu może potencjalnie potrzebować innych wartości, wtedy najlepiej pobawić się z jego parametrami.
W PowerShellu do specyfikowania argumentów służy słowo kluczowe param. Można je stosować zarówno do samych skryptów, ale także do zawartych w nich funkcji. Tak jest - może nie wspominałem o tym wcześniej, ale w PSh jak najbardziej można definiować własne funkcje na użytek lokalny skryptu:
W obu przypadkach (skryptów i funkcji) instrukcja param powinna znaleźć się na samym początku i wystąpić co najwyżej raz.
Składnia deklaracji parametrów jest raczej prosta i wygląda następująco:
Kolejne elementy oddzielamy w niej przecinkami. Dla każdego z nich wartośćDomyślna nie jest obowiązkowa, lecz niepodanie jej nie czyni wcale argumentu obowiązkowym. Zamiast tego otrzyma on wartość "neutralną" (np. $null dla obiektów), jeśli nie zostanie przypisany w wywołaniu funkcji/skryptu. Żeby uczynić argument rzeczywiście niezbędnym, należy po prostu... rzucić wyjątek, jeśli nie został on użyty:
Może to się wydawać dziwne, ale nie zapominajmy, że języki powłok takich jak PowerShell są interpretowane Dlatego błąd w postaci braku wymaganego parametru (który normalnie wykryty by został podczas kompilacji) może dać o sobie znać dopiero w czasie wykonania.
Każdemu parametrowi możemy też przypisać typ, którym może być klasa z .NET-owego frameworka lub któryś z typów wbudowanych. Oczywiście nie musimy tego robić. Wtedy jednak będziemy mieli do czynienia z nieokreślonym obiektem (klasy System.Object), którego rodzaj możemy ewentualnie sprawdzić później (np. metodą GetType).
Specjalnym typem parametru jest switch, czyli przełącznik. Tworzy on parametr, któremu nie podajemy wartości, a jedynie uwzględniamy w wywołaniu (albo i nie). Jest to więc flaga podobna do Recurse czy -Verbose ze standardowych komend PowerShella lub tysięcy podobnych flag w programach i poleceniach z innych shelli. Semantycznie taki przełącznik jest potem zmienną logiczną typu bool:
To mniej więcej tyle, jeśli chodzi o definiowanie parametrów dla funkcji i skryptów. Jak teraz wygląda ich przekazywanie w trakcie wywołania?... No cóż, odpowiedź jest prosta: dokładnie tak samo, jak w przypadku wbudowanych komend PowerShella. Przede wszystkim możemy podawać ich nazwę poprzedzoną myślnikiem oraz wartość:
Nie jest to jednak zawsze konieczne. Zamiast tego możemy zdać się na ich kolejność w deklaracji param, co pozwala ominąć podawanie ich nazw w wywołaniu:
Pamiętajmy tylko, że skrypty (rzadziej funkcje) mogą mieć nierzadko i kilkanaście parametrów. Pomijanie ich nazw na pewno nie wpłynie wtedy pozytywnie na czytelność.
Styl dla kodu w WordzieDokumenty zawierające wstawione fragmenty kodu to zazwyczaj artykuły w sieci formatowane przy pomocy znaczników HTML. Rzadziej pojawia się potrzeba wstawienia listingu programu do tekstu edytowanego w pakiecie biurowym, ale jeśli już takowa zajdzie, to warto wiedzieć, jak to zrobić. A właściwie: jak to zrobić (w miarę) dobrze :)
Należy mianowicie pamiętać o tym, że poważne edytory tekstu pozwalają na zgrupowanie ustawień formatowania tekstu w postaci styli. Analogia do klas CSS jest tu dość znaczna, chociaż występują pewne drobne różnice. Jednak i tu, i tu mamy do czynienia z narzędziem, które powinno wykonywać większość pracy związanej z nadawaniem tekstowi wyglądu. Oczywiście miejscowe pogrubienia czy podkreślenia są więcej niż dopuszczalne, ale dla większych odstępstw w formatowaniu - które zwykle mają jeszcze uzasadnienie merytoryczne - należy korzystać z istniejących stylów lub definiować własne. Pod to kryterium podpada na pewno wstawianie do tekstu kawałków kodu.
Niestety, twórcy Worda z pakietu Office uznali najwyraźniej, że niepotrzebny jest predefiniowany styl dla kodu, więc trzeba go sobie stworzyć we własnym zakresie. Należy wówczas pamiętać o:
p i br w HTML. Wciśnięcie klawisza Enter dodaje nam jednak nowy akapit, co domyślnie oznacza również wstawienie sporego odstępu pionowego. Nie chcemy takiego odstępu w linijkach kodu. Dlatego powinniśmy uaktywnić opcję Nie dodawaj odstępu między akapitami o tym samym stylu w ustawieniach akapitu.
Stare pliki INIJest coś takiego jak aplikacje typu portable. Charakteryzują się tym, że nie wymagają instalacji i nie zostawiają żadnych "śladów" w systemie poza swoim własnym folderem. Takie programy są praktyczne, jeśli musimy korzystać z wielu różnych, nieswoich komputerów - wtedy można je przenieść na nośniku typu pendrive i uruchamiać bezpośrednio z niego.
Oczywiście nasze własne aplikacje nie muszą należeć do tej kategorii. Inaczej musielibyśmy na przykład zrezygnować z możliwości zapisywania ustawień programu w Rejestrze... Hmm, ale czy akurat tutaj jest czego żałować? :)
Ano niekoniecznie. Dawno, dawno temu popularnym sposobem przechowywania konfiguracji były pliki o rozszerzeniu .ini. Są to bardzo proste pliki tekstowe, zawierające pary klucz-wartość pogrupowane w sekcje. Składnia takiego pliku wygląda następująco:
[Sekcja2]
Klucz="Ala ma kota"
W Windows API wciąż istnieje interfejs pozwalający na odczytywanie i zapisywanie danych z takich plików, chociaż jest on trzymany podobno tylko dla kompatybilności. Obejmuje on funkcje specjalizujące się w obsłudze konkretnego pliku - mianowicie win.ini z głównego katalogu Windows - ale także dowolnego pliku .ini o podanej przez nas nazwie. Tymi bardziej elastycznymi funkcjami są:
GetPrivateProfileInt, GetPrivateProfileString, GetPrivateProfileStructWritePrivateProfileString, WritePrivateProfileStructGetPrivateProfileSectionNames) oraz listy kluczy w sekcji (GetPrivateProfileSection)Ich użycie jest dość proste. Jeśli na przykład chcielibyśmy pobrać wartość liczbową z powyższego pliku, to wystarczy poniższe wywołanie, o ile jest on zapisany w bieżącym katalogu jako plik.ini:
Dość podobnie wygląda korzystanie z pozostałych funkcji operujących na pojedynczych wartościach.
Dzisiaj pliki .ini są już trochę reliktem przeszłości, ale wydaje mi się, że do niektórych prostych zastosowań nadają się całkiem dobrze. A jeśli zdarzy się ten niefortunny przypadek, iż w którejś z przyszłych wersji Windows support dla nich zostanie porzucony, to cóż... składniowo są one na tyle proste, że ich parsowanie nie powinno być problemem ;-)
Triki z PowerShellem #14 – Moja własna mała konsolkaJak zdołałem (mam nadzieję) pokazać w kilkunastu notkach na temat PowerShella, narzędzie to pozwala na (pół)automatyczne wykonywanie wielu niekiedy skomplikowanych operacji, o ile tylko potrafimy je zakodować w postaci odpowiednich skryptów. Możemy więc ułatwić sobie życie szybkim uploadem na serwer FTP, wysyłaniem maili, a nawet (ło kurczę!) uaktualnianiem statusu na Twitterze :) Kiedyś możemy jednak chcieć takie pojedyncze rozwiązania złożyć w jakąś większą całość - na przykład w tytułową "małą własną konsolkę".
O co chodzi? W skrócie: o coś w rodzaju własnego shella, przyjmującego ograniczony i ściśle określony zestaw poleceń, pozwalających na wykonywanie prostych czynności. Różnica względem normalnej powłoki jest taka, iż komendy te mają być w założeniu bardzo wysokopoziomowe - każda z opisywanych dotąd przeze mnie powershellowych "sztuczek" podpadałaby pod li tylko jedno polecenie, jeśli w ogóle. Najbliższym graficznym odpowiednikiem czegoś takiego jest pasek narzędzi lub skrótów do programów.
Aby nasz mały shell stał się faktem, potrzebujemy tylko kilku rzeczy, wśród których są:
Read-Host, nad którą nie ma co się rozwodzić w jakiś specjalny sposób. Ot, po prostu daje nam w wyniku linijkę tekstu wpisaną do konsoli. Jeśli użyjemy parametru Prompt, nasz shell może mieć ładny znak zachęty :)switch jest tu niemal zbytkiem, zwłaszcza że w PowerShellu posiada on pożyteczny parametr -wildcard, pozwalający na dopasowanie ciągów znaków do wzorców zawierających symbole wieloznaczne (jak np. * lub ?). Dzięki temu można ograniczyć konieczność wpisywania całych nazw poleceń, jeśli jednoznaczna jest już sama pierwsza litera ("t*" zamiast "tweet", itp.).System.Diagonistics.Process i jej metody Start - czegoś w rodzaju arcyprzydatnej kiedyś funkcji Windows API o nazwie ShellExecute. Jeśli zaś chodzi o przekazywanie parametrów, to nie zapominajmy o metodach do obsługi stringów - cała klasa System.String jest przecież dostępna.|) możemy sobie z takimi aplikacjami radzić. PowerShell jest zresztą dobrym narzędziem do tworzenia używalnych front-endów do tego rodzaju programów.%ERRORLEVEL%, zawierającej kod wyjścia ostatnio uruchomionego programu. W PSh. jej odpowiednik ma bardziej opisową nazwę: $LASTEXITCODE. Przypomnieć warto, że dla kodów wyjścia wartością oznaczającą poprawne wykonanie programu jest zero.Składając te elementy w całość, możemy utworzyć shella z wygodnym dla nas zestawem poleceń. Kto wie, może będzie on nam odpowiadał bardziej niż pełne ikonek, kolorowe paski narzędzi :)
Zależności między projektami w Visual StudioZdarza się, że pracuje nad złożonym systemem, na który składa się kilka osobnych projektów. IDE znają dobrze takie przypadki i potrafią je obsługiwać - stąd chociażby pojęcie solution (dawniej workspace) w Visual Studio. Dla pojedynczych aplikacji i bibliotek wydaje się ono zbędne, jednak staje się nieodzowne wtedy, gdy nasze projekty zależą od siebie.
Typowa sytuacja to wspólna biblioteka (framework, engine czy co jeszcze kto woli) rozwijana razem z programami, które z niej korzystają. (W najprostszym przypadku to może być po prostu jakaś aplikacja testowa). Wówczas pojawiają się zależności między projektami na etapie ich budowania: wynik szeroko pojętej "kompilacji" jednego jest wejściem do procesu budowania innego. Jeśli nie poświęcimy temu faktowi należytej uwagi, to mogą nas czekać kłopoty. W najlepszym razie jest to konieczność wciskania F7 (Build Solution) więcej niż raz, aż do zbudowania wszystkich projektów. W gorszym - uruchamianie (i debugowanie!) aplikacji korzystającej z nieaktualnej, bo nieprzekompilowanej wersji biblioteki.
Zależności między projektami w procesie budowania da się na szczęście określić. W Visual Studio służy do tego opcja Project Dependencies z menu - a jakże - Project. Możemy w niej określić dla każdego projektu, z jakimi innymi projektami z tego samego solution jest on powiązany, czyli które z nich powinny być już wcześniej od niego zbudowane. Na podstawie tak podanej sieci zależności da się następnie określić właściwą kolejności "kompilacji" dla wszystkich projektów w danym solution. VS oczywiście to czyni, używając do tego zapewne sortowania topologicznego w analogiczny sposób jak dla kompilacji jednego projektu składającego się z wielu plików.